@roj-ai/sdk 0.1.36 → 0.2.2

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 (925) hide show
  1. package/dist/bootstrap.d.ts +420 -26
  2. package/dist/bootstrap.d.ts.map +1 -1
  3. package/dist/bootstrap.js +55 -24
  4. package/dist/bootstrap.js.map +1 -1
  5. package/dist/bun-platform/fs.d.ts.map +1 -1
  6. package/dist/bun-platform/fs.js +1 -0
  7. package/dist/bun-platform/fs.js.map +1 -1
  8. package/dist/bun-platform/index.d.ts +4 -1
  9. package/dist/bun-platform/index.d.ts.map +1 -1
  10. package/dist/bun-platform/index.js +7 -1
  11. package/dist/bun-platform/index.js.map +1 -1
  12. package/dist/bun-platform/server-lifecycle.d.ts +30 -0
  13. package/dist/bun-platform/server-lifecycle.d.ts.map +1 -0
  14. package/dist/bun-platform/server-lifecycle.js +182 -0
  15. package/dist/bun-platform/server-lifecycle.js.map +1 -0
  16. package/dist/bun-platform/shell.d.ts +33 -0
  17. package/dist/bun-platform/shell.d.ts.map +1 -0
  18. package/dist/bun-platform/shell.js +322 -0
  19. package/dist/bun-platform/shell.js.map +1 -0
  20. package/dist/config.d.ts +34 -0
  21. package/dist/config.d.ts.map +1 -1
  22. package/dist/config.js +97 -0
  23. package/dist/config.js.map +1 -1
  24. package/dist/core/agents/agent.d.ts +42 -7
  25. package/dist/core/agents/agent.d.ts.map +1 -1
  26. package/dist/core/agents/agent.js +202 -87
  27. package/dist/core/agents/agent.js.map +1 -1
  28. package/dist/core/agents/config.d.ts +8 -1
  29. package/dist/core/agents/config.d.ts.map +1 -1
  30. package/dist/core/agents/config.js +5 -1
  31. package/dist/core/agents/config.js.map +1 -1
  32. package/dist/core/agents/retry.d.ts +1 -1
  33. package/dist/core/agents/retry.d.ts.map +1 -1
  34. package/dist/core/agents/retry.js +14 -16
  35. package/dist/core/agents/retry.js.map +1 -1
  36. package/dist/core/agents/state.d.ts +3 -1
  37. package/dist/core/agents/state.d.ts.map +1 -1
  38. package/dist/core/agents/state.js +1 -1
  39. package/dist/core/agents/state.js.map +1 -1
  40. package/dist/core/context/state.d.ts +3 -3
  41. package/dist/core/context/state.js +2 -2
  42. package/dist/core/events/base-event-store.d.ts.map +1 -1
  43. package/dist/core/events/base-event-store.js +22 -14
  44. package/dist/core/events/base-event-store.js.map +1 -1
  45. package/dist/core/events/file.d.ts +39 -1
  46. package/dist/core/events/file.d.ts.map +1 -1
  47. package/dist/core/events/file.js +159 -20
  48. package/dist/core/events/file.js.map +1 -1
  49. package/dist/core/events/types.d.ts +1 -1
  50. package/dist/core/file-store/containment.d.ts +19 -0
  51. package/dist/core/file-store/containment.d.ts.map +1 -0
  52. package/dist/core/file-store/containment.js +62 -0
  53. package/dist/core/file-store/containment.js.map +1 -0
  54. package/dist/core/file-store/file-store.d.ts +22 -2
  55. package/dist/core/file-store/file-store.d.ts.map +1 -1
  56. package/dist/core/file-store/file-store.js +88 -20
  57. package/dist/core/file-store/file-store.js.map +1 -1
  58. package/dist/core/file-store/types.d.ts +13 -1
  59. package/dist/core/file-store/types.d.ts.map +1 -1
  60. package/dist/core/image/image-processor.d.ts.map +1 -1
  61. package/dist/core/image/image-processor.js +3 -1
  62. package/dist/core/image/image-processor.js.map +1 -1
  63. package/dist/core/image/types.d.ts +2 -0
  64. package/dist/core/image/types.d.ts.map +1 -1
  65. package/dist/core/image/vips-resizer.d.ts.map +1 -1
  66. package/dist/core/image/vips-resizer.js +81 -33
  67. package/dist/core/image/vips-resizer.js.map +1 -1
  68. package/dist/core/llm/anthropic.d.ts +0 -1
  69. package/dist/core/llm/anthropic.d.ts.map +1 -1
  70. package/dist/core/llm/anthropic.js +58 -72
  71. package/dist/core/llm/anthropic.js.map +1 -1
  72. package/dist/core/llm/logger.d.ts +14 -2
  73. package/dist/core/llm/logger.d.ts.map +1 -1
  74. package/dist/core/llm/logger.js +161 -36
  75. package/dist/core/llm/logger.js.map +1 -1
  76. package/dist/core/llm/openrouter.d.ts +0 -1
  77. package/dist/core/llm/openrouter.d.ts.map +1 -1
  78. package/dist/core/llm/openrouter.js +53 -66
  79. package/dist/core/llm/openrouter.js.map +1 -1
  80. package/dist/core/llm/provider-request.d.ts +10 -0
  81. package/dist/core/llm/provider-request.d.ts.map +1 -0
  82. package/dist/core/llm/provider-request.js +41 -0
  83. package/dist/core/llm/provider-request.js.map +1 -0
  84. package/dist/core/llm/provider.d.ts +11 -0
  85. package/dist/core/llm/provider.d.ts.map +1 -1
  86. package/dist/core/llm/provider.js +26 -0
  87. package/dist/core/llm/provider.js.map +1 -1
  88. package/dist/core/llm/state.d.ts +2 -2
  89. package/dist/core/llm/state.js +4 -4
  90. package/dist/core/plugins/plugin-builder.d.ts +57 -3
  91. package/dist/core/plugins/plugin-builder.d.ts.map +1 -1
  92. package/dist/core/plugins/plugin-builder.js +68 -14
  93. package/dist/core/plugins/plugin-builder.js.map +1 -1
  94. package/dist/core/preset/preset-builder.d.ts +3 -2
  95. package/dist/core/preset/preset-builder.d.ts.map +1 -1
  96. package/dist/core/preset/preset-builder.js +7 -16
  97. package/dist/core/preset/preset-builder.js.map +1 -1
  98. package/dist/core/sessions/context.d.ts +23 -5
  99. package/dist/core/sessions/context.d.ts.map +1 -1
  100. package/dist/core/sessions/runtime-activity.d.ts +33 -0
  101. package/dist/core/sessions/runtime-activity.d.ts.map +1 -0
  102. package/dist/core/sessions/runtime-activity.js +55 -0
  103. package/dist/core/sessions/runtime-activity.js.map +1 -0
  104. package/dist/core/sessions/schema.d.ts +23 -2
  105. package/dist/core/sessions/schema.d.ts.map +1 -1
  106. package/dist/core/sessions/schema.js +24 -3
  107. package/dist/core/sessions/schema.js.map +1 -1
  108. package/dist/core/sessions/session-manager.d.ts +83 -6
  109. package/dist/core/sessions/session-manager.d.ts.map +1 -1
  110. package/dist/core/sessions/session-manager.js +517 -118
  111. package/dist/core/sessions/session-manager.js.map +1 -1
  112. package/dist/core/sessions/session-store.d.ts +18 -0
  113. package/dist/core/sessions/session-store.d.ts.map +1 -1
  114. package/dist/core/sessions/session-store.js +33 -0
  115. package/dist/core/sessions/session-store.js.map +1 -1
  116. package/dist/core/sessions/session.d.ts +42 -6
  117. package/dist/core/sessions/session.d.ts.map +1 -1
  118. package/dist/core/sessions/session.js +176 -44
  119. package/dist/core/sessions/session.js.map +1 -1
  120. package/dist/core/sessions/state.d.ts +10 -1
  121. package/dist/core/sessions/state.d.ts.map +1 -1
  122. package/dist/core/sessions/state.js +11 -1
  123. package/dist/core/sessions/state.js.map +1 -1
  124. package/dist/core/system.d.ts +9 -0
  125. package/dist/core/system.d.ts.map +1 -1
  126. package/dist/core/system.js +4 -1
  127. package/dist/core/system.js.map +1 -1
  128. package/dist/core/tools/executor.d.ts +1 -1
  129. package/dist/core/wake-key.d.ts +34 -0
  130. package/dist/core/wake-key.d.ts.map +1 -0
  131. package/dist/core/wake-key.js +51 -0
  132. package/dist/core/wake-key.js.map +1 -0
  133. package/dist/index.d.ts +25 -13
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +23 -8
  136. package/dist/index.js.map +1 -1
  137. package/dist/lib/archive/archive-inspection.d.ts +48 -0
  138. package/dist/lib/archive/archive-inspection.d.ts.map +1 -0
  139. package/dist/lib/archive/archive-inspection.fixtures.d.ts +7 -0
  140. package/dist/lib/archive/archive-inspection.fixtures.d.ts.map +1 -0
  141. package/dist/lib/archive/archive-inspection.fixtures.js +134 -0
  142. package/dist/lib/archive/archive-inspection.fixtures.js.map +1 -0
  143. package/dist/lib/archive/archive-inspection.js +253 -0
  144. package/dist/lib/archive/archive-inspection.js.map +1 -0
  145. package/dist/lib/archive/index.d.ts +3 -0
  146. package/dist/lib/archive/index.d.ts.map +1 -0
  147. package/dist/lib/archive/index.js +2 -0
  148. package/dist/lib/archive/index.js.map +1 -0
  149. package/dist/lib/logger/console.d.ts +5 -12
  150. package/dist/lib/logger/console.d.ts.map +1 -1
  151. package/dist/lib/logger/console.js +5 -47
  152. package/dist/lib/logger/console.js.map +1 -1
  153. package/dist/lib/logger/file.d.ts +8 -11
  154. package/dist/lib/logger/file.d.ts.map +1 -1
  155. package/dist/lib/logger/file.js +26 -37
  156. package/dist/lib/logger/file.js.map +1 -1
  157. package/dist/lib/logger/index.d.ts +3 -1
  158. package/dist/lib/logger/index.d.ts.map +1 -1
  159. package/dist/lib/logger/index.js +3 -1
  160. package/dist/lib/logger/index.js.map +1 -1
  161. package/dist/lib/logger/jsonl.d.ts +21 -0
  162. package/dist/lib/logger/jsonl.d.ts.map +1 -0
  163. package/dist/lib/logger/jsonl.js +29 -0
  164. package/dist/lib/logger/jsonl.js.map +1 -0
  165. package/dist/lib/logger/logger.d.ts +22 -0
  166. package/dist/lib/logger/logger.d.ts.map +1 -1
  167. package/dist/lib/logger/logger.js +37 -0
  168. package/dist/lib/logger/logger.js.map +1 -1
  169. package/dist/lib/logger/session-log.d.ts +21 -0
  170. package/dist/lib/logger/session-log.d.ts.map +1 -0
  171. package/dist/lib/logger/session-log.js +37 -0
  172. package/dist/lib/logger/session-log.js.map +1 -0
  173. package/dist/lib/utils/concurrency.d.ts +1 -1
  174. package/dist/lib/utils/concurrency.d.ts.map +1 -1
  175. package/dist/lib/utils/concurrency.js +30 -7
  176. package/dist/lib/utils/concurrency.js.map +1 -1
  177. package/dist/lib/utils/fs-batch.d.ts +17 -0
  178. package/dist/lib/utils/fs-batch.d.ts.map +1 -0
  179. package/dist/lib/utils/fs-batch.js +38 -0
  180. package/dist/lib/utils/fs-batch.js.map +1 -0
  181. package/dist/lib/utils/result.d.ts +7 -22
  182. package/dist/lib/utils/result.d.ts.map +1 -1
  183. package/dist/lib/utils/result.js +6 -17
  184. package/dist/lib/utils/result.js.map +1 -1
  185. package/dist/lib/utils/sleep.d.ts +10 -0
  186. package/dist/lib/utils/sleep.d.ts.map +1 -0
  187. package/dist/lib/utils/sleep.js +26 -0
  188. package/dist/lib/utils/sleep.js.map +1 -0
  189. package/dist/platform/fs-revision.d.ts +21 -0
  190. package/dist/platform/fs-revision.d.ts.map +1 -0
  191. package/dist/platform/fs-revision.js +9 -0
  192. package/dist/platform/fs-revision.js.map +1 -0
  193. package/dist/platform/fs.d.ts +104 -1
  194. package/dist/platform/fs.d.ts.map +1 -1
  195. package/dist/platform/git.d.ts +59 -0
  196. package/dist/platform/git.d.ts.map +1 -0
  197. package/dist/platform/git.js +8 -0
  198. package/dist/platform/git.js.map +1 -0
  199. package/dist/platform/index.d.ts +40 -1
  200. package/dist/platform/index.d.ts.map +1 -1
  201. package/dist/platform/index.js +1 -1
  202. package/dist/platform/index.js.map +1 -1
  203. package/dist/platform/llm-call-log.d.ts +80 -0
  204. package/dist/platform/llm-call-log.d.ts.map +1 -0
  205. package/dist/platform/llm-call-log.js +12 -0
  206. package/dist/platform/llm-call-log.js.map +1 -0
  207. package/dist/platform/scheduler.d.ts +32 -0
  208. package/dist/platform/scheduler.d.ts.map +1 -0
  209. package/dist/platform/scheduler.js +46 -0
  210. package/dist/platform/scheduler.js.map +1 -0
  211. package/dist/platform/session-log.d.ts +36 -0
  212. package/dist/platform/session-log.d.ts.map +1 -0
  213. package/dist/platform/session-log.js +12 -0
  214. package/dist/platform/session-log.js.map +1 -0
  215. package/dist/platform/shell.d.ts +83 -0
  216. package/dist/platform/shell.d.ts.map +1 -0
  217. package/dist/platform/shell.js +13 -0
  218. package/dist/platform/shell.js.map +1 -0
  219. package/dist/plugins/agent-status/plugin.d.ts.map +1 -1
  220. package/dist/plugins/agent-status/plugin.js +1 -0
  221. package/dist/plugins/agent-status/plugin.js.map +1 -1
  222. package/dist/plugins/agents/plugin.d.ts.map +1 -1
  223. package/dist/plugins/agents/plugin.js +129 -62
  224. package/dist/plugins/agents/plugin.js.map +1 -1
  225. package/dist/plugins/filesystem/listing.d.ts +3 -0
  226. package/dist/plugins/filesystem/listing.d.ts.map +1 -1
  227. package/dist/plugins/filesystem/listing.js +66 -10
  228. package/dist/plugins/filesystem/listing.js.map +1 -1
  229. package/dist/plugins/filesystem/plugin.d.ts.map +1 -1
  230. package/dist/plugins/filesystem/plugin.js +8 -6
  231. package/dist/plugins/filesystem/plugin.js.map +1 -1
  232. package/dist/plugins/git-status/index.d.ts +1 -0
  233. package/dist/plugins/git-status/index.d.ts.map +1 -1
  234. package/dist/plugins/git-status/plugin.d.ts +38 -7
  235. package/dist/plugins/git-status/plugin.d.ts.map +1 -1
  236. package/dist/plugins/git-status/plugin.js +169 -64
  237. package/dist/plugins/git-status/plugin.js.map +1 -1
  238. package/dist/plugins/llm-debug/plugin.d.ts.map +1 -1
  239. package/dist/plugins/llm-debug/plugin.js +1 -0
  240. package/dist/plugins/llm-debug/plugin.js.map +1 -1
  241. package/dist/plugins/logs/plugin.d.ts +1 -4
  242. package/dist/plugins/logs/plugin.d.ts.map +1 -1
  243. package/dist/plugins/logs/plugin.js +7 -0
  244. package/dist/plugins/logs/plugin.js.map +1 -1
  245. package/dist/plugins/mailbox/helpers.d.ts +2 -2
  246. package/dist/plugins/mailbox/helpers.js +1 -1
  247. package/dist/plugins/mailbox/plugin.d.ts.map +1 -1
  248. package/dist/plugins/mailbox/plugin.js +38 -43
  249. package/dist/plugins/mailbox/plugin.js.map +1 -1
  250. package/dist/plugins/mailbox/query.d.ts +7 -2
  251. package/dist/plugins/mailbox/query.d.ts.map +1 -1
  252. package/dist/plugins/mailbox/query.js +14 -7
  253. package/dist/plugins/mailbox/query.js.map +1 -1
  254. package/dist/plugins/mailbox/state.d.ts +5 -4
  255. package/dist/plugins/mailbox/state.d.ts.map +1 -1
  256. package/dist/plugins/mailbox/state.js +6 -5
  257. package/dist/plugins/mailbox/state.js.map +1 -1
  258. package/dist/plugins/resources/filename.d.ts +4 -0
  259. package/dist/plugins/resources/filename.d.ts.map +1 -0
  260. package/dist/plugins/resources/filename.js +18 -0
  261. package/dist/plugins/resources/filename.js.map +1 -0
  262. package/dist/plugins/resources/plugin.d.ts +3 -0
  263. package/dist/plugins/resources/plugin.d.ts.map +1 -1
  264. package/dist/plugins/resources/plugin.js +97 -60
  265. package/dist/plugins/resources/plugin.js.map +1 -1
  266. package/dist/plugins/resources/state.d.ts +1 -1
  267. package/dist/plugins/resources/state.js +1 -1
  268. package/dist/plugins/result-eviction/plugin.d.ts.map +1 -1
  269. package/dist/plugins/result-eviction/plugin.js +6 -1
  270. package/dist/plugins/result-eviction/plugin.js.map +1 -1
  271. package/dist/plugins/services/plugin.d.ts +4 -1
  272. package/dist/plugins/services/plugin.d.ts.map +1 -1
  273. package/dist/plugins/services/plugin.js +251 -100
  274. package/dist/plugins/services/plugin.js.map +1 -1
  275. package/dist/plugins/services/prompt.d.ts.map +1 -1
  276. package/dist/plugins/services/prompt.js +1 -4
  277. package/dist/plugins/services/prompt.js.map +1 -1
  278. package/dist/plugins/services/schema.d.ts +15 -5
  279. package/dist/plugins/services/schema.d.ts.map +1 -1
  280. package/dist/plugins/services/service.d.ts +100 -18
  281. package/dist/plugins/services/service.d.ts.map +1 -1
  282. package/dist/plugins/services/service.js +680 -230
  283. package/dist/plugins/services/service.js.map +1 -1
  284. package/dist/plugins/session-lifecycle/plugin.d.ts +21 -1
  285. package/dist/plugins/session-lifecycle/plugin.d.ts.map +1 -1
  286. package/dist/plugins/session-lifecycle/plugin.js +53 -40
  287. package/dist/plugins/session-lifecycle/plugin.js.map +1 -1
  288. package/dist/plugins/session-state/plugin.d.ts +21 -13
  289. package/dist/plugins/session-state/plugin.d.ts.map +1 -1
  290. package/dist/plugins/session-state/plugin.js +214 -79
  291. package/dist/plugins/session-state/plugin.js.map +1 -1
  292. package/dist/plugins/session-stats/plugin.d.ts.map +1 -1
  293. package/dist/plugins/session-stats/plugin.js +1 -0
  294. package/dist/plugins/session-stats/plugin.js.map +1 -1
  295. package/dist/plugins/shell/executor.d.ts +17 -15
  296. package/dist/plugins/shell/executor.d.ts.map +1 -1
  297. package/dist/plugins/shell/executor.js +130 -195
  298. package/dist/plugins/shell/executor.js.map +1 -1
  299. package/dist/plugins/shell/index.d.ts +2 -2
  300. package/dist/plugins/shell/index.d.ts.map +1 -1
  301. package/dist/plugins/shell/index.js +2 -2
  302. package/dist/plugins/shell/index.js.map +1 -1
  303. package/dist/plugins/shell/plugin.d.ts +5 -4
  304. package/dist/plugins/shell/plugin.d.ts.map +1 -1
  305. package/dist/plugins/shell/plugin.js +4 -8
  306. package/dist/plugins/shell/plugin.js.map +1 -1
  307. package/dist/plugins/skills/discovery.d.ts.map +1 -1
  308. package/dist/plugins/skills/discovery.js +10 -8
  309. package/dist/plugins/skills/discovery.js.map +1 -1
  310. package/dist/plugins/skills/index.d.ts +1 -1
  311. package/dist/plugins/skills/index.d.ts.map +1 -1
  312. package/dist/plugins/skills/plugin.d.ts +1 -1
  313. package/dist/plugins/skills/plugin.d.ts.map +1 -1
  314. package/dist/plugins/skills/plugin.js +23 -30
  315. package/dist/plugins/skills/plugin.js.map +1 -1
  316. package/dist/plugins/skills/prompts.d.ts +3 -3
  317. package/dist/plugins/skills/prompts.d.ts.map +1 -1
  318. package/dist/plugins/skills/prompts.js.map +1 -1
  319. package/dist/plugins/skills/schema.d.ts +4 -2
  320. package/dist/plugins/skills/schema.d.ts.map +1 -1
  321. package/dist/plugins/todo/schema.d.ts +1 -1
  322. package/dist/plugins/uploads/plugin.d.ts +11 -4
  323. package/dist/plugins/uploads/plugin.d.ts.map +1 -1
  324. package/dist/plugins/uploads/plugin.js +891 -225
  325. package/dist/plugins/uploads/plugin.js.map +1 -1
  326. package/dist/plugins/uploads/preprocessor.d.ts +14 -0
  327. package/dist/plugins/uploads/preprocessor.d.ts.map +1 -1
  328. package/dist/plugins/uploads/preprocessor.js +11 -0
  329. package/dist/plugins/uploads/preprocessor.js.map +1 -1
  330. package/dist/plugins/uploads/preprocessors/image-classifier.d.ts +1 -1
  331. package/dist/plugins/uploads/preprocessors/image-classifier.d.ts.map +1 -1
  332. package/dist/plugins/uploads/preprocessors/image-classifier.js +51 -26
  333. package/dist/plugins/uploads/preprocessors/image-classifier.js.map +1 -1
  334. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.d.ts +2 -2
  335. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.d.ts.map +1 -1
  336. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js +41 -16
  337. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js.map +1 -1
  338. package/dist/plugins/uploads/preprocessors/pdf-preprocessor.d.ts +1 -1
  339. package/dist/plugins/uploads/preprocessors/pdf-preprocessor.d.ts.map +1 -1
  340. package/dist/plugins/uploads/preprocessors/pdf-preprocessor.js +29 -14
  341. package/dist/plugins/uploads/preprocessors/pdf-preprocessor.js.map +1 -1
  342. package/dist/plugins/uploads/preprocessors/zip-preprocessor.d.ts +1 -1
  343. package/dist/plugins/uploads/preprocessors/zip-preprocessor.d.ts.map +1 -1
  344. package/dist/plugins/uploads/preprocessors/zip-preprocessor.js +62 -34
  345. package/dist/plugins/uploads/preprocessors/zip-preprocessor.js.map +1 -1
  346. package/dist/plugins/uploads/schema.d.ts +25 -2
  347. package/dist/plugins/uploads/schema.d.ts.map +1 -1
  348. package/dist/plugins/uploads/schema.js +24 -3
  349. package/dist/plugins/uploads/schema.js.map +1 -1
  350. package/dist/plugins/uploads/state.d.ts +13 -1
  351. package/dist/plugins/uploads/state.d.ts.map +1 -1
  352. package/dist/plugins/uploads/state.js +4 -1
  353. package/dist/plugins/uploads/state.js.map +1 -1
  354. package/dist/plugins/user-chat/plugin.d.ts +12 -5
  355. package/dist/plugins/user-chat/plugin.d.ts.map +1 -1
  356. package/dist/plugins/user-chat/plugin.js +141 -32
  357. package/dist/plugins/user-chat/plugin.js.map +1 -1
  358. package/dist/plugins/workers/context.d.ts +35 -13
  359. package/dist/plugins/workers/context.d.ts.map +1 -1
  360. package/dist/plugins/workers/context.js +82 -32
  361. package/dist/plugins/workers/context.js.map +1 -1
  362. package/dist/plugins/workers/definition.d.ts +7 -0
  363. package/dist/plugins/workers/definition.d.ts.map +1 -1
  364. package/dist/plugins/workers/definition.js.map +1 -1
  365. package/dist/plugins/workers/index.d.ts +4 -4
  366. package/dist/plugins/workers/index.d.ts.map +1 -1
  367. package/dist/plugins/workers/index.js +2 -2
  368. package/dist/plugins/workers/index.js.map +1 -1
  369. package/dist/plugins/workers/plugin.d.ts +10 -57
  370. package/dist/plugins/workers/plugin.d.ts.map +1 -1
  371. package/dist/plugins/workers/plugin.js +385 -123
  372. package/dist/plugins/workers/plugin.js.map +1 -1
  373. package/dist/plugins/workers/state.d.ts +69 -0
  374. package/dist/plugins/workers/state.d.ts.map +1 -0
  375. package/dist/plugins/workers/state.js +52 -0
  376. package/dist/plugins/workers/state.js.map +1 -0
  377. package/dist/plugins/workers/worker.d.ts +15 -4
  378. package/dist/plugins/workers/worker.d.ts.map +1 -1
  379. package/dist/testing/conformance.d.ts +106 -0
  380. package/dist/testing/conformance.d.ts.map +1 -0
  381. package/dist/testing/conformance.js +1463 -0
  382. package/dist/testing/conformance.js.map +1 -0
  383. package/dist/testing/node-platform.d.ts.map +1 -1
  384. package/dist/testing/node-platform.js +5 -0
  385. package/dist/testing/node-platform.js.map +1 -1
  386. package/dist/testing/test-harness.d.ts +11 -1
  387. package/dist/testing/test-harness.d.ts.map +1 -1
  388. package/dist/testing/test-harness.js +17 -37
  389. package/dist/testing/test-harness.js.map +1 -1
  390. package/dist/testing/wait-helpers.d.ts.map +1 -1
  391. package/dist/testing/wait-helpers.js +1 -3
  392. package/dist/testing/wait-helpers.js.map +1 -1
  393. package/dist/transport/adapter/client-adapter.d.ts +6 -0
  394. package/dist/transport/adapter/client-adapter.d.ts.map +1 -1
  395. package/dist/transport/adapter/client-adapter.js +50 -3
  396. package/dist/transport/adapter/client-adapter.js.map +1 -1
  397. package/dist/transport/adapter/heartbeat.d.ts +16 -0
  398. package/dist/transport/adapter/heartbeat.d.ts.map +1 -0
  399. package/dist/transport/adapter/heartbeat.js +41 -0
  400. package/dist/transport/adapter/heartbeat.js.map +1 -0
  401. package/dist/transport/adapter/server-adapter.d.ts.map +1 -1
  402. package/dist/transport/adapter/server-adapter.js +6 -0
  403. package/dist/transport/adapter/server-adapter.js.map +1 -1
  404. package/dist/transport/http/app.d.ts +3 -30
  405. package/dist/transport/http/app.d.ts.map +1 -1
  406. package/dist/transport/http/app.js +3 -7
  407. package/dist/transport/http/app.js.map +1 -1
  408. package/dist/transport/http/context.d.ts +40 -0
  409. package/dist/transport/http/context.d.ts.map +1 -0
  410. package/dist/transport/http/context.js +17 -0
  411. package/dist/transport/http/context.js.map +1 -0
  412. package/dist/transport/http/fetch-guard.d.ts +49 -0
  413. package/dist/transport/http/fetch-guard.d.ts.map +1 -0
  414. package/dist/transport/http/fetch-guard.js +312 -0
  415. package/dist/transport/http/fetch-guard.js.map +1 -0
  416. package/dist/transport/http/index.d.ts +1 -1
  417. package/dist/transport/http/index.d.ts.map +1 -1
  418. package/dist/transport/http/middleware/bearer-auth.d.ts +1 -1
  419. package/dist/transport/http/middleware/bearer-auth.d.ts.map +1 -1
  420. package/dist/transport/http/middleware/error-handler.d.ts +2 -2
  421. package/dist/transport/http/middleware/error-handler.d.ts.map +1 -1
  422. package/dist/transport/http/path-containment.d.ts +20 -0
  423. package/dist/transport/http/path-containment.d.ts.map +1 -0
  424. package/dist/transport/http/path-containment.js +31 -0
  425. package/dist/transport/http/path-containment.js.map +1 -0
  426. package/dist/transport/http/responses.d.ts +30 -0
  427. package/dist/transport/http/responses.d.ts.map +1 -0
  428. package/dist/transport/http/responses.js +5 -0
  429. package/dist/transport/http/responses.js.map +1 -0
  430. package/dist/transport/http/routes/files.d.ts +1 -1
  431. package/dist/transport/http/routes/files.d.ts.map +1 -1
  432. package/dist/transport/http/routes/files.js +54 -155
  433. package/dist/transport/http/routes/files.js.map +1 -1
  434. package/dist/transport/http/routes/resources.d.ts +1 -1
  435. package/dist/transport/http/routes/resources.d.ts.map +1 -1
  436. package/dist/transport/http/routes/resources.js +92 -57
  437. package/dist/transport/http/routes/resources.js.map +1 -1
  438. package/dist/transport/http/routes/rpc.d.ts +6 -1
  439. package/dist/transport/http/routes/rpc.d.ts.map +1 -1
  440. package/dist/transport/http/routes/rpc.js +51 -21
  441. package/dist/transport/http/routes/rpc.js.map +1 -1
  442. package/dist/transport/http/routes/upload.d.ts +1 -1
  443. package/dist/transport/http/routes/upload.d.ts.map +1 -1
  444. package/dist/transport/http/routes/upload.js +256 -169
  445. package/dist/transport/http/routes/upload.js.map +1 -1
  446. package/dist/user-config.d.ts +34 -7
  447. package/dist/user-config.d.ts.map +1 -1
  448. package/dist/user-config.js +71 -0
  449. package/dist/user-config.js.map +1 -1
  450. package/package.json +17 -7
  451. package/src/bootstrap.ts +119 -35
  452. package/src/bun-platform/fs.ts +1 -0
  453. package/src/bun-platform/index.ts +18 -1
  454. package/src/bun-platform/server-lifecycle.ts +218 -0
  455. package/src/bun-platform/shell.ts +362 -0
  456. package/src/config.ts +130 -0
  457. package/src/core/agents/agent.ts +210 -92
  458. package/src/core/agents/config.ts +8 -0
  459. package/src/core/agents/retry.ts +16 -17
  460. package/src/core/agents/state.ts +2 -0
  461. package/src/core/events/base-event-store.ts +24 -16
  462. package/src/core/events/file.ts +198 -22
  463. package/src/core/file-store/containment.ts +75 -0
  464. package/src/core/file-store/file-store.ts +106 -25
  465. package/src/core/file-store/types.ts +14 -1
  466. package/src/core/image/image-processor.ts +3 -1
  467. package/src/core/image/types.ts +2 -0
  468. package/src/core/image/vips-resizer.ts +102 -37
  469. package/src/core/llm/anthropic.ts +63 -79
  470. package/src/core/llm/logger.ts +175 -37
  471. package/src/core/llm/openrouter.ts +57 -72
  472. package/src/core/llm/provider-request.ts +40 -0
  473. package/src/core/llm/provider.ts +28 -0
  474. package/src/core/plugins/plugin-builder.ts +106 -14
  475. package/src/core/preset/preset-builder.ts +12 -22
  476. package/src/core/sessions/context.ts +18 -0
  477. package/src/core/sessions/runtime-activity.ts +78 -0
  478. package/src/core/sessions/schema.ts +29 -3
  479. package/src/core/sessions/session-manager.ts +560 -140
  480. package/src/core/sessions/session-store.ts +38 -0
  481. package/src/core/sessions/session.ts +187 -47
  482. package/src/core/sessions/state.ts +11 -0
  483. package/src/core/system.ts +15 -0
  484. package/src/core/wake-key.ts +65 -0
  485. package/src/index.ts +32 -12
  486. package/src/lib/archive/archive-inspection.fixtures.ts +138 -0
  487. package/src/lib/archive/archive-inspection.ts +359 -0
  488. package/src/lib/archive/index.ts +17 -0
  489. package/src/lib/logger/console.ts +7 -57
  490. package/src/lib/logger/file.ts +28 -50
  491. package/src/lib/logger/index.ts +3 -1
  492. package/src/lib/logger/jsonl.ts +36 -0
  493. package/src/lib/logger/logger.ts +48 -0
  494. package/src/lib/logger/session-log.ts +42 -0
  495. package/src/lib/utils/concurrency.ts +37 -8
  496. package/src/lib/utils/fs-batch.ts +49 -0
  497. package/src/lib/utils/result.ts +7 -31
  498. package/src/lib/utils/sleep.ts +23 -0
  499. package/src/platform/fs-revision.ts +21 -0
  500. package/src/platform/fs.ts +109 -1
  501. package/src/platform/git.ts +67 -0
  502. package/src/platform/index.ts +51 -1
  503. package/src/platform/llm-call-log.ts +86 -0
  504. package/src/platform/scheduler.ts +71 -0
  505. package/src/platform/session-log.ts +39 -0
  506. package/src/platform/shell.ts +89 -0
  507. package/src/plugins/agent-status/plugin.ts +1 -0
  508. package/src/plugins/agents/plugin.ts +134 -81
  509. package/src/plugins/filesystem/listing.ts +70 -12
  510. package/src/plugins/filesystem/plugin.ts +8 -6
  511. package/src/plugins/git-status/index.ts +1 -0
  512. package/src/plugins/git-status/plugin.ts +211 -77
  513. package/src/plugins/llm-debug/plugin.ts +1 -0
  514. package/src/plugins/logs/plugin.ts +9 -0
  515. package/src/plugins/mailbox/plugin.ts +46 -64
  516. package/src/plugins/mailbox/query.ts +15 -7
  517. package/src/plugins/mailbox/state.ts +1 -0
  518. package/src/plugins/resources/filename.ts +19 -0
  519. package/src/plugins/resources/plugin.ts +111 -59
  520. package/src/plugins/result-eviction/plugin.ts +6 -1
  521. package/src/plugins/services/plugin.ts +254 -98
  522. package/src/plugins/services/prompt.ts +1 -6
  523. package/src/plugins/services/schema.ts +17 -3
  524. package/src/plugins/services/service.ts +702 -252
  525. package/src/plugins/session-lifecycle/plugin.ts +56 -41
  526. package/src/plugins/session-state/plugin.ts +242 -88
  527. package/src/plugins/session-stats/plugin.ts +1 -0
  528. package/src/plugins/shell/executor.ts +144 -226
  529. package/src/plugins/shell/index.ts +1 -4
  530. package/src/plugins/shell/plugin.ts +7 -9
  531. package/src/plugins/skills/discovery.ts +10 -8
  532. package/src/plugins/skills/index.ts +1 -1
  533. package/src/plugins/skills/plugin.ts +19 -27
  534. package/src/plugins/skills/prompts.ts +3 -3
  535. package/src/plugins/skills/schema.ts +5 -2
  536. package/src/plugins/uploads/plugin.ts +991 -273
  537. package/src/plugins/uploads/preprocessor.ts +25 -0
  538. package/src/plugins/uploads/preprocessors/image-classifier.ts +56 -25
  539. package/src/plugins/uploads/preprocessors/markitdown-preprocessor.ts +41 -15
  540. package/src/plugins/uploads/preprocessors/pdf-preprocessor.ts +32 -16
  541. package/src/plugins/uploads/preprocessors/zip-preprocessor.ts +67 -38
  542. package/src/plugins/uploads/schema.ts +30 -3
  543. package/src/plugins/uploads/state.ts +12 -0
  544. package/src/plugins/user-chat/plugin.ts +196 -40
  545. package/src/plugins/workers/context.ts +102 -39
  546. package/src/plugins/workers/definition.ts +7 -0
  547. package/src/plugins/workers/index.ts +4 -4
  548. package/src/plugins/workers/plugin.ts +461 -151
  549. package/src/plugins/workers/state.ts +64 -0
  550. package/src/plugins/workers/worker.ts +15 -4
  551. package/src/testing/conformance.ts +1751 -0
  552. package/src/testing/node-platform.ts +5 -0
  553. package/src/testing/test-harness.ts +21 -38
  554. package/src/testing/wait-helpers.ts +1 -4
  555. package/src/transport/adapter/client-adapter.ts +60 -3
  556. package/src/transport/adapter/heartbeat.ts +50 -0
  557. package/src/transport/adapter/server-adapter.ts +6 -0
  558. package/src/transport/http/app.ts +7 -35
  559. package/src/transport/http/context.ts +46 -0
  560. package/src/transport/http/fetch-guard.ts +318 -0
  561. package/src/transport/http/index.ts +1 -1
  562. package/src/transport/http/middleware/bearer-auth.ts +1 -1
  563. package/src/transport/http/middleware/error-handler.ts +1 -1
  564. package/src/transport/http/path-containment.ts +44 -0
  565. package/src/transport/http/responses.ts +20 -0
  566. package/src/transport/http/routes/files.ts +69 -159
  567. package/src/transport/http/routes/resources.ts +124 -93
  568. package/src/transport/http/routes/rpc.ts +63 -26
  569. package/src/transport/http/routes/upload.ts +327 -258
  570. package/src/user-config.ts +93 -7
  571. package/dist/config.test.d.ts +0 -2
  572. package/dist/config.test.d.ts.map +0 -1
  573. package/dist/config.test.js +0 -155
  574. package/dist/config.test.js.map +0 -1
  575. package/dist/core/agent-loop.integration.test.d.ts +0 -2
  576. package/dist/core/agent-loop.integration.test.d.ts.map +0 -1
  577. package/dist/core/agent-loop.integration.test.js +0 -414
  578. package/dist/core/agent-loop.integration.test.js.map +0 -1
  579. package/dist/core/agents/agent-config.test.d.ts +0 -2
  580. package/dist/core/agents/agent-config.test.d.ts.map +0 -1
  581. package/dist/core/agents/agent-config.test.js +0 -194
  582. package/dist/core/agents/agent-config.test.js.map +0 -1
  583. package/dist/core/agents/agent-shutdown.test.d.ts +0 -6
  584. package/dist/core/agents/agent-shutdown.test.d.ts.map +0 -1
  585. package/dist/core/agents/agent-shutdown.test.js +0 -180
  586. package/dist/core/agents/agent-shutdown.test.js.map +0 -1
  587. package/dist/core/agents/agent.test.d.ts +0 -2
  588. package/dist/core/agents/agent.test.d.ts.map +0 -1
  589. package/dist/core/agents/agent.test.js +0 -313
  590. package/dist/core/agents/agent.test.js.map +0 -1
  591. package/dist/core/agents/communicator.d.ts +0 -3
  592. package/dist/core/agents/communicator.d.ts.map +0 -1
  593. package/dist/core/agents/communicator.js +0 -13
  594. package/dist/core/agents/communicator.js.map +0 -1
  595. package/dist/core/agents/handler-events.test.d.ts +0 -5
  596. package/dist/core/agents/handler-events.test.d.ts.map +0 -1
  597. package/dist/core/agents/handler-events.test.js +0 -115
  598. package/dist/core/agents/handler-events.test.js.map +0 -1
  599. package/dist/core/agents/response-sanitizer.test.d.ts +0 -2
  600. package/dist/core/agents/response-sanitizer.test.d.ts.map +0 -1
  601. package/dist/core/agents/response-sanitizer.test.js +0 -101
  602. package/dist/core/agents/response-sanitizer.test.js.map +0 -1
  603. package/dist/core/error-recovery.integration.test.d.ts +0 -2
  604. package/dist/core/error-recovery.integration.test.d.ts.map +0 -1
  605. package/dist/core/error-recovery.integration.test.js +0 -288
  606. package/dist/core/error-recovery.integration.test.js.map +0 -1
  607. package/dist/core/event-sourcing.integration.test.d.ts +0 -2
  608. package/dist/core/event-sourcing.integration.test.d.ts.map +0 -1
  609. package/dist/core/event-sourcing.integration.test.js +0 -154
  610. package/dist/core/event-sourcing.integration.test.js.map +0 -1
  611. package/dist/core/events/file.test.d.ts +0 -2
  612. package/dist/core/events/file.test.d.ts.map +0 -1
  613. package/dist/core/events/file.test.js +0 -284
  614. package/dist/core/events/file.test.js.map +0 -1
  615. package/dist/core/events/memory.test.d.ts +0 -2
  616. package/dist/core/events/memory.test.d.ts.map +0 -1
  617. package/dist/core/events/memory.test.js +0 -502
  618. package/dist/core/events/memory.test.js.map +0 -1
  619. package/dist/core/image/image-processor.test.d.ts +0 -2
  620. package/dist/core/image/image-processor.test.d.ts.map +0 -1
  621. package/dist/core/image/image-processor.test.js +0 -171
  622. package/dist/core/image/image-processor.test.js.map +0 -1
  623. package/dist/core/image/vips-resizer.test.d.ts +0 -2
  624. package/dist/core/image/vips-resizer.test.d.ts.map +0 -1
  625. package/dist/core/image/vips-resizer.test.js +0 -336
  626. package/dist/core/image/vips-resizer.test.js.map +0 -1
  627. package/dist/core/llm/anthropic.test.d.ts +0 -2
  628. package/dist/core/llm/anthropic.test.d.ts.map +0 -1
  629. package/dist/core/llm/anthropic.test.js +0 -464
  630. package/dist/core/llm/anthropic.test.js.map +0 -1
  631. package/dist/core/llm/cache-breakpoints.test.d.ts +0 -2
  632. package/dist/core/llm/cache-breakpoints.test.d.ts.map +0 -1
  633. package/dist/core/llm/cache-breakpoints.test.js +0 -69
  634. package/dist/core/llm/cache-breakpoints.test.js.map +0 -1
  635. package/dist/core/llm/cache-live.test.d.ts +0 -16
  636. package/dist/core/llm/cache-live.test.d.ts.map +0 -1
  637. package/dist/core/llm/cache-live.test.js +0 -137
  638. package/dist/core/llm/cache-live.test.js.map +0 -1
  639. package/dist/core/llm/logger.test.d.ts +0 -7
  640. package/dist/core/llm/logger.test.d.ts.map +0 -1
  641. package/dist/core/llm/logger.test.js +0 -228
  642. package/dist/core/llm/logger.test.js.map +0 -1
  643. package/dist/core/llm/message-sanitization.test.d.ts +0 -2
  644. package/dist/core/llm/message-sanitization.test.d.ts.map +0 -1
  645. package/dist/core/llm/message-sanitization.test.js +0 -181
  646. package/dist/core/llm/message-sanitization.test.js.map +0 -1
  647. package/dist/core/llm/mock.test.d.ts +0 -2
  648. package/dist/core/llm/mock.test.d.ts.map +0 -1
  649. package/dist/core/llm/mock.test.js +0 -318
  650. package/dist/core/llm/mock.test.js.map +0 -1
  651. package/dist/core/llm/model-shortlist-live.test.d.ts +0 -35
  652. package/dist/core/llm/model-shortlist-live.test.d.ts.map +0 -1
  653. package/dist/core/llm/model-shortlist-live.test.js +0 -452
  654. package/dist/core/llm/model-shortlist-live.test.js.map +0 -1
  655. package/dist/core/llm/openrouter-mapping.test.d.ts +0 -2
  656. package/dist/core/llm/openrouter-mapping.test.d.ts.map +0 -1
  657. package/dist/core/llm/openrouter-mapping.test.js +0 -190
  658. package/dist/core/llm/openrouter-mapping.test.js.map +0 -1
  659. package/dist/core/llm/openrouter.test.d.ts +0 -2
  660. package/dist/core/llm/openrouter.test.d.ts.map +0 -1
  661. package/dist/core/llm/openrouter.test.js +0 -377
  662. package/dist/core/llm/openrouter.test.js.map +0 -1
  663. package/dist/core/llm/provider-integration.test.d.ts +0 -12
  664. package/dist/core/llm/provider-integration.test.d.ts.map +0 -1
  665. package/dist/core/llm/provider-integration.test.js +0 -350
  666. package/dist/core/llm/provider-integration.test.js.map +0 -1
  667. package/dist/core/llm/reasoning-details.test.d.ts +0 -2
  668. package/dist/core/llm/reasoning-details.test.d.ts.map +0 -1
  669. package/dist/core/llm/reasoning-details.test.js +0 -144
  670. package/dist/core/llm/reasoning-details.test.js.map +0 -1
  671. package/dist/core/llm/routing-provider.test.d.ts +0 -2
  672. package/dist/core/llm/routing-provider.test.d.ts.map +0 -1
  673. package/dist/core/llm/routing-provider.test.js +0 -94
  674. package/dist/core/llm/routing-provider.test.js.map +0 -1
  675. package/dist/core/llm/snapshot-middleware.test.d.ts +0 -2
  676. package/dist/core/llm/snapshot-middleware.test.d.ts.map +0 -1
  677. package/dist/core/llm/snapshot-middleware.test.js +0 -144
  678. package/dist/core/llm/snapshot-middleware.test.js.map +0 -1
  679. package/dist/core/llm/thinking-blocks.test.d.ts +0 -2
  680. package/dist/core/llm/thinking-blocks.test.d.ts.map +0 -1
  681. package/dist/core/llm/thinking-blocks.test.js +0 -291
  682. package/dist/core/llm/thinking-blocks.test.js.map +0 -1
  683. package/dist/core/multi-agent.integration.test.d.ts +0 -2
  684. package/dist/core/multi-agent.integration.test.d.ts.map +0 -1
  685. package/dist/core/multi-agent.integration.test.js +0 -298
  686. package/dist/core/multi-agent.integration.test.js.map +0 -1
  687. package/dist/core/plugin-hooks.integration.test.d.ts +0 -2
  688. package/dist/core/plugin-hooks.integration.test.d.ts.map +0 -1
  689. package/dist/core/plugin-hooks.integration.test.js +0 -458
  690. package/dist/core/plugin-hooks.integration.test.js.map +0 -1
  691. package/dist/core/reasoning-round-trip.integration.test.d.ts +0 -2
  692. package/dist/core/reasoning-round-trip.integration.test.d.ts.map +0 -1
  693. package/dist/core/reasoning-round-trip.integration.test.js +0 -150
  694. package/dist/core/reasoning-round-trip.integration.test.js.map +0 -1
  695. package/dist/core/session-lifecycle.integration.test.d.ts +0 -2
  696. package/dist/core/session-lifecycle.integration.test.d.ts.map +0 -1
  697. package/dist/core/session-lifecycle.integration.test.js +0 -159
  698. package/dist/core/session-lifecycle.integration.test.js.map +0 -1
  699. package/dist/core/sessions/fork-utils.test.d.ts +0 -2
  700. package/dist/core/sessions/fork-utils.test.d.ts.map +0 -1
  701. package/dist/core/sessions/fork-utils.test.js +0 -129
  702. package/dist/core/sessions/fork-utils.test.js.map +0 -1
  703. package/dist/core/sessions/session-overrides.integration.test.d.ts +0 -2
  704. package/dist/core/sessions/session-overrides.integration.test.d.ts.map +0 -1
  705. package/dist/core/sessions/session-overrides.integration.test.js +0 -154
  706. package/dist/core/sessions/session-overrides.integration.test.js.map +0 -1
  707. package/dist/core/sessions/session.test.d.ts +0 -2
  708. package/dist/core/sessions/session.test.d.ts.map +0 -1
  709. package/dist/core/sessions/session.test.js +0 -1100
  710. package/dist/core/sessions/session.test.js.map +0 -1
  711. package/dist/core/tools/executor.test.d.ts +0 -2
  712. package/dist/core/tools/executor.test.d.ts.map +0 -1
  713. package/dist/core/tools/executor.test.js +0 -144
  714. package/dist/core/tools/executor.test.js.map +0 -1
  715. package/dist/lib/logger/console.test.d.ts +0 -2
  716. package/dist/lib/logger/console.test.d.ts.map +0 -1
  717. package/dist/lib/logger/console.test.js +0 -258
  718. package/dist/lib/logger/console.test.js.map +0 -1
  719. package/dist/lib/never.d.ts +0 -2
  720. package/dist/lib/never.d.ts.map +0 -1
  721. package/dist/lib/never.js +0 -4
  722. package/dist/lib/never.js.map +0 -1
  723. package/dist/lib/utils/concurrency.test.d.ts +0 -2
  724. package/dist/lib/utils/concurrency.test.d.ts.map +0 -1
  725. package/dist/lib/utils/concurrency.test.js +0 -135
  726. package/dist/lib/utils/concurrency.test.js.map +0 -1
  727. package/dist/plugins/agent-status/agent-status.test.d.ts +0 -2
  728. package/dist/plugins/agent-status/agent-status.test.d.ts.map +0 -1
  729. package/dist/plugins/agent-status/agent-status.test.js +0 -136
  730. package/dist/plugins/agent-status/agent-status.test.js.map +0 -1
  731. package/dist/plugins/agents/agents.integration.test.d.ts +0 -2
  732. package/dist/plugins/agents/agents.integration.test.d.ts.map +0 -1
  733. package/dist/plugins/agents/agents.integration.test.js +0 -830
  734. package/dist/plugins/agents/agents.integration.test.js.map +0 -1
  735. package/dist/plugins/agents/supervision.integration.test.d.ts +0 -2
  736. package/dist/plugins/agents/supervision.integration.test.d.ts.map +0 -1
  737. package/dist/plugins/agents/supervision.integration.test.js +0 -215
  738. package/dist/plugins/agents/supervision.integration.test.js.map +0 -1
  739. package/dist/plugins/context-compact/compaction-live.test.d.ts +0 -17
  740. package/dist/plugins/context-compact/compaction-live.test.d.ts.map +0 -1
  741. package/dist/plugins/context-compact/compaction-live.test.js +0 -177
  742. package/dist/plugins/context-compact/compaction-live.test.js.map +0 -1
  743. package/dist/plugins/context-compact/context-compact.integration.test.d.ts +0 -2
  744. package/dist/plugins/context-compact/context-compact.integration.test.d.ts.map +0 -1
  745. package/dist/plugins/context-compact/context-compact.integration.test.js +0 -364
  746. package/dist/plugins/context-compact/context-compact.integration.test.js.map +0 -1
  747. package/dist/plugins/context-compact/context-compactor.test.d.ts +0 -2
  748. package/dist/plugins/context-compact/context-compactor.test.d.ts.map +0 -1
  749. package/dist/plugins/context-compact/context-compactor.test.js +0 -858
  750. package/dist/plugins/context-compact/context-compactor.test.js.map +0 -1
  751. package/dist/plugins/context-compact/history-offloader.test.d.ts +0 -2
  752. package/dist/plugins/context-compact/history-offloader.test.d.ts.map +0 -1
  753. package/dist/plugins/context-compact/history-offloader.test.js +0 -77
  754. package/dist/plugins/context-compact/history-offloader.test.js.map +0 -1
  755. package/dist/plugins/filesystem/filesystem.integration.test.d.ts +0 -2
  756. package/dist/plugins/filesystem/filesystem.integration.test.d.ts.map +0 -1
  757. package/dist/plugins/filesystem/filesystem.integration.test.js +0 -447
  758. package/dist/plugins/filesystem/filesystem.integration.test.js.map +0 -1
  759. package/dist/plugins/filesystem/schema.d.ts +0 -7
  760. package/dist/plugins/filesystem/schema.d.ts.map +0 -1
  761. package/dist/plugins/filesystem/schema.js +0 -2
  762. package/dist/plugins/filesystem/schema.js.map +0 -1
  763. package/dist/plugins/limits-guard/limit-guard.test.d.ts +0 -2
  764. package/dist/plugins/limits-guard/limit-guard.test.d.ts.map +0 -1
  765. package/dist/plugins/limits-guard/limit-guard.test.js +0 -194
  766. package/dist/plugins/limits-guard/limit-guard.test.js.map +0 -1
  767. package/dist/plugins/limits-guard/limits-guard.integration.test.d.ts +0 -2
  768. package/dist/plugins/limits-guard/limits-guard.integration.test.d.ts.map +0 -1
  769. package/dist/plugins/limits-guard/limits-guard.integration.test.js +0 -887
  770. package/dist/plugins/limits-guard/limits-guard.integration.test.js.map +0 -1
  771. package/dist/plugins/llm-debug/llm-debug.integration.test.d.ts +0 -2
  772. package/dist/plugins/llm-debug/llm-debug.integration.test.d.ts.map +0 -1
  773. package/dist/plugins/llm-debug/llm-debug.integration.test.js +0 -157
  774. package/dist/plugins/llm-debug/llm-debug.integration.test.js.map +0 -1
  775. package/dist/plugins/mailbox/mailbox.integration.test.d.ts +0 -2
  776. package/dist/plugins/mailbox/mailbox.integration.test.d.ts.map +0 -1
  777. package/dist/plugins/mailbox/mailbox.integration.test.js +0 -678
  778. package/dist/plugins/mailbox/mailbox.integration.test.js.map +0 -1
  779. package/dist/plugins/resources/resources.integration.test.d.ts +0 -2
  780. package/dist/plugins/resources/resources.integration.test.d.ts.map +0 -1
  781. package/dist/plugins/resources/resources.integration.test.js +0 -62
  782. package/dist/plugins/resources/resources.integration.test.js.map +0 -1
  783. package/dist/plugins/result-eviction/result-eviction.integration.test.d.ts +0 -2
  784. package/dist/plugins/result-eviction/result-eviction.integration.test.d.ts.map +0 -1
  785. package/dist/plugins/result-eviction/result-eviction.integration.test.js +0 -294
  786. package/dist/plugins/result-eviction/result-eviction.integration.test.js.map +0 -1
  787. package/dist/plugins/services/pid-registry.test.d.ts +0 -2
  788. package/dist/plugins/services/pid-registry.test.d.ts.map +0 -1
  789. package/dist/plugins/services/pid-registry.test.js +0 -161
  790. package/dist/plugins/services/pid-registry.test.js.map +0 -1
  791. package/dist/plugins/services/services.integration.test.d.ts +0 -2
  792. package/dist/plugins/services/services.integration.test.d.ts.map +0 -1
  793. package/dist/plugins/services/services.integration.test.js +0 -1057
  794. package/dist/plugins/services/services.integration.test.js.map +0 -1
  795. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.d.ts +0 -2
  796. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.d.ts.map +0 -1
  797. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js +0 -498
  798. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js.map +0 -1
  799. package/dist/plugins/session-stats/plugin.test.d.ts +0 -2
  800. package/dist/plugins/session-stats/plugin.test.d.ts.map +0 -1
  801. package/dist/plugins/session-stats/plugin.test.js +0 -145
  802. package/dist/plugins/session-stats/plugin.test.js.map +0 -1
  803. package/dist/plugins/shell/shell.integration.test.d.ts +0 -2
  804. package/dist/plugins/shell/shell.integration.test.d.ts.map +0 -1
  805. package/dist/plugins/shell/shell.integration.test.js +0 -234
  806. package/dist/plugins/shell/shell.integration.test.js.map +0 -1
  807. package/dist/plugins/shell/shell.test.d.ts +0 -2
  808. package/dist/plugins/shell/shell.test.d.ts.map +0 -1
  809. package/dist/plugins/shell/shell.test.js +0 -236
  810. package/dist/plugins/shell/shell.test.js.map +0 -1
  811. package/dist/plugins/skills/discovery.test.d.ts +0 -2
  812. package/dist/plugins/skills/discovery.test.d.ts.map +0 -1
  813. package/dist/plugins/skills/discovery.test.js +0 -312
  814. package/dist/plugins/skills/discovery.test.js.map +0 -1
  815. package/dist/plugins/skills/skills.integration.test.d.ts +0 -2
  816. package/dist/plugins/skills/skills.integration.test.d.ts.map +0 -1
  817. package/dist/plugins/skills/skills.integration.test.js +0 -475
  818. package/dist/plugins/skills/skills.integration.test.js.map +0 -1
  819. package/dist/plugins/todo/todo.integration.test.d.ts +0 -2
  820. package/dist/plugins/todo/todo.integration.test.d.ts.map +0 -1
  821. package/dist/plugins/todo/todo.integration.test.js +0 -605
  822. package/dist/plugins/todo/todo.integration.test.js.map +0 -1
  823. package/dist/plugins/uploads/preprocessors/image-classifier.test.d.ts +0 -2
  824. package/dist/plugins/uploads/preprocessors/image-classifier.test.d.ts.map +0 -1
  825. package/dist/plugins/uploads/preprocessors/image-classifier.test.js +0 -113
  826. package/dist/plugins/uploads/preprocessors/image-classifier.test.js.map +0 -1
  827. package/dist/plugins/uploads/uploads.integration.test.d.ts +0 -2
  828. package/dist/plugins/uploads/uploads.integration.test.d.ts.map +0 -1
  829. package/dist/plugins/uploads/uploads.integration.test.js +0 -639
  830. package/dist/plugins/uploads/uploads.integration.test.js.map +0 -1
  831. package/dist/plugins/user-chat/user-chat.integration.test.d.ts +0 -2
  832. package/dist/plugins/user-chat/user-chat.integration.test.d.ts.map +0 -1
  833. package/dist/plugins/user-chat/user-chat.integration.test.js +0 -754
  834. package/dist/plugins/user-chat/user-chat.integration.test.js.map +0 -1
  835. package/dist/plugins/workers/workers.integration.test.d.ts +0 -2
  836. package/dist/plugins/workers/workers.integration.test.d.ts.map +0 -1
  837. package/dist/plugins/workers/workers.integration.test.js +0 -629
  838. package/dist/plugins/workers/workers.integration.test.js.map +0 -1
  839. package/dist/prompts/macros.test.d.ts +0 -2
  840. package/dist/prompts/macros.test.d.ts.map +0 -1
  841. package/dist/prompts/macros.test.js +0 -80
  842. package/dist/prompts/macros.test.js.map +0 -1
  843. package/dist/testing/test-harness.test.d.ts +0 -2
  844. package/dist/testing/test-harness.test.d.ts.map +0 -1
  845. package/dist/testing/test-harness.test.js +0 -92
  846. package/dist/testing/test-harness.test.js.map +0 -1
  847. package/dist/transport/http/routes/rpc.integration.test.d.ts +0 -2
  848. package/dist/transport/http/routes/rpc.integration.test.d.ts.map +0 -1
  849. package/dist/transport/http/routes/rpc.integration.test.js +0 -189
  850. package/dist/transport/http/routes/rpc.integration.test.js.map +0 -1
  851. package/dist/transport/http/routes/rpc.test.d.ts +0 -2
  852. package/dist/transport/http/routes/rpc.test.d.ts.map +0 -1
  853. package/dist/transport/http/routes/rpc.test.js +0 -316
  854. package/dist/transport/http/routes/rpc.test.js.map +0 -1
  855. package/src/config.test.ts +0 -174
  856. package/src/core/agent-loop.integration.test.ts +0 -503
  857. package/src/core/agents/agent-config.test.ts +0 -240
  858. package/src/core/agents/agent-shutdown.test.ts +0 -236
  859. package/src/core/agents/agent.test.ts +0 -387
  860. package/src/core/agents/communicator.ts +0 -16
  861. package/src/core/agents/handler-events.test.ts +0 -167
  862. package/src/core/agents/response-sanitizer.test.ts +0 -137
  863. package/src/core/error-recovery.integration.test.ts +0 -343
  864. package/src/core/event-sourcing.integration.test.ts +0 -191
  865. package/src/core/events/file.test.ts +0 -436
  866. package/src/core/events/memory.test.ts +0 -741
  867. package/src/core/image/image-processor.test.ts +0 -218
  868. package/src/core/image/vips-resizer.test.ts +0 -388
  869. package/src/core/llm/anthropic.test.ts +0 -546
  870. package/src/core/llm/cache-breakpoints.test.ts +0 -85
  871. package/src/core/llm/cache-live.test.ts +0 -155
  872. package/src/core/llm/logger.test.ts +0 -270
  873. package/src/core/llm/message-sanitization.test.ts +0 -217
  874. package/src/core/llm/mock.test.ts +0 -402
  875. package/src/core/llm/model-shortlist-live.test.ts +0 -577
  876. package/src/core/llm/openrouter-mapping.test.ts +0 -234
  877. package/src/core/llm/openrouter.test.ts +0 -499
  878. package/src/core/llm/provider-integration.test.ts +0 -408
  879. package/src/core/llm/reasoning-details.test.ts +0 -177
  880. package/src/core/llm/routing-provider.test.ts +0 -113
  881. package/src/core/llm/snapshot-middleware.test.ts +0 -168
  882. package/src/core/llm/thinking-blocks.test.ts +0 -345
  883. package/src/core/multi-agent.integration.test.ts +0 -340
  884. package/src/core/plugin-hooks.integration.test.ts +0 -568
  885. package/src/core/reasoning-round-trip.integration.test.ts +0 -188
  886. package/src/core/session-lifecycle.integration.test.ts +0 -202
  887. package/src/core/sessions/fork-utils.test.ts +0 -158
  888. package/src/core/sessions/session-overrides.integration.test.ts +0 -210
  889. package/src/core/sessions/session.test.ts +0 -1736
  890. package/src/core/tools/executor.test.ts +0 -161
  891. package/src/lib/logger/console.test.ts +0 -348
  892. package/src/lib/never.ts +0 -3
  893. package/src/lib/utils/concurrency.test.ts +0 -169
  894. package/src/plugins/agent-status/agent-status.test.ts +0 -164
  895. package/src/plugins/agents/agents.integration.test.ts +0 -976
  896. package/src/plugins/agents/supervision.integration.test.ts +0 -249
  897. package/src/plugins/context-compact/compaction-live.test.ts +0 -221
  898. package/src/plugins/context-compact/context-compact.integration.test.ts +0 -418
  899. package/src/plugins/context-compact/context-compactor.test.ts +0 -1036
  900. package/src/plugins/context-compact/history-offloader.test.ts +0 -100
  901. package/src/plugins/filesystem/filesystem.integration.test.ts +0 -529
  902. package/src/plugins/filesystem/schema.ts +0 -6
  903. package/src/plugins/limits-guard/limit-guard.test.ts +0 -253
  904. package/src/plugins/limits-guard/limits-guard.integration.test.ts +0 -1012
  905. package/src/plugins/llm-debug/llm-debug.integration.test.ts +0 -192
  906. package/src/plugins/mailbox/mailbox.integration.test.ts +0 -794
  907. package/src/plugins/resources/resources.integration.test.ts +0 -68
  908. package/src/plugins/result-eviction/result-eviction.integration.test.ts +0 -332
  909. package/src/plugins/services/pid-registry.test.ts +0 -180
  910. package/src/plugins/services/services.integration.test.ts +0 -1223
  911. package/src/plugins/session-lifecycle/session-lifecycle.integration.test.ts +0 -639
  912. package/src/plugins/session-stats/plugin.test.ts +0 -160
  913. package/src/plugins/shell/shell.integration.test.ts +0 -273
  914. package/src/plugins/shell/shell.test.ts +0 -314
  915. package/src/plugins/skills/discovery.test.ts +0 -395
  916. package/src/plugins/skills/skills.integration.test.ts +0 -580
  917. package/src/plugins/todo/todo.integration.test.ts +0 -687
  918. package/src/plugins/uploads/preprocessors/image-classifier.test.ts +0 -142
  919. package/src/plugins/uploads/uploads.integration.test.ts +0 -831
  920. package/src/plugins/user-chat/user-chat.integration.test.ts +0 -893
  921. package/src/plugins/workers/workers.integration.test.ts +0 -778
  922. package/src/prompts/macros.test.ts +0 -107
  923. package/src/testing/test-harness.test.ts +0 -114
  924. package/src/transport/http/routes/rpc.integration.test.ts +0 -243
  925. package/src/transport/http/routes/rpc.test.ts +0 -372
