@xandout/libra-harness 0.1.34 → 0.1.91

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 (453) hide show
  1. package/README.md +30 -30
  2. package/dist/agent.d.ts +8 -0
  3. package/dist/agent.d.ts.map +1 -1
  4. package/dist/agent.js +205 -193
  5. package/dist/agent.js.map +1 -1
  6. package/dist/ai-sdk-model.d.ts.map +1 -1
  7. package/dist/ai-sdk-model.js +91 -78
  8. package/dist/ai-sdk-model.js.map +1 -1
  9. package/dist/context.d.ts +2 -0
  10. package/dist/context.d.ts.map +1 -1
  11. package/dist/{extras/extensions → extensions}/auto-steer/extension.d.ts +1 -1
  12. package/dist/extensions/auto-steer/extension.d.ts.map +1 -0
  13. package/dist/extensions/auto-steer/extension.js.map +1 -0
  14. package/dist/extensions/auto-steer/index.d.ts.map +1 -0
  15. package/dist/extensions/auto-steer/index.js.map +1 -0
  16. package/dist/extensions/code-tools/extension.d.ts +15 -0
  17. package/dist/extensions/code-tools/extension.d.ts.map +1 -0
  18. package/dist/extensions/code-tools/extension.js +73 -0
  19. package/dist/extensions/code-tools/extension.js.map +1 -0
  20. package/dist/extensions/code-tools/extension.test.d.ts.map +1 -0
  21. package/dist/extensions/code-tools/extension.test.js +504 -0
  22. package/dist/extensions/code-tools/extension.test.js.map +1 -0
  23. package/dist/extensions/code-tools/index.d.ts.map +1 -0
  24. package/dist/extensions/code-tools/index.js.map +1 -0
  25. package/dist/{extras/extensions → extensions}/code-tools/tools/code-search.d.ts +2 -2
  26. package/dist/extensions/code-tools/tools/code-search.d.ts.map +1 -0
  27. package/dist/{extras/extensions → extensions}/code-tools/tools/code-search.js +1 -1
  28. package/dist/extensions/code-tools/tools/code-search.js.map +1 -0
  29. package/dist/extensions/code-tools/tools/find.d.ts.map +1 -0
  30. package/dist/extensions/code-tools/tools/find.js +83 -0
  31. package/dist/extensions/code-tools/tools/find.js.map +1 -0
  32. package/dist/extensions/code-tools/tools/grep.d.ts.map +1 -0
  33. package/dist/extensions/code-tools/tools/grep.js +90 -0
  34. package/dist/extensions/code-tools/tools/grep.js.map +1 -0
  35. package/dist/extensions/code-tools/tools/read.d.ts.map +1 -0
  36. package/dist/{extras/extensions → extensions}/code-tools/tools/read.js +17 -25
  37. package/dist/extensions/code-tools/tools/read.js.map +1 -0
  38. package/dist/{extras/extensions → extensions}/code-tools/tools/shared.d.ts +5 -1
  39. package/dist/extensions/code-tools/tools/shared.d.ts.map +1 -0
  40. package/dist/{extras/extensions → extensions}/code-tools/tools/shared.js +68 -0
  41. package/dist/extensions/code-tools/tools/shared.js.map +1 -0
  42. package/dist/extensions/code-tools/tools/shell.d.ts +39 -0
  43. package/dist/extensions/code-tools/tools/shell.d.ts.map +1 -0
  44. package/dist/extensions/code-tools/tools/shell.js +441 -0
  45. package/dist/extensions/code-tools/tools/shell.js.map +1 -0
  46. package/dist/{extras/extensions → extensions}/code-tools/tools/todo.d.ts +0 -3
  47. package/dist/extensions/code-tools/tools/todo.d.ts.map +1 -0
  48. package/dist/{extras/extensions → extensions}/code-tools/tools/todo.js +0 -8
  49. package/dist/extensions/code-tools/tools/todo.js.map +1 -0
  50. package/dist/extensions/code-tools/tools/view-image.d.ts +10 -0
  51. package/dist/extensions/code-tools/tools/view-image.d.ts.map +1 -0
  52. package/dist/extensions/code-tools/tools/view-image.js +87 -0
  53. package/dist/extensions/code-tools/tools/view-image.js.map +1 -0
  54. package/dist/extensions/code-tools/tools/write.d.ts.map +1 -0
  55. package/dist/{extras/extensions → extensions}/code-tools/tools/write.js +47 -37
  56. package/dist/extensions/code-tools/tools/write.js.map +1 -0
  57. package/dist/{extras/extensions → extensions}/disk-session/extension.d.ts +45 -2
  58. package/dist/extensions/disk-session/extension.d.ts.map +1 -0
  59. package/dist/extensions/disk-session/extension.js +818 -0
  60. package/dist/extensions/disk-session/extension.js.map +1 -0
  61. package/dist/extensions/disk-session/extension.test.d.ts.map +1 -0
  62. package/dist/{extras/extensions → extensions}/disk-session/extension.test.js +445 -16
  63. package/dist/extensions/disk-session/extension.test.js.map +1 -0
  64. package/dist/extensions/disk-session/index.d.ts +3 -0
  65. package/dist/extensions/disk-session/index.d.ts.map +1 -0
  66. package/dist/extensions/disk-session/index.js +2 -0
  67. package/dist/extensions/disk-session/index.js.map +1 -0
  68. package/dist/{extras/extensions → extensions}/emoji/extension.d.ts +1 -1
  69. package/dist/extensions/emoji/extension.d.ts.map +1 -0
  70. package/dist/extensions/emoji/extension.js.map +1 -0
  71. package/dist/extensions/emoji/index.d.ts.map +1 -0
  72. package/dist/extensions/emoji/index.js.map +1 -0
  73. package/dist/extensions/filesystem/extension.d.ts.map +1 -0
  74. package/dist/extensions/filesystem/extension.js.map +1 -0
  75. package/dist/extensions/filesystem/extension.test.d.ts.map +1 -0
  76. package/dist/extensions/filesystem/extension.test.js.map +1 -0
  77. package/dist/extensions/filesystem/index.d.ts.map +1 -0
  78. package/dist/extensions/filesystem/index.js.map +1 -0
  79. package/dist/extensions/index.d.ts +3 -0
  80. package/dist/extensions/index.d.ts.map +1 -0
  81. package/dist/extensions/index.js +2 -0
  82. package/dist/extensions/index.js.map +1 -0
  83. package/dist/{extras/extensions → extensions}/keyword-extractor/extension.d.ts +1 -1
  84. package/dist/extensions/keyword-extractor/extension.d.ts.map +1 -0
  85. package/dist/{extras/extensions → extensions}/keyword-extractor/extension.js +1 -1
  86. package/dist/extensions/keyword-extractor/extension.js.map +1 -0
  87. package/dist/extensions/keyword-extractor/extension.test.d.ts.map +1 -0
  88. package/dist/extensions/keyword-extractor/extension.test.js.map +1 -0
  89. package/dist/extensions/keyword-extractor/index.d.ts.map +1 -0
  90. package/dist/extensions/keyword-extractor/index.js.map +1 -0
  91. package/dist/extensions/keyword-extractor/nlp.d.ts.map +1 -0
  92. package/dist/extensions/keyword-extractor/nlp.js.map +1 -0
  93. package/dist/extensions/keyword-extractor/nlp.test.d.ts.map +1 -0
  94. package/dist/extensions/keyword-extractor/nlp.test.js.map +1 -0
  95. package/dist/{extras/extension-loader.d.ts → extensions/loader.d.ts} +1 -1
  96. package/dist/extensions/loader.d.ts.map +1 -0
  97. package/dist/{extras/extension-loader.js → extensions/loader.js} +2 -2
  98. package/dist/extensions/loader.js.map +1 -0
  99. package/dist/{extras/extensions → extensions}/logger/extension.d.ts +1 -1
  100. package/dist/extensions/logger/extension.d.ts.map +1 -0
  101. package/dist/{extras/extensions → extensions}/logger/extension.js +1 -1
  102. package/dist/extensions/logger/extension.js.map +1 -0
  103. package/dist/extensions/logger/index.d.ts.map +1 -0
  104. package/dist/extensions/logger/index.js.map +1 -0
  105. package/dist/{extras/extensions → extensions}/mcp/extension.d.ts +1 -1
  106. package/dist/extensions/mcp/extension.d.ts.map +1 -0
  107. package/dist/extensions/mcp/extension.js.map +1 -0
  108. package/dist/extensions/mcp/extension.test.d.ts.map +1 -0
  109. package/dist/{extras/extensions → extensions}/mcp/extension.test.js +1 -1
  110. package/dist/extensions/mcp/extension.test.js.map +1 -0
  111. package/dist/extensions/mcp/index.d.ts.map +1 -0
  112. package/dist/extensions/mcp/index.js.map +1 -0
  113. package/dist/{extras/extensions → extensions}/mem-session/extension.d.ts +2 -2
  114. package/dist/extensions/mem-session/extension.d.ts.map +1 -0
  115. package/dist/extensions/mem-session/extension.js.map +1 -0
  116. package/dist/extensions/mem-session/index.d.ts.map +1 -0
  117. package/dist/extensions/mem-session/index.js.map +1 -0
  118. package/dist/{extras/extensions → extensions}/memory/extension.d.ts +1 -1
  119. package/dist/extensions/memory/extension.d.ts.map +1 -0
  120. package/dist/{extras/extensions → extensions}/memory/extension.js +1 -1
  121. package/dist/extensions/memory/extension.js.map +1 -0
  122. package/dist/extensions/memory/index.d.ts +4 -0
  123. package/dist/extensions/memory/index.d.ts.map +1 -0
  124. package/dist/extensions/memory/index.js.map +1 -0
  125. package/dist/{extras/extensions → extensions}/memory/llm-extractor.d.ts +1 -1
  126. package/dist/extensions/memory/llm-extractor.d.ts.map +1 -0
  127. package/dist/{extras/extensions → extensions}/memory/llm-extractor.js +1 -1
  128. package/dist/extensions/memory/llm-extractor.js.map +1 -0
  129. package/dist/{extras/extensions → extensions}/memory/types.d.ts +2 -2
  130. package/dist/extensions/memory/types.d.ts.map +1 -0
  131. package/dist/extensions/memory/types.js.map +1 -0
  132. package/dist/{extras/extensions → extensions}/otel/extension.d.ts +1 -1
  133. package/dist/extensions/otel/extension.d.ts.map +1 -0
  134. package/dist/{extras/extensions → extensions}/otel/extension.js +1 -1
  135. package/dist/extensions/otel/extension.js.map +1 -0
  136. package/dist/extensions/otel/extension.test.d.ts.map +1 -0
  137. package/dist/{extras/extensions → extensions}/otel/extension.test.js +1 -1
  138. package/dist/extensions/otel/extension.test.js.map +1 -0
  139. package/dist/extensions/otel/index.d.ts.map +1 -0
  140. package/dist/extensions/otel/index.js.map +1 -0
  141. package/dist/extensions/otel/jsonl-span-exporter.d.ts.map +1 -0
  142. package/dist/extensions/otel/jsonl-span-exporter.js.map +1 -0
  143. package/dist/{extras/extensions → extensions}/scripts/extension.d.ts +1 -1
  144. package/dist/extensions/scripts/extension.d.ts.map +1 -0
  145. package/dist/extensions/scripts/extension.js.map +1 -0
  146. package/dist/extensions/scripts/extension.test.d.ts.map +1 -0
  147. package/dist/extensions/scripts/extension.test.js.map +1 -0
  148. package/dist/extensions/scripts/index.d.ts.map +1 -0
  149. package/dist/extensions/scripts/index.js.map +1 -0
  150. package/dist/{extras/extensions → extensions}/skills/extension.d.ts +1 -1
  151. package/dist/extensions/skills/extension.d.ts.map +1 -0
  152. package/dist/extensions/skills/extension.js.map +1 -0
  153. package/dist/extensions/skills/extension.test.d.ts.map +1 -0
  154. package/dist/{extras/extensions → extensions}/skills/extension.test.js +1 -1
  155. package/dist/extensions/skills/extension.test.js.map +1 -0
  156. package/dist/extensions/skills/index.d.ts.map +1 -0
  157. package/dist/extensions/skills/index.js.map +1 -0
  158. package/dist/{extras/extensions → extensions}/streaming/extension.d.ts +1 -1
  159. package/dist/extensions/streaming/extension.d.ts.map +1 -0
  160. package/dist/extensions/streaming/extension.js.map +1 -0
  161. package/dist/extensions/streaming/index.d.ts.map +1 -0
  162. package/dist/extensions/streaming/index.js.map +1 -0
  163. package/dist/{extras/extensions → extensions}/structured-output/extension.d.ts +1 -1
  164. package/dist/extensions/structured-output/extension.d.ts.map +1 -0
  165. package/dist/extensions/structured-output/extension.js.map +1 -0
  166. package/dist/extensions/structured-output/index.d.ts.map +1 -0
  167. package/dist/extensions/structured-output/index.js.map +1 -0
  168. package/dist/{extras/extensions → extensions}/timestamp/extension.d.ts +1 -1
  169. package/dist/extensions/timestamp/extension.d.ts.map +1 -0
  170. package/dist/extensions/timestamp/extension.js.map +1 -0
  171. package/dist/extensions/timestamp/index.d.ts.map +1 -0
  172. package/dist/extensions/timestamp/index.js.map +1 -0
  173. package/dist/{extras/extensions → extensions}/token-stats/extension.d.ts +1 -1
  174. package/dist/extensions/token-stats/extension.d.ts.map +1 -0
  175. package/dist/extensions/token-stats/extension.js.map +1 -0
  176. package/dist/extensions/token-stats/extension.test.d.ts.map +1 -0
  177. package/dist/{extras/extensions → extensions}/token-stats/extension.test.js +1 -1
  178. package/dist/extensions/token-stats/extension.test.js.map +1 -0
  179. package/dist/extensions/token-stats/index.d.ts.map +1 -0
  180. package/dist/extensions/token-stats/index.js.map +1 -0
  181. package/dist/{extras/extensions → extensions}/tool-buffer/extension.d.ts +1 -1
  182. package/dist/extensions/tool-buffer/extension.d.ts.map +1 -0
  183. package/dist/extensions/tool-buffer/extension.js.map +1 -0
  184. package/dist/extensions/tool-buffer/extension.test.d.ts.map +1 -0
  185. package/dist/{extras/extensions → extensions}/tool-buffer/extension.test.js +1 -1
  186. package/dist/extensions/tool-buffer/extension.test.js.map +1 -0
  187. package/dist/extensions/tool-buffer/index.d.ts.map +1 -0
  188. package/dist/extensions/tool-buffer/index.js.map +1 -0
  189. package/dist/{extras/extensions → extensions}/weather-tool/extension.d.ts +1 -1
  190. package/dist/extensions/weather-tool/extension.d.ts.map +1 -0
  191. package/dist/extensions/weather-tool/extension.js.map +1 -0
  192. package/dist/extensions/weather-tool/index.d.ts.map +1 -0
  193. package/dist/extensions/weather-tool/index.js.map +1 -0
  194. package/dist/handle.d.ts +4 -0
  195. package/dist/handle.d.ts.map +1 -1
  196. package/dist/{extras/models → models}/ai-sdk-resolver.d.ts +1 -1
  197. package/dist/models/ai-sdk-resolver.d.ts.map +1 -0
  198. package/dist/{extras/models → models}/ai-sdk-resolver.js +1 -1
  199. package/dist/models/ai-sdk-resolver.js.map +1 -0
  200. package/dist/models/index.d.ts.map +1 -0
  201. package/dist/models/index.js.map +1 -0
  202. package/dist/{extras/models → models}/routing-model.d.ts +1 -1
  203. package/dist/models/routing-model.d.ts.map +1 -0
  204. package/dist/{extras/models → models}/routing-model.js +1 -1
  205. package/dist/models/routing-model.js.map +1 -0
  206. package/dist/openai-provider/index.d.ts.map +1 -0
  207. package/dist/openai-provider/index.js.map +1 -0
  208. package/dist/{extras/openai-provider → openai-provider}/server.d.ts +1 -1
  209. package/dist/openai-provider/server.d.ts.map +1 -0
  210. package/dist/openai-provider/server.js.map +1 -0
  211. package/package.json +108 -83
  212. package/dist/extras/extension-loader.d.ts.map +0 -1
  213. package/dist/extras/extension-loader.js.map +0 -1
  214. package/dist/extras/extensions/auto-steer/extension.d.ts.map +0 -1
  215. package/dist/extras/extensions/auto-steer/extension.js.map +0 -1
  216. package/dist/extras/extensions/auto-steer/index.d.ts.map +0 -1
  217. package/dist/extras/extensions/auto-steer/index.js.map +0 -1
  218. package/dist/extras/extensions/code-tools/extension.d.ts +0 -83
  219. package/dist/extras/extensions/code-tools/extension.d.ts.map +0 -1
  220. package/dist/extras/extensions/code-tools/extension.js +0 -93
  221. package/dist/extras/extensions/code-tools/extension.js.map +0 -1
  222. package/dist/extras/extensions/code-tools/extension.test.d.ts.map +0 -1
  223. package/dist/extras/extensions/code-tools/extension.test.js +0 -656
  224. package/dist/extras/extensions/code-tools/extension.test.js.map +0 -1
  225. package/dist/extras/extensions/code-tools/index.d.ts.map +0 -1
  226. package/dist/extras/extensions/code-tools/index.js.map +0 -1
  227. package/dist/extras/extensions/code-tools/tools/code-search.d.ts.map +0 -1
  228. package/dist/extras/extensions/code-tools/tools/code-search.js.map +0 -1
  229. package/dist/extras/extensions/code-tools/tools/find.d.ts.map +0 -1
  230. package/dist/extras/extensions/code-tools/tools/find.js +0 -161
  231. package/dist/extras/extensions/code-tools/tools/find.js.map +0 -1
  232. package/dist/extras/extensions/code-tools/tools/grep.d.ts.map +0 -1
  233. package/dist/extras/extensions/code-tools/tools/grep.js +0 -307
  234. package/dist/extras/extensions/code-tools/tools/grep.js.map +0 -1
  235. package/dist/extras/extensions/code-tools/tools/read.d.ts.map +0 -1
  236. package/dist/extras/extensions/code-tools/tools/read.js.map +0 -1
  237. package/dist/extras/extensions/code-tools/tools/shared.d.ts.map +0 -1
  238. package/dist/extras/extensions/code-tools/tools/shared.js.map +0 -1
  239. package/dist/extras/extensions/code-tools/tools/shell.d.ts +0 -49
  240. package/dist/extras/extensions/code-tools/tools/shell.d.ts.map +0 -1
  241. package/dist/extras/extensions/code-tools/tools/shell.js +0 -623
  242. package/dist/extras/extensions/code-tools/tools/shell.js.map +0 -1
  243. package/dist/extras/extensions/code-tools/tools/todo.d.ts.map +0 -1
  244. package/dist/extras/extensions/code-tools/tools/todo.js.map +0 -1
  245. package/dist/extras/extensions/code-tools/tools/write.d.ts.map +0 -1
  246. package/dist/extras/extensions/code-tools/tools/write.js.map +0 -1
  247. package/dist/extras/extensions/disk-session/extension.d.ts.map +0 -1
  248. package/dist/extras/extensions/disk-session/extension.js +0 -640
  249. package/dist/extras/extensions/disk-session/extension.js.map +0 -1
  250. package/dist/extras/extensions/disk-session/extension.test.d.ts.map +0 -1
  251. package/dist/extras/extensions/disk-session/extension.test.js.map +0 -1
  252. package/dist/extras/extensions/disk-session/index.d.ts +0 -3
  253. package/dist/extras/extensions/disk-session/index.d.ts.map +0 -1
  254. package/dist/extras/extensions/disk-session/index.js +0 -2
  255. package/dist/extras/extensions/disk-session/index.js.map +0 -1
  256. package/dist/extras/extensions/emoji/extension.d.ts.map +0 -1
  257. package/dist/extras/extensions/emoji/extension.js.map +0 -1
  258. package/dist/extras/extensions/emoji/index.d.ts.map +0 -1
  259. package/dist/extras/extensions/emoji/index.js.map +0 -1
  260. package/dist/extras/extensions/filesystem/extension.d.ts.map +0 -1
  261. package/dist/extras/extensions/filesystem/extension.js.map +0 -1
  262. package/dist/extras/extensions/filesystem/extension.test.d.ts.map +0 -1
  263. package/dist/extras/extensions/filesystem/extension.test.js.map +0 -1
  264. package/dist/extras/extensions/filesystem/index.d.ts.map +0 -1
  265. package/dist/extras/extensions/filesystem/index.js.map +0 -1
  266. package/dist/extras/extensions/keyword-extractor/extension.d.ts.map +0 -1
  267. package/dist/extras/extensions/keyword-extractor/extension.js.map +0 -1
  268. package/dist/extras/extensions/keyword-extractor/extension.test.d.ts.map +0 -1
  269. package/dist/extras/extensions/keyword-extractor/extension.test.js.map +0 -1
  270. package/dist/extras/extensions/keyword-extractor/index.d.ts.map +0 -1
  271. package/dist/extras/extensions/keyword-extractor/index.js.map +0 -1
  272. package/dist/extras/extensions/keyword-extractor/nlp.d.ts.map +0 -1
  273. package/dist/extras/extensions/keyword-extractor/nlp.js.map +0 -1
  274. package/dist/extras/extensions/keyword-extractor/nlp.test.d.ts.map +0 -1
  275. package/dist/extras/extensions/keyword-extractor/nlp.test.js.map +0 -1
  276. package/dist/extras/extensions/logger/extension.d.ts.map +0 -1
  277. package/dist/extras/extensions/logger/extension.js.map +0 -1
  278. package/dist/extras/extensions/logger/index.d.ts.map +0 -1
  279. package/dist/extras/extensions/logger/index.js.map +0 -1
  280. package/dist/extras/extensions/mcp/extension.d.ts.map +0 -1
  281. package/dist/extras/extensions/mcp/extension.js.map +0 -1
  282. package/dist/extras/extensions/mcp/extension.test.d.ts.map +0 -1
  283. package/dist/extras/extensions/mcp/extension.test.js.map +0 -1
  284. package/dist/extras/extensions/mcp/index.d.ts.map +0 -1
  285. package/dist/extras/extensions/mcp/index.js.map +0 -1
  286. package/dist/extras/extensions/mem-session/extension.d.ts.map +0 -1
  287. package/dist/extras/extensions/mem-session/extension.js.map +0 -1
  288. package/dist/extras/extensions/mem-session/index.d.ts.map +0 -1
  289. package/dist/extras/extensions/mem-session/index.js.map +0 -1
  290. package/dist/extras/extensions/memory/extension.d.ts.map +0 -1
  291. package/dist/extras/extensions/memory/extension.js.map +0 -1
  292. package/dist/extras/extensions/memory/index.d.ts +0 -5
  293. package/dist/extras/extensions/memory/index.d.ts.map +0 -1
  294. package/dist/extras/extensions/memory/index.js.map +0 -1
  295. package/dist/extras/extensions/memory/llm-extractor.d.ts.map +0 -1
  296. package/dist/extras/extensions/memory/llm-extractor.js.map +0 -1
  297. package/dist/extras/extensions/memory/types.d.ts.map +0 -1
  298. package/dist/extras/extensions/memory/types.js.map +0 -1
  299. package/dist/extras/extensions/otel/extension.d.ts.map +0 -1
  300. package/dist/extras/extensions/otel/extension.js.map +0 -1
  301. package/dist/extras/extensions/otel/extension.test.d.ts.map +0 -1
  302. package/dist/extras/extensions/otel/extension.test.js.map +0 -1
  303. package/dist/extras/extensions/otel/index.d.ts.map +0 -1
  304. package/dist/extras/extensions/otel/index.js.map +0 -1
  305. package/dist/extras/extensions/otel/jsonl-span-exporter.d.ts.map +0 -1
  306. package/dist/extras/extensions/otel/jsonl-span-exporter.js.map +0 -1
  307. package/dist/extras/extensions/scripts/extension.d.ts.map +0 -1
  308. package/dist/extras/extensions/scripts/extension.js.map +0 -1
  309. package/dist/extras/extensions/scripts/extension.test.d.ts.map +0 -1
  310. package/dist/extras/extensions/scripts/extension.test.js.map +0 -1
  311. package/dist/extras/extensions/scripts/index.d.ts.map +0 -1
  312. package/dist/extras/extensions/scripts/index.js.map +0 -1
  313. package/dist/extras/extensions/skills/extension.d.ts.map +0 -1
  314. package/dist/extras/extensions/skills/extension.js.map +0 -1
  315. package/dist/extras/extensions/skills/extension.test.d.ts.map +0 -1
  316. package/dist/extras/extensions/skills/extension.test.js.map +0 -1
  317. package/dist/extras/extensions/skills/index.d.ts.map +0 -1
  318. package/dist/extras/extensions/skills/index.js.map +0 -1
  319. package/dist/extras/extensions/streaming/extension.d.ts.map +0 -1
  320. package/dist/extras/extensions/streaming/extension.js.map +0 -1
  321. package/dist/extras/extensions/streaming/index.d.ts.map +0 -1
  322. package/dist/extras/extensions/streaming/index.js.map +0 -1
  323. package/dist/extras/extensions/structured-output/extension.d.ts.map +0 -1
  324. package/dist/extras/extensions/structured-output/extension.js.map +0 -1
  325. package/dist/extras/extensions/structured-output/index.d.ts.map +0 -1
  326. package/dist/extras/extensions/structured-output/index.js.map +0 -1
  327. package/dist/extras/extensions/timestamp/extension.d.ts.map +0 -1
  328. package/dist/extras/extensions/timestamp/extension.js.map +0 -1
  329. package/dist/extras/extensions/timestamp/index.d.ts.map +0 -1
  330. package/dist/extras/extensions/timestamp/index.js.map +0 -1
  331. package/dist/extras/extensions/token-stats/extension.d.ts.map +0 -1
  332. package/dist/extras/extensions/token-stats/extension.js.map +0 -1
  333. package/dist/extras/extensions/token-stats/extension.test.d.ts.map +0 -1
  334. package/dist/extras/extensions/token-stats/extension.test.js.map +0 -1
  335. package/dist/extras/extensions/token-stats/index.d.ts.map +0 -1
  336. package/dist/extras/extensions/token-stats/index.js.map +0 -1
  337. package/dist/extras/extensions/tool-buffer/extension.d.ts.map +0 -1
  338. package/dist/extras/extensions/tool-buffer/extension.js.map +0 -1
  339. package/dist/extras/extensions/tool-buffer/extension.test.d.ts.map +0 -1
  340. package/dist/extras/extensions/tool-buffer/extension.test.js.map +0 -1
  341. package/dist/extras/extensions/tool-buffer/index.d.ts.map +0 -1
  342. package/dist/extras/extensions/tool-buffer/index.js.map +0 -1
  343. package/dist/extras/extensions/weather-tool/extension.d.ts.map +0 -1
  344. package/dist/extras/extensions/weather-tool/extension.js.map +0 -1
  345. package/dist/extras/extensions/weather-tool/index.d.ts.map +0 -1
  346. package/dist/extras/extensions/weather-tool/index.js.map +0 -1
  347. package/dist/extras/models/ai-sdk-resolver.d.ts.map +0 -1
  348. package/dist/extras/models/ai-sdk-resolver.js.map +0 -1
  349. package/dist/extras/models/index.d.ts.map +0 -1
  350. package/dist/extras/models/index.js.map +0 -1
  351. package/dist/extras/models/routing-model.d.ts.map +0 -1
  352. package/dist/extras/models/routing-model.js.map +0 -1
  353. package/dist/extras/openai-provider/index.d.ts.map +0 -1
  354. package/dist/extras/openai-provider/index.js.map +0 -1
  355. package/dist/extras/openai-provider/server.d.ts.map +0 -1
  356. package/dist/extras/openai-provider/server.js.map +0 -1
  357. /package/dist/{extras/extensions → extensions}/auto-steer/extension.js +0 -0
  358. /package/dist/{extras/extensions → extensions}/auto-steer/extension.json +0 -0
  359. /package/dist/{extras/extensions → extensions}/auto-steer/index.d.ts +0 -0
  360. /package/dist/{extras/extensions → extensions}/auto-steer/index.js +0 -0
  361. /package/dist/{extras/extensions → extensions}/code-tools/extension.json +0 -0
  362. /package/dist/{extras/extensions → extensions}/code-tools/extension.test.d.ts +0 -0
  363. /package/dist/{extras/extensions → extensions}/code-tools/index.d.ts +0 -0
  364. /package/dist/{extras/extensions → extensions}/code-tools/index.js +0 -0
  365. /package/dist/{extras/extensions → extensions}/code-tools/tools/find.d.ts +0 -0
  366. /package/dist/{extras/extensions → extensions}/code-tools/tools/grep.d.ts +0 -0
  367. /package/dist/{extras/extensions → extensions}/code-tools/tools/read.d.ts +0 -0
  368. /package/dist/{extras/extensions → extensions}/code-tools/tools/write.d.ts +0 -0
  369. /package/dist/{extras/extensions → extensions}/disk-session/extension.json +0 -0
  370. /package/dist/{extras/extensions → extensions}/disk-session/extension.test.d.ts +0 -0
  371. /package/dist/{extras/extensions → extensions}/emoji/extension.js +0 -0
  372. /package/dist/{extras/extensions → extensions}/emoji/extension.json +0 -0
  373. /package/dist/{extras/extensions → extensions}/emoji/index.d.ts +0 -0
  374. /package/dist/{extras/extensions → extensions}/emoji/index.js +0 -0
  375. /package/dist/{extras/extensions → extensions}/filesystem/extension.d.ts +0 -0
  376. /package/dist/{extras/extensions → extensions}/filesystem/extension.js +0 -0
  377. /package/dist/{extras/extensions → extensions}/filesystem/extension.json +0 -0
  378. /package/dist/{extras/extensions → extensions}/filesystem/extension.test.d.ts +0 -0
  379. /package/dist/{extras/extensions → extensions}/filesystem/extension.test.js +0 -0
  380. /package/dist/{extras/extensions → extensions}/filesystem/index.d.ts +0 -0
  381. /package/dist/{extras/extensions → extensions}/filesystem/index.js +0 -0
  382. /package/dist/{extras/extensions → extensions}/keyword-extractor/extension.json +0 -0
  383. /package/dist/{extras/extensions → extensions}/keyword-extractor/extension.test.d.ts +0 -0
  384. /package/dist/{extras/extensions → extensions}/keyword-extractor/extension.test.js +0 -0
  385. /package/dist/{extras/extensions → extensions}/keyword-extractor/index.d.ts +0 -0
  386. /package/dist/{extras/extensions → extensions}/keyword-extractor/index.js +0 -0
  387. /package/dist/{extras/extensions → extensions}/keyword-extractor/nlp.d.ts +0 -0
  388. /package/dist/{extras/extensions → extensions}/keyword-extractor/nlp.js +0 -0
  389. /package/dist/{extras/extensions → extensions}/keyword-extractor/nlp.test.d.ts +0 -0
  390. /package/dist/{extras/extensions → extensions}/keyword-extractor/nlp.test.js +0 -0
  391. /package/dist/{extras/extensions → extensions}/logger/extension.json +0 -0
  392. /package/dist/{extras/extensions → extensions}/logger/index.d.ts +0 -0
  393. /package/dist/{extras/extensions → extensions}/logger/index.js +0 -0
  394. /package/dist/{extras/extensions → extensions}/mcp/extension.js +0 -0
  395. /package/dist/{extras/extensions → extensions}/mcp/extension.json +0 -0
  396. /package/dist/{extras/extensions → extensions}/mcp/extension.test.d.ts +0 -0
  397. /package/dist/{extras/extensions → extensions}/mcp/index.d.ts +0 -0
  398. /package/dist/{extras/extensions → extensions}/mcp/index.js +0 -0
  399. /package/dist/{extras/extensions → extensions}/mem-session/extension.js +0 -0
  400. /package/dist/{extras/extensions → extensions}/mem-session/extension.json +0 -0
  401. /package/dist/{extras/extensions → extensions}/mem-session/index.d.ts +0 -0
  402. /package/dist/{extras/extensions → extensions}/mem-session/index.js +0 -0
  403. /package/dist/{extras/extensions → extensions}/memory/extension.json +0 -0
  404. /package/dist/{extras/extensions → extensions}/memory/index.js +0 -0
  405. /package/dist/{extras/extensions → extensions}/memory/types.js +0 -0
  406. /package/dist/{extras/extensions → extensions}/otel/extension.json +0 -0
  407. /package/dist/{extras/extensions → extensions}/otel/extension.test.d.ts +0 -0
  408. /package/dist/{extras/extensions → extensions}/otel/index.d.ts +0 -0
  409. /package/dist/{extras/extensions → extensions}/otel/index.js +0 -0
  410. /package/dist/{extras/extensions → extensions}/otel/jsonl-span-exporter.d.ts +0 -0
  411. /package/dist/{extras/extensions → extensions}/otel/jsonl-span-exporter.js +0 -0
  412. /package/dist/{extras/extensions → extensions}/scripts/extension.js +0 -0
  413. /package/dist/{extras/extensions → extensions}/scripts/extension.json +0 -0
  414. /package/dist/{extras/extensions → extensions}/scripts/extension.test.d.ts +0 -0
  415. /package/dist/{extras/extensions → extensions}/scripts/extension.test.js +0 -0
  416. /package/dist/{extras/extensions → extensions}/scripts/index.d.ts +0 -0
  417. /package/dist/{extras/extensions → extensions}/scripts/index.js +0 -0
  418. /package/dist/{extras/extensions → extensions}/skills/extension.js +0 -0
  419. /package/dist/{extras/extensions → extensions}/skills/extension.json +0 -0
  420. /package/dist/{extras/extensions → extensions}/skills/extension.test.d.ts +0 -0
  421. /package/dist/{extras/extensions → extensions}/skills/index.d.ts +0 -0
  422. /package/dist/{extras/extensions → extensions}/skills/index.js +0 -0
  423. /package/dist/{extras/extensions → extensions}/streaming/extension.js +0 -0
  424. /package/dist/{extras/extensions → extensions}/streaming/extension.json +0 -0
  425. /package/dist/{extras/extensions → extensions}/streaming/index.d.ts +0 -0
  426. /package/dist/{extras/extensions → extensions}/streaming/index.js +0 -0
  427. /package/dist/{extras/extensions → extensions}/structured-output/extension.js +0 -0
  428. /package/dist/{extras/extensions → extensions}/structured-output/extension.json +0 -0
  429. /package/dist/{extras/extensions → extensions}/structured-output/index.d.ts +0 -0
  430. /package/dist/{extras/extensions → extensions}/structured-output/index.js +0 -0
  431. /package/dist/{extras/extensions → extensions}/timestamp/extension.js +0 -0
  432. /package/dist/{extras/extensions → extensions}/timestamp/extension.json +0 -0
  433. /package/dist/{extras/extensions → extensions}/timestamp/index.d.ts +0 -0
  434. /package/dist/{extras/extensions → extensions}/timestamp/index.js +0 -0
  435. /package/dist/{extras/extensions → extensions}/token-stats/extension.js +0 -0
  436. /package/dist/{extras/extensions → extensions}/token-stats/extension.json +0 -0
  437. /package/dist/{extras/extensions → extensions}/token-stats/extension.test.d.ts +0 -0
  438. /package/dist/{extras/extensions → extensions}/token-stats/index.d.ts +0 -0
  439. /package/dist/{extras/extensions → extensions}/token-stats/index.js +0 -0
  440. /package/dist/{extras/extensions → extensions}/tool-buffer/extension.js +0 -0
  441. /package/dist/{extras/extensions → extensions}/tool-buffer/extension.json +0 -0
  442. /package/dist/{extras/extensions → extensions}/tool-buffer/extension.test.d.ts +0 -0
  443. /package/dist/{extras/extensions → extensions}/tool-buffer/index.d.ts +0 -0
  444. /package/dist/{extras/extensions → extensions}/tool-buffer/index.js +0 -0
  445. /package/dist/{extras/extensions → extensions}/weather-tool/extension.js +0 -0
  446. /package/dist/{extras/extensions → extensions}/weather-tool/extension.json +0 -0
  447. /package/dist/{extras/extensions → extensions}/weather-tool/index.d.ts +0 -0
  448. /package/dist/{extras/extensions → extensions}/weather-tool/index.js +0 -0
  449. /package/dist/{extras/models → models}/index.d.ts +0 -0
  450. /package/dist/{extras/models → models}/index.js +0 -0
  451. /package/dist/{extras/openai-provider → openai-provider}/index.d.ts +0 -0
  452. /package/dist/{extras/openai-provider → openai-provider}/index.js +0 -0
  453. /package/dist/{extras/openai-provider → openai-provider}/server.js +0 -0
