@machina.ai/cell-cli-core 1.38.1-rc2 → 1.40.1-rc2

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 (822) hide show
  1. package/dist/docs/AFTER_MERGE_PROMPT.md +1 -1
  2. package/dist/docs/admin/enterprise-controls.md +1 -1
  3. package/dist/docs/changelogs/index.md +42 -0
  4. package/dist/docs/changelogs/latest.md +254 -361
  5. package/dist/docs/changelogs/preview.md +237 -406
  6. package/dist/docs/cli/acp-mode.md +6 -6
  7. package/dist/docs/cli/auto-memory.md +143 -0
  8. package/dist/docs/cli/checkpointing.md +5 -5
  9. package/dist/docs/cli/cli-reference.md +12 -11
  10. package/dist/docs/cli/creating-skills.md +2 -2
  11. package/dist/docs/cli/custom-commands.md +15 -14
  12. package/dist/docs/cli/enterprise.md +17 -14
  13. package/dist/docs/cli/gemini-ignore.md +2 -2
  14. package/dist/docs/cli/generation-settings.md +21 -20
  15. package/dist/docs/cli/model-routing.md +2 -2
  16. package/dist/docs/cli/model-steering.md +1 -1
  17. package/dist/docs/cli/plan-mode.md +11 -6
  18. package/dist/docs/cli/sandbox.md +7 -5
  19. package/dist/docs/cli/settings.md +32 -28
  20. package/dist/docs/cli/system-prompt.md +8 -8
  21. package/dist/docs/cli/telemetry.md +18 -11
  22. package/dist/docs/cli/themes.md +2 -2
  23. package/dist/docs/cli/trusted-folders.md +41 -13
  24. package/dist/docs/cli/tutorials/mcp-setup.md +1 -1
  25. package/dist/docs/cli/tutorials/memory-management.md +3 -1
  26. package/dist/docs/cli/tutorials/plan-mode-steering.md +2 -2
  27. package/dist/docs/cli/tutorials/session-management.md +1 -1
  28. package/dist/docs/cli/tutorials/shell-commands.md +1 -1
  29. package/dist/docs/cli/tutorials/task-planning.md +3 -3
  30. package/dist/docs/core/index.md +5 -6
  31. package/dist/docs/core/local-model-routing.md +1 -1
  32. package/dist/docs/core/remote-agents.md +1 -1
  33. package/dist/docs/core/subagents.md +38 -8
  34. package/dist/docs/extensions/best-practices.md +5 -4
  35. package/dist/docs/extensions/reference.md +6 -5
  36. package/dist/docs/extensions/releasing.md +6 -5
  37. package/dist/docs/extensions/writing-extensions.md +11 -11
  38. package/dist/docs/get-started/{authentication.md → authentication.mdx} +139 -93
  39. package/dist/docs/get-started/gemini-3.md +1 -1
  40. package/dist/docs/get-started/index.md +4 -4
  41. package/dist/docs/get-started/installation.mdx +201 -0
  42. package/dist/docs/hooks/best-practices.md +18 -17
  43. package/dist/docs/hooks/index.md +10 -8
  44. package/dist/docs/hooks/reference.md +10 -10
  45. package/dist/docs/ide-integration/ide-companion-spec.md +14 -14
  46. package/dist/docs/ide-integration/index.md +4 -4
  47. package/dist/docs/index.md +2 -2
  48. package/dist/docs/integration-tests.md +84 -2
  49. package/dist/docs/issue-and-pr-automation.md +8 -7
  50. package/dist/docs/npm.md +2 -2
  51. package/dist/docs/reference/commands.md +11 -11
  52. package/dist/docs/reference/configuration.md +150 -47
  53. package/dist/docs/reference/keyboard-shortcuts.md +79 -2
  54. package/dist/docs/reference/memport.md +2 -3
  55. package/dist/docs/reference/policy-engine.md +60 -26
  56. package/dist/docs/reference/tools.md +38 -4
  57. package/dist/docs/release-confidence.md +1 -1
  58. package/dist/docs/releases.md +19 -19
  59. package/dist/docs/resources/faq.md +5 -5
  60. package/dist/docs/resources/tos-privacy.md +10 -9
  61. package/dist/docs/resources/troubleshooting.md +17 -16
  62. package/dist/docs/resources/uninstall.md +5 -4
  63. package/dist/docs/sidebar.json +13 -1
  64. package/dist/docs/tools/ask-user.md +3 -3
  65. package/dist/docs/tools/file-system.md +7 -7
  66. package/dist/docs/tools/mcp-resources.md +44 -0
  67. package/dist/docs/tools/mcp-server.md +42 -39
  68. package/dist/docs/tools/shell.md +5 -5
  69. package/dist/docs/tools/tracker.md +61 -0
  70. package/dist/package.json +5 -4
  71. package/dist/src/agent/content-utils.d.ts +0 -6
  72. package/dist/src/agent/content-utils.js +0 -14
  73. package/dist/src/agent/content-utils.js.map +1 -1
  74. package/dist/src/agent/content-utils.test.js +1 -18
  75. package/dist/src/agent/content-utils.test.js.map +1 -1
  76. package/dist/src/agent/event-translator.js +8 -3
  77. package/dist/src/agent/event-translator.js.map +1 -1
  78. package/dist/src/agent/event-translator.test.js +14 -9
  79. package/dist/src/agent/event-translator.test.js.map +1 -1
  80. package/dist/src/agent/legacy-agent-session.js +9 -3
  81. package/dist/src/agent/legacy-agent-session.js.map +1 -1
  82. package/dist/src/agent/legacy-agent-session.test.js +4 -3
  83. package/dist/src/agent/legacy-agent-session.test.js.map +1 -1
  84. package/dist/src/agent/tool-display-utils.d.ts +30 -0
  85. package/dist/src/agent/tool-display-utils.js +69 -0
  86. package/dist/src/agent/tool-display-utils.js.map +1 -0
  87. package/dist/src/agent/tool-display-utils.test.js +101 -0
  88. package/dist/src/agent/tool-display-utils.test.js.map +1 -0
  89. package/dist/src/agent/types.d.ts +25 -5
  90. package/dist/src/agents/a2aUtils.js +28 -15
  91. package/dist/src/agents/a2aUtils.js.map +1 -1
  92. package/dist/src/agents/a2aUtils.test.js +43 -0
  93. package/dist/src/agents/a2aUtils.test.js.map +1 -1
  94. package/dist/src/agents/agent-tool.d.ts +31 -0
  95. package/dist/src/agents/agent-tool.js +155 -0
  96. package/dist/src/agents/agent-tool.js.map +1 -0
  97. package/dist/src/agents/agent-tool.test.js +110 -0
  98. package/dist/src/agents/agent-tool.test.js.map +1 -0
  99. package/dist/src/agents/agentLoader.d.ts +79 -4
  100. package/dist/src/agents/agentLoader.js +40 -2
  101. package/dist/src/agents/agentLoader.js.map +1 -1
  102. package/dist/src/agents/agentLoader.test.js +32 -0
  103. package/dist/src/agents/agentLoader.test.js.map +1 -1
  104. package/dist/src/agents/browser/analyzeScreenshot.js +1 -1
  105. package/dist/src/agents/browser/analyzeScreenshot.js.map +1 -1
  106. package/dist/src/agents/browser/analyzeScreenshot.test.js +19 -7
  107. package/dist/src/agents/browser/analyzeScreenshot.test.js.map +1 -1
  108. package/dist/src/agents/browser/browserAgentInvocation.d.ts +2 -2
  109. package/dist/src/agents/browser/browserAgentInvocation.js +2 -1
  110. package/dist/src/agents/browser/browserAgentInvocation.js.map +1 -1
  111. package/dist/src/agents/browser/browserAgentInvocation.test.js +61 -17
  112. package/dist/src/agents/browser/browserAgentInvocation.test.js.map +1 -1
  113. package/dist/src/agents/browser/mcpToolWrapper.js +1 -1
  114. package/dist/src/agents/browser/mcpToolWrapper.js.map +1 -1
  115. package/dist/src/agents/browser/mcpToolWrapper.test.js +22 -10
  116. package/dist/src/agents/browser/mcpToolWrapper.test.js.map +1 -1
  117. package/dist/src/agents/codebase-investigator.js +2 -2
  118. package/dist/src/agents/codebase-investigator.js.map +1 -1
  119. package/dist/src/agents/generalist-agent.js +3 -2
  120. package/dist/src/agents/generalist-agent.js.map +1 -1
  121. package/dist/src/agents/generalist-agent.test.js +1 -0
  122. package/dist/src/agents/generalist-agent.test.js.map +1 -1
  123. package/dist/src/agents/local-executor.d.ts +1 -1
  124. package/dist/src/agents/local-executor.js +10 -7
  125. package/dist/src/agents/local-executor.js.map +1 -1
  126. package/dist/src/agents/local-executor.test.js +5 -3
  127. package/dist/src/agents/local-executor.test.js.map +1 -1
  128. package/dist/src/agents/local-invocation.d.ts +2 -2
  129. package/dist/src/agents/local-invocation.js +8 -2
  130. package/dist/src/agents/local-invocation.js.map +1 -1
  131. package/dist/src/agents/local-invocation.test.js +29 -13
  132. package/dist/src/agents/local-invocation.test.js.map +1 -1
  133. package/dist/src/agents/registry.d.ts +2 -0
  134. package/dist/src/agents/registry.js +20 -19
  135. package/dist/src/agents/registry.js.map +1 -1
  136. package/dist/src/agents/registry.test.js +19 -30
  137. package/dist/src/agents/registry.test.js.map +1 -1
  138. package/dist/src/agents/remote-invocation.d.ts +3 -4
  139. package/dist/src/agents/remote-invocation.js +2 -1
  140. package/dist/src/agents/remote-invocation.js.map +1 -1
  141. package/dist/src/agents/remote-invocation.test.js +45 -18
  142. package/dist/src/agents/remote-invocation.test.js.map +1 -1
  143. package/dist/src/agents/skill-extraction-agent.d.ts +3 -2
  144. package/dist/src/agents/skill-extraction-agent.js +99 -56
  145. package/dist/src/agents/skill-extraction-agent.js.map +1 -1
  146. package/dist/src/agents/skill-extraction-agent.test.js +54 -0
  147. package/dist/src/agents/skill-extraction-agent.test.js.map +1 -0
  148. package/dist/src/availability/policyCatalog.js +1 -1
  149. package/dist/src/availability/policyCatalog.js.map +1 -1
  150. package/dist/src/availability/policyCatalog.test.js +1 -1
  151. package/dist/src/availability/policyCatalog.test.js.map +1 -1
  152. package/dist/src/code_assist/oauth2.js +14 -4
  153. package/dist/src/code_assist/oauth2.js.map +1 -1
  154. package/dist/src/commands/memory.d.ts +77 -0
  155. package/dist/src/commands/memory.js +494 -0
  156. package/dist/src/commands/memory.js.map +1 -1
  157. package/dist/src/commands/memory.test.js +720 -1
  158. package/dist/src/commands/memory.test.js.map +1 -1
  159. package/dist/src/config/config-agents-reload.test.js +26 -31
  160. package/dist/src/config/config-agents-reload.test.js.map +1 -1
  161. package/dist/src/config/config.d.ts +24 -10
  162. package/dist/src/config/config.js +148 -82
  163. package/dist/src/config/config.js.map +1 -1
  164. package/dist/src/config/config.test.js +373 -10
  165. package/dist/src/config/config.test.js.map +1 -1
  166. package/dist/src/config/constants.d.ts +1 -0
  167. package/dist/src/config/constants.js +2 -0
  168. package/dist/src/config/constants.js.map +1 -1
  169. package/dist/src/config/defaultModelConfigs.js +7 -7
  170. package/dist/src/config/defaultModelConfigs.js.map +1 -1
  171. package/dist/src/config/memory.js +1 -1
  172. package/dist/src/config/memory.js.map +1 -1
  173. package/dist/src/config/path-validation.test.js +15 -6
  174. package/dist/src/config/path-validation.test.js.map +1 -1
  175. package/dist/src/config/projectRegistry.js +113 -32
  176. package/dist/src/config/projectRegistry.js.map +1 -1
  177. package/dist/src/config/projectRegistry.test.js +51 -0
  178. package/dist/src/config/projectRegistry.test.js.map +1 -1
  179. package/dist/src/config/storage.d.ts +5 -1
  180. package/dist/src/config/storage.js +14 -1
  181. package/dist/src/config/storage.js.map +1 -1
  182. package/dist/src/config/storage.test.js +12 -0
  183. package/dist/src/config/storage.test.js.map +1 -1
  184. package/dist/src/confirmation-bus/message-bus.d.ts +4 -1
  185. package/dist/src/confirmation-bus/message-bus.js +39 -1
  186. package/dist/src/confirmation-bus/message-bus.js.map +1 -1
  187. package/dist/src/confirmation-bus/message-bus.test.js +43 -0
  188. package/dist/src/confirmation-bus/message-bus.test.js.map +1 -1
  189. package/dist/src/context/config/configLoader.d.ts +13 -0
  190. package/dist/src/context/config/configLoader.js +65 -0
  191. package/dist/src/context/config/configLoader.js.map +1 -0
  192. package/dist/src/context/config/configLoader.test.d.ts +6 -0
  193. package/dist/src/context/config/configLoader.test.js +79 -0
  194. package/dist/src/context/config/configLoader.test.js.map +1 -0
  195. package/dist/src/context/config/profiles.d.ts +17 -0
  196. package/dist/src/context/config/profiles.js +93 -0
  197. package/dist/src/context/config/profiles.js.map +1 -0
  198. package/dist/src/context/config/registry.d.ts +21 -0
  199. package/dist/src/context/config/registry.js +32 -0
  200. package/dist/src/context/config/registry.js.map +1 -0
  201. package/dist/src/context/config/schema.d.ts +45 -0
  202. package/dist/src/context/config/schema.js +47 -0
  203. package/dist/src/context/config/schema.js.map +1 -0
  204. package/dist/src/context/config/types.d.ts +39 -0
  205. package/dist/src/context/config/types.js +7 -0
  206. package/dist/src/context/config/types.js.map +1 -0
  207. package/dist/src/context/contextManager.barrier.test.d.ts +6 -0
  208. package/dist/src/context/contextManager.barrier.test.js +56 -0
  209. package/dist/src/context/contextManager.barrier.test.js.map +1 -0
  210. package/dist/src/context/contextManager.d.ts +49 -0
  211. package/dist/src/context/contextManager.js +120 -0
  212. package/dist/src/context/contextManager.js.map +1 -0
  213. package/dist/src/context/eventBus.d.ts +28 -0
  214. package/dist/src/context/eventBus.js +27 -0
  215. package/dist/src/context/eventBus.js.map +1 -0
  216. package/dist/src/context/graph/behaviorRegistry.d.ts +28 -0
  217. package/dist/src/context/graph/behaviorRegistry.js +14 -0
  218. package/dist/src/context/graph/behaviorRegistry.js.map +1 -0
  219. package/dist/src/context/graph/builtinBehaviors.d.ts +11 -0
  220. package/dist/src/context/graph/builtinBehaviors.js +145 -0
  221. package/dist/src/context/graph/builtinBehaviors.js.map +1 -0
  222. package/dist/src/context/graph/fromGraph.d.ts +9 -0
  223. package/dist/src/context/graph/fromGraph.js +34 -0
  224. package/dist/src/context/graph/fromGraph.js.map +1 -0
  225. package/dist/src/context/graph/mapper.d.ts +16 -0
  226. package/dist/src/context/graph/mapper.js +16 -0
  227. package/dist/src/context/graph/mapper.js.map +1 -0
  228. package/dist/src/context/graph/render.d.ts +15 -0
  229. package/dist/src/context/graph/render.js +72 -0
  230. package/dist/src/context/graph/render.js.map +1 -0
  231. package/dist/src/context/graph/toGraph.d.ts +10 -0
  232. package/dist/src/context/graph/toGraph.js +172 -0
  233. package/dist/src/context/graph/toGraph.js.map +1 -0
  234. package/dist/src/context/graph/types.d.ts +139 -0
  235. package/dist/src/context/graph/types.js +36 -0
  236. package/dist/src/context/graph/types.js.map +1 -0
  237. package/dist/src/context/historyObserver.d.ts +27 -0
  238. package/dist/src/context/historyObserver.js +64 -0
  239. package/dist/src/context/historyObserver.js.map +1 -0
  240. package/dist/src/context/pipeline/contextWorkingBuffer.d.ts +33 -0
  241. package/dist/src/context/pipeline/contextWorkingBuffer.js +197 -0
  242. package/dist/src/context/pipeline/contextWorkingBuffer.js.map +1 -0
  243. package/dist/src/context/pipeline/contextWorkingBuffer.test.d.ts +6 -0
  244. package/dist/src/context/pipeline/contextWorkingBuffer.test.js +89 -0
  245. package/dist/src/context/pipeline/contextWorkingBuffer.test.js.map +1 -0
  246. package/dist/src/context/pipeline/environment.d.ts +27 -0
  247. package/dist/src/context/pipeline/environment.js +2 -0
  248. package/dist/src/context/pipeline/environment.js.map +1 -0
  249. package/dist/src/context/pipeline/environmentImpl.d.ts +28 -0
  250. package/dist/src/context/pipeline/environmentImpl.js +40 -0
  251. package/dist/src/context/pipeline/environmentImpl.js.map +1 -0
  252. package/dist/src/context/pipeline/environmentImpl.test.d.ts +1 -0
  253. package/dist/src/context/pipeline/environmentImpl.test.js +32 -0
  254. package/dist/src/context/pipeline/environmentImpl.test.js.map +1 -0
  255. package/dist/src/context/pipeline/inbox.d.ts +15 -0
  256. package/dist/src/context/pipeline/inbox.js +52 -0
  257. package/dist/src/context/pipeline/inbox.js.map +1 -0
  258. package/dist/src/context/pipeline/inbox.test.d.ts +1 -0
  259. package/dist/src/context/pipeline/inbox.test.js +36 -0
  260. package/dist/src/context/pipeline/inbox.test.js.map +1 -0
  261. package/dist/src/context/pipeline/orchestrator.d.ts +22 -0
  262. package/dist/src/context/pipeline/orchestrator.js +126 -0
  263. package/dist/src/context/pipeline/orchestrator.js.map +1 -0
  264. package/dist/src/context/pipeline/orchestrator.test.d.ts +6 -0
  265. package/dist/src/context/pipeline/orchestrator.test.js +154 -0
  266. package/dist/src/context/pipeline/orchestrator.test.js.map +1 -0
  267. package/dist/src/context/pipeline.d.ts +52 -0
  268. package/dist/src/context/pipeline.js +7 -0
  269. package/dist/src/context/pipeline.js.map +1 -0
  270. package/dist/src/context/processors/blobDegradationProcessor.d.ts +6 -0
  271. package/dist/src/context/processors/blobDegradationProcessor.js +127 -0
  272. package/dist/src/context/processors/blobDegradationProcessor.js.map +1 -0
  273. package/dist/src/context/processors/blobDegradationProcessor.test.d.ts +6 -0
  274. package/dist/src/context/processors/blobDegradationProcessor.test.js +72 -0
  275. package/dist/src/context/processors/blobDegradationProcessor.test.js.map +1 -0
  276. package/dist/src/context/processors/historyTruncationProcessor.d.ts +11 -0
  277. package/dist/src/context/processors/historyTruncationProcessor.js +61 -0
  278. package/dist/src/context/processors/historyTruncationProcessor.js.map +1 -0
  279. package/dist/src/context/processors/nodeDistillationProcessor.d.ts +8 -0
  280. package/dist/src/context/processors/nodeDistillationProcessor.js +167 -0
  281. package/dist/src/context/processors/nodeDistillationProcessor.js.map +1 -0
  282. package/dist/src/context/processors/nodeDistillationProcessor.test.d.ts +6 -0
  283. package/dist/src/context/processors/nodeDistillationProcessor.test.js +77 -0
  284. package/dist/src/context/processors/nodeDistillationProcessor.test.js.map +1 -0
  285. package/dist/src/context/processors/nodeTruncationProcessor.d.ts +8 -0
  286. package/dist/src/context/processors/nodeTruncationProcessor.js +109 -0
  287. package/dist/src/context/processors/nodeTruncationProcessor.js.map +1 -0
  288. package/dist/src/context/processors/nodeTruncationProcessor.test.d.ts +6 -0
  289. package/dist/src/context/processors/nodeTruncationProcessor.test.js +71 -0
  290. package/dist/src/context/processors/nodeTruncationProcessor.test.js.map +1 -0
  291. package/dist/src/context/processors/rollingSummaryProcessor.d.ts +8 -0
  292. package/dist/src/context/processors/rollingSummaryProcessor.js +129 -0
  293. package/dist/src/context/processors/rollingSummaryProcessor.js.map +1 -0
  294. package/dist/src/context/processors/rollingSummaryProcessor.test.d.ts +1 -0
  295. package/dist/src/context/processors/rollingSummaryProcessor.test.js +60 -0
  296. package/dist/src/context/processors/rollingSummaryProcessor.test.js.map +1 -0
  297. package/dist/src/context/processors/stateSnapshotAsyncProcessor.d.ts +9 -0
  298. package/dist/src/context/processors/stateSnapshotAsyncProcessor.js +75 -0
  299. package/dist/src/context/processors/stateSnapshotAsyncProcessor.js.map +1 -0
  300. package/dist/src/context/processors/stateSnapshotAsyncProcessor.test.d.ts +1 -0
  301. package/dist/src/context/processors/stateSnapshotAsyncProcessor.test.js +80 -0
  302. package/dist/src/context/processors/stateSnapshotAsyncProcessor.test.js.map +1 -0
  303. package/dist/src/context/processors/stateSnapshotProcessor.d.ts +9 -0
  304. package/dist/src/context/processors/stateSnapshotProcessor.js +130 -0
  305. package/dist/src/context/processors/stateSnapshotProcessor.js.map +1 -0
  306. package/dist/src/context/processors/stateSnapshotProcessor.test.d.ts +1 -0
  307. package/dist/src/context/processors/stateSnapshotProcessor.test.js +91 -0
  308. package/dist/src/context/processors/stateSnapshotProcessor.test.js.map +1 -0
  309. package/dist/src/context/processors/toolMaskingProcessor.d.ts +8 -0
  310. package/dist/src/context/processors/toolMaskingProcessor.js +194 -0
  311. package/dist/src/context/processors/toolMaskingProcessor.js.map +1 -0
  312. package/dist/src/context/processors/toolMaskingProcessor.test.d.ts +1 -0
  313. package/dist/src/context/processors/toolMaskingProcessor.test.js +50 -0
  314. package/dist/src/context/processors/toolMaskingProcessor.test.js.map +1 -0
  315. package/dist/src/context/system-tests/lifecycle.golden.test.d.ts +6 -0
  316. package/dist/src/context/system-tests/lifecycle.golden.test.js +195 -0
  317. package/dist/src/context/system-tests/lifecycle.golden.test.js.map +1 -0
  318. package/dist/src/context/system-tests/simulationHarness.d.ts +41 -0
  319. package/dist/src/context/system-tests/simulationHarness.js +88 -0
  320. package/dist/src/context/system-tests/simulationHarness.js.map +1 -0
  321. package/dist/src/context/testing/contextTestUtils.d.ts +44 -0
  322. package/dist/src/context/testing/contextTestUtils.js +176 -0
  323. package/dist/src/context/testing/contextTestUtils.js.map +1 -0
  324. package/dist/src/context/testing/testProfile.d.ts +7 -0
  325. package/dist/src/context/testing/testProfile.js +20 -0
  326. package/dist/src/context/testing/testProfile.js.map +1 -0
  327. package/dist/src/context/tracer.d.ts +19 -0
  328. package/dist/src/context/tracer.js +79 -0
  329. package/dist/src/context/tracer.js.map +1 -0
  330. package/dist/src/context/tracer.test.d.ts +6 -0
  331. package/dist/src/context/tracer.test.js +71 -0
  332. package/dist/src/context/tracer.test.js.map +1 -0
  333. package/dist/src/context/utils/contextTokenCalculator.d.ts +53 -0
  334. package/dist/src/context/utils/contextTokenCalculator.js +97 -0
  335. package/dist/src/context/utils/contextTokenCalculator.js.map +1 -0
  336. package/dist/src/context/utils/snapshotGenerator.d.ts +12 -0
  337. package/dist/src/context/utils/snapshotGenerator.js +43 -0
  338. package/dist/src/context/utils/snapshotGenerator.js.map +1 -0
  339. package/dist/src/core/agentChatHistory.d.ts +26 -0
  340. package/dist/src/core/agentChatHistory.js +50 -0
  341. package/dist/src/core/agentChatHistory.js.map +1 -0
  342. package/dist/src/core/client.js +3 -1
  343. package/dist/src/core/client.js.map +1 -1
  344. package/dist/src/core/client.test.js +4 -0
  345. package/dist/src/core/client.test.js.map +1 -1
  346. package/dist/src/core/contentGenerator.d.ts +8 -1
  347. package/dist/src/core/contentGenerator.js +46 -4
  348. package/dist/src/core/contentGenerator.js.map +1 -1
  349. package/dist/src/core/contentGenerator.test.js +174 -8
  350. package/dist/src/core/contentGenerator.test.js.map +1 -1
  351. package/dist/src/core/coreToolHookTriggers.d.ts +1 -1
  352. package/dist/src/core/coreToolHookTriggers.js +5 -1
  353. package/dist/src/core/coreToolHookTriggers.js.map +1 -1
  354. package/dist/src/core/coreToolHookTriggers.test.js +1 -1
  355. package/dist/src/core/coreToolHookTriggers.test.js.map +1 -1
  356. package/dist/src/core/geminiChat.d.ts +2 -1
  357. package/dist/src/core/geminiChat.js +7 -2
  358. package/dist/src/core/geminiChat.js.map +1 -1
  359. package/dist/src/core/geminiChat.test.js +19 -6
  360. package/dist/src/core/geminiChat.test.js.map +1 -1
  361. package/dist/src/core/geminiChat_network_retry.test.js +42 -0
  362. package/dist/src/core/geminiChat_network_retry.test.js.map +1 -1
  363. package/dist/src/core/localLiteRtLmClient.js +2 -0
  364. package/dist/src/core/localLiteRtLmClient.js.map +1 -1
  365. package/dist/src/core/localLiteRtLmClient.test.js +7 -0
  366. package/dist/src/core/localLiteRtLmClient.test.js.map +1 -1
  367. package/dist/src/core/loggingContentGenerator.js +19 -6
  368. package/dist/src/core/loggingContentGenerator.js.map +1 -1
  369. package/dist/src/core/loggingContentGenerator.test.js +55 -0
  370. package/dist/src/core/loggingContentGenerator.test.js.map +1 -1
  371. package/dist/src/core/prompts-substitution.test.js +1 -0
  372. package/dist/src/core/prompts-substitution.test.js.map +1 -1
  373. package/dist/src/core/prompts.d.ts +1 -1
  374. package/dist/src/core/prompts.js +2 -2
  375. package/dist/src/core/prompts.js.map +1 -1
  376. package/dist/src/core/prompts.test.js +39 -8
  377. package/dist/src/core/prompts.test.js.map +1 -1
  378. package/dist/src/generated/git-commit.d.ts +2 -2
  379. package/dist/src/generated/git-commit.js +2 -2
  380. package/dist/src/hooks/hookRunner.js +8 -0
  381. package/dist/src/hooks/hookRunner.js.map +1 -1
  382. package/dist/src/hooks/hookRunner.test.js +23 -0
  383. package/dist/src/hooks/hookRunner.test.js.map +1 -1
  384. package/dist/src/ide/ide-client.js +3 -4
  385. package/dist/src/ide/ide-client.js.map +1 -1
  386. package/dist/src/index.d.ts +7 -3
  387. package/dist/src/index.js +7 -2
  388. package/dist/src/index.js.map +1 -1
  389. package/dist/src/mcp/mcpLauncher.js +1 -1
  390. package/dist/src/mcp/mcpLauncher.js.map +1 -1
  391. package/dist/src/mcp/oauth-provider.test.js +24 -17
  392. package/dist/src/mcp/oauth-provider.test.js.map +1 -1
  393. package/dist/src/policy/config.d.ts +2 -0
  394. package/dist/src/policy/config.js +67 -12
  395. package/dist/src/policy/config.js.map +1 -1
  396. package/dist/src/policy/core-tools-mapping.test.d.ts +6 -0
  397. package/dist/src/policy/core-tools-mapping.test.js +44 -0
  398. package/dist/src/policy/core-tools-mapping.test.js.map +1 -0
  399. package/dist/src/policy/policies/agents.toml +10 -0
  400. package/dist/src/policy/policies/plan.toml +17 -43
  401. package/dist/src/policy/policies/read-only.toml +24 -38
  402. package/dist/src/policy/policy-engine.d.ts +1 -1
  403. package/dist/src/policy/policy-engine.js +72 -67
  404. package/dist/src/policy/policy-engine.js.map +1 -1
  405. package/dist/src/policy/policy-engine.test.js +71 -4
  406. package/dist/src/policy/policy-engine.test.js.map +1 -1
  407. package/dist/src/policy/sandboxPolicyManager.js +4 -4
  408. package/dist/src/policy/sandboxPolicyManager.js.map +1 -1
  409. package/dist/src/policy/shell-safety-regression.test.d.ts +6 -0
  410. package/dist/src/policy/shell-safety-regression.test.js +86 -0
  411. package/dist/src/policy/shell-safety-regression.test.js.map +1 -0
  412. package/dist/src/policy/shell-safety.test.js +24 -0
  413. package/dist/src/policy/shell-safety.test.js.map +1 -1
  414. package/dist/src/policy/shell-substitution.test.d.ts +6 -0
  415. package/dist/src/policy/shell-substitution.test.js +75 -0
  416. package/dist/src/policy/shell-substitution.test.js.map +1 -0
  417. package/dist/src/policy/toml-loader.test.js +25 -11
  418. package/dist/src/policy/toml-loader.test.js.map +1 -1
  419. package/dist/src/policy/types.d.ts +6 -2
  420. package/dist/src/policy/types.js +4 -2
  421. package/dist/src/policy/types.js.map +1 -1
  422. package/dist/src/prompts/promptProvider.d.ts +1 -1
  423. package/dist/src/prompts/promptProvider.js +41 -24
  424. package/dist/src/prompts/promptProvider.js.map +1 -1
  425. package/dist/src/prompts/promptProvider.test.js +36 -2
  426. package/dist/src/prompts/promptProvider.test.js.map +1 -1
  427. package/dist/src/prompts/snippets-memory-v2.test.d.ts +6 -0
  428. package/dist/src/prompts/snippets-memory-v2.test.js +94 -0
  429. package/dist/src/prompts/snippets-memory-v2.test.js.map +1 -0
  430. package/dist/src/prompts/snippets.d.ts +19 -1
  431. package/dist/src/prompts/snippets.js +33 -6
  432. package/dist/src/prompts/snippets.js.map +1 -1
  433. package/dist/src/prompts/snippets.legacy.d.ts +6 -1
  434. package/dist/src/prompts/snippets.legacy.js +14 -7
  435. package/dist/src/prompts/snippets.legacy.js.map +1 -1
  436. package/dist/src/prompts/utils.test.js +1 -0
  437. package/dist/src/prompts/utils.test.js.map +1 -1
  438. package/dist/src/routing/modelRouterService.js +1 -1
  439. package/dist/src/routing/modelRouterService.js.map +1 -1
  440. package/dist/src/sandbox/linux/LinuxSandboxManager.d.ts +2 -0
  441. package/dist/src/sandbox/linux/LinuxSandboxManager.js +43 -19
  442. package/dist/src/sandbox/linux/LinuxSandboxManager.js.map +1 -1
  443. package/dist/src/sandbox/linux/LinuxSandboxManager.test.js +16 -0
  444. package/dist/src/sandbox/linux/LinuxSandboxManager.test.js.map +1 -1
  445. package/dist/src/sandbox/linux/bwrapArgsBuilder.d.ts +3 -7
  446. package/dist/src/sandbox/linux/bwrapArgsBuilder.js +96 -105
  447. package/dist/src/sandbox/linux/bwrapArgsBuilder.js.map +1 -1
  448. package/dist/src/sandbox/linux/bwrapArgsBuilder.test.js +144 -41
  449. package/dist/src/sandbox/linux/bwrapArgsBuilder.test.js.map +1 -1
  450. package/dist/src/sandbox/macos/MacOsSandboxManager.js +19 -10
  451. package/dist/src/sandbox/macos/MacOsSandboxManager.js.map +1 -1
  452. package/dist/src/sandbox/macos/MacOsSandboxManager.test.js +24 -37
  453. package/dist/src/sandbox/macos/MacOsSandboxManager.test.js.map +1 -1
  454. package/dist/src/sandbox/macos/seatbeltArgsBuilder.d.ts +3 -9
  455. package/dist/src/sandbox/macos/seatbeltArgsBuilder.js +129 -96
  456. package/dist/src/sandbox/macos/seatbeltArgsBuilder.js.map +1 -1
  457. package/dist/src/sandbox/macos/seatbeltArgsBuilder.test.js +78 -77
  458. package/dist/src/sandbox/macos/seatbeltArgsBuilder.test.js.map +1 -1
  459. package/dist/src/sandbox/utils/fsUtils.d.ts +2 -3
  460. package/dist/src/sandbox/utils/fsUtils.js +12 -27
  461. package/dist/src/sandbox/utils/fsUtils.js.map +1 -1
  462. package/dist/src/sandbox/utils/fsUtils.test.js +87 -29
  463. package/dist/src/sandbox/utils/fsUtils.test.js.map +1 -1
  464. package/dist/src/sandbox/windows/GeminiSandbox.cs +186 -77
  465. package/dist/src/sandbox/windows/WindowsSandboxManager.d.ts +4 -16
  466. package/dist/src/sandbox/windows/WindowsSandboxManager.js +138 -204
  467. package/dist/src/sandbox/windows/WindowsSandboxManager.js.map +1 -1
  468. package/dist/src/sandbox/windows/WindowsSandboxManager.test.js +105 -122
  469. package/dist/src/sandbox/windows/WindowsSandboxManager.test.js.map +1 -1
  470. package/dist/src/scheduler/policy.js +1 -2
  471. package/dist/src/scheduler/policy.js.map +1 -1
  472. package/dist/src/scheduler/policy.test.js +58 -2
  473. package/dist/src/scheduler/policy.test.js.map +1 -1
  474. package/dist/src/scheduler/scheduler.d.ts +2 -1
  475. package/dist/src/scheduler/scheduler.js +13 -14
  476. package/dist/src/scheduler/scheduler.js.map +1 -1
  477. package/dist/src/scheduler/scheduler.test.js +66 -0
  478. package/dist/src/scheduler/scheduler.test.js.map +1 -1
  479. package/dist/src/scheduler/scheduler_hooks.test.js +1 -0
  480. package/dist/src/scheduler/scheduler_hooks.test.js.map +1 -1
  481. package/dist/src/scheduler/scheduler_parallel.test.js +2 -0
  482. package/dist/src/scheduler/scheduler_parallel.test.js.map +1 -1
  483. package/dist/src/scheduler/tool-executor.js +2 -0
  484. package/dist/src/scheduler/tool-executor.js.map +1 -1
  485. package/dist/src/services/chatRecordingService.d.ts +12 -153
  486. package/dist/src/services/chatRecordingService.js +444 -350
  487. package/dist/src/services/chatRecordingService.js.map +1 -1
  488. package/dist/src/services/chatRecordingService.test.js +174 -128
  489. package/dist/src/services/chatRecordingService.test.js.map +1 -1
  490. package/dist/src/services/chatRecordingTypes.d.ts +111 -0
  491. package/dist/src/services/chatRecordingTypes.js +10 -0
  492. package/dist/src/services/chatRecordingTypes.js.map +1 -0
  493. package/dist/src/services/gitService.d.ts +2 -0
  494. package/dist/src/services/gitService.js +10 -1
  495. package/dist/src/services/gitService.js.map +1 -1
  496. package/dist/src/services/gitService.test.js +6 -2
  497. package/dist/src/services/gitService.test.js.map +1 -1
  498. package/dist/src/services/keychainService.d.ts +2 -2
  499. package/dist/src/services/keychainService.js +9 -9
  500. package/dist/src/services/keychainService.js.map +1 -1
  501. package/dist/src/services/keychainService.test.js +7 -7
  502. package/dist/src/services/keychainService.test.js.map +1 -1
  503. package/dist/src/services/keychainTypes.d.ts +1 -1
  504. package/dist/src/services/memoryPatchUtils.d.ts +42 -0
  505. package/dist/src/services/memoryPatchUtils.js +216 -0
  506. package/dist/src/services/memoryPatchUtils.js.map +1 -0
  507. package/dist/src/services/memoryService.d.ts +21 -1
  508. package/dist/src/services/memoryService.js +405 -64
  509. package/dist/src/services/memoryService.js.map +1 -1
  510. package/dist/src/services/memoryService.test.js +686 -2
  511. package/dist/src/services/memoryService.test.js.map +1 -1
  512. package/dist/src/services/sandboxManager.d.ts +33 -19
  513. package/dist/src/services/sandboxManager.integration.test.js +728 -266
  514. package/dist/src/services/sandboxManager.integration.test.js.map +1 -1
  515. package/dist/src/services/sandboxManager.js +65 -62
  516. package/dist/src/services/sandboxManager.js.map +1 -1
  517. package/dist/src/services/sandboxManager.test.js +17 -114
  518. package/dist/src/services/sandboxManager.test.js.map +1 -1
  519. package/dist/src/services/sandboxedFileSystemService.js +72 -62
  520. package/dist/src/services/sandboxedFileSystemService.js.map +1 -1
  521. package/dist/src/services/sessionSummaryUtils.d.ts +1 -1
  522. package/dist/src/services/sessionSummaryUtils.js +111 -38
  523. package/dist/src/services/sessionSummaryUtils.js.map +1 -1
  524. package/dist/src/services/sessionSummaryUtils.test.js +204 -51
  525. package/dist/src/services/sessionSummaryUtils.test.js.map +1 -1
  526. package/dist/src/services/shellExecutionService.d.ts +19 -0
  527. package/dist/src/services/shellExecutionService.js +88 -34
  528. package/dist/src/services/shellExecutionService.js.map +1 -1
  529. package/dist/src/services/shellExecutionService.test.js +38 -4
  530. package/dist/src/services/shellExecutionService.test.js.map +1 -1
  531. package/dist/src/telemetry/activity-monitor.js +1 -0
  532. package/dist/src/telemetry/activity-monitor.js.map +1 -1
  533. package/dist/src/telemetry/config.js +3 -0
  534. package/dist/src/telemetry/config.js.map +1 -1
  535. package/dist/src/telemetry/conseca-logger.js +18 -20
  536. package/dist/src/telemetry/conseca-logger.js.map +1 -1
  537. package/dist/src/telemetry/conseca-logger.test.js +100 -0
  538. package/dist/src/telemetry/conseca-logger.test.js.map +1 -1
  539. package/dist/src/telemetry/event-loop-monitor.d.ts +17 -0
  540. package/dist/src/telemetry/event-loop-monitor.js +76 -0
  541. package/dist/src/telemetry/event-loop-monitor.js.map +1 -0
  542. package/dist/src/telemetry/index.d.ts +2 -1
  543. package/dist/src/telemetry/index.js +2 -1
  544. package/dist/src/telemetry/index.js.map +1 -1
  545. package/dist/src/telemetry/llmRole.d.ts +2 -1
  546. package/dist/src/telemetry/llmRole.js +1 -0
  547. package/dist/src/telemetry/llmRole.js.map +1 -1
  548. package/dist/src/telemetry/loggers.test.js +184 -8
  549. package/dist/src/telemetry/loggers.test.js.map +1 -1
  550. package/dist/src/telemetry/memory-monitor.d.ts +1 -0
  551. package/dist/src/telemetry/memory-monitor.js +8 -1
  552. package/dist/src/telemetry/memory-monitor.js.map +1 -1
  553. package/dist/src/telemetry/memory-monitor.test.js +6 -1
  554. package/dist/src/telemetry/memory-monitor.test.js.map +1 -1
  555. package/dist/src/telemetry/metrics.d.ts +12 -0
  556. package/dist/src/telemetry/metrics.js +19 -0
  557. package/dist/src/telemetry/metrics.js.map +1 -1
  558. package/dist/src/telemetry/sdk.js +20 -1
  559. package/dist/src/telemetry/sdk.js.map +1 -1
  560. package/dist/src/telemetry/trace.d.ts +23 -6
  561. package/dist/src/telemetry/trace.js +71 -22
  562. package/dist/src/telemetry/trace.js.map +1 -1
  563. package/dist/src/telemetry/trace.test.js +79 -15
  564. package/dist/src/telemetry/trace.test.js.map +1 -1
  565. package/dist/src/telemetry/types.js +61 -15
  566. package/dist/src/telemetry/types.js.map +1 -1
  567. package/dist/src/test-utils/mock-tool.d.ts +3 -2
  568. package/dist/src/test-utils/mock-tool.js +4 -3
  569. package/dist/src/test-utils/mock-tool.js.map +1 -1
  570. package/dist/src/tools/activate-skill.js +1 -1
  571. package/dist/src/tools/activate-skill.js.map +1 -1
  572. package/dist/src/tools/activate-skill.test.js +6 -2
  573. package/dist/src/tools/activate-skill.test.js.map +1 -1
  574. package/dist/src/tools/ask-user.d.ts +2 -2
  575. package/dist/src/tools/ask-user.js +1 -1
  576. package/dist/src/tools/ask-user.js.map +1 -1
  577. package/dist/src/tools/ask-user.test.js +9 -3
  578. package/dist/src/tools/ask-user.test.js.map +1 -1
  579. package/dist/src/tools/complete-task.d.ts +2 -2
  580. package/dist/src/tools/complete-task.js +1 -1
  581. package/dist/src/tools/complete-task.js.map +1 -1
  582. package/dist/src/tools/complete-task.test.js +9 -3
  583. package/dist/src/tools/complete-task.test.js.map +1 -1
  584. package/dist/src/tools/definitions/base-declarations.d.ts +2 -0
  585. package/dist/src/tools/definitions/base-declarations.js +3 -0
  586. package/dist/src/tools/definitions/base-declarations.js.map +1 -1
  587. package/dist/src/tools/definitions/coreTools.d.ts +3 -1
  588. package/dist/src/tools/definitions/coreTools.js +13 -1
  589. package/dist/src/tools/definitions/coreTools.js.map +1 -1
  590. package/dist/src/tools/definitions/model-family-sets/default-legacy.js +29 -1
  591. package/dist/src/tools/definitions/model-family-sets/default-legacy.js.map +1 -1
  592. package/dist/src/tools/definitions/model-family-sets/gemini-3.js +29 -1
  593. package/dist/src/tools/definitions/model-family-sets/gemini-3.js.map +1 -1
  594. package/dist/src/tools/definitions/types.d.ts +2 -0
  595. package/dist/src/tools/edit.js +20 -4
  596. package/dist/src/tools/edit.js.map +1 -1
  597. package/dist/src/tools/edit.test.js +41 -18
  598. package/dist/src/tools/edit.test.js.map +1 -1
  599. package/dist/src/tools/enter-plan-mode.d.ts +2 -2
  600. package/dist/src/tools/enter-plan-mode.js +1 -1
  601. package/dist/src/tools/enter-plan-mode.js.map +1 -1
  602. package/dist/src/tools/enter-plan-mode.test.js +10 -4
  603. package/dist/src/tools/enter-plan-mode.test.js.map +1 -1
  604. package/dist/src/tools/exit-plan-mode.d.ts +2 -2
  605. package/dist/src/tools/exit-plan-mode.js +9 -12
  606. package/dist/src/tools/exit-plan-mode.js.map +1 -1
  607. package/dist/src/tools/exit-plan-mode.test.js +44 -17
  608. package/dist/src/tools/exit-plan-mode.test.js.map +1 -1
  609. package/dist/src/tools/get-internal-docs.js +6 -3
  610. package/dist/src/tools/get-internal-docs.js.map +1 -1
  611. package/dist/src/tools/get-internal-docs.test.js +4 -4
  612. package/dist/src/tools/get-internal-docs.test.js.map +1 -1
  613. package/dist/src/tools/glob.js +1 -1
  614. package/dist/src/tools/glob.js.map +1 -1
  615. package/dist/src/tools/glob.test.js +16 -16
  616. package/dist/src/tools/glob.test.js.map +1 -1
  617. package/dist/src/tools/grep.js +21 -12
  618. package/dist/src/tools/grep.js.map +1 -1
  619. package/dist/src/tools/grep.test.js +18 -18
  620. package/dist/src/tools/grep.test.js.map +1 -1
  621. package/dist/src/tools/line-endings.test.js +3 -3
  622. package/dist/src/tools/line-endings.test.js.map +1 -1
  623. package/dist/src/tools/list-mcp-resources.d.ts +24 -0
  624. package/dist/src/tools/list-mcp-resources.js +74 -0
  625. package/dist/src/tools/list-mcp-resources.js.map +1 -0
  626. package/dist/src/tools/list-mcp-resources.test.d.ts +6 -0
  627. package/dist/src/tools/list-mcp-resources.test.js +79 -0
  628. package/dist/src/tools/list-mcp-resources.test.js.map +1 -0
  629. package/dist/src/tools/ls.js +2 -2
  630. package/dist/src/tools/ls.js.map +1 -1
  631. package/dist/src/tools/ls.test.js +21 -21
  632. package/dist/src/tools/ls.test.js.map +1 -1
  633. package/dist/src/tools/mcp-client-manager.d.ts +3 -1
  634. package/dist/src/tools/mcp-client-manager.js +24 -1
  635. package/dist/src/tools/mcp-client-manager.js.map +1 -1
  636. package/dist/src/tools/mcp-client-manager.test.js +43 -0
  637. package/dist/src/tools/mcp-client-manager.test.js.map +1 -1
  638. package/dist/src/tools/mcp-client.js +10 -12
  639. package/dist/src/tools/mcp-client.js.map +1 -1
  640. package/dist/src/tools/mcp-client.test.js +14 -2
  641. package/dist/src/tools/mcp-client.test.js.map +1 -1
  642. package/dist/src/tools/mcp-tool.d.ts +2 -2
  643. package/dist/src/tools/mcp-tool.js +1 -1
  644. package/dist/src/tools/mcp-tool.js.map +1 -1
  645. package/dist/src/tools/mcp-tool.test.js +51 -21
  646. package/dist/src/tools/mcp-tool.test.js.map +1 -1
  647. package/dist/src/tools/memoryTool.d.ts +4 -3
  648. package/dist/src/tools/memoryTool.js +43 -14
  649. package/dist/src/tools/memoryTool.js.map +1 -1
  650. package/dist/src/tools/memoryTool.test.js +29 -9
  651. package/dist/src/tools/memoryTool.test.js.map +1 -1
  652. package/dist/src/tools/read-file.js +1 -1
  653. package/dist/src/tools/read-file.js.map +1 -1
  654. package/dist/src/tools/read-file.test.js +17 -17
  655. package/dist/src/tools/read-file.test.js.map +1 -1
  656. package/dist/src/tools/read-many-files.js +4 -4
  657. package/dist/src/tools/read-many-files.js.map +1 -1
  658. package/dist/src/tools/read-many-files.test.js +70 -24
  659. package/dist/src/tools/read-many-files.test.js.map +1 -1
  660. package/dist/src/tools/read-mcp-resource.d.ts +25 -0
  661. package/dist/src/tools/read-mcp-resource.js +120 -0
  662. package/dist/src/tools/read-mcp-resource.js.map +1 -0
  663. package/dist/src/tools/read-mcp-resource.test.d.ts +6 -0
  664. package/dist/src/tools/read-mcp-resource.test.js +110 -0
  665. package/dist/src/tools/read-mcp-resource.test.js.map +1 -0
  666. package/dist/src/tools/ripGrep.d.ts +3 -2
  667. package/dist/src/tools/ripGrep.js +26 -55
  668. package/dist/src/tools/ripGrep.js.map +1 -1
  669. package/dist/src/tools/ripGrep.test.js +113 -167
  670. package/dist/src/tools/ripGrep.test.js.map +1 -1
  671. package/dist/src/tools/shell.d.ts +2 -2
  672. package/dist/src/tools/shell.js +51 -21
  673. package/dist/src/tools/shell.js.map +1 -1
  674. package/dist/src/tools/shell.test.js +479 -76
  675. package/dist/src/tools/shell.test.js.map +1 -1
  676. package/dist/src/tools/shellBackgroundTools.d.ts +3 -3
  677. package/dist/src/tools/shellBackgroundTools.integration.test.js +6 -2
  678. package/dist/src/tools/shellBackgroundTools.integration.test.js.map +1 -1
  679. package/dist/src/tools/shellBackgroundTools.js +2 -2
  680. package/dist/src/tools/shellBackgroundTools.js.map +1 -1
  681. package/dist/src/tools/shellBackgroundTools.test.js +30 -10
  682. package/dist/src/tools/shellBackgroundTools.test.js.map +1 -1
  683. package/dist/src/tools/tool-error.d.ts +1 -0
  684. package/dist/src/tools/tool-error.js +1 -0
  685. package/dist/src/tools/tool-error.js.map +1 -1
  686. package/dist/src/tools/tool-names.d.ts +5 -4
  687. package/dist/src/tools/tool-names.js +8 -2
  688. package/dist/src/tools/tool-names.js.map +1 -1
  689. package/dist/src/tools/tool-registry.js +137 -114
  690. package/dist/src/tools/tool-registry.js.map +1 -1
  691. package/dist/src/tools/tool-registry.test.js +3 -1
  692. package/dist/src/tools/tool-registry.test.js.map +1 -1
  693. package/dist/src/tools/tools.d.ts +6 -6
  694. package/dist/src/tools/tools.js +6 -2
  695. package/dist/src/tools/tools.js.map +1 -1
  696. package/dist/src/tools/topicTool.d.ts +2 -2
  697. package/dist/src/tools/topicTool.js +1 -1
  698. package/dist/src/tools/topicTool.js.map +1 -1
  699. package/dist/src/tools/topicTool.test.js +6 -2
  700. package/dist/src/tools/topicTool.test.js.map +1 -1
  701. package/dist/src/tools/trackerTools.d.ts +7 -7
  702. package/dist/src/tools/trackerTools.js +6 -6
  703. package/dist/src/tools/trackerTools.js.map +1 -1
  704. package/dist/src/tools/web-fetch.js +1 -1
  705. package/dist/src/tools/web-fetch.js.map +1 -1
  706. package/dist/src/tools/web-fetch.test.js +59 -23
  707. package/dist/src/tools/web-fetch.test.js.map +1 -1
  708. package/dist/src/tools/web-search.js +1 -1
  709. package/dist/src/tools/web-search.js.map +1 -1
  710. package/dist/src/tools/web-search.test.js +5 -5
  711. package/dist/src/tools/web-search.test.js.map +1 -1
  712. package/dist/src/tools/write-file.js +22 -4
  713. package/dist/src/tools/write-file.js.map +1 -1
  714. package/dist/src/tools/write-file.test.js +29 -11
  715. package/dist/src/tools/write-file.test.js.map +1 -1
  716. package/dist/src/tools/write-todos.js +1 -1
  717. package/dist/src/tools/write-todos.js.map +1 -1
  718. package/dist/src/utils/compatibility.js +6 -1
  719. package/dist/src/utils/compatibility.js.map +1 -1
  720. package/dist/src/utils/compatibility.test.js +23 -0
  721. package/dist/src/utils/compatibility.test.js.map +1 -1
  722. package/dist/src/utils/errors.d.ts +3 -0
  723. package/dist/src/utils/errors.js +6 -0
  724. package/dist/src/utils/errors.js.map +1 -1
  725. package/dist/src/utils/fileUtils.d.ts +1 -2
  726. package/dist/src/utils/fileUtils.js +80 -40
  727. package/dist/src/utils/fileUtils.js.map +1 -1
  728. package/dist/src/utils/fileUtils.test.js +61 -0
  729. package/dist/src/utils/fileUtils.test.js.map +1 -1
  730. package/dist/src/utils/filesearch/fileSearch.d.ts +2 -0
  731. package/dist/src/utils/filesearch/fileSearch.js +97 -6
  732. package/dist/src/utils/filesearch/fileSearch.js.map +1 -1
  733. package/dist/src/utils/filesearch/fileSearch.test.js +54 -0
  734. package/dist/src/utils/filesearch/fileSearch.test.js.map +1 -1
  735. package/dist/src/utils/filesearch/fileWatcher.d.ts +25 -0
  736. package/dist/src/utils/filesearch/fileWatcher.js +86 -0
  737. package/dist/src/utils/filesearch/fileWatcher.js.map +1 -0
  738. package/dist/src/utils/filesearch/fileWatcher.test.js +142 -0
  739. package/dist/src/utils/filesearch/fileWatcher.test.js.map +1 -0
  740. package/dist/src/utils/getFolderStructure.js +4 -2
  741. package/dist/src/utils/getFolderStructure.js.map +1 -1
  742. package/dist/src/utils/gitIgnoreParser.js +1 -1
  743. package/dist/src/utils/gitIgnoreParser.js.map +1 -1
  744. package/dist/src/utils/googleQuotaErrors.d.ts +2 -1
  745. package/dist/src/utils/googleQuotaErrors.js +30 -35
  746. package/dist/src/utils/googleQuotaErrors.js.map +1 -1
  747. package/dist/src/utils/googleQuotaErrors.test.js +24 -0
  748. package/dist/src/utils/googleQuotaErrors.test.js.map +1 -1
  749. package/dist/src/utils/ignoreFileParser.js +1 -1
  750. package/dist/src/utils/ignoreFileParser.js.map +1 -1
  751. package/dist/src/utils/memoryDiscovery.js +15 -5
  752. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  753. package/dist/src/utils/oauth-flow.js +17 -5
  754. package/dist/src/utils/oauth-flow.js.map +1 -1
  755. package/dist/src/utils/oauth-flow.test.js +20 -0
  756. package/dist/src/utils/oauth-flow.test.js.map +1 -1
  757. package/dist/src/utils/paths.d.ts +9 -0
  758. package/dist/src/utils/paths.js +37 -0
  759. package/dist/src/utils/paths.js.map +1 -1
  760. package/dist/src/utils/paths.test.js +45 -1
  761. package/dist/src/utils/paths.test.js.map +1 -1
  762. package/dist/src/utils/planUtils.d.ts +11 -2
  763. package/dist/src/utils/planUtils.js +43 -11
  764. package/dist/src/utils/planUtils.js.map +1 -1
  765. package/dist/src/utils/planUtils.test.js +10 -9
  766. package/dist/src/utils/planUtils.test.js.map +1 -1
  767. package/dist/src/utils/process-utils.d.ts +2 -1
  768. package/dist/src/utils/process-utils.js +64 -33
  769. package/dist/src/utils/process-utils.js.map +1 -1
  770. package/dist/src/utils/process-utils.test.js +9 -0
  771. package/dist/src/utils/process-utils.test.js.map +1 -1
  772. package/dist/src/utils/retry.js +18 -6
  773. package/dist/src/utils/retry.js.map +1 -1
  774. package/dist/src/utils/retry.test.js +30 -0
  775. package/dist/src/utils/retry.test.js.map +1 -1
  776. package/dist/src/utils/sessionOperations.js +3 -2
  777. package/dist/src/utils/sessionOperations.js.map +1 -1
  778. package/dist/src/utils/shell-utils.d.ts +2 -0
  779. package/dist/src/utils/shell-utils.js +237 -107
  780. package/dist/src/utils/shell-utils.js.map +1 -1
  781. package/dist/src/utils/tool-utils.d.ts +1 -29
  782. package/dist/src/utils/tool-utils.js +0 -39
  783. package/dist/src/utils/tool-utils.js.map +1 -1
  784. package/dist/src/utils/tool-utils.test.js +2 -76
  785. package/dist/src/utils/tool-utils.test.js.map +1 -1
  786. package/dist/src/utils/tool-visibility.d.ts +40 -0
  787. package/dist/src/utils/tool-visibility.js +111 -0
  788. package/dist/src/utils/tool-visibility.js.map +1 -0
  789. package/dist/src/utils/tool-visibility.test.d.ts +6 -0
  790. package/dist/src/utils/tool-visibility.test.js +96 -0
  791. package/dist/src/utils/tool-visibility.test.js.map +1 -0
  792. package/dist/src/utils/trust.d.ts +64 -0
  793. package/dist/src/utils/trust.js +276 -0
  794. package/dist/src/utils/trust.js.map +1 -0
  795. package/dist/src/utils/trust.test.d.ts +6 -0
  796. package/dist/src/utils/trust.test.js +159 -0
  797. package/dist/src/utils/trust.test.js.map +1 -0
  798. package/dist/tsconfig.tsbuildinfo +1 -1
  799. package/package.json +5 -4
  800. package/dist/docs/get-started/installation.md +0 -181
  801. package/dist/src/agents/memory-manager-agent.d.ts +0 -25
  802. package/dist/src/agents/memory-manager-agent.js +0 -138
  803. package/dist/src/agents/memory-manager-agent.js.map +0 -1
  804. package/dist/src/agents/memory-manager-agent.test.js +0 -123
  805. package/dist/src/agents/memory-manager-agent.test.js.map +0 -1
  806. package/dist/src/agents/subagent-tool-wrapper.d.ts +0 -38
  807. package/dist/src/agents/subagent-tool-wrapper.js +0 -58
  808. package/dist/src/agents/subagent-tool-wrapper.js.map +0 -1
  809. package/dist/src/agents/subagent-tool-wrapper.test.js +0 -123
  810. package/dist/src/agents/subagent-tool-wrapper.test.js.map +0 -1
  811. package/dist/src/agents/subagent-tool.d.ts +0 -18
  812. package/dist/src/agents/subagent-tool.js +0 -134
  813. package/dist/src/agents/subagent-tool.js.map +0 -1
  814. package/dist/src/agents/subagent-tool.test.js +0 -287
  815. package/dist/src/agents/subagent-tool.test.js.map +0 -1
  816. package/dist/src/policy/policies/tracker.toml +0 -34
  817. package/dist/src/prompts/snippets-memory-manager.test.js +0 -31
  818. package/dist/src/prompts/snippets-memory-manager.test.js.map +0 -1
  819. /package/dist/src/{agents/memory-manager-agent.test.d.ts → agent/tool-display-utils.test.d.ts} +0 -0
  820. /package/dist/src/agents/{subagent-tool.test.d.ts → agent-tool.test.d.ts} +0 -0
  821. /package/dist/src/{prompts/snippets-memory-manager.test.d.ts → agents/skill-extraction-agent.test.d.ts} +0 -0
  822. /package/dist/src/{agents/subagent-tool-wrapper.test.d.ts → utils/filesearch/fileWatcher.test.d.ts} +0 -0