@@ -10,8 +10,8 @@
10
10
  import { join } from 'node:path'
11
11
  import z4 from 'zod/v4'
12
12
  import { COMMUNICATOR_ROLE, ORCHESTRATOR_ROLE } from '~/core/agents/agent-roles.js'
13
- import type { AgentId } from '~/core/agents/schema.js'
14
- import { generateAgentId } from '~/core/agents/schema.js'
13
+ import { parseAgentWakeKey, parsePluginWakeKey } from '~/core/wake-key.js'
14
+ import { AgentId, generateAgentId } from '~/core/agents/schema.js'
15
15
  import { agentEvents } from '~/core/agents/state.js'
16
16
  import { type DomainError, PresetErrors, SessionErrors, ValidationErrors } from '~/core/errors.js'
17
17
  import { withSessionId } from '~/core/events/test-helpers.js'
@@ -19,18 +19,22 @@ import type { DomainEvent } from '~/core/events/types.js'
19
19
  import type { FileStore } from '~/core/file-store/types.js'
20
20
  import type { LLMLogger } from '~/core/llm/logger.js'
21
21
  import type { LLMProvider } from '~/core/llm/provider.js'
22
- import type { CallerContext, ConfiguredPlugin, ManagerMethodContext, PluginDefinition } from '~/core/plugins/plugin-builder.js'
22
+ import { DEFAULT_PLUGIN_ORDER } from '~/core/plugins/plugin-builder.js'
23
+ import type { CallerContext, ConfiguredPlugin, ManagerMethodContext, PluginDefinition, SessionCloseReason } from '~/core/plugins/plugin-builder.js'
24
+ import { AGENT_CALLER } from '~/core/plugins/plugin-builder.js'
23
25
  import type { Preset } from '~/core/preset/index.js'