@@ -0,0 +1,818 @@
1
+ import { readFileSync, appendFileSync, mkdirSync, readdirSync, writeFileSync, existsSync, renameSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { messageContentToText } from '@xandout/libra-harness';
4
+ /**
5
+ * Default resolver: reads `metadata.session` as a `SessionIdentity`,
6
+ * falls back to `metadata.sessionId` as a plain key, then to `'default'`.
7
+ */
8
+ const defaultResolver = {
9
+ resolve(metadata) {
10
+ const session = metadata.session;
11
+ if (session && typeof session.key === 'string')
12
+ return session;
13
+ const sessionId = metadata.sessionId;
14
+ if (sessionId)
15
+ return { key: sessionId, messageTs: '' };
16
+ return { key: 'default', messageTs: '' };
17
+ },
18
+ };
19
+ /**
20
+ * Sanitizes a message sequence to strictly conform to LLM tool-call schemas:
21
+ * 1. Every message with role 'tool' MUST directly follow an assistant message
22
+ * with a matching tool call id (or follow valid sibling tool messages for that same assistant).
23
+ * Any orphan or duplicate tool messages are dropped.
24
+ * 2. If an assistant message has toolCalls, but some or all tool calls were never
25
+ * fulfilled (e.g. session interrupted mid-turn or tool execution halted), its
26
+ * toolCalls array is pruned to only the fulfilled tool calls.
27
+ * 3. If an assistant message has toolCalls but none were fulfilled:
28
+ * - If the assistant message has non-empty text content, toolCalls is stripped.
29
+ * - If the assistant message has no text content, it is removed entirely.
30
+ */
31
+ export function sanitizeConversationMessages(messages) {
32
+ const result = [];
33
+ let pendingAssistantIdx = -1;
34
+ let pendingToolCallIds = null;
35
+ let fulfilledToolCallIds = new Set();
36
+ function finalizePendingAssistant() {
37
+ if (pendingAssistantIdx === -1 || !pendingToolCallIds)
38
+ return;
39
+ const assistantMsg = result[pendingAssistantIdx];
40
+ if (assistantMsg && assistantMsg.toolCalls) {
41
+ const keptCalls = assistantMsg.toolCalls.filter((tc) => fulfilledToolCallIds.has(tc.id));
42
+ if (keptCalls.length > 0) {
43
+ assistantMsg.toolCalls = keptCalls;
44
+ }
45
+ else {
46
+ delete assistantMsg.toolCalls;
47
+ const text = messageContentToText(assistantMsg.content).trim();
48
+ if (!text) {
49
+ result.splice(pendingAssistantIdx, 1);
50
+ }
51
+ }
52
+ }
53
+ pendingAssistantIdx = -1;
54
+ pendingToolCallIds = null;
55
+ fulfilledToolCallIds = new Set();
56
+ }
57
+ for (const msg of messages) {
58
+ if (msg.role === 'tool') {
59
+ if (!pendingToolCallIds || !msg.toolCallId || !pendingToolCallIds.has(msg.toolCallId)) {
60
+ // Orphan tool message with no matching preceding assistant tool call — drop it
61
+ continue;
62
+ }
63
+ if (fulfilledToolCallIds.has(msg.toolCallId)) {
64
+ // Duplicate tool message for the same tool call id — drop it
65
+ continue;
66
+ }
67
+ fulfilledToolCallIds.add(msg.toolCallId);
68
+ result.push(msg);
69
+ continue;
70
+ }
71
+ // Any non-tool message finalizes the preceding assistant's tool-calls
72
+ finalizePendingAssistant();
73
+ if (msg.role === 'assistant') {
74
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
75
+ pendingAssistantIdx = result.length;
76
+ pendingToolCallIds = new Set(msg.toolCalls.map((tc) => tc.id));
77
+ fulfilledToolCallIds = new Set();
78
+ result.push({ ...msg, toolCalls: [...msg.toolCalls] });
79
+ }
80
+ else {
81
+ result.push(msg);
82
+ }
83
+ }
84
+ else {
85
+ // user or system message
86
+ result.push(msg);
87
+ }
88
+ }
89
+ finalizePendingAssistant();
90
+ return result;
91
+ }
92
+ export function isContextLengthError(err) {
93
+ if (!err)
94
+ return false;
95
+ const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();
96
+ return (msg.includes('context_length') ||
97
+ msg.includes('context length') ||
98
+ msg.includes('prompt is too long') ||
99
+ msg.includes('maximum context length') ||
100
+ msg.includes('exceeds the context window') ||
101
+ msg.includes('too many tokens') ||
102
+ msg.includes('token limit') ||
103
+ msg.includes('max_tokens') ||
104
+ msg.includes('string_above_max_length'));
105
+ }
106
+ export async function generateSessionSummary(model, records) {
107
+ const summarySystemPrompt = 'You are a precise conversation summarizer for an AI agent. ' +
108
+ 'Provide a dense, structured summary of the provided conversation history. ' +
109
+ 'Preserve all essential technical details, user goals, key decisions, file paths, ' +
110
+ 'code changes, commands executed, tool outputs, errors, and pending tasks. ' +
111
+ 'Do not include conversational filler. Output only the summary.';
112
+ const transcript = records
113
+ .map((r) => {
114
+ const text = messageContentToText(r.content).trim();
115
+ const role = r.role.toUpperCase();
116
+ const tools = r.toolCalls ? ` [called: ${r.toolCalls.map((tc) => tc.name).join(', ')}]` : '';
117
+ return `[${role}${tools}]: ${text}`;
118
+ })
119
+ .filter((line) => line.length > 0)
120
+ .join('\n\n');
121
+ const response = await model.generate({
122
+ messages: [
123
+ {
124
+ role: 'user',
125
+ content: `Please summarize this earlier conversation segment to preserve context:\n\n${transcript}`,
126
+ },
127
+ ],
128
+ systemPrompt: summarySystemPrompt,
129
+ });
130
+ return messageContentToText(response.message.content).trim();
131
+ }
132
+ /**
133
+ * Disk-backed session extension.
134
+ *
135
+ * ## Architecture
136
+ *
137
+ * **One JSONL file per session** (`<sessionKey>.jsonl`). Append-only —
138
+ * every message the agent sees (human or bot, top-level or threaded) is
139
+ * appended. This log is the source of truth.
140
+ *
141
+ * **Snapshot at beforeTurn**: when a turn starts, the extension takes a
142
+ * read-only snapshot of the session log at that moment. The turn runs
143
+ * against the snapshot. Concurrent turns each take their own snapshot
144
+ * and don't see each other's in-progress work.
145
+ *
146
+ * **Fork for threads**: when a thread reply comes in (identity has
147
+ * `threadTs`), the snapshot is filtered to include only:
148
+ * 1. Top-level messages before the thread parent (channel context)
149
+ * 2. All messages in that thread (parent + replies)
150
+ * 3. Recent top-level messages after the last thread reply
151
+ *
152
+ * **Append after turn**: when the turn finishes, new messages (user +
153
+ * assistant + tool calls) are appended to the session log. No data is
154
+ * ever rewritten or reordered.
155
+ *
156
+ * **Stable prefix for LLM caching**: the messages array is built as
157
+ * [system prompt] + [stable session history] + [new user message]
158
+ * The session history grows monotonically (append-only), so earlier
159
+ * tokens stay cached upstream. Per-turn metadata is injected at the end
160
+ * of the context (by a host-side `beforeContext` hook), not the
161
+ * beginning, to preserve the cache prefix.
162
+ *
163
+ * ## Host integration
164
+ *
165
+ * The host supplies a {@link SessionResolver} (or writes
166
+ * `metadata.session`) so the extension knows which session a turn
167
+ * belongs to. The extension itself is host-agnostic — it doesn't know
168
+ * about Slack, Discord, or any other platform.
169
+ */
170
+ export default function createDiskSessionExtension(config) {
171
+ const dir = config?.sessionDir ?? './sessions';
172
+ const maxRecords = config?.maxRecords ?? 1000;
173
+ const maxContextMessages = config?.maxContextMessages ?? 50;
174
+ const contextEvictionStep = config?.contextEvictionStep ?? Math.max(1, Math.floor(maxContextMessages / 2));
175
+ const autoSummarize = config?.autoSummarize ?? true;
176
+ const fallbackThresholds = config?.fallbackThresholds ?? [
177
+ maxContextMessages,
178
+ Math.max(10, Math.floor(maxContextMessages / 2)),
179
+ Math.max(5, Math.floor(maxContextMessages / 4)),
180
+ ];
181
+ const channelContextMessages = config?.channelContextMessages ?? 10;
182
+ const recentChannelMessages = config?.recentChannelMessages ?? 5;
183
+ const loadOnStartup = config?.loadOnStartup ?? true;
184
+ const resolver = config?.resolver ?? defaultResolver;
185
+ mkdirSync(dir, { recursive: true });
186
+ // In-memory cache: sessionKey → SessionRecord[]
187
+ // This is the live log. Reads take a snapshot (copy); writes append.
188
+ const store = new Map();
189
+ // Effective context limit per session for fallback backoff
190
+ const sessionLimits = new Map();
191
+ // ── Load existing sessions from disk ──────────────────────────
192
+ if (loadOnStartup) {
193
+ try {
194
+ const files = readdirSync(dir).filter((f) => f.endsWith('.jsonl'));
195
+ let totalRecords = 0;
196
+ for (const file of files) {
197
+ try {
198
+ const raw = readFileSync(join(dir, file), 'utf-8');
199
+ const lines = raw.split('\n').filter((l) => l.trim());
200
+ const records = lines.map((l) => JSON.parse(l));
201
+ const sessionKey = file.replace(/\.jsonl$/, '');
202
+ store.set(sessionKey, records.slice(-maxRecords));
203
+ totalRecords += records.length;
204
+ }
205
+ catch {
206
+ // Skip corrupt files.
207
+ }
208
+ }
209
+ if (store.size > 0 && config?.verbose !== false) {
210
+ console.log(`[disk-session] loaded ${store.size} session(s), ${totalRecords} record(s) from ${dir}`);
211
+ }
212
+ }
213
+ catch {
214
+ // Directory doesn't exist — start empty.
215
+ }
216
+ }
217
+ function filePath(sessionKey) {
218
+ const safe = sessionKey.replace(/[^a-zA-Z0-9_-]/g, '_');
219
+ return join(dir, `${safe}.jsonl`);
220
+ }
221
+ function appendToFile(sessionKey, records) {
222
+ if (records.length === 0)
223
+ return;
224
+ const lines = records.map((r) => JSON.stringify(r)).join('\n') + '\n';
225
+ try {
226
+ appendFileSync(filePath(sessionKey), lines);
227
+ }
228
+ catch (err) {
229
+ console.error(`[disk-session] failed to append to ${sessionKey}:`, err);
230
+ }
231
+ }
232
+ function persistRecords(sessionKey, newRecords) {
233
+ const records = store.get(sessionKey) ?? [];
234
+ records.push(...newRecords);
235
+ if (records.length > maxRecords) {
236
+ records.splice(0, records.length - maxRecords);
237
+ }
238
+ store.set(sessionKey, records);
239
+ appendToFile(sessionKey, newRecords);
240
+ }
241
+ function handleCompaction(turn, key, messageTs) {
242
+ const summary = turn.response?.message ?? '';
243
+ const oldPath = filePath(key);
244
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
245
+ const archivedName = `${key.replace(/[^a-zA-Z0-9_-]/g, '_')}_${timestamp}.jsonl`;
246
+ const archivedPath = join(dir, archivedName);
247
+ if (existsSync(oldPath)) {
248
+ renameSync(oldPath, archivedPath);
249
+ }
250
+ const summaryRecord = {
251
+ role: 'assistant',
252
+ content: `[Session summary — prior conversation compacted ${new Date().toISOString()}]\n\n${summary}`,
253
+ ts: messageTs || String(Date.now() / 1000),
254
+ recordedAt: new Date().toISOString(),
255
+ };
256
+ store.set(key, [summaryRecord]);
257
+ appendToFile(key, [summaryRecord]);
258
+ turn.metadata['_compactArchivedFile'] = archivedName;
259
+ }
260
+ // ── Convert between Message and SessionRecord ──────────────────
261
+ function toMessage(r) {
262
+ return {
263
+ // `toMessage` is only called on records that passed
264
+ // `isConversationMessage`, which excludes 'control' (and 'tool').
265
+ role: r.role,
266
+ content: r.content,
267
+ ...(r.toolCalls ? { toolCalls: r.toolCalls } : {}),
268
+ ...(r.toolCallId ? { toolCallId: r.toolCallId } : {}),
269
+ ...(r.name ? { name: r.name } : {}),
270
+ };
271
+ }
272
+ function toRecord(msg, ts, threadTs) {
273
+ return {
274
+ role: msg.role,
275
+ content: msg.content,
276
+ ...(msg.toolCalls ? { toolCalls: msg.toolCalls } : {}),
277
+ ...(msg.toolCallId ? { toolCallId: msg.toolCallId } : {}),
278
+ ...(msg.name ? { name: msg.name } : {}),
279
+ ts,
280
+ ...(threadTs ? { threadTs } : {}),
281
+ recordedAt: new Date().toISOString(),
282
+ };
283
+ }
284
+ // Filter for context windows: keep user, system, assistant, and tool messages.
285
+ // We no longer filter out tool calls here. Instead, we rely on turn-boundary
286
+ // slicing to ensure we don't split a tool sequence.
287
+ const isConversationMessage = (r) => {
288
+ if (r.role === 'control')
289
+ return false;
290
+ return true;
291
+ };
292
+ // Drop trailing user messages that don't have a following assistant
293
+ // response. This happens when a turn was interrupted (crash, halt,
294
+ // kill -9). Including an unanswered user request from a prior session
295
+ // confuses the agent — it sees a request it never responded to.
296
+ function dropIncompleteTrailingTurn(records) {
297
+ const result = [...records];
298
+ while (result.length > 0 && result[result.length - 1].role === 'user') {
299
+ result.pop();
300
+ }
301
+ return result;
302
+ }
303
+ function dropIncompleteTrailingMessages(messages) {
304
+ const result = [...messages];
305
+ while (result.length > 0 && result[result.length - 1].role === 'user') {
306
+ result.pop();
307
+ }
308
+ return result;
309
+ }
310
+ function sliceAtTurnBoundary(records, max, step) {
311
+ if (records.length <= max)
312
+ return records;
313
+ const evictionStep = step && step > 0 ? step : 1;
314
+ let startIndex;
315
+ if (evictionStep <= 1) {
316
+ startIndex = records.length - max;
317
+ }
318
+ else {
319
+ const baseline = Math.max(0, max - evictionStep);
320
+ const excess = records.length - baseline;
321
+ const chunks = Math.floor(excess / evictionStep);
322
+ startIndex = chunks * evictionStep;
323
+ }
324
+ // Skip forward until we find a turn boundary ('user' or 'system')
325
+ while (startIndex < records.length &&
326
+ records[startIndex].role !== 'user' &&
327
+ records[startIndex].role !== 'system') {
328
+ startIndex++;
329
+ }
330
+ return records.slice(startIndex);
331
+ }
332
+ // ── Build context (the "fork") from a snapshot ────────────────
333
+ // The snapshot is a read-only copy of the session records at the
334
+ // moment the turn started. This function builds the messages array
335
+ // that the agent will see.
336
+ //
337
+ // For top-level messages and DMs: last N records (sliced at turn boundary).
338
+ // For thread replies: channel context before parent + thread history.
339
+ function buildContext(snapshot, threadTs, isDirect, maxContext = maxContextMessages, step = contextEvictionStep) {
340
+ if (snapshot.length === 0)
341
+ return [];
342
+ let rawRecords;
343
+ // DM or top-level message: last N messages, but safe-sliced to not
344
+ // split tool-call sequences.
345
+ if (isDirect || !threadTs) {
346
+ const filtered = snapshot.filter(isConversationMessage);
347
+ const complete = dropIncompleteTrailingTurn(filtered);
348
+ rawRecords = sliceAtTurnBoundary(complete, maxContext, step);
349
+ }
350
+ else {
351
+ // Thread: fork from channel context.
352
+ const parentIdx = snapshot.findIndex((r) => r.ts === threadTs);
353
+ if (parentIdx === -1) {
354
+ // Parent not in snapshot (evicted from cache or very old).
355
+ // Fall back to last N messages.
356
+ const filtered = snapshot.filter(isConversationMessage);
357
+ const complete = dropIncompleteTrailingTurn(filtered);
358
+ rawRecords = sliceAtTurnBoundary(complete, maxContext, step);
359
+ }
360
+ else {
361
+ // Top-level messages before the parent (channel context at fork point).
362
+ const topLevelBefore = snapshot
363
+ .slice(0, parentIdx)
364
+ .filter((r) => !r.threadTs && isConversationMessage(r));
365
+ const slicedTopLevelBefore = sliceAtTurnBoundary(topLevelBefore, channelContextMessages);
366
+ // All messages in this thread (including the parent).
367
+ const threadMessages = snapshot
368
+ .filter((r) => (r.ts === threadTs || r.threadTs === threadTs) && isConversationMessage(r));
369
+ // Recent top-level messages after the last thread reply.
370
+ const lastThreadTs = threadMessages[threadMessages.length - 1]?.ts ?? threadTs;
371
+ let lastThreadIdx = parentIdx;
372
+ for (let i = snapshot.length - 1; i >= 0; i--) {
373
+ if (snapshot[i].ts === lastThreadTs) {
374
+ lastThreadIdx = i;
375
+ break;
376
+ }
377
+ }
378
+ const recentTopLevel = snapshot
379
+ .slice(lastThreadIdx + 1)
380
+ .filter((r) => !r.threadTs && isConversationMessage(r));
381
+ const slicedRecentTopLevel = recentChannelMessages > 0
382
+ ? sliceAtTurnBoundary(recentTopLevel, recentChannelMessages)
383
+ : [];
384
+ rawRecords = [...slicedTopLevelBefore, ...threadMessages, ...slicedRecentTopLevel];
385
+ }
386
+ }
387
+ const messages = rawRecords.map(toMessage);
388
+ const sanitized = sanitizeConversationMessages(messages);
389
+ return dropIncompleteTrailingMessages(sanitized);
390
+ }
391
+ // ── Resolve session identity from turn metadata ───────────────
392
+ function identityFromCtx(ctx) {
393
+ return resolver.resolve(ctx.turn.request.metadata ?? {});
394
+ }
395
+ return {
396
+ name: 'disk-session',
397
+ priority: -100,
398
+ install(agent) {
399
+ const activeModel = config?.model ?? agent.model;
400
+ // ── beforeTurn: take snapshot, build context, prepend ─────
401
+ // The snapshot is a copy of the session records at this moment.
402
+ // Concurrent turns each get their own snapshot — they don't
403
+ // see each other's in-progress work.
404
+ agent.hook('beforeTurn', 'disk-session', async (ctx) => {
405
+ const identity = identityFromCtx(ctx);
406
+ if (!identity)
407
+ return;
408
+ const { key, messageTs, threadTs, isDirect } = identity;
409
+ const isDm = isDirect ?? false;
410
+ const effectiveMax = sessionLimits.get(key) ?? maxContextMessages;
411
+ // ── Auto-summarization ──────────────────────────────────
412
+ // When conversation history reaches effectiveMax, auto-summarize the
413
+ // oldest chunk so earlier context is retained without thrashing prompt cache.
414
+ const liveRecords = store.get(key) ?? [];
415
+ const convCount = liveRecords.filter(isConversationMessage).length;
416
+ let autoCompacted = false;
417
+ let compactedCount = 0;
418
+ if (autoSummarize && activeModel && convCount >= effectiveMax) {
419
+ const step = config?.contextEvictionStep ?? Math.max(1, Math.floor(effectiveMax / 2));
420
+ let cutIndex = Math.min(step, liveRecords.length - 1);
421
+ while (cutIndex < liveRecords.length &&
422
+ liveRecords[cutIndex].role !== 'user' &&
423
+ liveRecords[cutIndex].role !== 'system') {
424
+ cutIndex++;
425
+ }
426
+ if (cutIndex > 0 && cutIndex < liveRecords.length) {
427
+ const recordsToSummarize = liveRecords.slice(0, cutIndex);
428
+ const recordsToKeep = liveRecords.slice(cutIndex);
429
+ try {
430
+ const summaryText = await generateSessionSummary(activeModel, recordsToSummarize);
431
+ if (summaryText) {
432
+ const summaryRecord = {
433
+ role: 'assistant',
434
+ content: `[Conversation summary — prior history compacted ${new Date().toISOString()}]\n\n${summaryText}`,
435
+ ts: recordsToSummarize[recordsToSummarize.length - 1]?.ts || String(Date.now() / 1000),
436
+ recordedAt: new Date().toISOString(),
437
+ };
438
+ const compactedRecords = [summaryRecord, ...recordsToKeep];
439
+ store.set(key, compactedRecords);
440
+ const oldPath = filePath(key);
441
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
442
+ const archivedName = `${key.replace(/[^a-zA-Z0-9_-]/g, '_')}_${timestamp}.jsonl`;
443
+ const archivedPath = join(dir, archivedName);
444
+ if (existsSync(oldPath)) {
445
+ try {
446
+ renameSync(oldPath, archivedPath);
447
+ }
448
+ catch { }
449
+ }
450
+ appendToFile(key, compactedRecords);
451
+ autoCompacted = true;
452
+ compactedCount = recordsToSummarize.length;
453
+ }
454
+ }
455
+ catch (err) {
456
+ console.warn('[disk-session] auto-summarization failed, using window slice:', err);
457
+ }
458
+ }
459
+ }
460
+ // Snapshot: copy the current records (read-only).
461
+ const currentRecords = store.get(key) ?? [];
462
+ const snapshot = [...currentRecords];
463
+ // Build the forked context from the snapshot.
464
+ const history = buildContext(snapshot, threadTs, isDm, effectiveMax, contextEvictionStep);
465
+ // ── Persist the user message immediately ────────────────
466
+ // Write the incoming user message to disk NOW, before the
467
+ // agent runs. If the process crashes mid-turn, the user's
468
+ // message is already saved. The assistant response is
469
+ // appended later in afterTurn.
470
+ //
471
+ // The system prompt is captured at afterTurn (not here) because
472
+ // beforeContext hooks (which run after beforeTurn) may modify
473
+ // ctx.turn.systemPrompt. Recording it here would miss those
474
+ // modifications. See afterTurn for the capture.
475
+ //
476
+ // Enrichment bag: any extension that ran before us in
477
+ // beforeTurn may have written into `sessionMeta`. We persist
478
+ // it opaquely — disk-session does not inspect the contents.
479
+ const sessionMeta = ctx.turn.metadata.sessionMeta;
480
+ const userRecord = {
481
+ ...toRecord({ role: 'user', content: ctx.turn.request.message }, messageTs, threadTs),
482
+ ...(sessionMeta ? { meta: sessionMeta } : {}),
483
+ };
484
+ persistRecords(key, [userRecord]);
485
+ // Track how many history messages we prepended so afterTurn
486
+ // knows where new messages start.
487
+ ctx.turn.metadata['_diskSessionHistoryLen'] = history.length;
488
+ // Immediately before the model acts: if auto-compaction occurred,
489
+ // inform the model so it can act accordingly. Never inform the human.
490
+ const messagesToPrepend = [...history];
491
+ if (autoCompacted) {
492
+ const modelNotice = {
493
+ role: 'system',
494
+ content: `[System Notice: Earlier conversation history (${compactedCount} messages) was automatically compacted into the summary above to preserve context. Refer to the summary for earlier decisions, code changes, and context.]`,
495
+ };
496
+ messagesToPrepend.push(modelNotice);
497
+ ctx.turn.metadata['_autoCompacted'] = true;
498
+ }
499
+ if (messagesToPrepend.length > 0) {
500
+ ctx.turn.messages = [...messagesToPrepend, ...ctx.turn.messages];
501
+ }
502
+ // Track all messages currently in ctx.turn.messages (both history and the
503
+ // initial user message just written) so beforeLLM only persists new steering messages.
504
+ const writtenMessages = new Set(ctx.turn.messages);
505
+ ctx.turn.metadata['_diskSessionWrittenMessages'] = writtenMessages;
506
+ });
507
+ // ── beforeLLM: persist any mid-turn steering messages ─────
508
+ // When turn.steer() is called, agent.ts injects steering messages
509
+ // into turn.messages with a [steering] prefix. We persist them to disk
510
+ // right before the LLM runs to respond to them.
511
+ agent.hook('beforeLLM', 'disk-session', async (ctx) => {
512
+ const identity = identityFromCtx(ctx);
513
+ if (!identity)
514
+ return;
515
+ const { key, messageTs, threadTs } = identity;
516
+ const written = ctx.turn.metadata['_diskSessionWrittenMessages'];
517
+ const sessionMeta = ctx.turn.metadata.sessionMeta;
518
+ const newSteering = [];
519
+ for (const msg of ctx.turn.messages) {
520
+ if (msg.role === 'user' && (!written || !written.has(msg))) {
521
+ newSteering.push({
522
+ ...toRecord(msg, messageTs, threadTs),
523
+ ...(sessionMeta ? { meta: sessionMeta } : {}),
524
+ });
525
+ written?.add(msg);
526
+ }
527
+ }
528
+ if (newSteering.length > 0) {
529
+ const records = store.get(key) ?? [];
530
+ records.push(...newSteering);
531
+ if (records.length > maxRecords) {
532
+ records.splice(0, records.length - maxRecords);
533
+ }
534
+ store.set(key, records);
535
+ appendToFile(key, newSteering);
536
+ }
537
+ });
538
+ // ── afterLLM: accumulate token usage + append assistant msg ──
539
+ // Each LLM call returns usage (prompt/completion tokens). We
540
+ // accumulate them across all iterations in the turn so the final
541
+ // assistant record has the total cost.
542
+ //
543
+ // We also append the assistant message (including tool calls) to
544
+ // the session log immediately, so the JSONL file is updated
545
+ // iteration by iteration rather than only at afterTurn. Tool
546
+ // results are appended in the afterTool hook below.
547
+ agent.hook('afterLLM', 'disk-session', async (ctx) => {
548
+ const identity = identityFromCtx(ctx);
549
+ if (!identity)
550
+ return;
551
+ const { key, messageTs, threadTs } = identity;
552
+ const usage = ctx.modelResponse?.usage;
553
+ if (usage) {
554
+ const prev = ctx.turn.metadata['_diskSessionUsage'] ?? { promptTokens: 0, completionTokens: 0, iterations: 0 };
555
+ ctx.turn.metadata['_diskSessionUsage'] = {
556
+ promptTokens: prev.promptTokens + usage.promptTokens,
557
+ completionTokens: prev.completionTokens + usage.completionTokens,
558
+ iterations: prev.iterations + 1,
559
+ ...(usage.cachedPromptTokens && {
560
+ cachedPromptTokens: (prev.cachedPromptTokens ?? 0) + usage.cachedPromptTokens,
561
+ }),
562
+ ...(usage.reasoningTokens && {
563
+ reasoningTokens: (prev.reasoningTokens ?? 0) + usage.reasoningTokens,
564
+ }),
565
+ };
566
+ }
567
+ // ── Incremental append: write the assistant message now ──
568
+ // The agent core pushes the assistant message to turn.messages
569
+ // AFTER afterLLM fires, so we can't read it from there yet.
570
+ // Instead, we build the record from modelResponse.message.
571
+ const modelResponse = ctx.modelResponse;
572
+ if (modelResponse?.message) {
573
+ const sessionMeta = ctx.turn.metadata.sessionMeta;
574
+ const usage = modelResponse.usage;
575
+ const record = {
576
+ ...toRecord(modelResponse.message, messageTs, threadTs),
577
+ ...(usage ? { usage: {
578
+ promptTokens: usage.promptTokens,
579
+ completionTokens: usage.completionTokens,
580
+ iterations: 1,
581
+ ...(usage.cachedPromptTokens !== undefined && { cachedPromptTokens: usage.cachedPromptTokens }),
582
+ ...(usage.reasoningTokens !== undefined && { reasoningTokens: usage.reasoningTokens }),
583
+ } } : {}),
584
+ ...(sessionMeta ? { meta: sessionMeta } : {}),
585
+ };
586
+ persistRecords(key, [record]);
587
+ }
588
+ });
589
+ // ── afterTool: append tool results incrementally ──────────────
590
+ // Each tool result is written to disk as soon as it completes,
591
+ // so the JSONL file reflects progress in real time.
592
+ agent.hook('afterTool', 'disk-session', async (ctx) => {
593
+ const identity = identityFromCtx(ctx);
594
+ if (!identity)
595
+ return;
596
+ const { key, messageTs, threadTs } = identity;
597
+ const toolResult = ctx.toolResult;
598
+ const toolCall = ctx.toolCall;
599
+ if (!toolResult || !toolCall)
600
+ return;
601
+ const sessionMeta = ctx.turn.metadata.sessionMeta;
602
+ const record = {
603
+ role: 'tool',
604
+ content: toolResult.content,
605
+ toolCallId: toolResult.toolCallId,
606
+ name: toolCall.name,
607
+ ts: messageTs,
608
+ ...(threadTs ? { threadTs } : {}),
609
+ recordedAt: new Date().toISOString(),
610
+ ...(sessionMeta ? { meta: sessionMeta } : {}),
611
+ };
612
+ persistRecords(key, [record]);
613
+ });
614
+ // ── afterTurn: finalize session turn ──────────────────────────
615
+ agent.hook('afterTurn', 'disk-session', async (ctx) => {
616
+ const identity = identityFromCtx(ctx);
617
+ if (!identity)
618
+ return;
619
+ const { key, messageTs, threadTs } = identity;
620
+ delete ctx.turn.metadata['_diskSessionHistoryLen'];
621
+ // ── Compaction: rotate the session file ──────────────────
622
+ // When metadata.compacting is set, this turn was a compaction
623
+ // request (triggered by /compact). The agent's response is the
624
+ // summary. Instead of appending to the old session, we:
625
+ // 1. Rename the old JSONL file with a timestamp suffix
626
+ // 2. Seed a new session with the summary as the first record
627
+ // The compaction request/response are already in the old file
628
+ // (written by beforeTurn + the normal append below would have
629
+ // run, but we return early before that).
630
+ const isCompacting = ctx.turn.request.metadata?.compacting === true;
631
+ if (isCompacting) {
632
+ handleCompaction(ctx.turn, key, messageTs);
633
+ return;
634
+ }
635
+ // ── Persist any trailing unwritten steering messages ─────
636
+ // (in case a steering message arrived and the turn halted before beforeLLM ran)
637
+ const written = ctx.turn.metadata['_diskSessionWrittenMessages'];
638
+ delete ctx.turn.metadata['_diskSessionWrittenMessages'];
639
+ const sessionMeta = ctx.turn.metadata.sessionMeta;
640
+ const unwrittenSteering = [];
641
+ for (const msg of ctx.turn.messages) {
642
+ if (msg.role === 'user' && (!written || !written.has(msg))) {
643
+ unwrittenSteering.push({
644
+ ...toRecord(msg, messageTs, threadTs),
645
+ ...(sessionMeta ? { meta: sessionMeta } : {}),
646
+ });
647
+ written?.add(msg);
648
+ }
649
+ }
650
+ if (unwrittenSteering.length > 0) {
651
+ persistRecords(key, unwrittenSteering);
652
+ }
653
+ // Pull accumulated usage for this turn (set by afterLLM hook).
654
+ const usage = ctx.turn.metadata['_diskSessionUsage'];
655
+ delete ctx.turn.metadata['_diskSessionUsage'];
656
+ // Attach accumulated usage to the last assistant record in memory.
657
+ if (usage) {
658
+ const records = store.get(key) ?? [];
659
+ for (let i = records.length - 1; i >= 0; i--) {
660
+ if (records[i].role === 'assistant') {
661
+ records[i].usage = usage;
662
+ break;
663
+ }
664
+ }
665
+ }
666
+ // Backfill system prompt on the last user record (in-memory only).
667
+ // The system prompt wasn't available at beforeTurn (beforeContext
668
+ // hooks hadn't run yet), so we update it now.
669
+ const finalSystemPrompt = ctx.turn.systemPrompt;
670
+ if (finalSystemPrompt) {
671
+ const records = store.get(key) ?? [];
672
+ for (let i = records.length - 1; i >= 0; i--) {
673
+ if (records[i].role === 'user') {
674
+ records[i].systemPrompt = finalSystemPrompt;
675
+ break;
676
+ }
677
+ }
678
+ }
679
+ // Trim in-memory cache (file keeps full history).
680
+ const records = store.get(key) ?? [];
681
+ if (records.length > maxRecords) {
682
+ records.splice(0, records.length - maxRecords);
683
+ store.set(key, records);
684
+ }
685
+ });
686
+ // ── onError: context length backoff fallback ───────────────
687
+ // If the model provider rejects a request due to context length,
688
+ // step down to the next fallback limit (e.g. 100 -> 50 -> 25)
689
+ // and compact the session immediately.
690
+ agent.hook('onError', 'disk-session', async (ctx) => {
691
+ const identity = identityFromCtx(ctx);
692
+ if (!identity)
693
+ return;
694
+ const { key } = identity;
695
+ if (isContextLengthError(ctx.error)) {
696
+ const currentLimit = sessionLimits.get(key) ?? maxContextMessages;
697
+ const nextLimit = fallbackThresholds.find((t) => t < currentLimit);
698
+ if (nextLimit && nextLimit > 0) {
699
+ sessionLimits.set(key, nextLimit);
700
+ const records = store.get(key) ?? [];
701
+ const convRecords = records.filter(isConversationMessage);
702
+ if (convRecords.length > nextLimit && activeModel) {
703
+ try {
704
+ const toEvict = convRecords.length - nextLimit;
705
+ let cut = Math.min(toEvict + Math.max(1, Math.floor(nextLimit / 2)), records.length - 1);
706
+ while (cut < records.length && records[cut].role !== 'user' && records[cut].role !== 'system') {
707
+ cut++;
708
+ }
709
+ if (cut > 0 && cut < records.length) {
710
+ const chunk = records.slice(0, cut);
711
+ const keep = records.slice(cut);
712
+ const summary = await generateSessionSummary(activeModel, chunk);
713
+ const summaryRecord = {
714
+ role: 'assistant',
715
+ content: `[Conversation summary — context limit backed off to ${nextLimit} messages ${new Date().toISOString()}]\n\n${summary}`,
716
+ ts: chunk[chunk.length - 1]?.ts || String(Date.now() / 1000),
717
+ recordedAt: new Date().toISOString(),
718
+ };
719
+ const compacted = [summaryRecord, ...keep];
720
+ store.set(key, compacted);
721
+ appendToFile(key, compacted);
722
+ }
723
+ }
724
+ catch { }
725
+ }
726
+ }
727
+ }
728
+ });
729
+ },
730
+ /** Get current effective message limit for a session (reflects any fallback backoff). */
731
+ getEffectiveLimit(sessionKey = 'default') {
732
+ return sessionLimits.get(sessionKey) ?? maxContextMessages;
733
+ },
734
+ /** Manually set effective message limit for a session. */
735
+ setEffectiveLimit(sessionKey, limit) {
736
+ sessionLimits.set(sessionKey, limit);
737
+ },
738
+ /** Get all records for a session. */
739
+ getRecords(sessionKey = 'default') {
740
+ return store.get(sessionKey) ?? [];
741
+ },
742
+ /**
743
+ * Append a control record (e.g. /halt) to the session log.
744
+ * Control records are persisted to disk but never included in the
745
+ * LLM context — they're for audit/logging only.
746
+ */
747
+ appendControl(sessionKey, content, ts, threadTs) {
748
+ const record = {
749
+ role: 'control',
750
+ content,
751
+ ts: ts ?? String(Date.now() / 1000),
752
+ ...(threadTs ? { threadTs } : {}),
753
+ recordedAt: new Date().toISOString(),
754
+ };
755
+ persistRecords(sessionKey, [record]);
756
+ },
757
+ /**
758
+ * Append a background message to the session log. Stored as a
759
+ * `system` record so the agent sees it as context ("here's what
760
+ * the channel discussed") rather than a message to respond to.
761
+ *
762
+ * Unlike `appendControl`, system records ARE included in the LLM
763
+ * context window — they appear in the conversation history when
764
+ * the agent is triggered, giving it awareness of recent channel
765
+ * activity without needing to be mentioned on every message.
766
+ *
767
+ * The host should include sender info in the content (e.g.
768
+ * `[U123]: hey anyone seen the invoice?`) so the agent can
769
+ * distinguish who said what. Additional metadata (files, blocks,
770
+ * etc.) goes in `opts.meta` and is persisted to the JSONL for
771
+ * audit/debugging but not shown to the LLM.
772
+ */
773
+ appendMessage(sessionKey, content, opts) {
774
+ const record = {
775
+ role: 'system',
776
+ content,
777
+ ts: opts?.ts ?? String(Date.now() / 1000),
778
+ ...(opts?.threadTs ? { threadTs: opts.threadTs } : {}),
779
+ recordedAt: new Date().toISOString(),
780
+ ...(opts?.meta ? { meta: opts.meta } : {}),
781
+ };
782
+ persistRecords(sessionKey, [record]);
783
+ },
784
+ /** List all session keys. */
785
+ getSessions() {
786
+ return Array.from(store.keys());
787
+ },
788
+ /** Clear a single session (memory + disk). */
789
+ clear(sessionKey = 'default') {
790
+ store.delete(sessionKey);
791
+ const path = filePath(sessionKey);
792
+ if (existsSync(path)) {
793
+ try {
794
+ writeFileSync(path, '');
795
+ }
796
+ catch {
797
+ // ignore
798
+ }
799
+ }
800
+ },
801
+ /** Clear all sessions. */
802
+ clearAll() {
803
+ for (const key of store.keys()) {
804
+ const path = filePath(key);
805
+ if (existsSync(path)) {
806
+ try {
807
+ writeFileSync(path, '');
808
+ }
809
+ catch {
810
+ // ignore
811
+ }
812
+ }
813
+ }
814
+ store.clear();
815
+ },
816
+ };
817
+ }
818
+ //# sourceMappingURL=extension.js.map