@@ -3,36 +3,215 @@
3
3
  * Copyright 2025 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import {} from '../scheduler/types.js';
7
6
  import {} from '../utils/thoughtUtils.js';
8
7
  import { getProjectHash } from '../utils/paths.js';
9
8
  import path from 'node:path';
10
- import fs from 'node:fs';
9
+ import * as fs from 'node:fs';
11
10
  import { sanitizeFilenamePart } from '../utils/fileUtils.js';
11
+ import { isNodeError } from '../utils/errors.js';
12
12
  import { deleteSessionArtifactsAsync, deleteSubagentSessionDirAndArtifactsAsync, } from '../utils/sessionOperations.js';
13
+ import readline from 'node:readline';
13
14
  import { randomUUID } from 'node:crypto';
14
15
  import { debugLogger } from '../utils/debugLogger.js';
15
- export const SESSION_FILE_PREFIX = 'session-';
16
+ import { SESSION_FILE_PREFIX, } from './chatRecordingTypes.js';
17
+ export * from './chatRecordingTypes.js';
16
18
  /**
17
19
  * Warning message shown when recording is disabled due to disk full.
18
20
  */
19
21
  const ENOSPC_WARNING_MESSAGE = 'Chat recording disabled: No space left on device. ' +
20
22
  'The conversation will continue but will not be saved to disk. ' +