24
26
  import { knownDefinitionNames, unknownOverrideTargets } from '~/core/preset/overrides.js'
25
- import type { SessionId } from '~/core/sessions/schema.js'
26
- import { generateSessionId } from '~/core/sessions/schema.js'
27
+ import type { SessionMetadata } from '~/core/sessions/schema.js'
28
+ import { generateSessionId, isValidSessionId, SessionId } from '~/core/sessions/schema.js'
27
29
  import type { SessionCreatedEvent, SessionOverridesPatch } from '~/core/sessions/state.js'
28
30
  import { checkRecoveryNeeded, isSessionCreatedEvent, reconstructSessionState, sessionEvents } from '~/core/sessions/state.js'
29
31
  import type { ToolExecutor } from '~/core/tools'
30
- import { FileLogger } from '~/lib/logger/file.js'
32
+ import type { ArchiveLimitOverrides } from '~/lib/archive/index.js'
31
33
  import type { Logger } from '~/lib/logger/logger.js'
34
+ import { createSessionLogger } from '~/lib/logger/session-log.js'
32
35
  import { TeeLogger } from '~/lib/logger/tee.js'
33
36
  import type { Platform } from '~/platform/index.js'
37
+ import { isLiveScheduler } from '~/platform/index.js'
34
38
  import type { Result } from '~/lib/utils/result.js'
