@roj-ai/sdk 0.1.35 → 0.2.1

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 (908) 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 +209 -90
  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 +27 -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.d.ts.map +1 -1
  42. package/dist/core/context/state.js +6 -2
  43. package/dist/core/context/state.js.map +1 -1
  44. package/dist/core/events/base-event-store.d.ts.map +1 -1
  45. package/dist/core/events/base-event-store.js +22 -14
  46. package/dist/core/events/base-event-store.js.map +1 -1
  47. package/dist/core/events/file.d.ts +39 -1
  48. package/dist/core/events/file.d.ts.map +1 -1
  49. package/dist/core/events/file.js +159 -20
  50. package/dist/core/events/file.js.map +1 -1
  51. package/dist/core/events/types.d.ts +1 -1
  52. package/dist/core/file-store/containment.d.ts +19 -0
  53. package/dist/core/file-store/containment.d.ts.map +1 -0
  54. package/dist/core/file-store/containment.js +62 -0
  55. package/dist/core/file-store/containment.js.map +1 -0
  56. package/dist/core/file-store/file-store.d.ts +22 -2
  57. package/dist/core/file-store/file-store.d.ts.map +1 -1
  58. package/dist/core/file-store/file-store.js +88 -20
  59. package/dist/core/file-store/file-store.js.map +1 -1
  60. package/dist/core/file-store/types.d.ts +13 -1
  61. package/dist/core/file-store/types.d.ts.map +1 -1
  62. package/dist/core/image/image-processor.d.ts.map +1 -1
  63. package/dist/core/image/image-processor.js +3 -1
  64. package/dist/core/image/image-processor.js.map +1 -1
  65. package/dist/core/image/types.d.ts +2 -0
  66. package/dist/core/image/types.d.ts.map +1 -1
  67. package/dist/core/image/vips-resizer.d.ts.map +1 -1
  68. package/dist/core/image/vips-resizer.js +81 -33
  69. package/dist/core/image/vips-resizer.js.map +1 -1
  70. package/dist/core/llm/anthropic.d.ts +0 -1
  71. package/dist/core/llm/anthropic.d.ts.map +1 -1
  72. package/dist/core/llm/anthropic.js +101 -74
  73. package/dist/core/llm/anthropic.js.map +1 -1
  74. package/dist/core/llm/logger.d.ts +14 -2
  75. package/dist/core/llm/logger.d.ts.map +1 -1
  76. package/dist/core/llm/logger.js +161 -36
  77. package/dist/core/llm/logger.js.map +1 -1
  78. package/dist/core/llm/openrouter.d.ts +0 -1
  79. package/dist/core/llm/openrouter.d.ts.map +1 -1
  80. package/dist/core/llm/openrouter.js +70 -74
  81. package/dist/core/llm/openrouter.js.map +1 -1
  82. package/dist/core/llm/provider-request.d.ts +10 -0
  83. package/dist/core/llm/provider-request.d.ts.map +1 -0
  84. package/dist/core/llm/provider-request.js +41 -0
  85. package/dist/core/llm/provider-request.js.map +1 -0
  86. package/dist/core/llm/provider.d.ts +45 -3
  87. package/dist/core/llm/provider.d.ts.map +1 -1
  88. package/dist/core/llm/provider.js +26 -0
  89. package/dist/core/llm/provider.js.map +1 -1
  90. package/dist/core/llm/state.d.ts +4 -2
  91. package/dist/core/llm/state.d.ts.map +1 -1
  92. package/dist/core/llm/state.js +15 -4
  93. package/dist/core/llm/state.js.map +1 -1
  94. package/dist/core/plugins/plugin-builder.d.ts +57 -3
  95. package/dist/core/plugins/plugin-builder.d.ts.map +1 -1
  96. package/dist/core/plugins/plugin-builder.js +68 -14
  97. package/dist/core/plugins/plugin-builder.js.map +1 -1
  98. package/dist/core/preset/preset-builder.d.ts +3 -2
  99. package/dist/core/preset/preset-builder.d.ts.map +1 -1
  100. package/dist/core/preset/preset-builder.js +7 -16
  101. package/dist/core/preset/preset-builder.js.map +1 -1
  102. package/dist/core/sessions/context.d.ts +23 -5
  103. package/dist/core/sessions/context.d.ts.map +1 -1
  104. package/dist/core/sessions/runtime-activity.d.ts +33 -0
  105. package/dist/core/sessions/runtime-activity.d.ts.map +1 -0
  106. package/dist/core/sessions/runtime-activity.js +55 -0
  107. package/dist/core/sessions/runtime-activity.js.map +1 -0
  108. package/dist/core/sessions/schema.d.ts +23 -2
  109. package/dist/core/sessions/schema.d.ts.map +1 -1
  110. package/dist/core/sessions/schema.js +24 -3
  111. package/dist/core/sessions/schema.js.map +1 -1
  112. package/dist/core/sessions/session-manager.d.ts +83 -6
  113. package/dist/core/sessions/session-manager.d.ts.map +1 -1
  114. package/dist/core/sessions/session-manager.js +517 -118
  115. package/dist/core/sessions/session-manager.js.map +1 -1
  116. package/dist/core/sessions/session-store.d.ts +18 -0
  117. package/dist/core/sessions/session-store.d.ts.map +1 -1
  118. package/dist/core/sessions/session-store.js +33 -0
  119. package/dist/core/sessions/session-store.js.map +1 -1
  120. package/dist/core/sessions/session.d.ts +42 -6
  121. package/dist/core/sessions/session.d.ts.map +1 -1
  122. package/dist/core/sessions/session.js +176 -44
  123. package/dist/core/sessions/session.js.map +1 -1
  124. package/dist/core/sessions/state.d.ts +10 -1
  125. package/dist/core/sessions/state.d.ts.map +1 -1
  126. package/dist/core/sessions/state.js +16 -1
  127. package/dist/core/sessions/state.js.map +1 -1
  128. package/dist/core/system.d.ts +9 -0
  129. package/dist/core/system.d.ts.map +1 -1
  130. package/dist/core/system.js +4 -1
  131. package/dist/core/system.js.map +1 -1
  132. package/dist/core/tools/executor.d.ts +1 -1
  133. package/dist/core/wake-key.d.ts +34 -0
  134. package/dist/core/wake-key.d.ts.map +1 -0
  135. package/dist/core/wake-key.js +51 -0
  136. package/dist/core/wake-key.js.map +1 -0
  137. package/dist/index.d.ts +24 -13
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/index.js +22 -8
  140. package/dist/index.js.map +1 -1
  141. package/dist/lib/archive/archive-inspection.d.ts +48 -0
  142. package/dist/lib/archive/archive-inspection.d.ts.map +1 -0
  143. package/dist/lib/archive/archive-inspection.fixtures.d.ts +7 -0
  144. package/dist/lib/archive/archive-inspection.fixtures.d.ts.map +1 -0
  145. package/dist/lib/archive/archive-inspection.fixtures.js +134 -0
  146. package/dist/lib/archive/archive-inspection.fixtures.js.map +1 -0
  147. package/dist/lib/archive/archive-inspection.js +253 -0
  148. package/dist/lib/archive/archive-inspection.js.map +1 -0
  149. package/dist/lib/archive/index.d.ts +3 -0
  150. package/dist/lib/archive/index.d.ts.map +1 -0
  151. package/dist/lib/archive/index.js +2 -0
  152. package/dist/lib/archive/index.js.map +1 -0
  153. package/dist/lib/logger/console.d.ts +5 -12
  154. package/dist/lib/logger/console.d.ts.map +1 -1
  155. package/dist/lib/logger/console.js +5 -47
  156. package/dist/lib/logger/console.js.map +1 -1
  157. package/dist/lib/logger/file.d.ts +8 -11
  158. package/dist/lib/logger/file.d.ts.map +1 -1
  159. package/dist/lib/logger/file.js +26 -37
  160. package/dist/lib/logger/file.js.map +1 -1
  161. package/dist/lib/logger/index.d.ts +3 -1
  162. package/dist/lib/logger/index.d.ts.map +1 -1
  163. package/dist/lib/logger/index.js +3 -1
  164. package/dist/lib/logger/index.js.map +1 -1
  165. package/dist/lib/logger/jsonl.d.ts +21 -0
  166. package/dist/lib/logger/jsonl.d.ts.map +1 -0
  167. package/dist/lib/logger/jsonl.js +29 -0
  168. package/dist/lib/logger/jsonl.js.map +1 -0
  169. package/dist/lib/logger/logger.d.ts +22 -0
  170. package/dist/lib/logger/logger.d.ts.map +1 -1
  171. package/dist/lib/logger/logger.js +37 -0
  172. package/dist/lib/logger/logger.js.map +1 -1
  173. package/dist/lib/logger/session-log.d.ts +21 -0
  174. package/dist/lib/logger/session-log.d.ts.map +1 -0
  175. package/dist/lib/logger/session-log.js +37 -0
  176. package/dist/lib/logger/session-log.js.map +1 -0
  177. package/dist/lib/utils/concurrency.d.ts +1 -1
  178. package/dist/lib/utils/concurrency.d.ts.map +1 -1
  179. package/dist/lib/utils/concurrency.js +30 -7
  180. package/dist/lib/utils/concurrency.js.map +1 -1
  181. package/dist/lib/utils/fs-batch.d.ts +17 -0
  182. package/dist/lib/utils/fs-batch.d.ts.map +1 -0
  183. package/dist/lib/utils/fs-batch.js +38 -0
  184. package/dist/lib/utils/fs-batch.js.map +1 -0
  185. package/dist/lib/utils/result.d.ts +7 -22
  186. package/dist/lib/utils/result.d.ts.map +1 -1
  187. package/dist/lib/utils/result.js +6 -17
  188. package/dist/lib/utils/result.js.map +1 -1
  189. package/dist/lib/utils/sleep.d.ts +10 -0
  190. package/dist/lib/utils/sleep.d.ts.map +1 -0
  191. package/dist/lib/utils/sleep.js +26 -0
  192. package/dist/lib/utils/sleep.js.map +1 -0
  193. package/dist/platform/fs-revision.d.ts +21 -0
  194. package/dist/platform/fs-revision.d.ts.map +1 -0
  195. package/dist/platform/fs-revision.js +9 -0
  196. package/dist/platform/fs-revision.js.map +1 -0
  197. package/dist/platform/fs.d.ts +104 -1
  198. package/dist/platform/fs.d.ts.map +1 -1
  199. package/dist/platform/git.d.ts +59 -0
  200. package/dist/platform/git.d.ts.map +1 -0
  201. package/dist/platform/git.js +8 -0
  202. package/dist/platform/git.js.map +1 -0
  203. package/dist/platform/index.d.ts +40 -1
  204. package/dist/platform/index.d.ts.map +1 -1
  205. package/dist/platform/index.js +1 -1
  206. package/dist/platform/index.js.map +1 -1
  207. package/dist/platform/llm-call-log.d.ts +80 -0
  208. package/dist/platform/llm-call-log.d.ts.map +1 -0
  209. package/dist/platform/llm-call-log.js +12 -0
  210. package/dist/platform/llm-call-log.js.map +1 -0
  211. package/dist/platform/scheduler.d.ts +32 -0
  212. package/dist/platform/scheduler.d.ts.map +1 -0
  213. package/dist/platform/scheduler.js +46 -0
  214. package/dist/platform/scheduler.js.map +1 -0
  215. package/dist/platform/session-log.d.ts +36 -0
  216. package/dist/platform/session-log.d.ts.map +1 -0
  217. package/dist/platform/session-log.js +12 -0
  218. package/dist/platform/session-log.js.map +1 -0
  219. package/dist/platform/shell.d.ts +83 -0
  220. package/dist/platform/shell.d.ts.map +1 -0
  221. package/dist/platform/shell.js +13 -0
  222. package/dist/platform/shell.js.map +1 -0
  223. package/dist/plugins/agent-status/plugin.d.ts.map +1 -1
  224. package/dist/plugins/agent-status/plugin.js +1 -0
  225. package/dist/plugins/agent-status/plugin.js.map +1 -1
  226. package/dist/plugins/agents/plugin.d.ts.map +1 -1
  227. package/dist/plugins/agents/plugin.js +129 -62
  228. package/dist/plugins/agents/plugin.js.map +1 -1
  229. package/dist/plugins/filesystem/listing.d.ts +3 -0
  230. package/dist/plugins/filesystem/listing.d.ts.map +1 -1
  231. package/dist/plugins/filesystem/listing.js +66 -10
  232. package/dist/plugins/filesystem/listing.js.map +1 -1
  233. package/dist/plugins/filesystem/plugin.d.ts.map +1 -1
  234. package/dist/plugins/filesystem/plugin.js +8 -6
  235. package/dist/plugins/filesystem/plugin.js.map +1 -1
  236. package/dist/plugins/git-status/plugin.d.ts +34 -7
  237. package/dist/plugins/git-status/plugin.d.ts.map +1 -1
  238. package/dist/plugins/git-status/plugin.js +168 -64
  239. package/dist/plugins/git-status/plugin.js.map +1 -1
  240. package/dist/plugins/llm-debug/plugin.d.ts.map +1 -1
  241. package/dist/plugins/llm-debug/plugin.js +1 -0
  242. package/dist/plugins/llm-debug/plugin.js.map +1 -1
  243. package/dist/plugins/logs/plugin.d.ts +1 -4
  244. package/dist/plugins/logs/plugin.d.ts.map +1 -1
  245. package/dist/plugins/logs/plugin.js +7 -0
  246. package/dist/plugins/logs/plugin.js.map +1 -1
  247. package/dist/plugins/mailbox/helpers.d.ts +2 -2
  248. package/dist/plugins/mailbox/helpers.js +1 -1
  249. package/dist/plugins/mailbox/plugin.d.ts.map +1 -1
  250. package/dist/plugins/mailbox/plugin.js +38 -43
  251. package/dist/plugins/mailbox/plugin.js.map +1 -1
  252. package/dist/plugins/mailbox/query.d.ts +7 -2
  253. package/dist/plugins/mailbox/query.d.ts.map +1 -1
  254. package/dist/plugins/mailbox/query.js +14 -7
  255. package/dist/plugins/mailbox/query.js.map +1 -1
  256. package/dist/plugins/mailbox/state.d.ts +5 -4
  257. package/dist/plugins/mailbox/state.d.ts.map +1 -1
  258. package/dist/plugins/mailbox/state.js +6 -5
  259. package/dist/plugins/mailbox/state.js.map +1 -1
  260. package/dist/plugins/resources/filename.d.ts +4 -0
  261. package/dist/plugins/resources/filename.d.ts.map +1 -0
  262. package/dist/plugins/resources/filename.js +18 -0
  263. package/dist/plugins/resources/filename.js.map +1 -0
  264. package/dist/plugins/resources/plugin.d.ts +3 -0
  265. package/dist/plugins/resources/plugin.d.ts.map +1 -1
  266. package/dist/plugins/resources/plugin.js +97 -60
  267. package/dist/plugins/resources/plugin.js.map +1 -1
  268. package/dist/plugins/resources/state.d.ts +1 -1
  269. package/dist/plugins/resources/state.js +1 -1
  270. package/dist/plugins/result-eviction/plugin.d.ts.map +1 -1
  271. package/dist/plugins/result-eviction/plugin.js +6 -1
  272. package/dist/plugins/result-eviction/plugin.js.map +1 -1
  273. package/dist/plugins/services/plugin.d.ts +4 -1
  274. package/dist/plugins/services/plugin.d.ts.map +1 -1
  275. package/dist/plugins/services/plugin.js +251 -100
  276. package/dist/plugins/services/plugin.js.map +1 -1
  277. package/dist/plugins/services/prompt.d.ts.map +1 -1
  278. package/dist/plugins/services/prompt.js +1 -4
  279. package/dist/plugins/services/prompt.js.map +1 -1
  280. package/dist/plugins/services/schema.d.ts +15 -5
  281. package/dist/plugins/services/schema.d.ts.map +1 -1
  282. package/dist/plugins/services/service.d.ts +100 -18
  283. package/dist/plugins/services/service.d.ts.map +1 -1
  284. package/dist/plugins/services/service.js +680 -230
  285. package/dist/plugins/services/service.js.map +1 -1
  286. package/dist/plugins/session-lifecycle/plugin.d.ts +21 -1
  287. package/dist/plugins/session-lifecycle/plugin.d.ts.map +1 -1
  288. package/dist/plugins/session-lifecycle/plugin.js +53 -40
  289. package/dist/plugins/session-lifecycle/plugin.js.map +1 -1
  290. package/dist/plugins/session-state/plugin.d.ts +21 -13
  291. package/dist/plugins/session-state/plugin.d.ts.map +1 -1
  292. package/dist/plugins/session-state/plugin.js +214 -79
  293. package/dist/plugins/session-state/plugin.js.map +1 -1
  294. package/dist/plugins/session-stats/plugin.d.ts.map +1 -1
  295. package/dist/plugins/session-stats/plugin.js +1 -0
  296. package/dist/plugins/session-stats/plugin.js.map +1 -1
  297. package/dist/plugins/shell/executor.d.ts +17 -15
  298. package/dist/plugins/shell/executor.d.ts.map +1 -1
  299. package/dist/plugins/shell/executor.js +130 -195
  300. package/dist/plugins/shell/executor.js.map +1 -1
  301. package/dist/plugins/shell/index.d.ts +2 -2
  302. package/dist/plugins/shell/index.d.ts.map +1 -1
  303. package/dist/plugins/shell/index.js +2 -2
  304. package/dist/plugins/shell/index.js.map +1 -1
  305. package/dist/plugins/shell/plugin.d.ts +5 -4
  306. package/dist/plugins/shell/plugin.d.ts.map +1 -1
  307. package/dist/plugins/shell/plugin.js +4 -8
  308. package/dist/plugins/shell/plugin.js.map +1 -1
  309. package/dist/plugins/skills/discovery.d.ts.map +1 -1
  310. package/dist/plugins/skills/discovery.js +10 -8
  311. package/dist/plugins/skills/discovery.js.map +1 -1
  312. package/dist/plugins/skills/index.d.ts +1 -1
  313. package/dist/plugins/skills/index.d.ts.map +1 -1
  314. package/dist/plugins/skills/plugin.d.ts +1 -1
  315. package/dist/plugins/skills/plugin.d.ts.map +1 -1
  316. package/dist/plugins/skills/plugin.js +23 -30
  317. package/dist/plugins/skills/plugin.js.map +1 -1
  318. package/dist/plugins/skills/prompts.d.ts +3 -3
  319. package/dist/plugins/skills/prompts.d.ts.map +1 -1
  320. package/dist/plugins/skills/prompts.js.map +1 -1
  321. package/dist/plugins/skills/schema.d.ts +4 -2
  322. package/dist/plugins/skills/schema.d.ts.map +1 -1
  323. package/dist/plugins/todo/schema.d.ts +1 -1
  324. package/dist/plugins/uploads/plugin.d.ts +11 -4
  325. package/dist/plugins/uploads/plugin.d.ts.map +1 -1
  326. package/dist/plugins/uploads/plugin.js +891 -225
  327. package/dist/plugins/uploads/plugin.js.map +1 -1
  328. package/dist/plugins/uploads/preprocessor.d.ts +14 -0
  329. package/dist/plugins/uploads/preprocessor.d.ts.map +1 -1
  330. package/dist/plugins/uploads/preprocessor.js +11 -0
  331. package/dist/plugins/uploads/preprocessor.js.map +1 -1
  332. package/dist/plugins/uploads/preprocessors/image-classifier.d.ts +1 -1
  333. package/dist/plugins/uploads/preprocessors/image-classifier.d.ts.map +1 -1
  334. package/dist/plugins/uploads/preprocessors/image-classifier.js +51 -26
  335. package/dist/plugins/uploads/preprocessors/image-classifier.js.map +1 -1
  336. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.d.ts +2 -2
  337. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.d.ts.map +1 -1
  338. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js +41 -16
  339. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js.map +1 -1
  340. package/dist/plugins/uploads/preprocessors/pdf-preprocessor.d.ts +1 -1
  341. package/dist/plugins/uploads/preprocessors/pdf-preprocessor.d.ts.map +1 -1
  342. package/dist/plugins/uploads/preprocessors/pdf-preprocessor.js +29 -14
  343. package/dist/plugins/uploads/preprocessors/pdf-preprocessor.js.map +1 -1
  344. package/dist/plugins/uploads/preprocessors/zip-preprocessor.d.ts +1 -1
  345. package/dist/plugins/uploads/preprocessors/zip-preprocessor.d.ts.map +1 -1
  346. package/dist/plugins/uploads/preprocessors/zip-preprocessor.js +62 -34
  347. package/dist/plugins/uploads/preprocessors/zip-preprocessor.js.map +1 -1
  348. package/dist/plugins/uploads/schema.d.ts +25 -2
  349. package/dist/plugins/uploads/schema.d.ts.map +1 -1
  350. package/dist/plugins/uploads/schema.js +24 -3
  351. package/dist/plugins/uploads/schema.js.map +1 -1
  352. package/dist/plugins/uploads/state.d.ts +13 -1
  353. package/dist/plugins/uploads/state.d.ts.map +1 -1
  354. package/dist/plugins/uploads/state.js +4 -1
  355. package/dist/plugins/uploads/state.js.map +1 -1
  356. package/dist/plugins/user-chat/plugin.d.ts +12 -5
  357. package/dist/plugins/user-chat/plugin.d.ts.map +1 -1
  358. package/dist/plugins/user-chat/plugin.js +141 -32
  359. package/dist/plugins/user-chat/plugin.js.map +1 -1
  360. package/dist/plugins/workers/context.d.ts +35 -13
  361. package/dist/plugins/workers/context.d.ts.map +1 -1
  362. package/dist/plugins/workers/context.js +82 -32
  363. package/dist/plugins/workers/context.js.map +1 -1
  364. package/dist/plugins/workers/definition.d.ts +7 -0
  365. package/dist/plugins/workers/definition.d.ts.map +1 -1
  366. package/dist/plugins/workers/definition.js.map +1 -1
  367. package/dist/plugins/workers/index.d.ts +4 -4
  368. package/dist/plugins/workers/index.d.ts.map +1 -1
  369. package/dist/plugins/workers/index.js +2 -2
  370. package/dist/plugins/workers/index.js.map +1 -1
  371. package/dist/plugins/workers/plugin.d.ts +10 -57
  372. package/dist/plugins/workers/plugin.d.ts.map +1 -1
  373. package/dist/plugins/workers/plugin.js +385 -123
  374. package/dist/plugins/workers/plugin.js.map +1 -1
  375. package/dist/plugins/workers/state.d.ts +69 -0
  376. package/dist/plugins/workers/state.d.ts.map +1 -0
  377. package/dist/plugins/workers/state.js +52 -0
  378. package/dist/plugins/workers/state.js.map +1 -0
  379. package/dist/plugins/workers/worker.d.ts +15 -4
  380. package/dist/plugins/workers/worker.d.ts.map +1 -1
  381. package/dist/testing/conformance.d.ts +106 -0
  382. package/dist/testing/conformance.d.ts.map +1 -0
  383. package/dist/testing/conformance.js +1463 -0
  384. package/dist/testing/conformance.js.map +1 -0
  385. package/dist/testing/node-platform.d.ts.map +1 -1
  386. package/dist/testing/node-platform.js +5 -0
  387. package/dist/testing/node-platform.js.map +1 -1
  388. package/dist/testing/test-harness.d.ts +11 -1
  389. package/dist/testing/test-harness.d.ts.map +1 -1
  390. package/dist/testing/test-harness.js +17 -37
  391. package/dist/testing/test-harness.js.map +1 -1
  392. package/dist/testing/wait-helpers.d.ts.map +1 -1
  393. package/dist/testing/wait-helpers.js +1 -3
  394. package/dist/testing/wait-helpers.js.map +1 -1
  395. package/dist/transport/adapter/client-adapter.d.ts +6 -0
  396. package/dist/transport/adapter/client-adapter.d.ts.map +1 -1
  397. package/dist/transport/adapter/client-adapter.js +50 -3
  398. package/dist/transport/adapter/client-adapter.js.map +1 -1
  399. package/dist/transport/adapter/heartbeat.d.ts +16 -0
  400. package/dist/transport/adapter/heartbeat.d.ts.map +1 -0
  401. package/dist/transport/adapter/heartbeat.js +41 -0
  402. package/dist/transport/adapter/heartbeat.js.map +1 -0
  403. package/dist/transport/adapter/server-adapter.d.ts.map +1 -1
  404. package/dist/transport/adapter/server-adapter.js +6 -0
  405. package/dist/transport/adapter/server-adapter.js.map +1 -1
  406. package/dist/transport/http/app.d.ts +3 -30
  407. package/dist/transport/http/app.d.ts.map +1 -1
  408. package/dist/transport/http/app.js +3 -7
  409. package/dist/transport/http/app.js.map +1 -1
  410. package/dist/transport/http/context.d.ts +40 -0
  411. package/dist/transport/http/context.d.ts.map +1 -0
  412. package/dist/transport/http/context.js +17 -0
  413. package/dist/transport/http/context.js.map +1 -0
  414. package/dist/transport/http/fetch-guard.d.ts +49 -0
  415. package/dist/transport/http/fetch-guard.d.ts.map +1 -0
  416. package/dist/transport/http/fetch-guard.js +312 -0
  417. package/dist/transport/http/fetch-guard.js.map +1 -0
  418. package/dist/transport/http/index.d.ts +1 -1
  419. package/dist/transport/http/index.d.ts.map +1 -1
  420. package/dist/transport/http/middleware/bearer-auth.d.ts +1 -1
  421. package/dist/transport/http/middleware/bearer-auth.d.ts.map +1 -1
  422. package/dist/transport/http/middleware/error-handler.d.ts +2 -2
  423. package/dist/transport/http/middleware/error-handler.d.ts.map +1 -1
  424. package/dist/transport/http/path-containment.d.ts +20 -0
  425. package/dist/transport/http/path-containment.d.ts.map +1 -0
  426. package/dist/transport/http/path-containment.js +31 -0
  427. package/dist/transport/http/path-containment.js.map +1 -0
  428. package/dist/transport/http/responses.d.ts +30 -0
  429. package/dist/transport/http/responses.d.ts.map +1 -0
  430. package/dist/transport/http/responses.js +5 -0
  431. package/dist/transport/http/responses.js.map +1 -0
  432. package/dist/transport/http/routes/files.d.ts +1 -1
  433. package/dist/transport/http/routes/files.d.ts.map +1 -1
  434. package/dist/transport/http/routes/files.js +54 -155
  435. package/dist/transport/http/routes/files.js.map +1 -1
  436. package/dist/transport/http/routes/resources.d.ts +1 -1
  437. package/dist/transport/http/routes/resources.d.ts.map +1 -1
  438. package/dist/transport/http/routes/resources.js +92 -57
  439. package/dist/transport/http/routes/resources.js.map +1 -1
  440. package/dist/transport/http/routes/rpc.d.ts +6 -1
  441. package/dist/transport/http/routes/rpc.d.ts.map +1 -1
  442. package/dist/transport/http/routes/rpc.js +51 -21
  443. package/dist/transport/http/routes/rpc.js.map +1 -1
  444. package/dist/transport/http/routes/upload.d.ts +1 -1
  445. package/dist/transport/http/routes/upload.d.ts.map +1 -1
  446. package/dist/transport/http/routes/upload.js +256 -169
  447. package/dist/transport/http/routes/upload.js.map +1 -1
  448. package/dist/user-config.d.ts +34 -7
  449. package/dist/user-config.d.ts.map +1 -1
  450. package/dist/user-config.js +71 -0
  451. package/dist/user-config.js.map +1 -1
  452. package/package.json +18 -8
  453. package/src/bootstrap.ts +119 -35
  454. package/src/bun-platform/fs.ts +1 -0
  455. package/src/bun-platform/index.ts +18 -1
  456. package/src/bun-platform/server-lifecycle.ts +218 -0
  457. package/src/bun-platform/shell.ts +362 -0
  458. package/src/config.ts +130 -0
  459. package/src/core/agents/agent.ts +219 -95
  460. package/src/core/agents/config.ts +8 -0
  461. package/src/core/agents/retry.ts +16 -17
  462. package/src/core/agents/state.ts +28 -0
  463. package/src/core/context/state.ts +4 -0
  464. package/src/core/events/base-event-store.ts +24 -16
  465. package/src/core/events/file.ts +198 -22
  466. package/src/core/file-store/containment.ts +75 -0
  467. package/src/core/file-store/file-store.ts +106 -25
  468. package/src/core/file-store/types.ts +14 -1
  469. package/src/core/image/image-processor.ts +3 -1
  470. package/src/core/image/types.ts +2 -0
  471. package/src/core/image/vips-resizer.ts +102 -37
  472. package/src/core/llm/anthropic.ts +127 -82
  473. package/src/core/llm/logger.ts +175 -37
  474. package/src/core/llm/openrouter.ts +82 -81
  475. package/src/core/llm/provider-request.ts +40 -0
  476. package/src/core/llm/provider.ts +72 -3
  477. package/src/core/llm/state.ts +12 -0
  478. package/src/core/plugins/plugin-builder.ts +106 -14
  479. package/src/core/preset/preset-builder.ts +12 -22
  480. package/src/core/sessions/context.ts +18 -0
  481. package/src/core/sessions/runtime-activity.ts +78 -0
  482. package/src/core/sessions/schema.ts +29 -3
  483. package/src/core/sessions/session-manager.ts +560 -140
  484. package/src/core/sessions/session-store.ts +38 -0
  485. package/src/core/sessions/session.ts +187 -47
  486. package/src/core/sessions/state.ts +16 -0
  487. package/src/core/system.ts +15 -0
  488. package/src/core/wake-key.ts +65 -0
  489. package/src/index.ts +31 -12
  490. package/src/lib/archive/archive-inspection.fixtures.ts +138 -0
  491. package/src/lib/archive/archive-inspection.ts +359 -0
  492. package/src/lib/archive/index.ts +17 -0
  493. package/src/lib/logger/console.ts +7 -57
  494. package/src/lib/logger/file.ts +28 -50
  495. package/src/lib/logger/index.ts +3 -1
  496. package/src/lib/logger/jsonl.ts +36 -0
  497. package/src/lib/logger/logger.ts +48 -0
  498. package/src/lib/logger/session-log.ts +42 -0
  499. package/src/lib/utils/concurrency.ts +37 -8
  500. package/src/lib/utils/fs-batch.ts +49 -0
  501. package/src/lib/utils/result.ts +7 -31
  502. package/src/lib/utils/sleep.ts +23 -0
  503. package/src/platform/fs-revision.ts +21 -0
  504. package/src/platform/fs.ts +109 -1
  505. package/src/platform/git.ts +67 -0
  506. package/src/platform/index.ts +51 -1
  507. package/src/platform/llm-call-log.ts +86 -0
  508. package/src/platform/scheduler.ts +71 -0
  509. package/src/platform/session-log.ts +39 -0
  510. package/src/platform/shell.ts +89 -0
  511. package/src/plugins/agent-status/plugin.ts +1 -0
  512. package/src/plugins/agents/plugin.ts +134 -81
  513. package/src/plugins/filesystem/listing.ts +70 -12
  514. package/src/plugins/filesystem/plugin.ts +8 -6
  515. package/src/plugins/git-status/plugin.ts +204 -77
  516. package/src/plugins/llm-debug/plugin.ts +1 -0
  517. package/src/plugins/logs/plugin.ts +9 -0
  518. package/src/plugins/mailbox/plugin.ts +46 -64
  519. package/src/plugins/mailbox/query.ts +15 -7
  520. package/src/plugins/mailbox/state.ts +1 -0
  521. package/src/plugins/resources/filename.ts +19 -0
  522. package/src/plugins/resources/plugin.ts +111 -59
  523. package/src/plugins/result-eviction/plugin.ts +6 -1
  524. package/src/plugins/services/plugin.ts +254 -98
  525. package/src/plugins/services/prompt.ts +1 -6
  526. package/src/plugins/services/schema.ts +17 -3
  527. package/src/plugins/services/service.ts +702 -252
  528. package/src/plugins/session-lifecycle/plugin.ts +56 -41
  529. package/src/plugins/session-state/plugin.ts +242 -88
  530. package/src/plugins/session-stats/plugin.ts +1 -0
  531. package/src/plugins/shell/executor.ts +144 -226
  532. package/src/plugins/shell/index.ts +1 -4
  533. package/src/plugins/shell/plugin.ts +7 -9
  534. package/src/plugins/skills/discovery.ts +10 -8
  535. package/src/plugins/skills/index.ts +1 -1
  536. package/src/plugins/skills/plugin.ts +19 -27
  537. package/src/plugins/skills/prompts.ts +3 -3
  538. package/src/plugins/skills/schema.ts +5 -2
  539. package/src/plugins/uploads/plugin.ts +991 -273
  540. package/src/plugins/uploads/preprocessor.ts +25 -0
  541. package/src/plugins/uploads/preprocessors/image-classifier.ts +56 -25
  542. package/src/plugins/uploads/preprocessors/markitdown-preprocessor.ts +41 -15
  543. package/src/plugins/uploads/preprocessors/pdf-preprocessor.ts +32 -16
  544. package/src/plugins/uploads/preprocessors/zip-preprocessor.ts +67 -38
  545. package/src/plugins/uploads/schema.ts +30 -3
  546. package/src/plugins/uploads/state.ts +12 -0
  547. package/src/plugins/user-chat/plugin.ts +196 -40
  548. package/src/plugins/workers/context.ts +102 -39
  549. package/src/plugins/workers/definition.ts +7 -0
  550. package/src/plugins/workers/index.ts +4 -4
  551. package/src/plugins/workers/plugin.ts +461 -151
  552. package/src/plugins/workers/state.ts +64 -0
  553. package/src/plugins/workers/worker.ts +15 -4
  554. package/src/testing/conformance.ts +1751 -0
  555. package/src/testing/node-platform.ts +5 -0
  556. package/src/testing/test-harness.ts +21 -38
  557. package/src/testing/wait-helpers.ts +1 -4
  558. package/src/transport/adapter/client-adapter.ts +60 -3
  559. package/src/transport/adapter/heartbeat.ts +50 -0
  560. package/src/transport/adapter/server-adapter.ts +6 -0
  561. package/src/transport/http/app.ts +7 -35
  562. package/src/transport/http/context.ts +46 -0
  563. package/src/transport/http/fetch-guard.ts +318 -0
  564. package/src/transport/http/index.ts +1 -1
  565. package/src/transport/http/middleware/bearer-auth.ts +1 -1
  566. package/src/transport/http/middleware/error-handler.ts +1 -1
  567. package/src/transport/http/path-containment.ts +44 -0
  568. package/src/transport/http/responses.ts +20 -0
  569. package/src/transport/http/routes/files.ts +69 -159
  570. package/src/transport/http/routes/resources.ts +124 -93
  571. package/src/transport/http/routes/rpc.ts +63 -26
  572. package/src/transport/http/routes/upload.ts +327 -258
  573. package/src/user-config.ts +93 -7
  574. package/dist/config.test.d.ts +0 -2
  575. package/dist/config.test.d.ts.map +0 -1
  576. package/dist/config.test.js +0 -155
  577. package/dist/config.test.js.map +0 -1
  578. package/dist/core/agent-loop.integration.test.d.ts +0 -2
  579. package/dist/core/agent-loop.integration.test.d.ts.map +0 -1
  580. package/dist/core/agent-loop.integration.test.js +0 -414
  581. package/dist/core/agent-loop.integration.test.js.map +0 -1
  582. package/dist/core/agents/agent-config.test.d.ts +0 -2
  583. package/dist/core/agents/agent-config.test.d.ts.map +0 -1
  584. package/dist/core/agents/agent-config.test.js +0 -194
  585. package/dist/core/agents/agent-config.test.js.map +0 -1
  586. package/dist/core/agents/agent-shutdown.test.d.ts +0 -6
  587. package/dist/core/agents/agent-shutdown.test.d.ts.map +0 -1
  588. package/dist/core/agents/agent-shutdown.test.js +0 -180
  589. package/dist/core/agents/agent-shutdown.test.js.map +0 -1
  590. package/dist/core/agents/agent.test.d.ts +0 -2
  591. package/dist/core/agents/agent.test.d.ts.map +0 -1
  592. package/dist/core/agents/agent.test.js +0 -313
  593. package/dist/core/agents/agent.test.js.map +0 -1
  594. package/dist/core/agents/communicator.d.ts +0 -3
  595. package/dist/core/agents/communicator.d.ts.map +0 -1
  596. package/dist/core/agents/communicator.js +0 -13
  597. package/dist/core/agents/communicator.js.map +0 -1
  598. package/dist/core/agents/handler-events.test.d.ts +0 -5
  599. package/dist/core/agents/handler-events.test.d.ts.map +0 -1
  600. package/dist/core/agents/handler-events.test.js +0 -115
  601. package/dist/core/agents/handler-events.test.js.map +0 -1
  602. package/dist/core/agents/response-sanitizer.test.d.ts +0 -2
  603. package/dist/core/agents/response-sanitizer.test.d.ts.map +0 -1
  604. package/dist/core/agents/response-sanitizer.test.js +0 -101
  605. package/dist/core/agents/response-sanitizer.test.js.map +0 -1
  606. package/dist/core/error-recovery.integration.test.d.ts +0 -2
  607. package/dist/core/error-recovery.integration.test.d.ts.map +0 -1
  608. package/dist/core/error-recovery.integration.test.js +0 -288
  609. package/dist/core/error-recovery.integration.test.js.map +0 -1
  610. package/dist/core/event-sourcing.integration.test.d.ts +0 -2
  611. package/dist/core/event-sourcing.integration.test.d.ts.map +0 -1
  612. package/dist/core/event-sourcing.integration.test.js +0 -154
  613. package/dist/core/event-sourcing.integration.test.js.map +0 -1
  614. package/dist/core/events/file.test.d.ts +0 -2
  615. package/dist/core/events/file.test.d.ts.map +0 -1
  616. package/dist/core/events/file.test.js +0 -284
  617. package/dist/core/events/file.test.js.map +0 -1
  618. package/dist/core/events/memory.test.d.ts +0 -2
  619. package/dist/core/events/memory.test.d.ts.map +0 -1
  620. package/dist/core/events/memory.test.js +0 -502
  621. package/dist/core/events/memory.test.js.map +0 -1
  622. package/dist/core/image/image-processor.test.d.ts +0 -2
  623. package/dist/core/image/image-processor.test.d.ts.map +0 -1
  624. package/dist/core/image/image-processor.test.js +0 -171
  625. package/dist/core/image/image-processor.test.js.map +0 -1
  626. package/dist/core/image/vips-resizer.test.d.ts +0 -2
  627. package/dist/core/image/vips-resizer.test.d.ts.map +0 -1
  628. package/dist/core/image/vips-resizer.test.js +0 -336
  629. package/dist/core/image/vips-resizer.test.js.map +0 -1
  630. package/dist/core/llm/anthropic.test.d.ts +0 -2
  631. package/dist/core/llm/anthropic.test.d.ts.map +0 -1
  632. package/dist/core/llm/anthropic.test.js +0 -464
  633. package/dist/core/llm/anthropic.test.js.map +0 -1
  634. package/dist/core/llm/cache-breakpoints.test.d.ts +0 -2
  635. package/dist/core/llm/cache-breakpoints.test.d.ts.map +0 -1
  636. package/dist/core/llm/cache-breakpoints.test.js +0 -69
  637. package/dist/core/llm/cache-breakpoints.test.js.map +0 -1
  638. package/dist/core/llm/cache-live.test.d.ts +0 -16
  639. package/dist/core/llm/cache-live.test.d.ts.map +0 -1
  640. package/dist/core/llm/cache-live.test.js +0 -137
  641. package/dist/core/llm/cache-live.test.js.map +0 -1
  642. package/dist/core/llm/logger.test.d.ts +0 -7
  643. package/dist/core/llm/logger.test.d.ts.map +0 -1
  644. package/dist/core/llm/logger.test.js +0 -228
  645. package/dist/core/llm/logger.test.js.map +0 -1
  646. package/dist/core/llm/message-sanitization.test.d.ts +0 -2
  647. package/dist/core/llm/message-sanitization.test.d.ts.map +0 -1
  648. package/dist/core/llm/message-sanitization.test.js +0 -181
  649. package/dist/core/llm/message-sanitization.test.js.map +0 -1
  650. package/dist/core/llm/mock.test.d.ts +0 -2
  651. package/dist/core/llm/mock.test.d.ts.map +0 -1
  652. package/dist/core/llm/mock.test.js +0 -318
  653. package/dist/core/llm/mock.test.js.map +0 -1
  654. package/dist/core/llm/openrouter-mapping.test.d.ts +0 -2
  655. package/dist/core/llm/openrouter-mapping.test.d.ts.map +0 -1
  656. package/dist/core/llm/openrouter-mapping.test.js +0 -172
  657. package/dist/core/llm/openrouter-mapping.test.js.map +0 -1
  658. package/dist/core/llm/openrouter.test.d.ts +0 -2
  659. package/dist/core/llm/openrouter.test.d.ts.map +0 -1
  660. package/dist/core/llm/openrouter.test.js +0 -377
  661. package/dist/core/llm/openrouter.test.js.map +0 -1
  662. package/dist/core/llm/provider-integration.test.d.ts +0 -12
  663. package/dist/core/llm/provider-integration.test.d.ts.map +0 -1
  664. package/dist/core/llm/provider-integration.test.js +0 -350
  665. package/dist/core/llm/provider-integration.test.js.map +0 -1
  666. package/dist/core/llm/routing-provider.test.d.ts +0 -2
  667. package/dist/core/llm/routing-provider.test.d.ts.map +0 -1
  668. package/dist/core/llm/routing-provider.test.js +0 -94
  669. package/dist/core/llm/routing-provider.test.js.map +0 -1
  670. package/dist/core/llm/snapshot-middleware.test.d.ts +0 -2
  671. package/dist/core/llm/snapshot-middleware.test.d.ts.map +0 -1
  672. package/dist/core/llm/snapshot-middleware.test.js +0 -144
  673. package/dist/core/llm/snapshot-middleware.test.js.map +0 -1
  674. package/dist/core/multi-agent.integration.test.d.ts +0 -2
  675. package/dist/core/multi-agent.integration.test.d.ts.map +0 -1
  676. package/dist/core/multi-agent.integration.test.js +0 -298
  677. package/dist/core/multi-agent.integration.test.js.map +0 -1
  678. package/dist/core/plugin-hooks.integration.test.d.ts +0 -2
  679. package/dist/core/plugin-hooks.integration.test.d.ts.map +0 -1
  680. package/dist/core/plugin-hooks.integration.test.js +0 -458
  681. package/dist/core/plugin-hooks.integration.test.js.map +0 -1
  682. package/dist/core/session-lifecycle.integration.test.d.ts +0 -2
  683. package/dist/core/session-lifecycle.integration.test.d.ts.map +0 -1
  684. package/dist/core/session-lifecycle.integration.test.js +0 -159
  685. package/dist/core/session-lifecycle.integration.test.js.map +0 -1
  686. package/dist/core/sessions/fork-utils.test.d.ts +0 -2
  687. package/dist/core/sessions/fork-utils.test.d.ts.map +0 -1
  688. package/dist/core/sessions/fork-utils.test.js +0 -129
  689. package/dist/core/sessions/fork-utils.test.js.map +0 -1
  690. package/dist/core/sessions/session-overrides.integration.test.d.ts +0 -2
  691. package/dist/core/sessions/session-overrides.integration.test.d.ts.map +0 -1
  692. package/dist/core/sessions/session-overrides.integration.test.js +0 -154
  693. package/dist/core/sessions/session-overrides.integration.test.js.map +0 -1
  694. package/dist/core/sessions/session.test.d.ts +0 -2
  695. package/dist/core/sessions/session.test.d.ts.map +0 -1
  696. package/dist/core/sessions/session.test.js +0 -1100
  697. package/dist/core/sessions/session.test.js.map +0 -1
  698. package/dist/core/tools/executor.test.d.ts +0 -2
  699. package/dist/core/tools/executor.test.d.ts.map +0 -1
  700. package/dist/core/tools/executor.test.js +0 -144
  701. package/dist/core/tools/executor.test.js.map +0 -1
  702. package/dist/lib/logger/console.test.d.ts +0 -2
  703. package/dist/lib/logger/console.test.d.ts.map +0 -1
  704. package/dist/lib/logger/console.test.js +0 -258
  705. package/dist/lib/logger/console.test.js.map +0 -1
  706. package/dist/lib/never.d.ts +0 -2
  707. package/dist/lib/never.d.ts.map +0 -1
  708. package/dist/lib/never.js +0 -4
  709. package/dist/lib/never.js.map +0 -1
  710. package/dist/lib/utils/concurrency.test.d.ts +0 -2
  711. package/dist/lib/utils/concurrency.test.d.ts.map +0 -1
  712. package/dist/lib/utils/concurrency.test.js +0 -135
  713. package/dist/lib/utils/concurrency.test.js.map +0 -1
  714. package/dist/plugins/agent-status/agent-status.test.d.ts +0 -2
  715. package/dist/plugins/agent-status/agent-status.test.d.ts.map +0 -1
  716. package/dist/plugins/agent-status/agent-status.test.js +0 -136
  717. package/dist/plugins/agent-status/agent-status.test.js.map +0 -1
  718. package/dist/plugins/agents/agents.integration.test.d.ts +0 -2
  719. package/dist/plugins/agents/agents.integration.test.d.ts.map +0 -1
  720. package/dist/plugins/agents/agents.integration.test.js +0 -830
  721. package/dist/plugins/agents/agents.integration.test.js.map +0 -1
  722. package/dist/plugins/agents/supervision.integration.test.d.ts +0 -2
  723. package/dist/plugins/agents/supervision.integration.test.d.ts.map +0 -1
  724. package/dist/plugins/agents/supervision.integration.test.js +0 -215
  725. package/dist/plugins/agents/supervision.integration.test.js.map +0 -1
  726. package/dist/plugins/context-compact/compaction-live.test.d.ts +0 -17
  727. package/dist/plugins/context-compact/compaction-live.test.d.ts.map +0 -1
  728. package/dist/plugins/context-compact/compaction-live.test.js +0 -177
  729. package/dist/plugins/context-compact/compaction-live.test.js.map +0 -1
  730. package/dist/plugins/context-compact/context-compact.integration.test.d.ts +0 -2
  731. package/dist/plugins/context-compact/context-compact.integration.test.d.ts.map +0 -1
  732. package/dist/plugins/context-compact/context-compact.integration.test.js +0 -364
  733. package/dist/plugins/context-compact/context-compact.integration.test.js.map +0 -1
  734. package/dist/plugins/context-compact/context-compactor.test.d.ts +0 -2
  735. package/dist/plugins/context-compact/context-compactor.test.d.ts.map +0 -1
  736. package/dist/plugins/context-compact/context-compactor.test.js +0 -858
  737. package/dist/plugins/context-compact/context-compactor.test.js.map +0 -1
  738. package/dist/plugins/context-compact/history-offloader.test.d.ts +0 -2
  739. package/dist/plugins/context-compact/history-offloader.test.d.ts.map +0 -1
  740. package/dist/plugins/context-compact/history-offloader.test.js +0 -77
  741. package/dist/plugins/context-compact/history-offloader.test.js.map +0 -1
  742. package/dist/plugins/filesystem/filesystem.integration.test.d.ts +0 -2
  743. package/dist/plugins/filesystem/filesystem.integration.test.d.ts.map +0 -1
  744. package/dist/plugins/filesystem/filesystem.integration.test.js +0 -447
  745. package/dist/plugins/filesystem/filesystem.integration.test.js.map +0 -1
  746. package/dist/plugins/filesystem/schema.d.ts +0 -7
  747. package/dist/plugins/filesystem/schema.d.ts.map +0 -1
  748. package/dist/plugins/filesystem/schema.js +0 -2
  749. package/dist/plugins/filesystem/schema.js.map +0 -1
  750. package/dist/plugins/limits-guard/limit-guard.test.d.ts +0 -2
  751. package/dist/plugins/limits-guard/limit-guard.test.d.ts.map +0 -1
  752. package/dist/plugins/limits-guard/limit-guard.test.js +0 -194
  753. package/dist/plugins/limits-guard/limit-guard.test.js.map +0 -1
  754. package/dist/plugins/limits-guard/limits-guard.integration.test.d.ts +0 -2
  755. package/dist/plugins/limits-guard/limits-guard.integration.test.d.ts.map +0 -1
  756. package/dist/plugins/limits-guard/limits-guard.integration.test.js +0 -887
  757. package/dist/plugins/limits-guard/limits-guard.integration.test.js.map +0 -1
  758. package/dist/plugins/llm-debug/llm-debug.integration.test.d.ts +0 -2
  759. package/dist/plugins/llm-debug/llm-debug.integration.test.d.ts.map +0 -1
  760. package/dist/plugins/llm-debug/llm-debug.integration.test.js +0 -157
  761. package/dist/plugins/llm-debug/llm-debug.integration.test.js.map +0 -1
  762. package/dist/plugins/mailbox/mailbox.integration.test.d.ts +0 -2
  763. package/dist/plugins/mailbox/mailbox.integration.test.d.ts.map +0 -1
  764. package/dist/plugins/mailbox/mailbox.integration.test.js +0 -678
  765. package/dist/plugins/mailbox/mailbox.integration.test.js.map +0 -1
  766. package/dist/plugins/resources/resources.integration.test.d.ts +0 -2
  767. package/dist/plugins/resources/resources.integration.test.d.ts.map +0 -1
  768. package/dist/plugins/resources/resources.integration.test.js +0 -62
  769. package/dist/plugins/resources/resources.integration.test.js.map +0 -1
  770. package/dist/plugins/result-eviction/result-eviction.integration.test.d.ts +0 -2
  771. package/dist/plugins/result-eviction/result-eviction.integration.test.d.ts.map +0 -1
  772. package/dist/plugins/result-eviction/result-eviction.integration.test.js +0 -294
  773. package/dist/plugins/result-eviction/result-eviction.integration.test.js.map +0 -1
  774. package/dist/plugins/services/pid-registry.test.d.ts +0 -2
  775. package/dist/plugins/services/pid-registry.test.d.ts.map +0 -1
  776. package/dist/plugins/services/pid-registry.test.js +0 -161
  777. package/dist/plugins/services/pid-registry.test.js.map +0 -1
  778. package/dist/plugins/services/services.integration.test.d.ts +0 -2
  779. package/dist/plugins/services/services.integration.test.d.ts.map +0 -1
  780. package/dist/plugins/services/services.integration.test.js +0 -1057
  781. package/dist/plugins/services/services.integration.test.js.map +0 -1
  782. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.d.ts +0 -2
  783. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.d.ts.map +0 -1
  784. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js +0 -498
  785. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js.map +0 -1
  786. package/dist/plugins/session-stats/plugin.test.d.ts +0 -2
  787. package/dist/plugins/session-stats/plugin.test.d.ts.map +0 -1
  788. package/dist/plugins/session-stats/plugin.test.js +0 -145
  789. package/dist/plugins/session-stats/plugin.test.js.map +0 -1
  790. package/dist/plugins/shell/shell.integration.test.d.ts +0 -2
  791. package/dist/plugins/shell/shell.integration.test.d.ts.map +0 -1
  792. package/dist/plugins/shell/shell.integration.test.js +0 -234
  793. package/dist/plugins/shell/shell.integration.test.js.map +0 -1
  794. package/dist/plugins/shell/shell.test.d.ts +0 -2
  795. package/dist/plugins/shell/shell.test.d.ts.map +0 -1
  796. package/dist/plugins/shell/shell.test.js +0 -236
  797. package/dist/plugins/shell/shell.test.js.map +0 -1
  798. package/dist/plugins/skills/discovery.test.d.ts +0 -2
  799. package/dist/plugins/skills/discovery.test.d.ts.map +0 -1
  800. package/dist/plugins/skills/discovery.test.js +0 -312
  801. package/dist/plugins/skills/discovery.test.js.map +0 -1
  802. package/dist/plugins/skills/skills.integration.test.d.ts +0 -2
  803. package/dist/plugins/skills/skills.integration.test.d.ts.map +0 -1
  804. package/dist/plugins/skills/skills.integration.test.js +0 -475
  805. package/dist/plugins/skills/skills.integration.test.js.map +0 -1
  806. package/dist/plugins/todo/todo.integration.test.d.ts +0 -2
  807. package/dist/plugins/todo/todo.integration.test.d.ts.map +0 -1
  808. package/dist/plugins/todo/todo.integration.test.js +0 -605
  809. package/dist/plugins/todo/todo.integration.test.js.map +0 -1
  810. package/dist/plugins/uploads/preprocessors/image-classifier.test.d.ts +0 -2
  811. package/dist/plugins/uploads/preprocessors/image-classifier.test.d.ts.map +0 -1
  812. package/dist/plugins/uploads/preprocessors/image-classifier.test.js +0 -113
  813. package/dist/plugins/uploads/preprocessors/image-classifier.test.js.map +0 -1
  814. package/dist/plugins/uploads/uploads.integration.test.d.ts +0 -2
  815. package/dist/plugins/uploads/uploads.integration.test.d.ts.map +0 -1
  816. package/dist/plugins/uploads/uploads.integration.test.js +0 -639
  817. package/dist/plugins/uploads/uploads.integration.test.js.map +0 -1
  818. package/dist/plugins/user-chat/user-chat.integration.test.d.ts +0 -2
  819. package/dist/plugins/user-chat/user-chat.integration.test.d.ts.map +0 -1
  820. package/dist/plugins/user-chat/user-chat.integration.test.js +0 -754
  821. package/dist/plugins/user-chat/user-chat.integration.test.js.map +0 -1
  822. package/dist/plugins/workers/workers.integration.test.d.ts +0 -2
  823. package/dist/plugins/workers/workers.integration.test.d.ts.map +0 -1
  824. package/dist/plugins/workers/workers.integration.test.js +0 -629
  825. package/dist/plugins/workers/workers.integration.test.js.map +0 -1
  826. package/dist/prompts/macros.test.d.ts +0 -2
  827. package/dist/prompts/macros.test.d.ts.map +0 -1
  828. package/dist/prompts/macros.test.js +0 -80
  829. package/dist/prompts/macros.test.js.map +0 -1
  830. package/dist/testing/test-harness.test.d.ts +0 -2
  831. package/dist/testing/test-harness.test.d.ts.map +0 -1
  832. package/dist/testing/test-harness.test.js +0 -92
  833. package/dist/testing/test-harness.test.js.map +0 -1
  834. package/dist/transport/http/routes/rpc.integration.test.d.ts +0 -2
  835. package/dist/transport/http/routes/rpc.integration.test.d.ts.map +0 -1
  836. package/dist/transport/http/routes/rpc.integration.test.js +0 -189
  837. package/dist/transport/http/routes/rpc.integration.test.js.map +0 -1
  838. package/dist/transport/http/routes/rpc.test.d.ts +0 -2
  839. package/dist/transport/http/routes/rpc.test.d.ts.map +0 -1
  840. package/dist/transport/http/routes/rpc.test.js +0 -316
  841. package/dist/transport/http/routes/rpc.test.js.map +0 -1
  842. package/src/config.test.ts +0 -174
  843. package/src/core/agent-loop.integration.test.ts +0 -503
  844. package/src/core/agents/agent-config.test.ts +0 -240
  845. package/src/core/agents/agent-shutdown.test.ts +0 -236
  846. package/src/core/agents/agent.test.ts +0 -387
  847. package/src/core/agents/communicator.ts +0 -16
  848. package/src/core/agents/handler-events.test.ts +0 -167
  849. package/src/core/agents/response-sanitizer.test.ts +0 -137
  850. package/src/core/error-recovery.integration.test.ts +0 -343
  851. package/src/core/event-sourcing.integration.test.ts +0 -191
  852. package/src/core/events/file.test.ts +0 -436
  853. package/src/core/events/memory.test.ts +0 -741
  854. package/src/core/image/image-processor.test.ts +0 -218
  855. package/src/core/image/vips-resizer.test.ts +0 -388
  856. package/src/core/llm/anthropic.test.ts +0 -546
  857. package/src/core/llm/cache-breakpoints.test.ts +0 -85
  858. package/src/core/llm/cache-live.test.ts +0 -155
  859. package/src/core/llm/logger.test.ts +0 -270
  860. package/src/core/llm/message-sanitization.test.ts +0 -217
  861. package/src/core/llm/mock.test.ts +0 -402
  862. package/src/core/llm/openrouter-mapping.test.ts +0 -210
  863. package/src/core/llm/openrouter.test.ts +0 -499
  864. package/src/core/llm/provider-integration.test.ts +0 -408
  865. package/src/core/llm/routing-provider.test.ts +0 -113
  866. package/src/core/llm/snapshot-middleware.test.ts +0 -168
  867. package/src/core/multi-agent.integration.test.ts +0 -340
  868. package/src/core/plugin-hooks.integration.test.ts +0 -568
  869. package/src/core/session-lifecycle.integration.test.ts +0 -202
  870. package/src/core/sessions/fork-utils.test.ts +0 -158
  871. package/src/core/sessions/session-overrides.integration.test.ts +0 -210
  872. package/src/core/sessions/session.test.ts +0 -1736
  873. package/src/core/tools/executor.test.ts +0 -161
  874. package/src/lib/logger/console.test.ts +0 -348
  875. package/src/lib/never.ts +0 -3
  876. package/src/lib/utils/concurrency.test.ts +0 -169
  877. package/src/plugins/agent-status/agent-status.test.ts +0 -164
  878. package/src/plugins/agents/agents.integration.test.ts +0 -976
  879. package/src/plugins/agents/supervision.integration.test.ts +0 -249
  880. package/src/plugins/context-compact/compaction-live.test.ts +0 -221
  881. package/src/plugins/context-compact/context-compact.integration.test.ts +0 -418
  882. package/src/plugins/context-compact/context-compactor.test.ts +0 -1036
  883. package/src/plugins/context-compact/history-offloader.test.ts +0 -100
  884. package/src/plugins/filesystem/filesystem.integration.test.ts +0 -529
  885. package/src/plugins/filesystem/schema.ts +0 -6
  886. package/src/plugins/limits-guard/limit-guard.test.ts +0 -253
  887. package/src/plugins/limits-guard/limits-guard.integration.test.ts +0 -1012
  888. package/src/plugins/llm-debug/llm-debug.integration.test.ts +0 -192
  889. package/src/plugins/mailbox/mailbox.integration.test.ts +0 -794
  890. package/src/plugins/resources/resources.integration.test.ts +0 -68
  891. package/src/plugins/result-eviction/result-eviction.integration.test.ts +0 -332
  892. package/src/plugins/services/pid-registry.test.ts +0 -180
  893. package/src/plugins/services/services.integration.test.ts +0 -1223
  894. package/src/plugins/session-lifecycle/session-lifecycle.integration.test.ts +0 -639
  895. package/src/plugins/session-stats/plugin.test.ts +0 -160
  896. package/src/plugins/shell/shell.integration.test.ts +0 -273
  897. package/src/plugins/shell/shell.test.ts +0 -314
  898. package/src/plugins/skills/discovery.test.ts +0 -395
  899. package/src/plugins/skills/skills.integration.test.ts +0 -580
  900. package/src/plugins/todo/todo.integration.test.ts +0 -687
  901. package/src/plugins/uploads/preprocessors/image-classifier.test.ts +0 -142
  902. package/src/plugins/uploads/uploads.integration.test.ts +0 -831
  903. package/src/plugins/user-chat/user-chat.integration.test.ts +0 -893
  904. package/src/plugins/workers/workers.integration.test.ts +0 -778
  905. package/src/prompts/macros.test.ts +0 -107
  906. package/src/testing/test-harness.test.ts +0 -114
  907. package/src/transport/http/routes/rpc.integration.test.ts +0 -243
  908. 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
+ }