@roj-ai/sdk 0.1.3 → 0.1.5

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 (493) hide show
  1. package/dist/bootstrap.js +191 -0
  2. package/dist/bootstrap.js.map +1 -0
  3. package/dist/builtin-events.js +8 -0
  4. package/dist/builtin-events.js.map +1 -0
  5. package/dist/bun-platform/fs.js +39 -0
  6. package/dist/bun-platform/fs.js.map +1 -0
  7. package/dist/bun-platform/index.js +18 -0
  8. package/dist/bun-platform/index.js.map +1 -0
  9. package/dist/bun-platform/process.js +21 -0
  10. package/dist/bun-platform/process.js.map +1 -0
  11. package/dist/config.js +54 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/config.test.js +155 -0
  14. package/dist/config.test.js.map +1 -0
  15. package/dist/core/agent-loop.integration.test.js +414 -0
  16. package/dist/core/agent-loop.integration.test.js.map +1 -0
  17. package/dist/core/agents/agent-config.test.js +194 -0
  18. package/dist/core/agents/agent-config.test.js.map +1 -0
  19. package/dist/core/agents/agent-roles.js +25 -0
  20. package/dist/core/agents/agent-roles.js.map +1 -0
  21. package/dist/core/agents/agent-shutdown.test.js +180 -0
  22. package/dist/core/agents/agent-shutdown.test.js.map +1 -0
  23. package/dist/core/agents/agent.js +1205 -0
  24. package/dist/core/agents/agent.js.map +1 -0
  25. package/dist/core/agents/agent.test.js +313 -0
  26. package/dist/core/agents/agent.test.js.map +1 -0
  27. package/dist/core/agents/communicator.js +13 -0
  28. package/dist/core/agents/communicator.js.map +1 -0
  29. package/dist/core/agents/config.js +5 -0
  30. package/dist/core/agents/config.js.map +1 -0
  31. package/dist/core/agents/context.js +2 -0
  32. package/dist/core/agents/context.js.map +1 -0
  33. package/dist/core/agents/debounce.js +74 -0
  34. package/dist/core/agents/debounce.js.map +1 -0
  35. package/dist/core/agents/handler-events.test.js +115 -0
  36. package/dist/core/agents/handler-events.test.js.map +1 -0
  37. package/dist/core/agents/index.js +2 -0
  38. package/dist/core/agents/index.js.map +1 -0
  39. package/dist/core/agents/response-sanitizer.js +46 -0
  40. package/dist/core/agents/response-sanitizer.js.map +1 -0
  41. package/dist/core/agents/response-sanitizer.test.js +101 -0
  42. package/dist/core/agents/response-sanitizer.test.js.map +1 -0
  43. package/dist/core/agents/retry.js +105 -0
  44. package/dist/core/agents/retry.js.map +1 -0
  45. package/dist/core/agents/schema.js +39 -0
  46. package/dist/core/agents/schema.js.map +1 -0
  47. package/dist/core/agents/state.js +90 -0
  48. package/dist/core/agents/state.js.map +1 -0
  49. package/dist/core/context/state.js +23 -0
  50. package/dist/core/context/state.js.map +1 -0
  51. package/dist/core/errors.js +38 -0
  52. package/dist/core/errors.js.map +1 -0
  53. package/dist/core/event-sourcing.integration.test.js +154 -0
  54. package/dist/core/event-sourcing.integration.test.js.map +1 -0
  55. package/dist/core/events/base-event-store.js +201 -0
  56. package/dist/core/events/base-event-store.js.map +1 -0
  57. package/dist/core/events/event-store.js +26 -0
  58. package/dist/core/events/event-store.js.map +1 -0
  59. package/dist/core/events/file.js +320 -0
  60. package/dist/core/events/file.js.map +1 -0
  61. package/dist/core/events/file.test.js +284 -0
  62. package/dist/core/events/file.test.js.map +1 -0
  63. package/dist/core/events/index.js +3 -0
  64. package/dist/core/events/index.js.map +1 -0
  65. package/dist/core/events/memory.js +101 -0
  66. package/dist/core/events/memory.js.map +1 -0
  67. package/dist/core/events/memory.test.js +502 -0
  68. package/dist/core/events/memory.test.js.map +1 -0
  69. package/dist/core/events/metadata-utils.js +107 -0
  70. package/dist/core/events/metadata-utils.js.map +1 -0
  71. package/dist/core/events/test-helpers.js +15 -0
  72. package/dist/core/events/test-helpers.js.map +1 -0
  73. package/dist/core/events/types.js +21 -0
  74. package/dist/core/events/types.js.map +1 -0
  75. package/dist/core/file-store/file-store.js +250 -0
  76. package/dist/core/file-store/file-store.js.map +1 -0
  77. package/dist/core/file-store/types.js +7 -0
  78. package/dist/core/file-store/types.js.map +1 -0
  79. package/dist/core/image/image-processor.js +106 -0
  80. package/dist/core/image/image-processor.js.map +1 -0
  81. package/dist/core/image/image-processor.test.js +171 -0
  82. package/dist/core/image/image-processor.test.js.map +1 -0
  83. package/dist/core/image/index.js +4 -0
  84. package/dist/core/image/index.js.map +1 -0
  85. package/dist/core/image/noop-resizer.js +6 -0
  86. package/dist/core/image/noop-resizer.js.map +1 -0
  87. package/dist/core/image/types.js +2 -0
  88. package/dist/core/image/types.js.map +1 -0
  89. package/dist/core/image/vips-resizer.js +100 -0
  90. package/dist/core/image/vips-resizer.js.map +1 -0
  91. package/dist/core/image/vips-resizer.test.js +324 -0
  92. package/dist/core/image/vips-resizer.test.js.map +1 -0
  93. package/dist/core/llm/anthropic.js +396 -0
  94. package/dist/core/llm/anthropic.js.map +1 -0
  95. package/dist/core/llm/anthropic.test.js +434 -0
  96. package/dist/core/llm/anthropic.test.js.map +1 -0
  97. package/dist/core/llm/cache-breakpoints.js +37 -0
  98. package/dist/core/llm/cache-breakpoints.js.map +1 -0
  99. package/dist/core/llm/cache-live.test.js +137 -0
  100. package/dist/core/llm/cache-live.test.js.map +1 -0
  101. package/dist/core/llm/index.js +9 -0
  102. package/dist/core/llm/index.js.map +1 -0
  103. package/dist/core/llm/llm-log-types.js +12 -0
  104. package/dist/core/llm/llm-log-types.js.map +1 -0
  105. package/dist/core/llm/logger.js +241 -0
  106. package/dist/core/llm/logger.js.map +1 -0
  107. package/dist/core/llm/logger.test.js +228 -0
  108. package/dist/core/llm/logger.test.js.map +1 -0
  109. package/dist/core/llm/logging-provider.js +49 -0
  110. package/dist/core/llm/logging-provider.js.map +1 -0
  111. package/dist/core/llm/middleware.js +114 -0
  112. package/dist/core/llm/middleware.js.map +1 -0
  113. package/dist/core/llm/mock.js +186 -0
  114. package/dist/core/llm/mock.js.map +1 -0
  115. package/dist/core/llm/mock.test.js +318 -0
  116. package/dist/core/llm/mock.test.js.map +1 -0
  117. package/dist/core/llm/openrouter-mapping.test.js +125 -0
  118. package/dist/core/llm/openrouter-mapping.test.js.map +1 -0
  119. package/dist/core/llm/openrouter.js +298 -0
  120. package/dist/core/llm/openrouter.js.map +1 -0
  121. package/dist/core/llm/openrouter.test.js +377 -0
  122. package/dist/core/llm/openrouter.test.js.map +1 -0
  123. package/dist/core/llm/provider-integration.test.js +350 -0
  124. package/dist/core/llm/provider-integration.test.js.map +1 -0
  125. package/dist/core/llm/provider.js +18 -0
  126. package/dist/core/llm/provider.js.map +1 -0
  127. package/dist/core/llm/routing-provider.js +52 -0
  128. package/dist/core/llm/routing-provider.js.map +1 -0
  129. package/dist/core/llm/routing-provider.test.js +94 -0
  130. package/dist/core/llm/routing-provider.test.js.map +1 -0
  131. package/dist/core/llm/schema.js +31 -0
  132. package/dist/core/llm/schema.js.map +1 -0
  133. package/dist/core/llm/snapshot-fetch.js +122 -0
  134. package/dist/core/llm/snapshot-fetch.js.map +1 -0
  135. package/dist/core/llm/snapshot-middleware.js +142 -0
  136. package/dist/core/llm/snapshot-middleware.js.map +1 -0
  137. package/dist/core/llm/snapshot-middleware.test.js +144 -0
  138. package/dist/core/llm/snapshot-middleware.test.js.map +1 -0
  139. package/dist/core/llm/state.js +48 -0
  140. package/dist/core/llm/state.js.map +1 -0
  141. package/dist/core/llm/tokens.js +40 -0
  142. package/dist/core/llm/tokens.js.map +1 -0
  143. package/dist/core/multi-agent.integration.test.js +298 -0
  144. package/dist/core/multi-agent.integration.test.js.map +1 -0
  145. package/dist/core/plugin-hooks.integration.test.js +344 -0
  146. package/dist/core/plugin-hooks.integration.test.js.map +1 -0
  147. package/dist/core/plugins/hook-types.js +5 -0
  148. package/dist/core/plugins/hook-types.js.map +1 -0
  149. package/dist/core/plugins/index.js +5 -0
  150. package/dist/core/plugins/index.js.map +1 -0
  151. package/dist/core/plugins/plugin-builder.js +321 -0
  152. package/dist/core/plugins/plugin-builder.js.map +1 -0
  153. package/dist/core/preset/config.js +54 -0
  154. package/dist/core/preset/config.js.map +1 -0
  155. package/dist/core/preset/index.js +6 -0
  156. package/dist/core/preset/index.js.map +1 -0
  157. package/dist/core/preset/preset-builder.js +63 -0
  158. package/dist/core/preset/preset-builder.js.map +1 -0
  159. package/dist/core/session-lifecycle.integration.test.js +159 -0
  160. package/dist/core/session-lifecycle.integration.test.js.map +1 -0
  161. package/dist/core/sessions/apply-event.js +41 -0
  162. package/dist/core/sessions/apply-event.js.map +1 -0
  163. package/dist/core/sessions/context.js +2 -0
  164. package/dist/core/sessions/context.js.map +1 -0
  165. package/dist/core/sessions/fork-utils.js +42 -0
  166. package/dist/core/sessions/fork-utils.js.map +1 -0
  167. package/dist/core/sessions/fork-utils.test.js +129 -0
  168. package/dist/core/sessions/fork-utils.test.js.map +1 -0
  169. package/dist/core/sessions/reducer.js +55 -0
  170. package/dist/core/sessions/reducer.js.map +1 -0
  171. package/dist/core/sessions/schema.js +66 -0
  172. package/dist/core/sessions/schema.js.map +1 -0
  173. package/dist/core/sessions/session-environment.js +2 -0
  174. package/dist/core/sessions/session-environment.js.map +1 -0
  175. package/dist/core/sessions/session-manager.js +650 -0
  176. package/dist/core/sessions/session-manager.js.map +1 -0
  177. package/dist/core/sessions/session-store.js +118 -0
  178. package/dist/core/sessions/session-store.js.map +1 -0
  179. package/dist/core/sessions/session.js +675 -0
  180. package/dist/core/sessions/session.js.map +1 -0
  181. package/dist/core/sessions/session.test.js +1095 -0
  182. package/dist/core/sessions/session.test.js.map +1 -0
  183. package/dist/core/sessions/state.js +377 -0
  184. package/dist/core/sessions/state.js.map +1 -0
  185. package/dist/core/system.js +66 -0
  186. package/dist/core/system.js.map +1 -0
  187. package/dist/core/tools/context.js +2 -0
  188. package/dist/core/tools/context.js.map +1 -0
  189. package/dist/core/tools/definition.js +4 -0
  190. package/dist/core/tools/definition.js.map +1 -0
  191. package/dist/core/tools/executor.js +82 -0
  192. package/dist/core/tools/executor.js.map +1 -0
  193. package/dist/core/tools/executor.test.js +143 -0
  194. package/dist/core/tools/executor.test.js.map +1 -0
  195. package/dist/core/tools/index.js +4 -0
  196. package/dist/core/tools/index.js.map +1 -0
  197. package/dist/core/tools/schema.js +20 -0
  198. package/dist/core/tools/schema.js.map +1 -0
  199. package/dist/core/tools/state.js +29 -0
  200. package/dist/core/tools/state.js.map +1 -0
  201. package/dist/index.js +70 -0
  202. package/dist/index.js.map +1 -0
  203. package/dist/lib/json/index.js +5 -0
  204. package/dist/lib/json/index.js.map +1 -0
  205. package/dist/lib/logger/console.js +147 -0
  206. package/dist/lib/logger/console.js.map +1 -0
  207. package/dist/lib/logger/console.test.js +258 -0
  208. package/dist/lib/logger/console.test.js.map +1 -0
  209. package/dist/lib/logger/file.js +54 -0
  210. package/dist/lib/logger/file.js.map +1 -0
  211. package/dist/lib/logger/index.js +4 -0
  212. package/dist/lib/logger/index.js.map +1 -0
  213. package/dist/lib/logger/logger.js +28 -0
  214. package/dist/lib/logger/logger.js.map +1 -0
  215. package/dist/lib/logger/ring-buffer.js +61 -0
  216. package/dist/lib/logger/ring-buffer.js.map +1 -0
  217. package/dist/lib/logger/tee.js +43 -0
  218. package/dist/lib/logger/tee.js.map +1 -0
  219. package/dist/lib/mime.js +22 -0
  220. package/dist/lib/mime.js.map +1 -0
  221. package/dist/lib/never.js +4 -0
  222. package/dist/lib/never.js.map +1 -0
  223. package/dist/lib/utils/hash.js +35 -0
  224. package/dist/lib/utils/hash.js.map +1 -0
  225. package/dist/lib/utils/result.js +21 -0
  226. package/dist/lib/utils/result.js.map +1 -0
  227. package/dist/platform/fs.js +8 -0
  228. package/dist/platform/fs.js.map +1 -0
  229. package/dist/platform/index.js +9 -0
  230. package/dist/platform/index.js.map +1 -0
  231. package/dist/platform/process.js +8 -0
  232. package/dist/platform/process.js.map +1 -0
  233. package/dist/plugins/agent-status/plugin.js +77 -0
  234. package/dist/plugins/agent-status/plugin.js.map +1 -0
  235. package/dist/plugins/agents/agents.integration.test.js +683 -0
  236. package/dist/plugins/agents/agents.integration.test.js.map +1 -0
  237. package/dist/plugins/agents/index.js +2 -0
  238. package/dist/plugins/agents/index.js.map +1 -0
  239. package/dist/plugins/agents/plugin.js +199 -0
  240. package/dist/plugins/agents/plugin.js.map +1 -0
  241. package/dist/plugins/context-compact/context-compact.integration.test.js +174 -0
  242. package/dist/plugins/context-compact/context-compact.integration.test.js.map +1 -0
  243. package/dist/plugins/context-compact/context-compactor.js +238 -0
  244. package/dist/plugins/context-compact/context-compactor.js.map +1 -0
  245. package/dist/plugins/context-compact/context-compactor.test.js +763 -0
  246. package/dist/plugins/context-compact/context-compactor.test.js.map +1 -0
  247. package/dist/plugins/context-compact/history-offloader.js +42 -0
  248. package/dist/plugins/context-compact/history-offloader.js.map +1 -0
  249. package/dist/plugins/context-compact/history-offloader.test.js +77 -0
  250. package/dist/plugins/context-compact/history-offloader.test.js.map +1 -0
  251. package/dist/plugins/context-compact/index.js +4 -0
  252. package/dist/plugins/context-compact/index.js.map +1 -0
  253. package/dist/plugins/context-compact/plugin.js +37 -0
  254. package/dist/plugins/context-compact/plugin.js.map +1 -0
  255. package/dist/plugins/filesystem/filesystem.integration.test.js +411 -0
  256. package/dist/plugins/filesystem/filesystem.integration.test.js.map +1 -0
  257. package/dist/plugins/filesystem/helpers.js +170 -0
  258. package/dist/plugins/filesystem/helpers.js.map +1 -0
  259. package/dist/plugins/filesystem/index.js +3 -0
  260. package/dist/plugins/filesystem/index.js.map +1 -0
  261. package/dist/plugins/filesystem/listing.js +247 -0
  262. package/dist/plugins/filesystem/listing.js.map +1 -0
  263. package/dist/plugins/filesystem/plugin.js +364 -0
  264. package/dist/plugins/filesystem/plugin.js.map +1 -0
  265. package/dist/plugins/filesystem/schema.js +2 -0
  266. package/dist/plugins/filesystem/schema.js.map +1 -0
  267. package/dist/plugins/git-status/index.js +2 -0
  268. package/dist/plugins/git-status/index.js.map +1 -0
  269. package/dist/plugins/git-status/plugin.js +144 -0
  270. package/dist/plugins/git-status/plugin.js.map +1 -0
  271. package/dist/plugins/limits-guard/config.js +5 -0
  272. package/dist/plugins/limits-guard/config.js.map +1 -0
  273. package/dist/plugins/limits-guard/index.js +3 -0
  274. package/dist/plugins/limits-guard/index.js.map +1 -0
  275. package/dist/plugins/limits-guard/limit-guard.js +125 -0
  276. package/dist/plugins/limits-guard/limit-guard.js.map +1 -0
  277. package/dist/plugins/limits-guard/limit-guard.test.js +121 -0
  278. package/dist/plugins/limits-guard/limit-guard.test.js.map +1 -0
  279. package/dist/plugins/limits-guard/limits-guard.integration.test.js +378 -0
  280. package/dist/plugins/limits-guard/limits-guard.integration.test.js.map +1 -0
  281. package/dist/plugins/limits-guard/plugin.js +240 -0
  282. package/dist/plugins/limits-guard/plugin.js.map +1 -0
  283. package/dist/plugins/llm-debug/index.js +2 -0
  284. package/dist/plugins/llm-debug/index.js.map +1 -0
  285. package/dist/plugins/llm-debug/llm-debug.integration.test.js +157 -0
  286. package/dist/plugins/llm-debug/llm-debug.integration.test.js.map +1 -0
  287. package/dist/plugins/llm-debug/plugin.js +148 -0
  288. package/dist/plugins/llm-debug/plugin.js.map +1 -0
  289. package/dist/plugins/logs/index.js +2 -0
  290. package/dist/plugins/logs/index.js.map +1 -0
  291. package/dist/plugins/logs/plugin.js +38 -0
  292. package/dist/plugins/logs/plugin.js.map +1 -0
  293. package/dist/plugins/mailbox/helpers.js +66 -0
  294. package/dist/plugins/mailbox/helpers.js.map +1 -0
  295. package/dist/plugins/mailbox/index.js +9 -0
  296. package/dist/plugins/mailbox/index.js.map +1 -0
  297. package/dist/plugins/mailbox/mailbox.integration.test.js +605 -0
  298. package/dist/plugins/mailbox/mailbox.integration.test.js.map +1 -0
  299. package/dist/plugins/mailbox/plugin.js +204 -0
  300. package/dist/plugins/mailbox/plugin.js.map +1 -0
  301. package/dist/plugins/mailbox/prompts.js +93 -0
  302. package/dist/plugins/mailbox/prompts.js.map +1 -0
  303. package/dist/plugins/mailbox/query.js +38 -0
  304. package/dist/plugins/mailbox/query.js.map +1 -0
  305. package/dist/plugins/mailbox/schema.js +32 -0
  306. package/dist/plugins/mailbox/schema.js.map +1 -0
  307. package/dist/plugins/mailbox/state.js +41 -0
  308. package/dist/plugins/mailbox/state.js.map +1 -0
  309. package/dist/plugins/resources/index.js +4 -0
  310. package/dist/plugins/resources/index.js.map +1 -0
  311. package/dist/plugins/resources/manifest.js +20 -0
  312. package/dist/plugins/resources/manifest.js.map +1 -0
  313. package/dist/plugins/resources/plugin.js +171 -0
  314. package/dist/plugins/resources/plugin.js.map +1 -0
  315. package/dist/plugins/resources/post-inject.js +32 -0
  316. package/dist/plugins/resources/post-inject.js.map +1 -0
  317. package/dist/plugins/resources/state.js +16 -0
  318. package/dist/plugins/resources/state.js.map +1 -0
  319. package/dist/plugins/result-eviction/index.js +2 -0
  320. package/dist/plugins/result-eviction/index.js.map +1 -0
  321. package/dist/plugins/result-eviction/plugin.js +43 -0
  322. package/dist/plugins/result-eviction/plugin.js.map +1 -0
  323. package/dist/plugins/result-eviction/result-eviction.integration.test.js +217 -0
  324. package/dist/plugins/result-eviction/result-eviction.integration.test.js.map +1 -0
  325. package/dist/plugins/services/plugin.js +453 -0
  326. package/dist/plugins/services/plugin.js.map +1 -0
  327. package/dist/plugins/services/port-pool.js +70 -0
  328. package/dist/plugins/services/port-pool.js.map +1 -0
  329. package/dist/plugins/services/prompt.js +40 -0
  330. package/dist/plugins/services/prompt.js.map +1 -0
  331. package/dist/plugins/services/schema.js +9 -0
  332. package/dist/plugins/services/schema.js.map +1 -0
  333. package/dist/plugins/services/service.js +470 -0
  334. package/dist/plugins/services/service.js.map +1 -0
  335. package/dist/plugins/services/services.integration.test.js +485 -0
  336. package/dist/plugins/services/services.integration.test.js.map +1 -0
  337. package/dist/plugins/session-lifecycle/index.js +2 -0
  338. package/dist/plugins/session-lifecycle/index.js.map +1 -0
  339. package/dist/plugins/session-lifecycle/plugin.js +273 -0
  340. package/dist/plugins/session-lifecycle/plugin.js.map +1 -0
  341. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js +498 -0
  342. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js.map +1 -0
  343. package/dist/plugins/session-state/plugin.js +159 -0
  344. package/dist/plugins/session-state/plugin.js.map +1 -0
  345. package/dist/plugins/session-stats/index.js +3 -0
  346. package/dist/plugins/session-stats/index.js.map +1 -0
  347. package/dist/plugins/session-stats/plugin.js +81 -0
  348. package/dist/plugins/session-stats/plugin.js.map +1 -0
  349. package/dist/plugins/shell/executor.js +339 -0
  350. package/dist/plugins/shell/executor.js.map +1 -0
  351. package/dist/plugins/shell/index.js +6 -0
  352. package/dist/plugins/shell/index.js.map +1 -0
  353. package/dist/plugins/shell/plugin.js +66 -0
  354. package/dist/plugins/shell/plugin.js.map +1 -0
  355. package/dist/plugins/shell/shell.integration.test.js +234 -0
  356. package/dist/plugins/shell/shell.integration.test.js.map +1 -0
  357. package/dist/plugins/shell/shell.test.js +236 -0
  358. package/dist/plugins/shell/shell.test.js.map +1 -0
  359. package/dist/plugins/skills/discovery.js +205 -0
  360. package/dist/plugins/skills/discovery.js.map +1 -0
  361. package/dist/plugins/skills/discovery.test.js +312 -0
  362. package/dist/plugins/skills/discovery.test.js.map +1 -0
  363. package/dist/plugins/skills/index.js +12 -0
  364. package/dist/plugins/skills/index.js.map +1 -0
  365. package/dist/plugins/skills/plugin.js +293 -0
  366. package/dist/plugins/skills/plugin.js.map +1 -0
  367. package/dist/plugins/skills/prompts.js +70 -0
  368. package/dist/plugins/skills/prompts.js.map +1 -0
  369. package/dist/plugins/skills/schema.js +18 -0
  370. package/dist/plugins/skills/schema.js.map +1 -0
  371. package/dist/plugins/skills/skills.integration.test.js +475 -0
  372. package/dist/plugins/skills/skills.integration.test.js.map +1 -0
  373. package/dist/plugins/snapshotting/index.js +3 -0
  374. package/dist/plugins/snapshotting/index.js.map +1 -0
  375. package/dist/plugins/snapshotting/jj-snapshotter.js +106 -0
  376. package/dist/plugins/snapshotting/jj-snapshotter.js.map +1 -0
  377. package/dist/plugins/snapshotting/plugin.js +28 -0
  378. package/dist/plugins/snapshotting/plugin.js.map +1 -0
  379. package/dist/plugins/snapshotting/snapshotter.js +2 -0
  380. package/dist/plugins/snapshotting/snapshotter.js.map +1 -0
  381. package/dist/plugins/todo/index.js +7 -0
  382. package/dist/plugins/todo/index.js.map +1 -0
  383. package/dist/plugins/todo/plugin.js +319 -0
  384. package/dist/plugins/todo/plugin.js.map +1 -0
  385. package/dist/plugins/todo/prompts.js +54 -0
  386. package/dist/plugins/todo/prompts.js.map +1 -0
  387. package/dist/plugins/todo/schema.js +18 -0
  388. package/dist/plugins/todo/schema.js.map +1 -0
  389. package/dist/plugins/todo/todo.integration.test.js +605 -0
  390. package/dist/plugins/todo/todo.integration.test.js.map +1 -0
  391. package/dist/plugins/uploads/index.js +8 -0
  392. package/dist/plugins/uploads/index.js.map +1 -0
  393. package/dist/plugins/uploads/plugin.js +346 -0
  394. package/dist/plugins/uploads/plugin.js.map +1 -0
  395. package/dist/plugins/uploads/preprocessor.js +44 -0
  396. package/dist/plugins/uploads/preprocessor.js.map +1 -0
  397. package/dist/plugins/uploads/preprocessors/image-classifier.js +127 -0
  398. package/dist/plugins/uploads/preprocessors/image-classifier.js.map +1 -0
  399. package/dist/plugins/uploads/preprocessors/index.js +7 -0
  400. package/dist/plugins/uploads/preprocessors/index.js.map +1 -0
  401. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js +204 -0
  402. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js.map +1 -0
  403. package/dist/plugins/uploads/preprocessors/zip-preprocessor.js +172 -0
  404. package/dist/plugins/uploads/preprocessors/zip-preprocessor.js.map +1 -0
  405. package/dist/plugins/uploads/schema.js +20 -0
  406. package/dist/plugins/uploads/schema.js.map +1 -0
  407. package/dist/plugins/uploads/state.js +22 -0
  408. package/dist/plugins/uploads/state.js.map +1 -0
  409. package/dist/plugins/uploads/uploads.integration.test.js +496 -0
  410. package/dist/plugins/uploads/uploads.integration.test.js.map +1 -0
  411. package/dist/plugins/user-chat/index.js +5 -0
  412. package/dist/plugins/user-chat/index.js.map +1 -0
  413. package/dist/plugins/user-chat/plugin.js +544 -0
  414. package/dist/plugins/user-chat/plugin.js.map +1 -0
  415. package/dist/plugins/user-chat/prompts.js +29 -0
  416. package/dist/plugins/user-chat/prompts.js.map +1 -0
  417. package/dist/plugins/user-chat/schema.js +46 -0
  418. package/dist/plugins/user-chat/schema.js.map +1 -0
  419. package/dist/plugins/user-chat/user-chat.integration.test.js +668 -0
  420. package/dist/plugins/user-chat/user-chat.integration.test.js.map +1 -0
  421. package/dist/plugins/workers/context.js +143 -0
  422. package/dist/plugins/workers/context.js.map +1 -0
  423. package/dist/plugins/workers/definition.js +30 -0
  424. package/dist/plugins/workers/definition.js.map +1 -0
  425. package/dist/plugins/workers/index.js +7 -0
  426. package/dist/plugins/workers/index.js.map +1 -0
  427. package/dist/plugins/workers/plugin.js +578 -0
  428. package/dist/plugins/workers/plugin.js.map +1 -0
  429. package/dist/plugins/workers/worker.js +18 -0
  430. package/dist/plugins/workers/worker.js.map +1 -0
  431. package/dist/plugins/workers/workers.integration.test.js +629 -0
  432. package/dist/plugins/workers/workers.integration.test.js.map +1 -0
  433. package/dist/prompts/base.js +239 -0
  434. package/dist/prompts/base.js.map +1 -0
  435. package/dist/prompts/builder.js +131 -0
  436. package/dist/prompts/builder.js.map +1 -0
  437. package/dist/prompts/index.js +20 -0
  438. package/dist/prompts/index.js.map +1 -0
  439. package/dist/prompts/macros.js +26 -0
  440. package/dist/prompts/macros.js.map +1 -0
  441. package/dist/prompts/macros.test.js +80 -0
  442. package/dist/prompts/macros.test.js.map +1 -0
  443. package/dist/testing/bootstrap-for-testing.js +28 -0
  444. package/dist/testing/bootstrap-for-testing.js.map +1 -0
  445. package/dist/testing/index.js +7 -0
  446. package/dist/testing/index.js.map +1 -0
  447. package/dist/testing/node-platform.js +65 -0
  448. package/dist/testing/node-platform.js.map +1 -0
  449. package/dist/testing/notification-collector.js +82 -0
  450. package/dist/testing/notification-collector.js.map +1 -0
  451. package/dist/testing/preset-helpers.js +37 -0
  452. package/dist/testing/preset-helpers.js.map +1 -0
  453. package/dist/testing/test-harness.js +226 -0
  454. package/dist/testing/test-harness.js.map +1 -0
  455. package/dist/testing/test-harness.test.js +51 -0
  456. package/dist/testing/test-harness.test.js.map +1 -0
  457. package/dist/testing/wait-helpers.js +64 -0
  458. package/dist/testing/wait-helpers.js.map +1 -0
  459. package/dist/transport/adapter/client-adapter.js +64 -0
  460. package/dist/transport/adapter/client-adapter.js.map +1 -0
  461. package/dist/transport/adapter/index.js +24 -0
  462. package/dist/transport/adapter/index.js.map +1 -0
  463. package/dist/transport/adapter/server-adapter.js +73 -0
  464. package/dist/transport/adapter/server-adapter.js.map +1 -0
  465. package/dist/transport/adapter/types.js +8 -0
  466. package/dist/transport/adapter/types.js.map +1 -0
  467. package/dist/transport/http/app.js +86 -0
  468. package/dist/transport/http/app.js.map +1 -0
  469. package/dist/transport/http/index.js +6 -0
  470. package/dist/transport/http/index.js.map +1 -0
  471. package/dist/transport/http/middleware/bearer-auth.js +33 -0
  472. package/dist/transport/http/middleware/bearer-auth.js.map +1 -0
  473. package/dist/transport/http/middleware/error-handler.js +56 -0
  474. package/dist/transport/http/middleware/error-handler.js.map +1 -0
  475. package/dist/transport/http/routes/files.js +237 -0
  476. package/dist/transport/http/routes/files.js.map +1 -0
  477. package/dist/transport/http/routes/resources.js +77 -0
  478. package/dist/transport/http/routes/resources.js.map +1 -0
  479. package/dist/transport/http/routes/rpc.integration.test.js +189 -0
  480. package/dist/transport/http/routes/rpc.integration.test.js.map +1 -0
  481. package/dist/transport/http/routes/rpc.js +110 -0
  482. package/dist/transport/http/routes/rpc.js.map +1 -0
  483. package/dist/transport/http/routes/rpc.test.js +316 -0
  484. package/dist/transport/http/routes/rpc.test.js.map +1 -0
  485. package/dist/transport/http/routes/upload.js +205 -0
  486. package/dist/transport/http/routes/upload.js.map +1 -0
  487. package/dist/transport/rpc/index.js +7 -0
  488. package/dist/transport/rpc/index.js.map +1 -0
  489. package/dist/transport/rpc/methods.js +8 -0
  490. package/dist/transport/rpc/methods.js.map +1 -0
  491. package/dist/user-config.js +14 -0
  492. package/dist/user-config.js.map +1 -0
  493. package/package.json +47 -57