35
39
  import { Err, Ok } from '~/lib/utils/result.js'
36
40
  import type { SpawnableAgentInfo } from '~/plugins/agents/index.js'
@@ -44,7 +48,8 @@ import { EventStore } from '../events/event-store.js'
44
48
  import { createApplyEvent } from './apply-event.js'
45
49
  import { rewriteEventsForFork } from './fork-utils.js'
46
50
  import { SessionStore } from './session-store.js'
47
- import { Session, type UserOutputCallback } from './session.js'
51
+ import { Session, type SessionReopenRegistration, type UserOutputCallback } from './session.js'
52
+ import { SessionRuntimeActivityController } from './runtime-activity.js'
48
53
 
49
54
  // ============================================================================
50
55
  // Errors
@@ -77,21 +82,48 @@ export interface SessionManagerOptions {
77
82
  dataFileStore: FileStore
78
83
  onUserOutput?: UserOutputCallback
79
84
  preprocessorRegistry?: PreprocessorRegistry
85
+ uploadArchiveLimits?: ArchiveLimitOverrides
86
+ resourceArchiveLimits?: ArchiveLimitOverrides
80
87
  llmLogger?: LLMLogger
81
88
  portPool?: PortPool
82
89
  pidRegistry?: ServicePidRegistry
83
90
  /** Host-environment adapters (filesystem, process). */
84
91
  platform: Platform
85
92
  systemPlugins?: readonly PluginDefinition<string, any, any, any, any>[]
93
+ /** Evict resident runtimes after this idle period. Absent or zero disables eviction. */
94
+ sessionIdleTimeoutMs?: number
95
+ }
96
+
97
+ interface SessionCacheEntry {
98
+ state: 'loading' | 'ready' | 'evicting'
99
+ promise: Promise<Session>
100
+ activity: SessionRuntimeActivityController
101
+ lastAccessAt: number
102
+ unloadPromise?: Promise<void>
103
+ listenerCleanup?: () => void
104
+ }
105
+
106
+ /** Why the manager is dropping a resident runtime — finer-grained than what plugins see. */
107
+ type RuntimeDisposalCause = 'idle' | 'closed' | 'disposed' | 'shutdown'
108
+
109
+ // Both parking causes map to `evicted`: the session survives and the next access rebuilds its runtime.
110
+ const RUNTIME_DISPOSAL_CLOSE_REASON: Record<RuntimeDisposalCause, SessionCloseReason> = {
111
+ idle: 'evicted',
112
+ disposed: 'evicted',
113
+ closed: 'closed',
114
+ shutdown: 'shutdown',
115
+ }
116
+
117
+ export interface AcquiredSessionLease {
118
+ session: Session
119
+ release: () => void
86
120
  }