21
23
  'Free up disk space and restart to enable recording.';
22
- /**
23
- * Service for automatically recording chat conversations to disk.
24
- *
25
- * This service provides comprehensive conversation recording that captures:
26
- * - All user and assistant messages
27
- * - Tool calls and their execution results
28
- * - Token usage statistics
29
- * - Assistant thoughts and reasoning
30
- *
31
- * Sessions are stored as JSON files in ~/.cell-cli/tmp/<project_hash>/chats/
32
- */
24
+ function hasProperty(obj, prop) {
25
+ return obj !== null && typeof obj === 'object' && prop in obj;
26
+ }
27
+ function isStringProperty(obj, prop) {
28
+ return hasProperty(obj, prop) && typeof obj[prop] === 'string';
29
+ }
30
+ function isObjectProperty(obj, prop) {
31
+ return (hasProperty(obj, prop) &&
32
+ obj[prop] !== null &&
33
+ typeof obj[prop] === 'object');
34
+ }
35
+ function isRewindRecord(record) {
36
+ return isStringProperty(record, '$rewindTo');
37
+ }
38
+ function isMessageRecord(record) {
39
+ return isStringProperty(record, 'id');
40
+ }
41
+ function isMetadataUpdateRecord(record) {
42
+ return isObjectProperty(record, '$set');
43
+ }
44
+ function isPartialMetadataRecord(record) {
45
+ return (isStringProperty(record, 'sessionId') &&
46
+ isStringProperty(record, 'projectHash'));
47
+ }
48
+ function isTextPart(part) {
49
+ return isStringProperty(part, 'text');
50
+ }
51
+ function isSessionIdRecord(record) {
52
+ return isStringProperty(record, 'sessionId');
53
+ }
54
+ export async function loadConversationRecord(filePath, options) {
55
+ if (!fs.existsSync(filePath)) {
56
+ return null;
57
+ }
58
+ try {
59
+ const fileStream = fs.createReadStream(filePath);
60
+ const rl = readline.createInterface({
61
+ input: fileStream,
62
+ crlfDelay: Infinity,
63
+ });
64
+ let metadata = {};
65
+ const messagesMap = new Map();
66
+ const messageIds = [];
67
+ const messageKinds = new Map();
68
+ let firstUserMessageStr;
69
+ for await (const line of rl) {
70
+ if (!line.trim())
71
+ continue;
72
+ try {
73
+ const record = JSON.parse(line);
74
+ if (isRewindRecord(record)) {
75
+ const rewindId = record.$rewindTo;
76
+ if (options?.metadataOnly) {
77
+ const idx = messageIds.indexOf(rewindId);
78
+ if (idx !== -1) {
79
+ const removedIds = messageIds.splice(idx);
80
+ for (const removedId of removedIds) {
81
+ messageKinds.delete(removedId);
82
+ }
83
+ }
84
+ else {
85
+ messageIds.length = 0;
86
+ messageKinds.clear();
87
+ }
88
+ }
89
+ else {
90
+ let found = false;
91
+ const idsToDelete = [];
92
+ for (const [id] of messagesMap) {
93
+ if (id === rewindId)
94
+ found = true;
95
+ if (found)
96
+ idsToDelete.push(id);
97
+ }
98
+ if (found) {
99
+ for (const id of idsToDelete) {
100
+ messagesMap.delete(id);
101
+ }
102
+ }
103
+ else {
104
+ messagesMap.clear();
105
+ }
106
+ }
107
+ }
108
+ else if (isMessageRecord(record)) {
109
+ const id = record.id;
110
+ const isUser = hasProperty(record, 'type') && record.type === 'user';
111
+ const isUserOrAssistant = hasProperty(record, 'type') &&
112
+ (record.type === 'user' || record.type === 'gemini');
113
+ // Track message count and first user message
114
+ if (options?.metadataOnly) {
115
+ messageIds.push(id);
116
+ messageKinds.set(id, { isUser, isUserOrAssistant });
117
+ }
118
+ if (!firstUserMessageStr &&
119
+ isUser &&
120
+ hasProperty(record, 'content') &&
121
+ record['content']) {
122
+ // Basic extraction of first user message for display
123
+ const rawContent = record['content'];
124
+ if (Array.isArray(rawContent)) {
125
+ firstUserMessageStr = rawContent
126
+ .map((p) => (isTextPart(p) ? p['text'] : ''))
127
+ .join('');
128
+ }
129
+ else if (typeof rawContent === 'string') {
130
+ firstUserMessageStr = rawContent;
131
+ }
132
+ }
133
+ if (!options?.metadataOnly) {
134
+ messagesMap.set(id, record);
135
+ if (options?.maxMessages &&
136
+ messagesMap.size > options.maxMessages) {
137
+ const firstKey = messagesMap.keys().next().value;
138
+ if (typeof firstKey === 'string')
139
+ messagesMap.delete(firstKey);
140
+ }
141
+ }
142
+ }
143
+ else if (isMetadataUpdateRecord(record)) {
144
+ // Metadata update
145
+ metadata = {
146
+ ...metadata,
147
+ ...record.$set,
148
+ };
149
+ }
150
+ else if (isPartialMetadataRecord(record)) {
151
+ // Initial metadata line
152
+ metadata = { ...metadata, ...record };
153
+ }
154
+ }
155
+ catch {
156
+ // ignore parse errors on individual lines
157
+ }
158
+ }
159
+ if (!metadata.sessionId || !metadata.projectHash) {
160
+ return await parseLegacyRecordFallback(filePath, options);
161
+ }
162
+ const metadataMessages = Array.isArray(metadata.messages)
163
+ ? metadata.messages
164
+ : [];
165
+ const loadedMessages = metadataMessages.length > 0
166
+ ? metadataMessages
167
+ : Array.from(messagesMap.values());
168
+ const metadataFirstUserMessage = metadataMessages.find((message) => message.type === 'user') ?? null;
169
+ let fallbackFirstUserMessage = firstUserMessageStr;
170
+ if (!fallbackFirstUserMessage && metadataFirstUserMessage) {
171
+ const rawContent = metadataFirstUserMessage.content;
172
+ if (Array.isArray(rawContent)) {
173
+ fallbackFirstUserMessage = rawContent
174
+ .map((part) => (isTextPart(part) ? part['text'] : ''))
175
+ .join('');
176
+ }
177
+ else if (typeof rawContent === 'string') {
178
+ fallbackFirstUserMessage = rawContent;
179
+ }
180
+ }
181
+ const userMessageCount = options?.metadataOnly
182
+ ? Array.from(messageKinds.values()).filter((m) => m.isUser).length
183
+ : loadedMessages.filter((m) => m.type === 'user').length;
184
+ const hasUserOrAssistant = options?.metadataOnly
185
+ ? Array.from(messageKinds.values()).some((m) => m.isUserOrAssistant)
186
+ : loadedMessages.some((m) => m.type === 'user' || m.type === 'gemini');
187
+ return {
188
+ sessionId: metadata.sessionId,
189
+ projectHash: metadata.projectHash,
190
+ startTime: metadata.startTime || new Date().toISOString(),
191
+ lastUpdated: metadata.lastUpdated || new Date().toISOString(),
192
+ summary: metadata.summary,
193
+ directories: metadata.directories,
194
+ kind: metadata.kind,
195
+ messages: options?.metadataOnly ? [] : loadedMessages,
196
+ messageCount: options?.metadataOnly
197
+ ? metadataMessages.length || messageIds.length
198
+ : loadedMessages.length,
199
+ userMessageCount: options?.metadataOnly && metadataMessages.length > 0
200
+ ? metadataMessages.filter((m) => m.type === 'user').length
201
+ : userMessageCount,
202
+ firstUserMessage: fallbackFirstUserMessage,
203
+ hasUserOrAssistantMessage: options?.metadataOnly && metadataMessages.length > 0
204
+ ? metadataMessages.some((m) => m.type === 'user' || m.type === 'gemini')
205
+ : hasUserOrAssistant,
206
+ };
207
+ }
208
+ catch (error) {
209
+ debugLogger.error('Error loading conversation record from JSONL:', error);
210
+ return null;
211
+ }
212
+ }
33
213
  export class ChatRecordingService {
34
214
  conversationFile = null;
35
- cachedLastConvData = null;
36
215
  cachedConversation = null;
37
216
  sessionId;
38
217
  projectHash;
@@ -45,28 +224,40 @@ export class ChatRecordingService {
45
224
  this.sessionId = context.promptId;
46
225
  this.projectHash = getProjectHash(context.config.getProjectRoot());
47
226
  }
48
- /**
49
- * Initializes the chat recording service: creates a new conversation file and associates it with
50
- * this service instance, or resumes from an existing session if resumedSessionData is provided.
51
- *
52
- * @param resumedSessionData Data from a previous session to resume from.
53
- * @param kind The kind of conversation (main or subagent).
54
- */
55
- initialize(resumedSessionData, kind) {
227
+ async initialize(resumedSessionData, kind) {
56
228
  try {
57
229
  this.kind = kind;
58
230
  if (resumedSessionData) {
59
- // Resume from existing session
60
231
  this.conversationFile = resumedSessionData.filePath;
61
232
  this.sessionId = resumedSessionData.conversation.sessionId;
62
233
  this.kind = resumedSessionData.conversation.kind;
63
- // Update the session ID in the existing file
64
- this.updateConversation((conversation) => {
65
- conversation.sessionId = this.sessionId;
66
- });
67
- // Clear any cached data to force fresh reads
68
- this.cachedLastConvData = null;
69
- this.cachedConversation = null;
234
+ const loadedRecord = await loadConversationRecord(this.conversationFile);
235
+ if (loadedRecord) {
236
+ this.cachedConversation = loadedRecord;
237
+ this.projectHash = this.cachedConversation.projectHash;
238
+ if (this.conversationFile.endsWith('.json')) {
239
+ this.conversationFile = this.conversationFile + 'l'; // e.g. session-foo.jsonl
240
+ // Migrate the entire legacy record to the new file
241
+ const initialMetadata = {
242
+ sessionId: this.sessionId,
243
+ projectHash: this.projectHash,
244
+ startTime: this.cachedConversation.startTime,
245
+ lastUpdated: this.cachedConversation.lastUpdated,
246
+ kind: this.cachedConversation.kind,
247
+ directories: this.cachedConversation.directories,
248
+ summary: this.cachedConversation.summary,
249
+ };
250
+ this.appendRecord(initialMetadata);
251
+ for (const msg of this.cachedConversation.messages) {
252
+ this.appendRecord(msg);
253
+ }
254
+ }
255
+ // Update the session ID in the existing file
256
+ this.updateMetadata({ sessionId: this.sessionId });
257
+ }
258
+ else {
259
+ throw new Error('Failed to load resumed session data from file');
260
+ }
70
261
  }
71
262
  else {
72
263
  // Create new session
@@ -91,10 +282,10 @@ export class ChatRecordingService {
91
282
  }
92
283
  let filename;
93
284
  if (this.kind === 'subagent') {
94
- filename = `${safeSessionId}.json`;
285
+ filename = `${safeSessionId}.jsonl`;
95
286
  }
96
287
  else {
97
- filename = `${SESSION_FILE_PREFIX}${timestamp}-${safeSessionId.slice(0, 8)}.json`;
288
+ filename = `${SESSION_FILE_PREFIX}${timestamp}-${safeSessionId.slice(0, 8)}.jsonl`;
98
289
  }
99
290
  this.conversationFile = path.join(chatsDir, filename);
100
291
  const directories = this.kind === 'subagent'
@@ -104,34 +295,71 @@ export class ChatRecordingService {
104
295
  ?.getDirectories() ?? []),
105
296
  ]
106
297
  : undefined;
107
- this.writeConversation({
298
+ const initialMetadata = {
108
299
  sessionId: this.sessionId,
109
300
  projectHash: this.projectHash,
110
301
  startTime: new Date().toISOString(),
111
302
  lastUpdated: new Date().toISOString(),
112
- messages: [],
113
- directories,
114
303
  kind: this.kind,
115
- });
304
+ directories,
305
+ };
306
+ this.appendRecord(initialMetadata);
307
+ this.cachedConversation = {
308
+ ...initialMetadata,
309
+ messages: [],
310
+ };
116
311
  }
117
- // Clear any queued data since this is a fresh start
118
312
  this.queuedThoughts = [];
119
313
  this.queuedTokens = null;
120
314
  }
121
315
  catch (error) {
122
- // Handle disk full (ENOSPC) gracefully - disable recording but allow CLI to continue
123
- if (error instanceof Error &&
124
- 'code' in error &&
125
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
126
- error.code === 'ENOSPC') {
316
+ if (isNodeError(error) && error.code === 'ENOSPC') {
127
317
  this.conversationFile = null;
128
318
  debugLogger.warn(ENOSPC_WARNING_MESSAGE);
129
- return; // Don't throw - allow the CLI to continue
319
+ return;
130
320
  }
131
321
  debugLogger.error('Error initializing chat recording service:', error);
132
322
  throw error;
133
323
  }
134
324
  }
325
+ appendRecord(record) {
326
+ if (!this.conversationFile)
327
+ return;
328
+ try {
329
+ const line = JSON.stringify(record) + '\n';
330
+ fs.mkdirSync(path.dirname(this.conversationFile), { recursive: true });
331
+ fs.appendFileSync(this.conversationFile, line);
332
+ }
333
+ catch (error) {
334
+ if (isNodeError(error) && error.code === 'ENOSPC') {
335
+ this.conversationFile = null;
336
+ debugLogger.warn(ENOSPC_WARNING_MESSAGE);
337
+ }
338
+ else {
339
+ throw error;
340
+ }
341
+ }
342
+ }
343
+ updateMetadata(updates) {
344
+ if (!this.cachedConversation)
345
+ return;
346
+ Object.assign(this.cachedConversation, updates);
347
+ this.appendRecord({ $set: updates });
348
+ }
349
+ pushMessage(msg) {
350
+ if (!this.cachedConversation)
351
+ return;
352
+ // We append the full message to the log
353
+ this.appendRecord(msg);
354
+ // Now update memory
355
+ const index = this.cachedConversation.messages.findIndex((m) => m.id === msg.id);
356
+ if (index !== -1) {
357
+ this.cachedConversation.messages[index] = msg;
358
+ }
359
+ else {
360
+ this.cachedConversation.messages.push(msg);
361
+ }
362
+ }
135
363
  getLastMessage(conversation) {
136
364
  return conversation.messages.at(-1);
137
365
  }
@@ -144,59 +372,36 @@ export class ChatRecordingService {
144
372
  displayContent,
145
373
  };
146
374
  }
147
- /**
148
- * Records a message in the conversation.
149
- */
150
375
  recordMessage(message) {
151
- if (!this.conversationFile)
376
+ if (!this.conversationFile || !this.cachedConversation)
152
377
  return;
153
378
  try {
154
- this.updateConversation((conversation) => {
155
- const msg = this.newMessage(message.type, message.content, message.displayContent);
156
- if (msg.type === 'gemini') {
157
- // If it's a new Gemini message then incorporate any queued thoughts.
158
- conversation.messages.push({
159
- ...msg,
160
- thoughts: this.queuedThoughts,
161
- tokens: this.queuedTokens,
162
- model: message.model,
163
- });
164
- this.queuedThoughts = [];
165
- this.queuedTokens = null;
166
- }
167
- else {
168
- // Or else just add it.
169
- conversation.messages.push(msg);
170
- }
171
- });
379
+ const msg = this.newMessage(message.type, message.content, message.displayContent);
380
+ if (msg.type === 'gemini') {
381
+ msg.thoughts = this.queuedThoughts;
382
+ msg.tokens = this.queuedTokens;
383
+ msg.model = message.model;
384
+ this.queuedThoughts = [];
385
+ this.queuedTokens = null;
386
+ }
387
+ this.pushMessage(msg);
388
+ this.updateMetadata({ lastUpdated: new Date().toISOString() });
172
389
  }
173
390
  catch (error) {
174
391
  debugLogger.error('Error saving message to chat history.', error);
175
392
  throw error;
176
393
  }
177
394
  }
178
- /**
179
- * Records a thought from the assistant's reasoning process.
180
- */
181
395
  recordThought(thought) {
182
396
  if (!this.conversationFile)
183
397
  return;
184
- try {
185
- this.queuedThoughts.push({
186
- ...thought,
187
- timestamp: new Date().toISOString(),
188
- });
189
- }
190
- catch (error) {
191
- debugLogger.error('Error saving thought to chat history.', error);
192
- throw error;
193
- }
398
+ this.queuedThoughts.push({
399
+ ...thought,
400
+ timestamp: new Date().toISOString(),
401
+ });
194
402
  }
195
- /**
196
- * Updates the tokens for the last message in the conversation (which should be by Gemini).
197
- */
198
403
  recordMessageTokens(respUsageMetadata) {
199
- if (!this.conversationFile)
404
+ if (!this.conversationFile || !this.cachedConversation)
200
405
  return;
201
406
  try {
202
407
  const tokens = {
@@ -207,18 +412,13 @@ export class ChatRecordingService {
207
412
  tool: respUsageMetadata.toolUsePromptTokenCount ?? 0,
208
413
  total: respUsageMetadata.totalTokenCount ?? 0,
209
414
  };
210
- const conversation = this.readConversation();
211
- const lastMsg = this.getLastMessage(conversation);
212
- // If the last message already has token info, it's because this new token info is for a
213
- // new message that hasn't been recorded yet.
415
+ const lastMsg = this.getLastMessage(this.cachedConversation);
214
416
  if (lastMsg && lastMsg.type === 'gemini' && !lastMsg.tokens) {
215
417
  lastMsg.tokens = tokens;
216
418
  this.queuedTokens = null;
217
- this.writeConversation(conversation);
419
+ this.pushMessage(lastMsg);
218
420
  }
219
421
  else {
220
- // Only queue tokens in memory; no disk I/O needed since the
221
- // conversation record itself hasn't changed.
222
422
  this.queuedTokens = tokens;
223
423
  }
224
424
  }
@@ -227,14 +427,9 @@ export class ChatRecordingService {
227
427
  throw error;
228
428
  }
229
429
  }
230
- /**
231
- * Adds tool calls to the last message in the conversation (which should be by Gemini).
232
- * This method enriches tool calls with metadata from the ToolRegistry.
233
- */
234
430
  recordToolCalls(model, toolCalls) {
235
- if (!this.conversationFile)
431
+ if (!this.conversationFile || !this.cachedConversation)
236
432
  return;
237
- // Enrich tool calls with metadata from the ToolRegistry
238
433
  const toolRegistry = this.context.toolRegistry;
239
434
  const enrichedToolCalls = toolCalls.map((toolCall) => {
240
435
  const toolInstance = toolRegistry.getTool(toolCall.name);
@@ -246,225 +441,79 @@ export class ChatRecordingService {
246
441
  };
247
442
  });
248
443
  try {
249
- this.updateConversation((conversation) => {
250
- const lastMsg = this.getLastMessage(conversation);
251
- // If a tool call was made, but the last message isn't from Gemini, it's because Gemini is
252
- // calling tools without starting the message with text. So the user submits a prompt, and
253
- // Gemini immediately calls a tool (maybe with some thinking first). In that case, create
254
- // a new empty Gemini message.
255
- // Also if there are any queued thoughts, it means this tool call(s) is from a new Gemini
256
- // message--because it's thought some more since we last, if ever, created a new Gemini
257
- // message from tool calls, when we dequeued the thoughts.
258
- if (!lastMsg ||
259
- lastMsg.type !== 'gemini' ||
260
- this.queuedThoughts.length > 0) {
261
- const newMsg = {
262
- ...this.newMessage('gemini', ''),
263
- // This isn't strictly necessary, but TypeScript apparently can't
264
- // tell that the first parameter to newMessage() becomes the
265
- // resulting message's type, and so it thinks that toolCalls may
266
- // not be present. Confirming the type here satisfies it.
267
- type: 'gemini',
268
- toolCalls: enrichedToolCalls,
269
- thoughts: this.queuedThoughts,
270
- model,
271
- };
272
- // If there are any queued thoughts join them to this message.
273
- if (this.queuedThoughts.length > 0) {
274
- newMsg.thoughts = this.queuedThoughts;
275
- this.queuedThoughts = [];
276
- }
277
- // If there's any queued tokens info join it to this message.
278
- if (this.queuedTokens) {
279
- newMsg.tokens = this.queuedTokens;
280
- this.queuedTokens = null;
281
- }
282
- conversation.messages.push(newMsg);
444
+ const lastMsg = this.getLastMessage(this.cachedConversation);
445
+ if (!lastMsg ||
446
+ lastMsg.type !== 'gemini' ||
447
+ this.queuedThoughts.length > 0) {
448
+ const newMsg = {
449
+ ...this.newMessage('gemini', ''),
450
+ type: 'gemini',
451
+ toolCalls: enrichedToolCalls,
452
+ thoughts: this.queuedThoughts,
453
+ model,
454
+ };
455
+ if (this.queuedThoughts.length > 0) {
456
+ newMsg.thoughts = this.queuedThoughts;
457
+ this.queuedThoughts = [];
283
458
  }
284
- else {
285
- // The last message is an existing Gemini message that we need to update.
286
- // Update any existing tool call entries.
287
- if (!lastMsg.toolCalls) {
288
- lastMsg.toolCalls = [];
459
+ if (this.queuedTokens) {
460
+ newMsg.tokens = this.queuedTokens;
461
+ this.queuedTokens = null;
462
+ }
463
+ this.pushMessage(newMsg);
464
+ }
465
+ else {
466
+ if (!lastMsg.toolCalls) {
467
+ lastMsg.toolCalls = [];
468
+ }
469
+ // Deep clone toolCalls to avoid modifying memory references directly
470
+ const updatedToolCalls = [...lastMsg.toolCalls];
471
+ for (const toolCall of enrichedToolCalls) {
472
+ const index = updatedToolCalls.findIndex((tc) => tc.id === toolCall.id);
473
+ if (index !== -1) {
474
+ updatedToolCalls[index] = {
475
+ ...updatedToolCalls[index],
476
+ ...toolCall,
477
+ };
289
478
  }
290
- lastMsg.toolCalls = lastMsg.toolCalls.map((toolCall) => {
291
- // If there are multiple tool calls with the same ID, this will take the first one.
292
- const incomingToolCall = toolCalls.find((tc) => tc.id === toolCall.id);
293
- if (incomingToolCall) {
294
- // Merge in the new data to keep preserve thoughts, etc., that were assigned to older
295
- // versions of the tool call.
296
- return { ...toolCall, ...incomingToolCall };
297
- }
298
- else {
299
- return toolCall;
300
- }
301
- });
302
- // Add any new tools calls that aren't in the message yet.
303
- for (const toolCall of enrichedToolCalls) {
304
- const existingToolCall = lastMsg.toolCalls.find((tc) => tc.id === toolCall.id);
305
- if (!existingToolCall) {
306
- lastMsg.toolCalls.push(toolCall);
307
- }
479
+ else {
480
+ updatedToolCalls.push(toolCall);
308
481
  }
309
482
  }
310
- });
311
- }
312
- catch (error) {
313
- debugLogger.error('Error adding tool call to message in chat history.', error);
314
- throw error;
315
- }
316
- }
317
- /**
318
- * Loads up the conversation record from disk.
319
- *
320
- * NOTE: The returned object is the live in-memory cache reference.
321
- * Any mutations to it will be visible to all subsequent reads.
322
- * Callers that mutate the result MUST call writeConversation() to
323
- * persist the changes to disk.
324
- */
325
- readConversation() {
326
- if (this.cachedConversation) {
327
- return this.cachedConversation;
328
- }
329
- try {
330
- this.cachedLastConvData = fs.readFileSync(this.conversationFile, 'utf8');
331
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
332
- this.cachedConversation = JSON.parse(this.cachedLastConvData);
333
- if (!this.cachedConversation) {
334
- // File is corrupt or contains "null". Fallback to an empty conversation.
335
- this.cachedConversation = {
336
- sessionId: this.sessionId,
337
- projectHash: this.projectHash,
338
- startTime: new Date().toISOString(),
339
- lastUpdated: new Date().toISOString(),
340
- messages: [],
341
- kind: this.kind,
342
- };
343
- }
344
- return this.cachedConversation;
345
- }
346
- catch (error) {
347
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
348
- if (error.code !== 'ENOENT') {
349
- debugLogger.error('Error reading conversation file.', error);
350
- throw error;
483
+ lastMsg.toolCalls = updatedToolCalls;
484
+ this.pushMessage(lastMsg);
351
485
  }
352
- // Placeholder empty conversation if file doesn't exist.
353
- this.cachedConversation = {
354
- sessionId: this.sessionId,
355
- projectHash: this.projectHash,
356
- startTime: new Date().toISOString(),
357
- lastUpdated: new Date().toISOString(),
358
- messages: [],
359
- kind: this.kind,
360
- };
361
- return this.cachedConversation;
362
- }
363
- }
364
- /**
365
- * Saves the conversation record; overwrites the file.
366
- */
367
- writeConversation(conversation, { allowEmpty = false } = {}) {
368
- try {
369
- if (!this.conversationFile)
370
- return;
371
- // Cache the conversation state even if we don't write to disk yet.
372
- // This ensures that subsequent reads (e.g. during recordMessage)
373
- // see the initial state (like directories) instead of trying to
374
- // read a non-existent file from disk.
375
- this.cachedConversation = conversation;
376
- // Don't write the file yet until there's at least one message.
377
- if (conversation.messages.length === 0 && !allowEmpty)
378
- return;
379
- const newContent = JSON.stringify(conversation, null, 2);
380
- // Skip the disk write if nothing actually changed (e.g.
381
- // updateMessagesFromHistory found no matching tool calls to update).
382
- // Compare before updating lastUpdated so the timestamp doesn't
383
- // cause a false diff.
384
- if (this.cachedLastConvData === newContent)
385
- return;
386
- conversation.lastUpdated = new Date().toISOString();
387
- const contentToWrite = JSON.stringify(conversation, null, 2);
388
- this.cachedLastConvData = contentToWrite;
389
- // Ensure directory exists before writing (handles cases where temp dir was cleaned)
390
- fs.mkdirSync(path.dirname(this.conversationFile), { recursive: true });
391
- fs.writeFileSync(this.conversationFile, contentToWrite);
392
486
  }
393
487
  catch (error) {
394
- // Handle disk full (ENOSPC) gracefully - disable recording but allow conversation to continue
395
- if (error instanceof Error &&
396
- 'code' in error &&
397
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
398
- error.code === 'ENOSPC') {
399
- this.conversationFile = null;
400
- this.cachedConversation = null;
401
- debugLogger.warn(ENOSPC_WARNING_MESSAGE);
402
- return; // Don't throw - allow the conversation to continue
403
- }
404
- debugLogger.error('Error writing conversation file.', error);
488
+ debugLogger.error('Error adding tool call to message in chat history.', error);
405
489
  throw error;
406
490
  }
407
491
  }
408
- /**
409
- * Convenient helper for updating the conversation without file reading and writing and time
410
- * updating boilerplate.
411
- */
412
- updateConversation(updateFn) {
413
- const conversation = this.readConversation();
414
- updateFn(conversation);
415
- this.writeConversation(conversation);
416
- }
417
- /**
418
- * Saves a summary for the current session.
419
- */
420
492
  saveSummary(summary) {
421
493
  if (!this.conversationFile)
422
494
  return;
423
495
  try {
424
- this.updateConversation((conversation) => {
425
- conversation.summary = summary;
426
- });
496
+ this.updateMetadata({ summary });
427
497
  }
428
498
  catch (error) {
429
499
  debugLogger.error('Error saving summary to chat history.', error);
430
- // Don't throw - we want graceful degradation
431
500
  }
432
501
  }
433
- /**
434
- * Records workspace directories to the session file.
435
- * Called when directories are added via /dir add.
436
- */
437
502
  recordDirectories(directories) {
438
503
  if (!this.conversationFile)
439
504
  return;
440
505
  try {
441
- this.updateConversation((conversation) => {
442
- conversation.directories = [...directories];
443
- });
506
+ this.updateMetadata({ directories: [...directories] });
444
507
  }
445
508
  catch (error) {
446
509
  debugLogger.error('Error saving directories to chat history.', error);
447
- // Don't throw - we want graceful degradation
448
510
  }
449
511
  }
450
- /**
451
- * Gets the current conversation data (for summary generation).
452
- */
453
512
  getConversation() {
454
513
  if (!this.conversationFile)
455
514
  return null;
456
- try {
457
- return this.readConversation();
458
- }
459
- catch (error) {
460
- debugLogger.error('Error reading conversation for summary.', error);
461
- return null;
462
- }
515
+ return this.cachedConversation;
463
516
  }
464
- /**
465
- * Gets the path to the current conversation file.
466
- * Returns null if the service hasn't been initialized yet or recording is disabled.
467
- */
468
517
  getConversationFilePath() {
469
518
  return this.conversationFile;
470
519
  }
@@ -484,7 +533,7 @@ export class ChatRecordingService {
484
533
  if (!(await fs.promises.stat(chatsDir).catch(() => null))) {
485
534
  return; // Nothing to delete
486
535
  }
487
- const matchingFiles = this.getMatchingSessionFiles(chatsDir, shortId);
536
+ const matchingFiles = await this.getMatchingSessionFiles(chatsDir, shortId);
488
537
  for (const file of matchingFiles) {
489
538
  await this.deleteSessionAndArtifacts(chatsDir, file, tempDir);
490
539
  }
@@ -494,13 +543,10 @@ export class ChatRecordingService {
494
543
  throw error;
495
544
  }
496
545
  }
497
- /**
498
- * Derives an 8-character shortId from a sessionId, filename, or basename.
499
- */
500
546
  deriveShortId(sessionIdOrBasename) {
501
547
  let shortId = sessionIdOrBasename;
502
548
  if (sessionIdOrBasename.startsWith(SESSION_FILE_PREFIX)) {
503
- const withoutExt = sessionIdOrBasename.replace('.json', '');
549
+ const withoutExt = sessionIdOrBasename.replace(/\.jsonl?$/, '');
504
550
  const parts = withoutExt.split('-');
505
551
  shortId = parts[parts.length - 1];
506
552
  }
@@ -515,12 +561,10 @@ export class ChatRecordingService {
515
561
  }
516
562
  return shortId;
517
563
  }
518
- /**
519
- * Finds all session files matching the pattern session-*-<shortId>.json
520
- */
521
- getMatchingSessionFiles(chatsDir, shortId) {
522
- const files = fs.readdirSync(chatsDir);
523
- return files.filter((f) => f.startsWith(SESSION_FILE_PREFIX) && f.endsWith(`-${shortId}.json`));
564
+ async getMatchingSessionFiles(chatsDir, shortId) {
565
+ const files = await fs.promises.readdir(chatsDir);
566
+ return files.filter((f) => f.startsWith(SESSION_FILE_PREFIX) &&
567
+ (f.endsWith(`-${shortId}.json`) || f.endsWith(`-${shortId}.jsonl`)));
524
568
  }
525
569
  /**
526
570
  * Deletes a single session file and its associated logs, tool-outputs, and directory.
@@ -528,15 +572,35 @@ export class ChatRecordingService {
528
572
  async deleteSessionAndArtifacts(chatsDir, file, tempDir) {
529
573
  const filePath = path.join(chatsDir, file);
530
574
  try {
531
- const fileContent = await fs.promises.readFile(filePath, 'utf8');
532
- const content = JSON.parse(fileContent);
533
- let fullSessionId;
534
- if (content && typeof content === 'object' && 'sessionId' in content) {
535
- const id = content['sessionId'];
536
- if (typeof id === 'string') {
537
- fullSessionId = id;
575
+ const CHUNK_SIZE = 4096;
576
+ const buffer = Buffer.alloc(CHUNK_SIZE);
577
+ let firstLine;
578
+ let fd;
579
+ try {
580
+ fd = await fs.promises.open(filePath, 'r');
581
+ const { bytesRead } = await fd.read(buffer, 0, CHUNK_SIZE, 0);
582
+ if (bytesRead === 0) {
583
+ await fd.close();
584
+ await fs.promises.unlink(filePath);
585
+ return;
586
+ }
587
+ const contentChunk = buffer.toString('utf8', 0, bytesRead);
588
+ const newlineIndex = contentChunk.indexOf('\n');
589
+ firstLine =
590
+ newlineIndex !== -1
591
+ ? contentChunk.substring(0, newlineIndex)
592
+ : contentChunk;
593
+ }
594
+ finally {
595
+ if (fd !== undefined) {
596
+ await fd.close();
538
597
  }
539
598
  }
599
+ const content = JSON.parse(firstLine);
600
+ let fullSessionId;
601
+ if (isSessionIdRecord(content)) {
602
+ fullSessionId = content['sessionId'];
603
+ }
540
604
  // Delete the session file
541
605
  await fs.promises.unlink(filePath);
542
606
  if (fullSessionId) {
@@ -554,69 +618,57 @@ export class ChatRecordingService {
554
618
  * All messages from (and including) the specified ID onwards are removed.
555
619
  */
556
620
  rewindTo(messageId) {
557
- if (!this.conversationFile) {
621
+ if (!this.conversationFile || !this.cachedConversation)
558
622
  return null;
559
- }
560
- const conversation = this.readConversation();
561
- const messageIndex = conversation.messages.findIndex((m) => m.id === messageId);
623
+ const messageIndex = this.cachedConversation.messages.findIndex((m) => m.id === messageId);
562
624
  if (messageIndex === -1) {
563
625
  debugLogger.error('Message to rewind to not found in conversation history');
564
- return conversation;
626
+ return this.cachedConversation;
565
627
  }
566
- conversation.messages = conversation.messages.slice(0, messageIndex);
567
- this.writeConversation(conversation, { allowEmpty: true });
568
- return conversation;
628
+ this.cachedConversation.messages = this.cachedConversation.messages.slice(0, messageIndex);
629
+ this.appendRecord({ $rewindTo: messageId });
630
+ return this.cachedConversation;
569
631
  }
570
- /**
571
- * Updates the conversation history based on the provided API Content array.
572
- * This is used to persist changes made to the history (like masking) back to disk.
573
- */
574
632
  updateMessagesFromHistory(history) {
575
- if (!this.conversationFile)
633
+ if (!this.conversationFile || !this.cachedConversation)
576
634
  return;
577
635
  try {
578
- this.updateConversation((conversation) => {
579
- // Create a map of tool results from the API history for quick lookup by call ID.
580
- // We store the full list of parts associated with each tool call ID to preserve
581
- // multi-modal data and proper trajectory structure.
582
- const partsMap = new Map();
583
- for (const content of history) {
584
- if (content.role === 'user' && content.parts) {
585
- // Find all unique call IDs in this message
586
- const callIds = content.parts
587
- .map((p) => p.functionResponse?.id)
588
- .filter((id) => !!id);
589
- if (callIds.length === 0)
590
- continue;
591
- // Use the first ID as a seed to capture any "leading" non-ID parts
592
- // in this specific content block.
593
- let currentCallId = callIds[0];
594
- for (const part of content.parts) {
595
- if (part.functionResponse?.id) {
596
- currentCallId = part.functionResponse.id;
597
- }
598
- if (!partsMap.has(currentCallId)) {
599
- partsMap.set(currentCallId, []);
600
- }
601
- partsMap.get(currentCallId).push(part);
636
+ const partsMap = new Map();
637
+ for (const content of history) {
638
+ if (content.role === 'user' && content.parts) {
639
+ const callIds = content.parts
640
+ .map((p) => p.functionResponse?.id)
641
+ .filter((id) => !!id);
642
+ if (callIds.length === 0)
643
+ continue;
644
+ let currentCallId = callIds[0];
645
+ for (const part of content.parts) {
646
+ if (part.functionResponse?.id) {
647
+ currentCallId = part.functionResponse.id;
648
+ }
649
+ if (!partsMap.has(currentCallId)) {
650
+ partsMap.set(currentCallId, []);
602
651
  }
652
+ partsMap.get(currentCallId).push(part);
603
653
  }
604
654
  }
605
- // Update the conversation records tool results if they've changed.
606
- for (const message of conversation.messages) {
607
- if (message.type === 'gemini' && message.toolCalls) {
608
- for (const toolCall of message.toolCalls) {
609
- const newParts = partsMap.get(toolCall.id);
610
- if (newParts !== undefined) {
611
- // Store the results as proper Parts (including functionResponse)
612
- // instead of stringifying them as text parts. This ensures the
613
- // tool trajectory is correctly reconstructed upon session resumption.
614
- toolCall.result = newParts;
615
- }
655
+ }
656
+ for (const message of this.cachedConversation.messages) {
657
+ let msgChanged = false;
658
+ if (message.type === 'gemini' && message.toolCalls) {
659
+ for (const toolCall of message.toolCalls) {
660
+ const newParts = partsMap.get(toolCall.id);
661
+ if (newParts !== undefined) {
662
+ toolCall.result = newParts;
663
+ msgChanged = true;
616
664
  }
617
665
  }
618
666
  }
619
- });
667
+ if (msgChanged) {
668
+ // Push updated message to log
669
+ this.pushMessage(message);
670
+ }
671
+ }
620
672
  }
621
673
  catch (error) {
622
674
  debugLogger.error('Error updating conversation history from memory.', error);
@@ -624,4 +676,46 @@ export class ChatRecordingService {
624
676
  }
625
677
  }
626
678
  }
679
+ async function parseLegacyRecordFallback(filePath, options) {
680
+ try {
681
+ const fileContent = await fs.promises.readFile(filePath, 'utf8');
682
+ const parsed = JSON.parse(fileContent);
683
+ const isLegacyRecord = (val) => typeof val === 'object' && val !== null && 'sessionId' in val;
684
+ if (isLegacyRecord(parsed)) {
685
+ const legacyRecord = parsed;
686
+ if (options?.metadataOnly) {
687
+ let fallbackFirstUserMessageStr;
688
+ const firstUserMessage = legacyRecord.messages?.find((m) => m.type === 'user');
689
+ if (firstUserMessage) {
690
+ const rawContent = firstUserMessage.content;
691
+ if (Array.isArray(rawContent)) {
692
+ fallbackFirstUserMessageStr = rawContent
693
+ .map((p) => (isTextPart(p) ? p['text'] : ''))
694
+ .join('');
695
+ }
696
+ else if (typeof rawContent === 'string') {
697
+ fallbackFirstUserMessageStr = rawContent;
698
+ }
699
+ }
700
+ return {
701
+ ...legacyRecord,
702
+ messages: [],
703
+ messageCount: legacyRecord.messages?.length || 0,
704
+ userMessageCount: legacyRecord.messages?.filter((m) => m.type === 'user').length || 0,
705
+ firstUserMessage: fallbackFirstUserMessageStr,
706
+ hasUserOrAssistantMessage: legacyRecord.messages?.some((m) => m.type === 'user' || m.type === 'gemini') || false,
707
+ };
708
+ }
709
+ return {
710
+ ...legacyRecord,
711
+ userMessageCount: legacyRecord.messages?.filter((m) => m.type === 'user').length || 0,
712
+ hasUserOrAssistantMessage: legacyRecord.messages?.some((m) => m.type === 'user' || m.type === 'gemini') || false,
713
+ };
714
+ }
715
+ }
716
+ catch {
717
+ // ignore legacy fallback parse error
718
+ }
719
+ return null;
720
+ }
627
721
  //# sourceMappingURL=chatRecordingService.js.map