@@ -0,0 +1,650 @@
1
+ /**
2
+ * SessionManager - Session lifecycle and cache management.
3
+ *
4
+ * Responsibilities:
5
+ * - Create and cache sessions
6
+ * - Load sessions from event store
7
+ * - Shutdown and cleanup
8
+ */
9
+ import { join } from 'node:path';
10
+ import { COMMUNICATOR_ROLE, ORCHESTRATOR_ROLE } from '../../core/agents/agent-roles.js';
11
+ import { generateAgentId } from '../../core/agents/schema.js';
12
+ import { agentEvents } from '../../core/agents/state.js';
13
+ import { PresetErrors, SessionErrors, ValidationErrors } from '../../core/errors.js';
14
+ import { withSessionId } from '../../core/events/test-helpers.js';
15
+ import { generateSessionId } from '../../core/sessions/schema.js';
16
+ import { checkRecoveryNeeded, isSessionCreatedEvent, reconstructSessionState, sessionEvents } from '../../core/sessions/state.js';
17
+ import { FileLogger } from '../../lib/logger/file.js';
18
+ import { TeeLogger } from '../../lib/logger/tee.js';
19
+ import { Err, Ok } from '../../lib/utils/result.js';
20
+ import { getAgentUnconsumedMailbox, selectMailboxState } from '../../plugins/mailbox/query.js';
21
+ import { selectSessionStats } from '../../plugins/session-stats/index.js';
22
+ import { createApplyEvent } from './apply-event.js';
23
+ import { rewriteEventsForFork } from './fork-utils.js';
24
+ import { SessionStore } from './session-store.js';
25
+ import { Session } from './session.js';
26
+ // ============================================================================
27
+ // Errors
28
+ // ============================================================================
29
+ /**
30
+ * Internal error for session loading failures.
31
+ * Wraps DomainError for proper error handling in async loading.
32
+ */
33
+ class SessionLoadError extends Error {
34
+ domainError;
35
+ constructor(domainError) {
36
+ super(`Session load error: ${domainError.type}`);
37
+ this.domainError = domainError;
38
+ this.name = 'SessionLoadError';
39
+ }
40
+ }
41
+ /**
42
+ * SessionManager manages session lifecycle and caching.
43
+ */
44
+ export class SessionManager {
45
+ sessions = new Map();
46
+ /** Unsubscribe functions for session event listeners, keyed by sessionId */
47
+ sessionListenerCleanup = new Map();
48
+ /** Manager-level methods collected from plugin definitions across all presets */
49
+ managerMethods;
50
+ eventStore;
51
+ llmProvider;
52
+ llmProviders;
53
+ toolExecutor;
54
+ presets;
55
+ logger;
56
+ basePath;
57
+ dataFileStore;
58
+ onUserOutput;
59
+ preprocessorRegistry;
60
+ llmLogger;
61
+ portPool;
62
+ platform;
63
+ systemPlugins;
64
+ constructor(options) {
65
+ this.eventStore = options.eventStore;
66
+ this.llmProvider = options.llmProvider;
67
+ this.llmProviders = options.llmProviders ?? new Map();
68
+ this.toolExecutor = options.toolExecutor;
69
+ this.presets = options.presets;
70
+ this.logger = options.logger;
71
+ this.basePath = options.basePath;
72
+ this.dataFileStore = options.dataFileStore;
73
+ this.onUserOutput = options.onUserOutput;
74
+ this.preprocessorRegistry = options.preprocessorRegistry;
75
+ this.llmLogger = options.llmLogger;
76
+ this.portPool = options.portPool;
77
+ this.platform = options.platform;
78
+ this.systemPlugins = options.systemPlugins ?? [];
79
+ this.managerMethods = this.collectManagerMethods();
80
+ }
81
+ /** Expose platform adapters (used by Session for building contexts). */
82
+ getPlatform() {
83
+ return this.platform;
84
+ }
85
+ /**
86
+ * Create a new session with the given preset.
87
+ */
88
+ async createSession(presetId, options) {
89
+ const preset = this.presets.get(presetId);
90
+ if (!preset) {
91
+ return Err(PresetErrors.notFound(presetId));
92
+ }
93
+ const sessionId = options?.sessionId ? options.sessionId : generateSessionId();
94
+ // First orchestrator gets seq 1
95
+ const orchestratorId = generateAgentId(ORCHESTRATOR_ROLE, 1);
96
+ // Resolve workspaceDir: API input overrides preset default
97
+ // Interpolate {sessionId} placeholder if present
98
+ const rawWorkspaceDir = options?.workspaceDir ?? preset.workspaceDir;
99
+ const workspaceDir = rawWorkspaceDir?.replace('{sessionId}', String(sessionId));
100
+ this.logger.info('Creating session', {
101
+ sessionId,
102
+ presetId,
103
+ optionsWorkspaceDir: options?.workspaceDir ?? null,
104
+ presetWorkspaceDir: preset.workspaceDir ?? null,
105
+ resolvedWorkspaceDir: workspaceDir ?? null,
106
+ });
107
+ const events = [
108
+ withSessionId(sessionId, sessionEvents.create('session_created', {
109
+ presetId,
110
+ ...(workspaceDir ? { workspaceDir } : {}),
111
+ })),
112
+ withSessionId(sessionId, agentEvents.create('agent_spawned', {
113
+ agentId: orchestratorId,
114
+ definitionName: ORCHESTRATOR_ROLE,
115
+ parentId: null,
116
+ })),
117
+ ];
118
+ // Spawn communicator if configured
119
+ const hasCommunicator = !!preset.communicator;
120
+ if (hasCommunicator) {
121
+ // First communicator gets seq 1
122
+ const communicatorId = generateAgentId(COMMUNICATOR_ROLE, 1);
123
+ events.push(withSessionId(sessionId, agentEvents.create('agent_spawned', {
124
+ agentId: communicatorId,
125
+ definitionName: COMMUNICATOR_ROLE,
126
+ parentId: null,
127
+ })));
128
+ // Link communicator to orchestrator
129
+ events.push(withSessionId(sessionId, agentEvents.create('communicator_linked', {
130
+ communicatorId,
131
+ orchestratorId,
132
+ })));
133
+ }
134
+ // Write events to event store
135
+ await this.eventStore.appendBatch(sessionId, events);
136
+ // Build plugins and composed reducer so plugin state slices are applied
137
+ const plugins = this.buildPlugins(preset);
138
+ const composedReducer = createApplyEvent(plugins);
139
+ // Reconstruct state with composed reducer (includes plugin state slices)
140
+ const state = reconstructSessionState(events, composedReducer);
141
+ if (!state) {
142
+ return Err(ValidationErrors.invalid('Failed to reconstruct session'));
143
+ }
144
+ // Create store and session (initPluginContexts + onSessionReady hooks run inside)
145
+ const store = new SessionStore(sessionId, this.eventStore, state, composedReducer);
146
+ const session = await this.createSessionInstance(store, preset, plugins);
147
+ // Cache session (wrap in resolved promise for consistency)
148
+ this.sessions.set(sessionId, Promise.resolve(session));
149
+ this.logger.info('Session created', {
150
+ sessionId,
151
+ presetId,
152
+ hasCommunicator,
153
+ });
154
+ return Ok(session);
155
+ }
156
+ /**
157
+ * Fork a session from a specific event index into a new independent session.
158
+ * The forked session gets a copy of all events up to the fork point.
159
+ */
160
+ async forkSession(sourceSessionId, eventIndex) {
161
+ // Load source events
162
+ const sourceEvents = await this.eventStore.load(sourceSessionId);
163
+ if (sourceEvents.length === 0) {
164
+ return Err(SessionErrors.notFound(String(sourceSessionId)));
165
+ }
166
+ // Validate eventIndex range
167
+ if (eventIndex < 0 || eventIndex >= sourceEvents.length) {
168
+ return Err(ValidationErrors.invalid(`eventIndex ${eventIndex} out of range [0, ${sourceEvents.length - 1}]`));
169
+ }
170
+ // Get source preset
171
+ const firstEvent = sourceEvents[0];
172
+ if (!isSessionCreatedEvent(firstEvent)) {
173
+ return Err(ValidationErrors.invalid('First event must be session_created'));
174
+ }
175
+ const preset = this.presets.get(firstEvent.presetId);
176
+ if (!preset) {
177
+ return Err(PresetErrors.notFound(firstEvent.presetId));
178
+ }
179
+ // Generate new session ID
180
+ const newSessionId = generateSessionId();
181
+ // Resolve workspace dir for the new session
182
+ const rawWorkspaceDir = preset.workspaceDir;
183
+ const sourceWorkspaceDir = firstEvent.workspaceDir;
184
+ if (sourceWorkspaceDir && rawWorkspaceDir && !rawWorkspaceDir.includes('{sessionId}')) {
185
+ return Err(ValidationErrors.invalid('Cannot fork: preset workspaceDir has no {sessionId} placeholder, forked session would share the same workspace directory'));
186
+ }
187
+ const newWorkspaceDir = rawWorkspaceDir?.replace('{sessionId}', String(newSessionId));
188
+ // Rewrite events for the fork
189
+ let forkedEvents = rewriteEventsForFork(sourceEvents, eventIndex, newSessionId, sourceSessionId);
190
+ // Update workspaceDir in session_created if it changed
191
+ if (newWorkspaceDir !== sourceWorkspaceDir) {
192
+ forkedEvents = forkedEvents.map((event) => {
193
+ if (event.type === 'session_created') {
194
+ return { ...event, workspaceDir: newWorkspaceDir };
195
+ }
196
+ return event;
197
+ });
198
+ }
199
+ // Write forked events to event store
200
+ await this.eventStore.appendBatch(newSessionId, forkedEvents);
201
+ // Build plugins and composed reducer so plugin state slices are applied
202
+ const plugins = this.buildPlugins(preset);
203
+ const composedReducer = createApplyEvent(plugins);
204
+ // Reconstruct state with composed reducer (includes plugin state slices)
205
+ const state = reconstructSessionState(forkedEvents, composedReducer);
206
+ if (!state) {
207
+ return Err(ValidationErrors.invalid('Failed to reconstruct forked session'));
208
+ }
209
+ // Create store
210
+ const store = new SessionStore(newSessionId, this.eventStore, state, composedReducer);
211
+ // Normalize stuck agents via session_restarted event
212
+ const recoveryData = checkRecoveryNeeded(state);
213
+ if (recoveryData) {
214
+ await store.emit(withSessionId(newSessionId, sessionEvents.create('session_restarted', {
215
+ resetAgentIds: recoveryData.resetAgentIds,
216
+ clearedToolAgentIds: recoveryData.clearedToolAgentIds,
217
+ })));
218
+ }
219
+ // Create session instance (auto-start services run via onSessionReady)
220
+ const session = await this.createSessionInstance(store, preset, plugins);
221
+ // Check for pending agents
222
+ session.checkPendingAgents();
223
+ // Cache session
224
+ this.sessions.set(newSessionId, Promise.resolve(session));
225
+ this.logger.info('Session forked', {
226
+ sourceSessionId,
227
+ newSessionId,
228
+ eventIndex,
229
+ });
230
+ return Ok(session);
231
+ }
232
+ /**
233
+ * Get a session by ID - from cache or load from event store.
234
+ */
235
+ async getSession(sessionId) {
236
+ // Check cache first
237
+ const cached = this.sessions.get(sessionId);
238
+ if (cached) {
239
+ try {
240
+ return Ok(await cached);
241
+ }
242
+ catch (error) {
243
+ // Previous load failed, remove from cache and try again
244
+ this.sessions.delete(sessionId);
245
+ if (error instanceof SessionLoadError) {
246
+ return Err(error.domainError);
247
+ }
248
+ throw error;
249
+ }
250
+ }
251
+ // Store promise immediately to prevent concurrent loads
252
+ const loadPromise = this.loadSession(sessionId);
253
+ this.sessions.set(sessionId, loadPromise);
254
+ try {
255
+ return Ok(await loadPromise);
256
+ }
257
+ catch (error) {
258
+ this.sessions.delete(sessionId);
259
+ if (error instanceof SessionLoadError) {
260
+ return Err(error.domainError);
261
+ }
262
+ throw error;
263
+ }
264
+ }
265
+ /**
266
+ * Internal session loading - throws SessionLoadError on domain errors.
267
+ */
268
+ async loadSession(sessionId) {
269
+ // We need to peek at events first to determine the preset, so we can build plugins
270
+ // and compose the reducer before loading the store
271
+ const events = await this.eventStore.load(sessionId);
272
+ if (events.length === 0) {
273
+ throw new SessionLoadError(SessionErrors.notFound(String(sessionId)));
274
+ }
275
+ const firstEvent = events[0];
276
+ if (!isSessionCreatedEvent(firstEvent)) {
277
+ throw new SessionLoadError(SessionErrors.notFound(String(sessionId)));
278
+ }
279
+ const preset = this.presets.get(firstEvent.presetId);
280
+ if (!preset) {
281
+ throw new SessionLoadError(PresetErrors.notFound(firstEvent.presetId));
282
+ }
283
+ // Build plugins and composed reducer so plugin state slices are applied
284
+ const plugins = this.buildPlugins(preset);
285
+ const composedReducer = createApplyEvent(plugins);
286
+ // Load store with composed reducer
287
+ const store = await SessionStore.load(sessionId, this.eventStore, composedReducer);
288
+ if (!store) {
289
+ throw new SessionLoadError(SessionErrors.notFound(String(sessionId)));
290
+ }
291
+ const state = store.getState();
292
+ // Don't cache closed sessions
293
+ if (state.status === 'closed') {
294
+ // Remove from cache since we don't cache closed sessions
295
+ this.sessions.delete(sessionId);
296
+ // Skip onSessionReady hooks — closed sessions are immutable, firing hooks
297
+ // would emit events to a sealed event log on every read / restart.
298
+ return await this.createSessionInstance(store, preset, plugins, { skipReadyHooks: true });
299
+ }
300
+ // Check if recovery is needed after restart
301
+ const recoveryData = checkRecoveryNeeded(state);
302
+ if (recoveryData) {
303
+ await store.emit(withSessionId(sessionId, sessionEvents.create('session_restarted', {
304
+ resetAgentIds: recoveryData.resetAgentIds,
305
+ clearedToolAgentIds: recoveryData.clearedToolAgentIds,
306
+ })));
307
+ this.logger.info('Session recovered after restart', {
308
+ sessionId,
309
+ resetAgents: recoveryData.resetAgentIds.length,
310
+ clearedToolAgents: recoveryData.clearedToolAgentIds.length,
311
+ });
312
+ }
313
+ // Create session (auto-start services run via onSessionReady)
314
+ const session = await this.createSessionInstance(store, preset, plugins);
315
+ // Check for pending agents
316
+ session.checkPendingAgents();
317
+ return session;
318
+ }
319
+ /**
320
+ * Call a plugin method on a session.
321
+ * @param sessionId - Session ID
322
+ * @param method - Full method name (e.g., "services.start")
323
+ * @param input - Method input (must include sessionId field)
324
+ * @param agentId - Agent ID (optional — some methods don't operate on a specific agent)
325
+ */
326
+ async callPluginMethod(sessionId, method, input, agentId, caller) {
327
+ const sessionResult = await this.getSession(sessionId);
328
+ if (!sessionResult.ok)
329
+ return sessionResult;
330
+ return sessionResult.value.callPluginMethod(method, input, agentId, caller);
331
+ }
332
+ /**
333
+ * Call a manager-level plugin method.
334
+ * These methods operate outside session context (e.g., session creation, listing).
335
+ */
336
+ async callManagerMethod(method, input) {
337
+ const methodDef = this.managerMethods.get(method);
338
+ if (!methodDef) {
339
+ return Err(ValidationErrors.invalid(`Unknown manager method: ${method}`));
340
+ }
341
+ const parsed = methodDef.input.safeParse(input);
342
+ if (!parsed.success) {
343
+ return Err(ValidationErrors.invalid(`Invalid input for ${method}: ${parsed.error.message}`));
344
+ }
345
+ const ctx = {
346
+ sessionManager: this,
347
+ eventStore: this.eventStore,
348
+ presets: this.presets,
349
+ logger: this.logger.child({ method }),
350
+ llmLogger: this.llmLogger,
351
+ platform: this.platform,
352
+ };
353
+ return await methodDef.handler(ctx, parsed.data);
354
+ }
355
+ /**
356
+ * Get all registered manager methods.
357
+ */
358
+ getManagerMethods() {
359
+ const result = new Map();
360
+ for (const [name, def] of this.managerMethods) {
361
+ result.set(name, { input: def.input, output: def.output });
362
+ }
363
+ return result;
364
+ }
365
+ /**
366
+ * Load all active sessions from event store (for restart recovery).
367
+ *
368
+ * Closed sessions are skipped — they have no runtime to restore. Loading them
369
+ * would trigger callSessionReadyHooks and emit events to an immutable session log,
370
+ * causing write amplification on every agent startup.
371
+ */
372
+ async loadAllSessions() {
373
+ const sessionIds = await this.eventStore.listSessions();
374
+ let loaded = 0;
375
+ let skipped = 0;
376
+ for (const sessionId of sessionIds) {
377
+ try {
378
+ const metadata = await this.eventStore.getMetadata(sessionId);
379
+ if (metadata?.status === 'closed') {
380
+ skipped++;
381
+ continue;
382
+ }
383
+ await this.getSession(sessionId);
384
+ loaded++;
385
+ }
386
+ catch (error) {
387
+ this.logger.error('Failed to load session', error instanceof Error ? error : new Error(String(error)), { sessionId });
388
+ }
389
+ }
390
+ this.logger.info('Loaded sessions', { loaded, skipped, total: sessionIds.length });
391
+ }
392
+ /**
393
+ * Get runtime stats including last activity timestamp and per-session metrics.
394
+ *
395
+ * Only open (non-closed) sessions contribute to activity metrics. Closed sessions
396
+ * are immutable artifacts — their event log timestamps must not be interpreted as
397
+ * "the sandbox is doing work", otherwise the worker alarm sees stale activity and
398
+ * keeps the sandbox alive forever.
399
+ */
400
+ async getStats() {
401
+ let pendingAgents = 0;
402
+ let processingAgents = 0;
403
+ let lastActivityAt = null;
404
+ // Wait for all sessions, ignoring failures
405
+ const sessions = await Promise.all(Array.from(this.sessions.values()).map((p) => p.catch(() => null)));
406
+ // Filter out closed sessions — they do not contribute to activity
407
+ const openSessions = sessions.filter((s) => s !== null && s.state.status !== 'closed');
408
+ // Fetch metadata only for open sessions
409
+ const metadataResults = await Promise.all(openSessions.map((s) => this.eventStore.getMetadata(s.state.id).catch(() => null)));
410
+ for (const metadata of metadataResults) {
411
+ if (metadata?.lastActivityAt) {
412
+ if (lastActivityAt === null
413
+ || metadata.lastActivityAt > lastActivityAt) {
414
+ lastActivityAt = metadata.lastActivityAt;
415
+ }
416
+ }
417
+ }
418
+ const sessionStats = [];
419
+ for (const session of openSessions) {
420
+ for (const [agentId, agentState] of session.state.agents) {
421
+ if (agentState.status === 'pending') {
422
+ const hasUnconsumed = getAgentUnconsumedMailbox(selectMailboxState(session.state), agentId).length > 0;
423
+ if (hasUnconsumed) {
424
+ pendingAgents++;
425
+ }
426
+ }
427
+ if (agentState.status === 'inferring'
428
+ || agentState.status === 'tool_exec') {
429
+ processingAgents++;
430
+ }
431
+ }
432
+ sessionStats.push({
433
+ id: session.state.id,
434
+ presetId: session.state.presetId,
435
+ status: session.state.status,
436
+ metrics: selectSessionStats(session.state),
437
+ });
438
+ }
439
+ return {
440
+ sessionCount: openSessions.length,
441
+ pendingAgents,
442
+ processingAgents,
443
+ lastActivityAt,
444
+ sessions: sessionStats,
445
+ };
446
+ }
447
+ /**
448
+ * Shutdown - clean up all sessions.
449
+ */
450
+ async shutdown() {
451
+ // Wait for all sessions, ignoring failures
452
+ const sessions = await Promise.all(Array.from(this.sessions.values()).map((p) => p.catch(() => null)));
453
+ for (const session of sessions) {
454
+ if (session) {
455
+ session.shutdown();
456
+ }
457
+ }
458
+ this.sessions.clear();
459
+ for (const cleanup of this.sessionListenerCleanup.values()) {
460
+ cleanup();
461
+ }
462
+ this.sessionListenerCleanup.clear();
463
+ this.logger.info('SessionManager shutdown complete');
464
+ }
465
+ // ============================================================================
466
+ // Private methods
467
+ // ============================================================================
468
+ /**
469
+ * Build ConfiguredPlugin[] for a session.
470
+ *
471
+ * Iterates all system-registered plugins. For each:
472
+ * 1. Check if preset has explicit SessionPluginConfig → use that config
473
+ * 2. If not, try auto-deriving infrastructure config (agents, uploads, services)
474
+ * 3. If no config at all → call .create() with no args (void config)
475
+ * 4. Check isSessionEnabled — skip plugin if not enabled
476
+ */
477
+ buildPlugins(preset) {
478
+ // Build a lookup from preset Sessionplugins
479
+ const presetConfigs = new Map();
480
+ for (const pluginConfig of preset.plugins ?? []) {
481
+ presetConfigs.set(pluginConfig.pluginName, pluginConfig.config);
482
+ }
483
+ // Build infra-derived configs
484
+ const infraConfigs = this.buildInfraConfigs(preset);
485
+ const plugins = [];
486
+ for (const pluginDef of this.systemPlugins) {
487
+ // Determine config: preset explicit > infra auto-derived > no config (void)
488
+ let config;
489
+ let hasConfig = false;
490
+ if (presetConfigs.has(pluginDef.name)) {
491
+ config = presetConfigs.get(pluginDef.name);
492
+ hasConfig = true;
493
+ }
494
+ else if (infraConfigs.has(pluginDef.name)) {
495
+ config = infraConfigs.get(pluginDef.name);
496
+ hasConfig = true;
497
+ }
498
+ const configured = hasConfig
499
+ ? pluginDef.create(config)
500
+ : pluginDef.create();
501
+ // Check isSessionEnabled — skip plugin if not enabled
502
+ if (configured.isSessionEnabled && !configured.isSessionEnabled({ pluginConfig: config })) {
503
+ continue;
504
+ }
505
+ plugins.push(configured);
506
+ }
507
+ // Process preset-only plugins (not registered as system plugins)
508
+ const registeredNames = new Set(plugins.map(p => p.name));
509
+ for (const pluginConfig of preset.plugins ?? []) {
510
+ if (registeredNames.has(pluginConfig.pluginName))
511
+ continue;
512
+ const configured = pluginConfig.definition.create(pluginConfig.config);
513
+ if (configured.isSessionEnabled && !configured.isSessionEnabled({ pluginConfig: pluginConfig.config })) {
514
+ continue;
515
+ }
516
+ plugins.push(configured);
517
+ registeredNames.add(configured.name);
518
+ }
519
+ // Validate that all declared dependencies are registered
520
+ for (const plugin of plugins) {
521
+ for (const depName of plugin.dependencyNames) {
522
+ if (!registeredNames.has(depName)) {
523
+ throw new Error(`Plugin "${plugin.name}" declares dependency on "${depName}", but "${depName}" is not registered. Add it to systemPlugins.`);
524
+ }
525
+ }
526
+ }
527
+ return plugins;
528
+ }
529
+ /**
530
+ * Build infrastructure-derived plugin configs from preset data.
531
+ * These are auto-derived for well-known plugins that need preset-level data.
532
+ */
533
+ buildInfraConfigs(preset) {
534
+ const configs = new Map();
535
+ // agents plugin — derive agentDefinitions from preset.agents
536
+ const agentDefinitions = new Map();
537
+ for (const agentDef of preset.agents) {
538
+ agentDefinitions.set(agentDef.name, {
539
+ name: agentDef.name,
540
+ inputSchema: agentDef.input,
541
+ });
542
+ }
543
+ configs.set('agents', { agentDefinitions });
544
+ // user-chat plugin — empty config
545
+ configs.set('user-chat', {});
546
+ // uploads plugin — needs dataFileStore and preprocessorRegistry from SessionManager
547
+ configs.set('uploads', {
548
+ dataFileStore: this.dataFileStore,
549
+ preprocessorRegistry: this.preprocessorRegistry,
550
+ });
551
+ // services plugin — collect services from all agent definitions
552
+ const allAgentConfigs = [preset.orchestrator, ...(preset.communicator ? [preset.communicator] : []), ...preset.agents];
553
+ const servicesByType = new Map();
554
+ for (const agentConfig of allAgentConfigs) {
555
+ for (const svc of agentConfig.services ?? []) {
556
+ servicesByType.set(svc.type, svc);
557
+ }
558
+ }
559
+ if (servicesByType.size > 0 && this.portPool) {
560
+ configs.set('services', { services: [...servicesByType.values()], portPool: this.portPool });
561
+ }
562
+ return configs;
563
+ }
564
+ /**
565
+ * Create a Session instance with all dependencies.
566
+ * Plugins must be pre-built via buildPlugins() so the composed reducer
567
+ * can be used for SessionStore before this method is called.
568
+ *
569
+ * @param opts.skipReadyHooks - Skip onSessionReady hooks. Used for closed sessions,
570
+ * which must remain immutable: running hooks would emit session_handler_* events
571
+ * to a sealed event log on every introspection / restart cycle.
572
+ */
573
+ async createSessionInstance(store, preset, plugins, opts = {}) {
574
+ // Only register cache eviction listener for active sessions (not closed)
575
+ if (store.getState().status !== 'closed') {
576
+ this.registerSessionEventListener(store.sessionId, store);
577
+ }
578
+ const sessionDir = this.getSessionDir(store.sessionId);
579
+ const sessionLogger = new TeeLogger([
580
+ this.logger.child({ sessionId: store.sessionId }),
581
+ new FileLogger(join(sessionDir, 'session.log'), this.platform.fs, { sessionId: String(store.sessionId) }),
582
+ ]);
583
+ // Create session
584
+ const session = new Session({
585
+ store,
586
+ preset,
587
+ llmProvider: this.llmProvider,
588
+ llmProviders: this.llmProviders,
589
+ toolExecutor: this.toolExecutor,
590
+ logger: sessionLogger,
591
+ onUserOutput: this.onUserOutput,
592
+ sessionDir,
593
+ plugins,
594
+ eventStore: this.eventStore,
595
+ llmLogger: this.llmLogger,
596
+ platform: this.platform,
597
+ });
598
+ // Ensure session and workspace directories exist before plugins run
599
+ await this.platform.fs.mkdir(sessionDir, { recursive: true });
600
+ const workspaceDir = store.getState().workspaceDir;
601
+ if (workspaceDir) {
602
+ await this.platform.fs.mkdir(workspaceDir, { recursive: true });
603
+ }
604
+ // Initialize plugin contexts (calls createContext for each plugin).
605
+ // Safe for closed sessions — createContext is pure local setup, no event emit.
606
+ await session.initPluginContexts();
607
+ // Call onSessionReady hooks with full context.
608
+ // Skipped for closed sessions to preserve event log immutability.
609
+ if (!opts.skipReadyHooks) {
610
+ await session.callSessionReadyHooks();
611
+ }
612
+ return session;
613
+ }
614
+ /**
615
+ * Collect manager methods from all system plugin definitions.
616
+ */
617
+ collectManagerMethods() {
618
+ const methods = new Map();
619
+ for (const pluginDef of this.systemPlugins) {
620
+ for (const [methodName, methodDef] of Object.entries(pluginDef.managerMethods)) {
621
+ methods.set(`${pluginDef.name}.${methodName}`, methodDef);
622
+ }
623
+ }
624
+ return methods;
625
+ }
626
+ /**
627
+ * Register event listener on a session's store for automatic cache eviction.
628
+ * When session_closed or session_reopened events fire, the session is evicted
629
+ * so next getSession() triggers a full load with recovery.
630
+ *
631
+ * Cleans up any previous listener for this sessionId (from a prior load)
632
+ * to prevent duplicate listeners firing on old stores.
633
+ */
634
+ registerSessionEventListener(sessionId, store) {
635
+ const prevCleanup = this.sessionListenerCleanup.get(sessionId);
636
+ if (prevCleanup)
637
+ prevCleanup();
638
+ const unsubscribe = store.onEvent((event) => {
639
+ if (event.type === 'session_closed' || event.type === 'session_reopened') {
640
+ this.sessions.delete(sessionId);
641
+ this.sessionListenerCleanup.delete(sessionId);
642
+ }
643
+ });
644
+ this.sessionListenerCleanup.set(sessionId, unsubscribe);
645
+ }
646
+ getSessionDir(sessionId) {
647
+ return join(this.basePath, 'sessions', String(sessionId));
648
+ }
649
+ }
650
+ //# sourceMappingURL=session-manager.js.map