87
121
 
88
122
  /**
89
123
  * SessionManager manages session lifecycle and caching.
90
124
  */
91
125
  export class SessionManager {
92
- private readonly sessions = new Map<SessionId, Promise<Session>>()
93
- /** Unsubscribe functions for session event listeners, keyed by sessionId */
94
- private readonly sessionListenerCleanup = new Map<SessionId, () => void>()
126
+ private readonly sessions = new Map<SessionId, SessionCacheEntry>()
95
127
  /** Manager-level methods collected from plugin definitions across all presets */
96
128
  private readonly managerMethods: Map<string, {
97
129
  input: z4.ZodType
@@ -109,13 +141,25 @@ export class SessionManager {
109
141
  private readonly dataFileStore: FileStore
110
142
  private readonly onUserOutput?: UserOutputCallback
111
143
  private readonly preprocessorRegistry?: PreprocessorRegistry
144
+ private readonly uploadArchiveLimits?: ArchiveLimitOverrides
145
+ private readonly resourceArchiveLimits?: ArchiveLimitOverrides
112
146
  private readonly llmLogger?: LLMLogger
113
147
  private readonly portPool?: PortPool
114
148
  private readonly pidRegistry?: ServicePidRegistry
115
149
  private readonly platform: Platform
116
150
  private readonly systemPlugins: readonly PluginDefinition<string, any, any, any, any>[]
151
+ private readonly sessionIdleTimeoutMs: number
152
+ private readonly evictionSweepTimer?: ReturnType<typeof setInterval>
153
+ private cacheHits = 0
154
+ private cacheMisses = 0
155
+ private cacheEvictions = 0
156
+ /** Set by shutdown(). Also fences wakes: one armed before it must not reload a session after it. */
157
+ private shuttingDown = false
117
158
 
118
159
  constructor(options: SessionManagerOptions) {
160
+ if (options.sessionIdleTimeoutMs !== undefined && (!Number.isSafeInteger(options.sessionIdleTimeoutMs) || options.sessionIdleTimeoutMs < 0)) {
161
+ throw new Error(`Invalid sessionIdleTimeoutMs: ${options.sessionIdleTimeoutMs}`)
162
+ }
119
163
  this.eventStore = options.eventStore
120
164
  this.llmProvider = options.llmProvider
121
165
  this.llmProviders = options.llmProviders ?? new Map()
@@ -126,12 +170,35 @@ export class SessionManager {
126
170
  this.dataFileStore = options.dataFileStore
127
171
  this.onUserOutput = options.onUserOutput
128
172
  this.preprocessorRegistry = options.preprocessorRegistry
173
+ this.uploadArchiveLimits = options.uploadArchiveLimits
174
+ this.resourceArchiveLimits = options.resourceArchiveLimits
129
175
  this.llmLogger = options.llmLogger
130
176
  this.portPool = options.portPool
131
177
  this.pidRegistry = options.pidRegistry
132
178
  this.platform = options.platform
133
179
  this.systemPlugins = options.systemPlugins ?? []
180
+ this.sessionIdleTimeoutMs = options.sessionIdleTimeoutMs ?? 0
134
181
  this.managerMethods = this.collectManagerMethods()
182
+ if (this.sessionIdleTimeoutMs > 0) {
183
+ const sweepIntervalMs = Math.min(this.sessionIdleTimeoutMs, 60_000)
184
+ this.evictionSweepTimer = setInterval(() => {
185
+ void this.evictIdleSessions()
186
+ }, sweepIntervalMs)
187
+ this.evictionSweepTimer.unref()
188
+ }
189
+
190
+ // A live scheduler has nowhere else to deliver. Hosts that wake out-of-band
191
+ // (a Durable Object alarm) call dispatchWake() from their own handler.
192
+ const scheduler = this.platform.scheduler
193
+ if (isLiveScheduler(scheduler)) {
194
+ scheduler.onWake(async (key) => {
195
+ try {
196
+ await this.dispatchWake(key)
197
+ } catch (error) {
198
+ this.logger.error('Scheduler wake dispatch failed', error instanceof Error ? error : new Error(String(error)), { key })
199
+ }
200
+ })
201
+ }
135
202
  }
136
203
 
137
204
  /** Expose platform adapters (used by Session for building contexts). */
@@ -139,6 +206,76 @@ export class SessionManager {
139
206
  return this.platform
140
207
  }
141
208
 
209
+ /**
210
+ * Deliver a scheduler wake that has come due.
211
+ *
212
+ * The host's entry point back into the SDK — on Cloudflare, called from
213
+ * `alarm()` in an isolate that never armed the wake. SessionManager owns it
214
+ * because it is the only thing that can turn a session id back into a live
215
+ * session, so the key alone is enough input.
216
+ *
217
+ * Two vocabularies route here: `agent:` wakes re-enter the agent loop,
218
+ * `plugin:` wakes call a plugin method. Anything else is a quiet no-op, and so
219
+ * is a key naming a session, agent or plugin that is gone — wakes outlive what
220
+ * they point at. Only genuinely unexpected failures (event store IO) throw, so
221
+ * a host that retries alarms retries those and only those.
222
+ */
223
+ async dispatchWake(key: string): Promise<void> {
224
+ const agentWake = parseAgentWakeKey(key)
225
+ if (agentWake) {
226
+ await this.withWakeTarget(key, agentWake.sessionId, async (session) => {
227
+ await session.getAgent(agentWake.agentId)?.deliverWake(agentWake.kind)
228
+ })
229
+ return
230
+ }
231
+
232
+ const pluginWake = parsePluginWakeKey(key)
233
+ if (pluginWake) {
234
+ await this.withWakeTarget(key, pluginWake.sessionId, async (session) => {
235
+ const result = await session.callPluginMethod(
236
+ `${pluginWake.pluginName}.${pluginWake.method}`,
237
+ pluginWake.agentId === undefined ? {} : { agentId: pluginWake.agentId },
238
+ pluginWake.agentId,
239
+ AGENT_CALLER,
240
+ )
241
+ // A preset that no longer registers the plugin lands here, same as a
242
+ // missing agent does: the wake points at something that is gone.
243
+ if (!result.ok) this.logger.debug('Scheduler wake method rejected', { key, error: result.error.type })
244
+ })
245
+ return
246
+ }
247
+
248
+ this.logger.debug('Ignoring unrecognized scheduler wake key', { key })
249
+ }
250
+
251
+ /** Run `deliver` against the session a due wake names, under a runtime lease. */
252
+ private async withWakeTarget(key: string, sessionId: SessionId, deliver: (session: Session) => Promise<void>): Promise<void> {
253
+ // Nothing armed before shutdown may load a session back in afterwards.
254
+ if (this.shuttingDown) return
255
+ // Nor may a wake that lands mid-teardown rebuild what is being torn down —
256
+ // getSession() would wait out the unload and reload. onSessionReady re-arms.
257
+ const resident = this.sessions.get(sessionId)
258
+ if (resident && (resident.state === 'evicting' || resident.activity.getSnapshot().state !== 'ready')) return
259
+
260
+ const sessionResult = await this.getSession(sessionId)
261
+ if (!sessionResult.ok) {
262
+ this.logger.debug('Scheduler wake for a session that no longer loads', { key, error: sessionResult.error.type })
263
+ return
264
+ }
265
+ const session = sessionResult.value
266
+ // A closed session's log is sealed; re-entering it would only fail to write.
267
+ if (session.state.status === 'closed') return
268
+
269
+ // Lease the delivery, not the delay before it — an idle session stays evictable while it waits.
270
+ const release = session.tryAcquireRuntimeLease(`wake:${key}`)
271
+ if (!release) return
272
+ try {
273
+ await deliver(session)
274
+ } finally {
275
+ release()
276
+ }
277
+ }
278
+
142
279
  /**
143
280
  * Create a new session with the given preset.
144
281
  */
@@ -146,6 +283,7 @@ export class SessionManager {
146
283
  presetId: string,
147
284
  options?: { workspaceDir?: string; sessionId?: string; overrides?: SessionOverridesPatch },
148
285
  ): Promise<Result<Session, DomainError>> {
286
+ if (this.shuttingDown) return Err(ValidationErrors.invalid('Session manager is shutting down'))
149
287
  const preset = this.presets.get(presetId)
150
288
  if (!preset) {
151
289
  return Err(PresetErrors.notFound(presetId))
@@ -160,7 +298,12 @@ export class SessionManager {
160
298
  }
161
299
  }
162
300
 
163
- const sessionId = options?.sessionId ? (options.sessionId as any) : generateSessionId()
301
+ // Validate before anything derives a path from it — the id reaches join() for the
302
+ // session dir, the event log and the file logger, and path.join collapses `..`.
303
+ if (options?.sessionId !== undefined && !isValidSessionId(options.sessionId)) {
304
+ return Err(ValidationErrors.invalid(`Invalid session id: ${JSON.stringify(options.sessionId)}`))
305
+ }
306
+ const sessionId = options?.sessionId ? SessionId(options.sessionId) : generateSessionId()
164
307
  // First orchestrator gets seq 1
165
308
  const orchestratorId = generateAgentId(ORCHESTRATOR_ROLE, 1)
166
309
 
@@ -229,25 +372,40 @@ export class SessionManager {
229
372
  ))
230
373
  }
231
374
 
232
- // Write events to event store
233
- await this.eventStore.appendBatch(sessionId, events)
234
-
235
- // Build plugins and composed reducer so plugin state slices are applied
236
- const plugins = this.buildPlugins(preset)
237
- const composedReducer = createApplyEvent(plugins)
238
-
239
- // Reconstruct state with composed reducer (includes plugin state slices)
240
- const state = reconstructSessionState(events, composedReducer)
241
- if (!state) {
242
- return Err(ValidationErrors.invalid('Failed to reconstruct session'))
375
+ if (this.sessions.has(sessionId)) return Err(SessionErrors.alreadyExists(String(sessionId)))
376
+ const activity = new SessionRuntimeActivityController()
377
+ let entry: SessionCacheEntry
378
+ const creationPromise = Promise.resolve().then(async () => {
379
+ if (await this.eventStore.exists(sessionId)) throw new SessionLoadError(SessionErrors.alreadyExists(String(sessionId)))
380
+ await this.eventStore.appendBatch(sessionId, events)
381
+ const plugins = this.buildPlugins(preset)
382
+ const composedReducer = createApplyEvent(plugins)
383
+ const state = reconstructSessionState(events, composedReducer)
384
+ if (!state) throw new SessionLoadError(ValidationErrors.invalid('Failed to reconstruct session'))
385
+ const store = new SessionStore(sessionId, this.eventStore, state, composedReducer)
386
+ return this.createSessionInstance(store, preset, plugins, entry)
387
+ })
388
+ entry = {
389
+ state: 'loading',
390
+ promise: creationPromise,
391
+ activity,
392
+ lastAccessAt: performance.now(),
243
393
  }
394
+ this.sessions.set(sessionId, entry)
244
395
 
245
- // Create store and session (initPluginContexts + onSessionReady hooks run inside)
246
- const store = new SessionStore(sessionId, this.eventStore, state, composedReducer)
247
- const session = await this.createSessionInstance(store, preset, plugins)
248
-
249
- // Cache session (wrap in resolved promise for consistency)
250
- this.sessions.set(sessionId, Promise.resolve(session))
396
+ let session: Session
397
+ try {
398
+ session = await creationPromise
399
+ if (this.sessions.get(sessionId) === entry && entry.state === 'loading') {
400
+ entry.state = 'ready'
401
+ entry.lastAccessAt = performance.now()
402
+ }
403
+ } catch (error) {
404
+ if (this.sessions.get(sessionId) === entry) this.sessions.delete(sessionId)
405
+ entry.listenerCleanup?.()
406
+ if (error instanceof SessionLoadError) return Err(error.domainError)
407
+ throw error
408
+ }
251
409
 
252
410
  this.logger.info('Session created', {
253
411
  sessionId,
@@ -266,8 +424,10 @@ export class SessionManager {
266
424
  sourceSessionId: SessionId,
267
425
  eventIndex: number,
268
426
  ): Promise<Result<Session, DomainError>> {
427
+ if (this.shuttingDown) return Err(ValidationErrors.invalid('Session manager is shutting down'))
269
428
  // Load source events
270
429
  const sourceEvents = await this.eventStore.load(sourceSessionId)
430
+ if (this.shuttingDown) return Err(ValidationErrors.invalid('Session manager is shutting down'))
271
431
  if (sourceEvents.length === 0) {
272
432
  return Err(SessionErrors.notFound(String(sourceSessionId)))
273
433
  }
@@ -317,43 +477,49 @@ export class SessionManager {
317
477
  })
318
478
  }
319
479
 
320
- // Write forked events to event store
321
- await this.eventStore.appendBatch(newSessionId, forkedEvents)
322
-
323
- // Build plugins and composed reducer so plugin state slices are applied
324
- const plugins = this.buildPlugins(preset)
325
- const composedReducer = createApplyEvent(plugins)
326
-
327
- // Reconstruct state with composed reducer (includes plugin state slices)
328
- const state = reconstructSessionState(forkedEvents, composedReducer)
329
- if (!state) {
330
- return Err(ValidationErrors.invalid('Failed to reconstruct forked session'))
480
+ const activity = new SessionRuntimeActivityController()
481
+ let entry: SessionCacheEntry
482
+ const forkPromise = Promise.resolve().then(async () => {
483
+ await this.eventStore.appendBatch(newSessionId, forkedEvents)
484
+ const plugins = this.buildPlugins(preset)
485
+ const composedReducer = createApplyEvent(plugins)
486
+ const state = reconstructSessionState(forkedEvents, composedReducer)
487
+ if (!state) throw new SessionLoadError(ValidationErrors.invalid('Failed to reconstruct forked session'))
488
+ const store = new SessionStore(newSessionId, this.eventStore, state, composedReducer)
489
+ const recoveryData = checkRecoveryNeeded(state)
490
+ if (recoveryData) {
491
+ await store.emit(withSessionId(
492
+ newSessionId,
493
+ sessionEvents.create('session_restarted', {
494
+ resetAgentIds: recoveryData.resetAgentIds,
495
+ clearedToolAgentIds: recoveryData.clearedToolAgentIds,
496
+ }),
497
+ ))
498
+ }
499
+ return this.createSessionInstance(store, preset, plugins, entry)
500
+ })
501
+ entry = {
502
+ state: 'loading',
503
+ promise: forkPromise,
504
+ activity,
505
+ lastAccessAt: performance.now(),
331
506
  }
507
+ this.sessions.set(newSessionId, entry)
332
508
 
333
- // Create store
334
- const store = new SessionStore(newSessionId, this.eventStore, state, composedReducer)
335
-
336
- // Normalize stuck agents via session_restarted event
337
- const recoveryData = checkRecoveryNeeded(state)
338
- if (recoveryData) {
339
- await store.emit(withSessionId(
340
- newSessionId,
341
- sessionEvents.create('session_restarted', {
342
- resetAgentIds: recoveryData.resetAgentIds,
343
- clearedToolAgentIds: recoveryData.clearedToolAgentIds,
344
- }),
345
- ))
509
+ let session: Session
510
+ try {
511
+ session = await forkPromise
512
+ if (this.sessions.get(newSessionId) === entry && entry.state === 'loading') entry.state = 'ready'
513
+ } catch (error) {
514
+ if (this.sessions.get(newSessionId) === entry) this.sessions.delete(newSessionId)
515
+ entry.listenerCleanup?.()
516
+ if (error instanceof SessionLoadError) return Err(error.domainError)
517
+ throw error
346
518
  }
347
519
 
348
- // Create session instance (auto-start services run via onSessionReady)
349
- const session = await this.createSessionInstance(store, preset, plugins)
350
-
351
520
  // Check for pending agents
352
521
  session.checkPendingAgents()
353
522
 
354
- // Cache session
355
- this.sessions.set(newSessionId, Promise.resolve(session))
356
-
357
523
  this.logger.info('Session forked', {
358
524
  sourceSessionId,
359
525
  newSessionId,
@@ -369,40 +535,59 @@ export class SessionManager {
369
535
  async getSession(
370
536
  sessionId: SessionId,
371
537
  ): Promise<Result<Session, DomainError>> {
372
- // Check cache first
373
- const cached = this.sessions.get(sessionId)
374
- if (cached) {
375
- try {
376
- return Ok(await cached)
377
- } catch (error) {
378
- // Previous load failed, remove from cache and try again
379
- this.sessions.delete(sessionId)
380
- if (error instanceof SessionLoadError) {
381
- return Err(error.domainError)
382
- }
383
- throw error
538
+ while (true) {
539
+ if (this.shuttingDown) return Err(ValidationErrors.invalid('Session manager is shutting down'))
540
+ let entry = this.sessions.get(sessionId)
541
+ if (entry?.state === 'evicting') {
542
+ await entry.unloadPromise
543
+ continue
544
+ }
545
+ if (entry?.state === 'ready' && entry.activity.getSnapshot().state !== 'ready') {
546
+ const session = await entry.promise
547
+ await this.beginCacheEntryDisposal(sessionId, entry, session, 'disposed')
548
+ continue
384
549
  }
385
- }
386
550
 
387
- // Store promise immediately to prevent concurrent loads
388
- const loadPromise = this.loadSession(sessionId)
389
- this.sessions.set(sessionId, loadPromise)
551
+ if (entry) {
552
+ this.cacheHits++
553
+ entry.lastAccessAt = performance.now()
554
+ } else {
555
+ this.cacheMisses++
556
+ const activity = new SessionRuntimeActivityController()
557
+ let loadingEntry: SessionCacheEntry
558
+ const promise = Promise.resolve().then(() => this.loadSession(sessionId, loadingEntry))
559
+ loadingEntry = {
560
+ state: 'loading',
561
+ activity,
562
+ lastAccessAt: performance.now(),
563
+ promise,
564
+ }
565
+ entry = loadingEntry
566
+ this.sessions.set(sessionId, entry)
567
+ }
390
568
 
391
- try {
392
- return Ok(await loadPromise)
393
- } catch (error) {
394
- this.sessions.delete(sessionId)
395
- if (error instanceof SessionLoadError) {
396
- return Err(error.domainError)
569
+ try {
570
+ const session = await entry.promise
571
+ if (this.sessions.get(sessionId) === entry && entry.state === 'loading') {
572
+ if (session.state.status === 'closed') this.sessions.delete(sessionId)
573
+ else {
574
+ entry.state = 'ready'
575
+ entry.lastAccessAt = performance.now()
576
+ }
577
+ }
578
+ return Ok(session)
579
+ } catch (error) {
580
+ if (this.sessions.get(sessionId) === entry) this.sessions.delete(sessionId)
581
+ if (error instanceof SessionLoadError) return Err(error.domainError)
582
+ throw error
397
583
  }
398
- throw error
399
584
  }
400
585
  }
401
586
 
402
587
  /**
403
588
  * Internal session loading - throws SessionLoadError on domain errors.
404
589
  */
405
- private async loadSession(sessionId: SessionId): Promise<Session> {
590
+ private async loadSession(sessionId: SessionId, entry: SessionCacheEntry): Promise<Session> {
406
591
  // We need to peek at events first to determine the preset, so we can build plugins
407
592
  // and compose the reducer before loading the store
408
593
  const events = await this.eventStore.load(sessionId)
@@ -425,7 +610,7 @@ export class SessionManager {
425
610
  const composedReducer = createApplyEvent(plugins)
426
611
 
427
612
  // Load store with composed reducer
428
- const store = await SessionStore.load(sessionId, this.eventStore, composedReducer)
613
+ const store = await SessionStore.fromEvents(sessionId, this.eventStore, events, composedReducer)
429
614
  if (!store) {
430
615
  throw new SessionLoadError(SessionErrors.notFound(String(sessionId)))
431
616
  }
@@ -434,11 +619,9 @@ export class SessionManager {
434
619
 
435
620
  // Don't cache closed sessions
436
621
  if (state.status === 'closed') {
437
- // Remove from cache since we don't cache closed sessions
438
- this.sessions.delete(sessionId)
439
622
  // Skip onSessionReady hooks — closed sessions are immutable, firing hooks
440
623
  // would emit events to a sealed event log on every read / restart.
441
- return await this.createSessionInstance(store, preset, plugins, { skipReadyHooks: true })
624
+ return await this.createSessionInstance(store, preset, plugins, entry, { skipReadyHooks: true })
442
625
  }
443
626
 
444
627
  // Check if recovery is needed after restart
@@ -460,7 +643,7 @@ export class SessionManager {
460
643
  }
461
644
 
462
645
  // Create session (auto-start services run via onSessionReady)
463
- const session = await this.createSessionInstance(store, preset, plugins)
646
+ const session = await this.createSessionInstance(store, preset, plugins, entry)
464
647
 
465
648
  // Check for pending agents
466
649
  session.checkPendingAgents()
@@ -482,10 +665,55 @@ export class SessionManager {
482
665
  agentId?: AgentId,
483
666
  caller?: CallerContext,
484
667
  ): Promise<Result<unknown, DomainError>> {
485
- const sessionResult = await this.getSession(sessionId)
486
- if (!sessionResult.ok) return sessionResult
668
+ return this.withSessionLease(sessionId, `request:${method}`, (session) => (
669
+ session.callPluginMethod(method, input, agentId, caller)
670
+ ))
671
+ }
487
672
 
488
- return sessionResult.value.callPluginMethod(method, input, agentId, caller)
673
+ /** Run an operation while atomically keeping the selected runtime resident. */
674
+ async withSessionLease<T>(
675
+ sessionId: SessionId,
676
+ reason: string,
677
+ operation: (session: Session) => Promise<Result<T, DomainError>>,
678
+ ): Promise<Result<T, DomainError>> {
679
+ const acquired = await this.acquireSessionLease(sessionId, reason)
680
+ if (!acquired.ok) return acquired
681
+ try {
682
+ return await operation(acquired.value.session)
683
+ } finally {
684
+ acquired.value.release()
685
+ }
686
+ }
687
+
688
+ /** Atomically look up a runtime and acquire a caller-managed lease on it. */
689
+ async acquireSessionLease(
690
+ sessionId: SessionId,
691
+ reason: string,
692
+ ): Promise<Result<AcquiredSessionLease, DomainError>> {
693
+ while (true) {
694
+ const sessionResult = await this.getSession(sessionId)
695
+ if (!sessionResult.ok) return sessionResult
696
+
697
+ const entry = this.sessions.get(sessionId)
698
+ if (!entry) return Ok({ session: sessionResult.value, release: () => {} })
699
+ const release = entry.activity.tryAcquire(reason)
700
+ if (!release) {
701
+ if (entry.unloadPromise) await entry.unloadPromise
702
+ continue
703
+ }
704
+
705
+ entry.lastAccessAt = performance.now()
706
+ let released = false
707
+ return Ok({
708
+ session: sessionResult.value,
709
+ release: () => {
710
+ if (released) return
711
+ released = true
712
+ entry.lastAccessAt = performance.now()
713
+ release()
714
+ },
715
+ })
716
+ }
489
717
  }
490
718
 
491
719
  /**
@@ -572,6 +800,7 @@ export class SessionManager {
572
800
  */
573
801
  async getStats(): Promise<{
574
802
  sessionCount: number
803
+ loadedSessionCount: number
575
804
  pendingAgents: number
576
805
  processingAgents: number
577
806
  lastActivityAt: number | null
@@ -586,9 +815,14 @@ export class SessionManager {
586
815
  let processingAgents = 0
587
816
  let lastActivityAt: number | null = null
588
817
 
589
- // Wait for all sessions, ignoring failures
818
+ const metadataResult = await this.eventStore.listSessionsWithMetadata()
819
+ const openMetadata = metadataResult.sessions.filter((metadata) => metadata.status !== 'closed')
820
+
821
+ // Wait for resident sessions, ignoring failed and evicting loads.
590
822
  const sessions = await Promise.all(
591
- Array.from(this.sessions.values()).map((p) => p.catch(() => null)),
823
+ Array.from(this.sessions.values())
824
+ .filter((entry) => entry.state !== 'evicting')
825
+ .map((entry) => entry.promise.catch(() => null)),
592
826
  )
593
827
 
594
828
  // Filter out closed sessions — they do not contribute to activity
@@ -596,13 +830,8 @@ export class SessionManager {
596
830
  (s): s is Session => s !== null && s.state.status !== 'closed',
597
831
  )
598
832
 
599
- // Fetch metadata only for open sessions
600
- const metadataResults = await Promise.all(
601
- openSessions.map((s) => this.eventStore.getMetadata(s.state.id).catch(() => null)),
602
- )
603
-
604
- for (const metadata of metadataResults) {
605
- if (metadata?.lastActivityAt) {
833
+ for (const metadata of openMetadata) {
834
+ if (metadata.lastActivityAt) {
606
835
  if (
607
836
  lastActivityAt === null
608
837
  || metadata.lastActivityAt > lastActivityAt
@@ -619,6 +848,7 @@ export class SessionManager {
619
848
  metrics: SessionStatsState
620
849
  }> = []
621
850
 
851
+ const loadedById = new Map(openSessions.map((session) => [session.id, session]))
622
852
  for (const session of openSessions) {
623
853
  for (const [agentId, agentState] of session.state.agents) {
624
854
  if (agentState.status === 'pending') {
@@ -635,16 +865,21 @@ export class SessionManager {
635
865
  }
636
866
  }
637
867
 
868
+ }
869
+
870
+ for (const metadata of openMetadata) {
871
+ const loaded = loadedById.get(metadata.sessionId)
638
872
  sessionStats.push({
639
- id: session.state.id,
640
- presetId: session.state.presetId,
641
- status: session.state.status,
642
- metrics: selectSessionStats(session.state),
873
+ id: metadata.sessionId,
874
+ presetId: metadata.presetId,
875
+ status: loaded?.state.status ?? metadata.status,
876
+ metrics: loaded ? selectSessionStats(loaded.state) : statsFromMetadata(metadata),
643
877
  })
644
878
  }
645
879
 
646
880
  return {
647
- sessionCount: openSessions.length,
881
+ sessionCount: openMetadata.length,
882
+ loadedSessionCount: openSessions.length,
648
883
  pendingAgents,
649
884
  processingAgents,
650
885
  lastActivityAt,
@@ -656,36 +891,92 @@ export class SessionManager {
656
891
  * Shutdown - clean up all sessions.
657
892
  */
658
893
  async shutdown(): Promise<void> {
659
- // Wait for all sessions, ignoring failures
660
- const sessions = await Promise.all(
661
- Array.from(this.sessions.values()).map((p) => p.catch(() => null)),
662
- )
663
-
664
- for (const session of sessions) {
665
- if (session) {
666
- session.shutdown()
894
+ this.shuttingDown = true
895
+ if (this.evictionSweepTimer) clearInterval(this.evictionSweepTimer)
896
+ await Promise.all([...this.sessions].map(async ([sessionId, entry]) => {
897
+ try {
898
+ const session = await entry.promise
899
+ await this.beginCacheEntryDisposal(sessionId, entry, session, 'shutdown')
900
+ } catch (error) {
901
+ entry.listenerCleanup?.()
902
+ entry.listenerCleanup = undefined
903
+ this.logger.error(
904
+ 'Failed to dispose session during shutdown',
905
+ error instanceof Error ? error : new Error(String(error)),
906
+ { sessionId },
907
+ )
667
908
  }
668
- }
909
+ }))
669
910
  this.sessions.clear()
670
- for (const cleanup of this.sessionListenerCleanup.values()) {
671
- cleanup()
672
- }
673
- this.sessionListenerCleanup.clear()
674
911
  this.logger.info('SessionManager shutdown complete')
675
912
  }
676
913
 
914
+ /** Narrow runtime-cache diagnostics for lifecycle tests and operational logs. */
915
+ getRuntimeCacheStats(): {
916
+ hits: number
917
+ misses: number
918
+ evictions: number
919
+ loadedSessionCount: number
920
+ sessions: Array<{
921
+ id: SessionId
922
+ state: SessionCacheEntry['state']
923
+ lastAccessAt: number
924
+ activeLeaseCount: number
925
+ leaseReasons: Readonly<Record<string, number>>
926
+ }>
927
+ } {
928
+ return {
929
+ hits: this.cacheHits,
930
+ misses: this.cacheMisses,
931
+ evictions: this.cacheEvictions,
932
+ loadedSessionCount: this.sessions.size,
933
+ sessions: [...this.sessions].map(([id, entry]) => {
934
+ const activity = entry.activity.getSnapshot()
935
+ return {
936
+ id,
937
+ state: entry.state,
938
+ lastAccessAt: Math.max(entry.lastAccessAt, activity.lastActivityAt),
939
+ activeLeaseCount: activity.activeCount,
940
+ leaseReasons: activity.reasons,
941
+ }
942
+ }),
943
+ }
944
+ }
945
+
946
+ /**
947
+ * Sessions whose runtime is already resident and ready.
948
+ *
949
+ * Deliberately does not load, and does not refresh `lastAccessAt` — a passive
950
+ * reader must not keep a runtime alive or resurrect an evicted one. Use this
951
+ * over `getSession()` for read-only sweeps across sessions.
952
+ */
953
+ async listResidentSessions(): Promise<Session[]> {
954
+ const entries = [...this.sessions].filter(([, entry]) => entry.state === 'ready')
955
+ const sessions = await Promise.all(entries.map(async ([sessionId, entry]) => {
956
+ const session = await entry.promise.catch(() => null)
957
+ // Re-check: the entry can start evicting while we await the resolved promise.
958
+ if (!session || this.sessions.get(sessionId) !== entry || entry.state !== 'ready') return null
959
+ return session
960
+ }))
961
+ return sessions.filter((session): session is Session => session !== null)
962
+ }
963
+
677
964
  // ============================================================================
678
965
  // Private methods
679
966
  // ============================================================================
680
967
 
681
968
  /**
682
- * Build ConfiguredPlugin[] for a session.
969
+ * Build ConfiguredPlugin[] for a session, in hook order.
683
970
  *
684
971
  * Iterates all system-registered plugins. For each:
685
972
  * 1. Check if preset has explicit SessionPluginConfig → use that config
686
973
  * 2. If not, try auto-deriving infrastructure config (agents, uploads, services)
687
974
  * 3. If no config at all → call .create() with no args (void config)
688
975
  * 4. Check isSessionEnabled — skip plugin if not enabled
976
+ *
977
+ * The result is sorted by each plugin's declared `.order()` — the precedence
978
+ * between plugins that both want the same hook, since most agent hooks stop
979
+ * at the first non-null result.
689
980
  */
690
981
  private buildPlugins(preset: Preset): ConfiguredPlugin[] {
691
982
  // Build a lookup from preset Sessionplugins
@@ -759,7 +1050,8 @@ export class SessionManager {
759
1050
  }
760
1051
  }
761
1052
 
762
- return plugins
1053
+ // Stable, so plugins that declare no order keep their registration order.
1054
+ return plugins.sort((a, b) => (a.order ?? DEFAULT_PLUGIN_ORDER) - (b.order ?? DEFAULT_PLUGIN_ORDER))
763
1055
  }
764
1056
 
765
1057
  /**
@@ -786,8 +1078,13 @@ export class SessionManager {
786
1078
  configs.set('uploads', {
787
1079
  dataFileStore: this.dataFileStore,
788
1080
  preprocessorRegistry: this.preprocessorRegistry,
1081
+ archiveLimits: this.uploadArchiveLimits,
789
1082
  })
790
1083
 
1084
+ if (this.resourceArchiveLimits) {
1085
+ configs.set('resources', { archiveLimits: this.resourceArchiveLimits })
1086
+ }
1087
+
791
1088
  // services plugin — collect services from all agent definitions
792
1089
  const allAgentConfigs = [preset.orchestrator, ...(preset.communicator ? [preset.communicator] : []), ...preset.agents]
793
1090
  const servicesByType = new Map<string, ServiceConfig>()
@@ -816,17 +1113,13 @@ export class SessionManager {
816
1113
  store: SessionStore,
817
1114
  preset: Preset,
818
1115
  plugins: ConfiguredPlugin[],
1116
+ entry: SessionCacheEntry,
819
1117
  opts: { skipReadyHooks?: boolean } = {},
820
1118
  ): Promise<Session> {
821
- // Only register cache eviction listener for active sessions (not closed)
822
- if (store.getState().status !== 'closed') {
823
- this.registerSessionEventListener(store.sessionId, store)
824
- }
825
-
826
1119
  const sessionDir = this.getSessionDir(store.sessionId)
827
1120
  const sessionLogger = new TeeLogger([
828
1121
  this.logger.child({ sessionId: store.sessionId }),
829
- new FileLogger(join(sessionDir, 'session.log'), this.platform.fs, { sessionId: String(store.sessionId) }),
1122
+ createSessionLogger(this.platform, String(store.sessionId), join(sessionDir, 'session.log')),
830
1123
  ])
831
1124
 
832
1125
  // Create session
@@ -843,8 +1136,15 @@ export class SessionManager {
843
1136
  eventStore: this.eventStore,
844
1137
  llmLogger: this.llmLogger,
845
1138
  platform: this.platform,
1139
+ runtimeActivity: entry.activity,
1140
+ registerReopenedSession: (reopenedSession) => this.registerReopenedSession(reopenedSession, entry.activity),
846
1141
  })
847
1142
 
1143
+ // Only register cache eviction listener for active sessions (not closed)
1144
+ if (store.getState().status !== 'closed') {
1145
+ this.registerSessionEventListener(store.sessionId, store, session, entry)
1146
+ }
1147
+
848
1148
  // Ensure session and workspace directories exist before plugins run
849
1149
  await this.platform.fs.mkdir(sessionDir, { recursive: true })
850
1150
  const workspaceDir = store.getState().workspaceDir
@@ -852,14 +1152,17 @@ export class SessionManager {
852
1152
  await this.platform.fs.mkdir(workspaceDir, { recursive: true })
853
1153
  }
854
1154
 
855
- // Initialize plugin contexts (calls createContext for each plugin).
856
- // Safe for closed sessions — createContext is pure local setup, no event emit.
857
- await session.initPluginContexts()
1155
+ try {
1156
+ // Safe for closed sessions — createContext is pure local setup, no event emit.
1157
+ await session.initPluginContexts()
858
1158
 
859
- // Call onSessionReady hooks with full context.
860
- // Skipped for closed sessions to preserve event log immutability.
861
- if (!opts.skipReadyHooks) {
862
- await session.callSessionReadyHooks()
1159
+ // Skipped for closed sessions to preserve event log immutability.
1160
+ if (!opts.skipReadyHooks) await session.callSessionReadyHooks()
1161
+ } catch (error) {
1162
+ await session.dispose('evicted')
1163
+ entry.listenerCleanup?.()
1164
+ entry.listenerCleanup = undefined
1165
+ throw error
863
1166
  }
864
1167
 
865
1168
  return session
@@ -896,20 +1199,137 @@ export class SessionManager {
896
1199
  * Cleans up any previous listener for this sessionId (from a prior load)
897
1200
  * to prevent duplicate listeners firing on old stores.
898
1201
  */
899
- private registerSessionEventListener(sessionId: SessionId, store: SessionStore): void {
900
- const prevCleanup = this.sessionListenerCleanup.get(sessionId)
901
- if (prevCleanup) prevCleanup()
902
-
1202
+ private registerSessionEventListener(sessionId: SessionId, store: SessionStore, session: Session, entry: SessionCacheEntry): void {
1203
+ entry.listenerCleanup?.()
903
1204
  const unsubscribe = store.onEvent((event) => {
904
- if (event.type === 'session_closed' || event.type === 'session_reopened') {
905
- this.sessions.delete(sessionId)
906
- this.sessionListenerCleanup.delete(sessionId)
1205
+ if (event.type === 'session_closed') {
1206
+ if (this.sessions.get(sessionId) === entry) this.beginCacheEntryDisposal(sessionId, entry, session, 'closed')
1207
+ else void session.dispose('closed')
1208
+ } else if (event.type === 'session_reopened') {
1209
+ if (this.sessions.get(sessionId) === entry) this.sessions.delete(sessionId)
1210
+ unsubscribe()
1211
+ entry.listenerCleanup = undefined
907
1212
  }
908
1213
  })
909
- this.sessionListenerCleanup.set(sessionId, unsubscribe)
1214
+ entry.listenerCleanup = unsubscribe
1215
+ }
1216
+
1217
+ private registerReopenedSession(
1218
+ session: Session,
1219
+ activity: SessionRuntimeActivityController,
1220
+ ): Result<SessionReopenRegistration | undefined, DomainError> {
1221
+ if (this.shuttingDown) return Err(ValidationErrors.invalid('Session manager is shutting down'))
1222
+ if (activity.getSnapshot().state !== 'ready') return Ok(undefined)
1223
+ if (this.sessions.has(session.id)) return Err(SessionErrors.alreadyExists(String(session.id)))
1224
+
1225
+ const deferred = Promise.withResolvers<Session>()
1226
+ void deferred.promise.catch(() => {})
1227
+ const entry: SessionCacheEntry = {
1228
+ state: 'loading',
1229
+ promise: deferred.promise,
1230
+ activity,
1231
+ lastAccessAt: performance.now(),
1232
+ }
1233
+ this.sessions.set(session.id, entry)
1234
+
1235
+ return Ok({
1236
+ complete: async () => {
1237
+ if (this.sessions.get(session.id) !== entry) {
1238
+ throw new Error(`Reopened session lost cache ownership: ${session.id}`)
1239
+ }
1240
+ this.registerSessionEventListener(session.id, session.store, session, entry)
1241
+ try {
1242
+ await session.callSessionReadyHooks()
1243
+ session.checkPendingAgents()
1244
+ if (this.sessions.get(session.id) !== entry || entry.state !== 'loading' || activity.getSnapshot().state !== 'ready') {
1245
+ throw new Error(`Reopened session became unavailable during ready hooks: ${session.id}`)
1246
+ }
1247
+ entry.state = 'ready'
1248
+ entry.lastAccessAt = performance.now()
1249
+ deferred.resolve(session)
1250
+ } catch (error) {
1251
+ if (this.sessions.get(session.id) === entry) this.sessions.delete(session.id)
1252
+ entry.listenerCleanup?.()
1253
+ entry.listenerCleanup = undefined
1254
+ deferred.reject(error)
1255
+ await session.dispose('evicted')
1256
+ throw error
1257
+ }
1258
+ },
1259
+ abort: (error) => {
1260
+ if (this.sessions.get(session.id) === entry) this.sessions.delete(session.id)
1261
+ entry.listenerCleanup?.()
1262
+ entry.listenerCleanup = undefined
1263
+ deferred.reject(error)
1264
+ },
1265
+ })
1266
+ }
1267
+
1268
+ private async evictIdleSessions(): Promise<void> {
1269
+ if (this.sessionIdleTimeoutMs === 0) return
1270
+ const now = performance.now()
1271
+ const disposals: Promise<void>[] = []
1272
+ for (const [sessionId, entry] of this.sessions) {
1273
+ if (entry.state !== 'ready') continue
1274
+ const activity = entry.activity.getSnapshot()
1275
+ if (now - Math.max(entry.lastAccessAt, activity.lastActivityAt) < this.sessionIdleTimeoutMs) continue
1276
+ if (!entry.activity.tryBeginUnload()) continue
1277
+ const session = await entry.promise
1278
+ disposals.push(this.beginCacheEntryDisposal(sessionId, entry, session, 'idle'))
1279
+ }
1280
+ await Promise.all(disposals)
1281
+ }
1282
+
1283
+ private beginCacheEntryDisposal(
1284
+ sessionId: SessionId,
1285
+ entry: SessionCacheEntry,
1286
+ session: Session,
1287
+ reason: RuntimeDisposalCause,
1288
+ ): Promise<void> {
1289
+ if (entry.unloadPromise) return entry.unloadPromise
1290
+ entry.state = 'evicting'
1291
+ entry.activity.beginForcedUnload()
1292
+ entry.unloadPromise = session.dispose(RUNTIME_DISPOSAL_CLOSE_REASON[reason])
1293
+ .catch((error) => {
1294
+ this.logger.error(
1295
+ 'Failed to dispose session runtime',
1296
+ error instanceof Error ? error : new Error(String(error)),
1297
+ { sessionId, reason },
1298
+ )
1299
+ })
1300
+ .finally(() => {
1301
+ if (this.sessions.get(sessionId) === entry) this.sessions.delete(sessionId)
1302
+ entry.listenerCleanup?.()
1303
+ entry.listenerCleanup = undefined
1304
+ if (reason === 'idle') this.cacheEvictions++
1305
+ this.logger.debug('Session runtime evicted', { sessionId, reason })
1306
+ })
1307
+ return entry.unloadPromise
910
1308
  }
911
1309
 
912
1310
  private getSessionDir(sessionId: SessionId): string {
913
1311
  return join(this.basePath, 'sessions', String(sessionId))
914
1312
  }
915
1313
  }
1314
+
1315
+ function statsFromMetadata(metadata: SessionMetadata): SessionStatsState {
1316
+ return {
1317
+ totalTokens: metadata.metrics?.totalTokens ?? 0,
1318
+ promptTokens: metadata.metrics?.inputTokens ?? 0,
1319
+ completionTokens: metadata.metrics?.outputTokens ?? 0,
1320
+ cacheReadTokens: 0,
1321
+ cacheWriteTokens: 0,
1322
+ totalCost: metadata.metrics?.totalCost ?? 0,
1323
+ llmCalls: metadata.metrics?.totalLLMCalls ?? 0,
1324
+ llmErrors: 0,
1325
+ toolCalls: metadata.metrics?.totalToolCalls ?? 0,
1326
+ toolErrors: 0,
1327
+ userMessages: metadata.metrics?.totalMessages ?? 0,
1328
+ compactions: 0,
1329
+ agentCount: metadata.metrics?.totalAgents ?? 0,
1330
+ firstEventAt: metadata.createdAt,
1331
+ lastEventAt: metadata.lastActivityAt,
1332
+ byProvider: {},
1333
+ byAgent: {},
1334
+ }
1335
+ }