@roj-ai/sdk 0.1.36 → 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 (922) hide show
  1. package/dist/bootstrap.d.ts +420 -26
  2. package/dist/bootstrap.d.ts.map +1 -1
  3. package/dist/bootstrap.js +55 -24
  4. package/dist/bootstrap.js.map +1 -1
  5. package/dist/bun-platform/fs.d.ts.map +1 -1
  6. package/dist/bun-platform/fs.js +1 -0
  7. package/dist/bun-platform/fs.js.map +1 -1
  8. package/dist/bun-platform/index.d.ts +4 -1
  9. package/dist/bun-platform/index.d.ts.map +1 -1
  10. package/dist/bun-platform/index.js +7 -1
  11. package/dist/bun-platform/index.js.map +1 -1
  12. package/dist/bun-platform/server-lifecycle.d.ts +30 -0
  13. package/dist/bun-platform/server-lifecycle.d.ts.map +1 -0
  14. package/dist/bun-platform/server-lifecycle.js +182 -0
  15. package/dist/bun-platform/server-lifecycle.js.map +1 -0
  16. package/dist/bun-platform/shell.d.ts +33 -0
  17. package/dist/bun-platform/shell.d.ts.map +1 -0
  18. package/dist/bun-platform/shell.js +322 -0
  19. package/dist/bun-platform/shell.js.map +1 -0
  20. package/dist/config.d.ts +34 -0
  21. package/dist/config.d.ts.map +1 -1
  22. package/dist/config.js +97 -0
  23. package/dist/config.js.map +1 -1
  24. package/dist/core/agents/agent.d.ts +42 -7
  25. package/dist/core/agents/agent.d.ts.map +1 -1
  26. package/dist/core/agents/agent.js +202 -87
  27. package/dist/core/agents/agent.js.map +1 -1
  28. package/dist/core/agents/config.d.ts +8 -1
  29. package/dist/core/agents/config.d.ts.map +1 -1
  30. package/dist/core/agents/config.js +5 -1
  31. package/dist/core/agents/config.js.map +1 -1
  32. package/dist/core/agents/retry.d.ts +1 -1
  33. package/dist/core/agents/retry.d.ts.map +1 -1
  34. package/dist/core/agents/retry.js +14 -16
  35. package/dist/core/agents/retry.js.map +1 -1
  36. package/dist/core/agents/state.d.ts +3 -1
  37. package/dist/core/agents/state.d.ts.map +1 -1
  38. package/dist/core/agents/state.js +1 -1
  39. package/dist/core/agents/state.js.map +1 -1
  40. package/dist/core/context/state.d.ts +3 -3
  41. package/dist/core/context/state.js +2 -2
  42. package/dist/core/events/base-event-store.d.ts.map +1 -1
  43. package/dist/core/events/base-event-store.js +22 -14
  44. package/dist/core/events/base-event-store.js.map +1 -1
  45. package/dist/core/events/file.d.ts +39 -1
  46. package/dist/core/events/file.d.ts.map +1 -1
  47. package/dist/core/events/file.js +159 -20
  48. package/dist/core/events/file.js.map +1 -1
  49. package/dist/core/events/types.d.ts +1 -1
  50. package/dist/core/file-store/containment.d.ts +19 -0
  51. package/dist/core/file-store/containment.d.ts.map +1 -0
  52. package/dist/core/file-store/containment.js +62 -0
  53. package/dist/core/file-store/containment.js.map +1 -0
  54. package/dist/core/file-store/file-store.d.ts +22 -2
  55. package/dist/core/file-store/file-store.d.ts.map +1 -1
  56. package/dist/core/file-store/file-store.js +88 -20
  57. package/dist/core/file-store/file-store.js.map +1 -1
  58. package/dist/core/file-store/types.d.ts +13 -1
  59. package/dist/core/file-store/types.d.ts.map +1 -1
  60. package/dist/core/image/image-processor.d.ts.map +1 -1
  61. package/dist/core/image/image-processor.js +3 -1
  62. package/dist/core/image/image-processor.js.map +1 -1
  63. package/dist/core/image/types.d.ts +2 -0
  64. package/dist/core/image/types.d.ts.map +1 -1
  65. package/dist/core/image/vips-resizer.d.ts.map +1 -1
  66. package/dist/core/image/vips-resizer.js +81 -33
  67. package/dist/core/image/vips-resizer.js.map +1 -1
  68. package/dist/core/llm/anthropic.d.ts +0 -1
  69. package/dist/core/llm/anthropic.d.ts.map +1 -1
  70. package/dist/core/llm/anthropic.js +58 -72
  71. package/dist/core/llm/anthropic.js.map +1 -1
  72. package/dist/core/llm/logger.d.ts +14 -2
  73. package/dist/core/llm/logger.d.ts.map +1 -1
  74. package/dist/core/llm/logger.js +161 -36
  75. package/dist/core/llm/logger.js.map +1 -1
  76. package/dist/core/llm/openrouter.d.ts +0 -1
  77. package/dist/core/llm/openrouter.d.ts.map +1 -1
  78. package/dist/core/llm/openrouter.js +53 -66
  79. package/dist/core/llm/openrouter.js.map +1 -1
  80. package/dist/core/llm/provider-request.d.ts +10 -0
  81. package/dist/core/llm/provider-request.d.ts.map +1 -0
  82. package/dist/core/llm/provider-request.js +41 -0
  83. package/dist/core/llm/provider-request.js.map +1 -0
  84. package/dist/core/llm/provider.d.ts +11 -0
  85. package/dist/core/llm/provider.d.ts.map +1 -1
  86. package/dist/core/llm/provider.js +26 -0
  87. package/dist/core/llm/provider.js.map +1 -1
  88. package/dist/core/llm/state.d.ts +2 -2
  89. package/dist/core/llm/state.js +4 -4
  90. package/dist/core/plugins/plugin-builder.d.ts +57 -3
  91. package/dist/core/plugins/plugin-builder.d.ts.map +1 -1
  92. package/dist/core/plugins/plugin-builder.js +68 -14
  93. package/dist/core/plugins/plugin-builder.js.map +1 -1
  94. package/dist/core/preset/preset-builder.d.ts +3 -2
  95. package/dist/core/preset/preset-builder.d.ts.map +1 -1
  96. package/dist/core/preset/preset-builder.js +7 -16
  97. package/dist/core/preset/preset-builder.js.map +1 -1
  98. package/dist/core/sessions/context.d.ts +23 -5
  99. package/dist/core/sessions/context.d.ts.map +1 -1
  100. package/dist/core/sessions/runtime-activity.d.ts +33 -0
  101. package/dist/core/sessions/runtime-activity.d.ts.map +1 -0
  102. package/dist/core/sessions/runtime-activity.js +55 -0
  103. package/dist/core/sessions/runtime-activity.js.map +1 -0
  104. package/dist/core/sessions/schema.d.ts +23 -2
  105. package/dist/core/sessions/schema.d.ts.map +1 -1
  106. package/dist/core/sessions/schema.js +24 -3
  107. package/dist/core/sessions/schema.js.map +1 -1
  108. package/dist/core/sessions/session-manager.d.ts +83 -6
  109. package/dist/core/sessions/session-manager.d.ts.map +1 -1
  110. package/dist/core/sessions/session-manager.js +517 -118
  111. package/dist/core/sessions/session-manager.js.map +1 -1
  112. package/dist/core/sessions/session-store.d.ts +18 -0
  113. package/dist/core/sessions/session-store.d.ts.map +1 -1
  114. package/dist/core/sessions/session-store.js +33 -0
  115. package/dist/core/sessions/session-store.js.map +1 -1
  116. package/dist/core/sessions/session.d.ts +42 -6
  117. package/dist/core/sessions/session.d.ts.map +1 -1
  118. package/dist/core/sessions/session.js +176 -44
  119. package/dist/core/sessions/session.js.map +1 -1
  120. package/dist/core/sessions/state.d.ts +10 -1
  121. package/dist/core/sessions/state.d.ts.map +1 -1
  122. package/dist/core/sessions/state.js +11 -1
  123. package/dist/core/sessions/state.js.map +1 -1
  124. package/dist/core/system.d.ts +9 -0
  125. package/dist/core/system.d.ts.map +1 -1
  126. package/dist/core/system.js +4 -1
  127. package/dist/core/system.js.map +1 -1
  128. package/dist/core/tools/executor.d.ts +1 -1
  129. package/dist/core/wake-key.d.ts +34 -0
  130. package/dist/core/wake-key.d.ts.map +1 -0
  131. package/dist/core/wake-key.js +51 -0
  132. package/dist/core/wake-key.js.map +1 -0
  133. package/dist/index.d.ts +23 -13
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +22 -8
  136. package/dist/index.js.map +1 -1
  137. package/dist/lib/archive/archive-inspection.d.ts +48 -0
  138. package/dist/lib/archive/archive-inspection.d.ts.map +1 -0
  139. package/dist/lib/archive/archive-inspection.fixtures.d.ts +7 -0
  140. package/dist/lib/archive/archive-inspection.fixtures.d.ts.map +1 -0
  141. package/dist/lib/archive/archive-inspection.fixtures.js +134 -0
  142. package/dist/lib/archive/archive-inspection.fixtures.js.map +1 -0
  143. package/dist/lib/archive/archive-inspection.js +253 -0
  144. package/dist/lib/archive/archive-inspection.js.map +1 -0
  145. package/dist/lib/archive/index.d.ts +3 -0
  146. package/dist/lib/archive/index.d.ts.map +1 -0
  147. package/dist/lib/archive/index.js +2 -0
  148. package/dist/lib/archive/index.js.map +1 -0
  149. package/dist/lib/logger/console.d.ts +5 -12
  150. package/dist/lib/logger/console.d.ts.map +1 -1
  151. package/dist/lib/logger/console.js +5 -47
  152. package/dist/lib/logger/console.js.map +1 -1
  153. package/dist/lib/logger/file.d.ts +8 -11
  154. package/dist/lib/logger/file.d.ts.map +1 -1
  155. package/dist/lib/logger/file.js +26 -37
  156. package/dist/lib/logger/file.js.map +1 -1
  157. package/dist/lib/logger/index.d.ts +3 -1
  158. package/dist/lib/logger/index.d.ts.map +1 -1
  159. package/dist/lib/logger/index.js +3 -1
  160. package/dist/lib/logger/index.js.map +1 -1
  161. package/dist/lib/logger/jsonl.d.ts +21 -0
  162. package/dist/lib/logger/jsonl.d.ts.map +1 -0
  163. package/dist/lib/logger/jsonl.js +29 -0
  164. package/dist/lib/logger/jsonl.js.map +1 -0
  165. package/dist/lib/logger/logger.d.ts +22 -0
  166. package/dist/lib/logger/logger.d.ts.map +1 -1
  167. package/dist/lib/logger/logger.js +37 -0
  168. package/dist/lib/logger/logger.js.map +1 -1
  169. package/dist/lib/logger/session-log.d.ts +21 -0
  170. package/dist/lib/logger/session-log.d.ts.map +1 -0
  171. package/dist/lib/logger/session-log.js +37 -0
  172. package/dist/lib/logger/session-log.js.map +1 -0
  173. package/dist/lib/utils/concurrency.d.ts +1 -1
  174. package/dist/lib/utils/concurrency.d.ts.map +1 -1
  175. package/dist/lib/utils/concurrency.js +30 -7
  176. package/dist/lib/utils/concurrency.js.map +1 -1
  177. package/dist/lib/utils/fs-batch.d.ts +17 -0
  178. package/dist/lib/utils/fs-batch.d.ts.map +1 -0
  179. package/dist/lib/utils/fs-batch.js +38 -0
  180. package/dist/lib/utils/fs-batch.js.map +1 -0
  181. package/dist/lib/utils/result.d.ts +7 -22
  182. package/dist/lib/utils/result.d.ts.map +1 -1
  183. package/dist/lib/utils/result.js +6 -17
  184. package/dist/lib/utils/result.js.map +1 -1
  185. package/dist/lib/utils/sleep.d.ts +10 -0
  186. package/dist/lib/utils/sleep.d.ts.map +1 -0
  187. package/dist/lib/utils/sleep.js +26 -0
  188. package/dist/lib/utils/sleep.js.map +1 -0
  189. package/dist/platform/fs-revision.d.ts +21 -0
  190. package/dist/platform/fs-revision.d.ts.map +1 -0
  191. package/dist/platform/fs-revision.js +9 -0
  192. package/dist/platform/fs-revision.js.map +1 -0
  193. package/dist/platform/fs.d.ts +104 -1
  194. package/dist/platform/fs.d.ts.map +1 -1
  195. package/dist/platform/git.d.ts +59 -0
  196. package/dist/platform/git.d.ts.map +1 -0
  197. package/dist/platform/git.js +8 -0
  198. package/dist/platform/git.js.map +1 -0
  199. package/dist/platform/index.d.ts +40 -1
  200. package/dist/platform/index.d.ts.map +1 -1
  201. package/dist/platform/index.js +1 -1
  202. package/dist/platform/index.js.map +1 -1
  203. package/dist/platform/llm-call-log.d.ts +80 -0
  204. package/dist/platform/llm-call-log.d.ts.map +1 -0
  205. package/dist/platform/llm-call-log.js +12 -0
  206. package/dist/platform/llm-call-log.js.map +1 -0
  207. package/dist/platform/scheduler.d.ts +32 -0
  208. package/dist/platform/scheduler.d.ts.map +1 -0
  209. package/dist/platform/scheduler.js +46 -0
  210. package/dist/platform/scheduler.js.map +1 -0
  211. package/dist/platform/session-log.d.ts +36 -0
  212. package/dist/platform/session-log.d.ts.map +1 -0
  213. package/dist/platform/session-log.js +12 -0
  214. package/dist/platform/session-log.js.map +1 -0
  215. package/dist/platform/shell.d.ts +83 -0
  216. package/dist/platform/shell.d.ts.map +1 -0
  217. package/dist/platform/shell.js +13 -0
  218. package/dist/platform/shell.js.map +1 -0
  219. package/dist/plugins/agent-status/plugin.d.ts.map +1 -1
  220. package/dist/plugins/agent-status/plugin.js +1 -0
  221. package/dist/plugins/agent-status/plugin.js.map +1 -1
  222. package/dist/plugins/agents/plugin.d.ts.map +1 -1
  223. package/dist/plugins/agents/plugin.js +129 -62
  224. package/dist/plugins/agents/plugin.js.map +1 -1
  225. package/dist/plugins/filesystem/listing.d.ts +3 -0
  226. package/dist/plugins/filesystem/listing.d.ts.map +1 -1
  227. package/dist/plugins/filesystem/listing.js +66 -10
  228. package/dist/plugins/filesystem/listing.js.map +1 -1
  229. package/dist/plugins/filesystem/plugin.d.ts.map +1 -1
  230. package/dist/plugins/filesystem/plugin.js +8 -6
  231. package/dist/plugins/filesystem/plugin.js.map +1 -1
  232. package/dist/plugins/git-status/plugin.d.ts +34 -7
  233. package/dist/plugins/git-status/plugin.d.ts.map +1 -1
  234. package/dist/plugins/git-status/plugin.js +168 -64
  235. package/dist/plugins/git-status/plugin.js.map +1 -1
  236. package/dist/plugins/llm-debug/plugin.d.ts.map +1 -1
  237. package/dist/plugins/llm-debug/plugin.js +1 -0
  238. package/dist/plugins/llm-debug/plugin.js.map +1 -1
  239. package/dist/plugins/logs/plugin.d.ts +1 -4
  240. package/dist/plugins/logs/plugin.d.ts.map +1 -1
  241. package/dist/plugins/logs/plugin.js +7 -0
  242. package/dist/plugins/logs/plugin.js.map +1 -1
  243. package/dist/plugins/mailbox/helpers.d.ts +2 -2
  244. package/dist/plugins/mailbox/helpers.js +1 -1
  245. package/dist/plugins/mailbox/plugin.d.ts.map +1 -1
  246. package/dist/plugins/mailbox/plugin.js +38 -43
  247. package/dist/plugins/mailbox/plugin.js.map +1 -1
  248. package/dist/plugins/mailbox/query.d.ts +7 -2
  249. package/dist/plugins/mailbox/query.d.ts.map +1 -1
  250. package/dist/plugins/mailbox/query.js +14 -7
  251. package/dist/plugins/mailbox/query.js.map +1 -1
  252. package/dist/plugins/mailbox/state.d.ts +5 -4
  253. package/dist/plugins/mailbox/state.d.ts.map +1 -1
  254. package/dist/plugins/mailbox/state.js +6 -5
  255. package/dist/plugins/mailbox/state.js.map +1 -1
  256. package/dist/plugins/resources/filename.d.ts +4 -0
  257. package/dist/plugins/resources/filename.d.ts.map +1 -0
  258. package/dist/plugins/resources/filename.js +18 -0
  259. package/dist/plugins/resources/filename.js.map +1 -0
  260. package/dist/plugins/resources/plugin.d.ts +3 -0
  261. package/dist/plugins/resources/plugin.d.ts.map +1 -1
  262. package/dist/plugins/resources/plugin.js +97 -60
  263. package/dist/plugins/resources/plugin.js.map +1 -1
  264. package/dist/plugins/resources/state.d.ts +1 -1
  265. package/dist/plugins/resources/state.js +1 -1
  266. package/dist/plugins/result-eviction/plugin.d.ts.map +1 -1
  267. package/dist/plugins/result-eviction/plugin.js +6 -1
  268. package/dist/plugins/result-eviction/plugin.js.map +1 -1
  269. package/dist/plugins/services/plugin.d.ts +4 -1
  270. package/dist/plugins/services/plugin.d.ts.map +1 -1
  271. package/dist/plugins/services/plugin.js +251 -100
  272. package/dist/plugins/services/plugin.js.map +1 -1
  273. package/dist/plugins/services/prompt.d.ts.map +1 -1
  274. package/dist/plugins/services/prompt.js +1 -4
  275. package/dist/plugins/services/prompt.js.map +1 -1
  276. package/dist/plugins/services/schema.d.ts +15 -5
  277. package/dist/plugins/services/schema.d.ts.map +1 -1
  278. package/dist/plugins/services/service.d.ts +100 -18
  279. package/dist/plugins/services/service.d.ts.map +1 -1
  280. package/dist/plugins/services/service.js +680 -230
  281. package/dist/plugins/services/service.js.map +1 -1
  282. package/dist/plugins/session-lifecycle/plugin.d.ts +21 -1
  283. package/dist/plugins/session-lifecycle/plugin.d.ts.map +1 -1
  284. package/dist/plugins/session-lifecycle/plugin.js +53 -40
  285. package/dist/plugins/session-lifecycle/plugin.js.map +1 -1
  286. package/dist/plugins/session-state/plugin.d.ts +21 -13
  287. package/dist/plugins/session-state/plugin.d.ts.map +1 -1
  288. package/dist/plugins/session-state/plugin.js +214 -79
  289. package/dist/plugins/session-state/plugin.js.map +1 -1
  290. package/dist/plugins/session-stats/plugin.d.ts.map +1 -1
  291. package/dist/plugins/session-stats/plugin.js +1 -0
  292. package/dist/plugins/session-stats/plugin.js.map +1 -1
  293. package/dist/plugins/shell/executor.d.ts +17 -15
  294. package/dist/plugins/shell/executor.d.ts.map +1 -1
  295. package/dist/plugins/shell/executor.js +130 -195
  296. package/dist/plugins/shell/executor.js.map +1 -1
  297. package/dist/plugins/shell/index.d.ts +2 -2
  298. package/dist/plugins/shell/index.d.ts.map +1 -1
  299. package/dist/plugins/shell/index.js +2 -2
  300. package/dist/plugins/shell/index.js.map +1 -1
  301. package/dist/plugins/shell/plugin.d.ts +5 -4
  302. package/dist/plugins/shell/plugin.d.ts.map +1 -1
  303. package/dist/plugins/shell/plugin.js +4 -8
  304. package/dist/plugins/shell/plugin.js.map +1 -1
  305. package/dist/plugins/skills/discovery.d.ts.map +1 -1
  306. package/dist/plugins/skills/discovery.js +10 -8
  307. package/dist/plugins/skills/discovery.js.map +1 -1
  308. package/dist/plugins/skills/index.d.ts +1 -1
  309. package/dist/plugins/skills/index.d.ts.map +1 -1
  310. package/dist/plugins/skills/plugin.d.ts +1 -1
  311. package/dist/plugins/skills/plugin.d.ts.map +1 -1
  312. package/dist/plugins/skills/plugin.js +23 -30
  313. package/dist/plugins/skills/plugin.js.map +1 -1
  314. package/dist/plugins/skills/prompts.d.ts +3 -3
  315. package/dist/plugins/skills/prompts.d.ts.map +1 -1
  316. package/dist/plugins/skills/prompts.js.map +1 -1
  317. package/dist/plugins/skills/schema.d.ts +4 -2
  318. package/dist/plugins/skills/schema.d.ts.map +1 -1
  319. package/dist/plugins/todo/schema.d.ts +1 -1
  320. package/dist/plugins/uploads/plugin.d.ts +11 -4
  321. package/dist/plugins/uploads/plugin.d.ts.map +1 -1
  322. package/dist/plugins/uploads/plugin.js +891 -225
  323. package/dist/plugins/uploads/plugin.js.map +1 -1
  324. package/dist/plugins/uploads/preprocessor.d.ts +14 -0
  325. package/dist/plugins/uploads/preprocessor.d.ts.map +1 -1
  326. package/dist/plugins/uploads/preprocessor.js +11 -0
  327. package/dist/plugins/uploads/preprocessor.js.map +1 -1
  328. package/dist/plugins/uploads/preprocessors/image-classifier.d.ts +1 -1
  329. package/dist/plugins/uploads/preprocessors/image-classifier.d.ts.map +1 -1
  330. package/dist/plugins/uploads/preprocessors/image-classifier.js +51 -26
  331. package/dist/plugins/uploads/preprocessors/image-classifier.js.map +1 -1
  332. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.d.ts +2 -2
  333. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.d.ts.map +1 -1
  334. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js +41 -16
  335. package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js.map +1 -1
  336. package/dist/plugins/uploads/preprocessors/pdf-preprocessor.d.ts +1 -1
  337. package/dist/plugins/uploads/preprocessors/pdf-preprocessor.d.ts.map +1 -1
  338. package/dist/plugins/uploads/preprocessors/pdf-preprocessor.js +29 -14
  339. package/dist/plugins/uploads/preprocessors/pdf-preprocessor.js.map +1 -1
  340. package/dist/plugins/uploads/preprocessors/zip-preprocessor.d.ts +1 -1
  341. package/dist/plugins/uploads/preprocessors/zip-preprocessor.d.ts.map +1 -1
  342. package/dist/plugins/uploads/preprocessors/zip-preprocessor.js +62 -34
  343. package/dist/plugins/uploads/preprocessors/zip-preprocessor.js.map +1 -1
  344. package/dist/plugins/uploads/schema.d.ts +25 -2
  345. package/dist/plugins/uploads/schema.d.ts.map +1 -1
  346. package/dist/plugins/uploads/schema.js +24 -3
  347. package/dist/plugins/uploads/schema.js.map +1 -1
  348. package/dist/plugins/uploads/state.d.ts +13 -1
  349. package/dist/plugins/uploads/state.d.ts.map +1 -1
  350. package/dist/plugins/uploads/state.js +4 -1
  351. package/dist/plugins/uploads/state.js.map +1 -1
  352. package/dist/plugins/user-chat/plugin.d.ts +12 -5
  353. package/dist/plugins/user-chat/plugin.d.ts.map +1 -1
  354. package/dist/plugins/user-chat/plugin.js +141 -32
  355. package/dist/plugins/user-chat/plugin.js.map +1 -1
  356. package/dist/plugins/workers/context.d.ts +35 -13
  357. package/dist/plugins/workers/context.d.ts.map +1 -1
  358. package/dist/plugins/workers/context.js +82 -32
  359. package/dist/plugins/workers/context.js.map +1 -1
  360. package/dist/plugins/workers/definition.d.ts +7 -0
  361. package/dist/plugins/workers/definition.d.ts.map +1 -1
  362. package/dist/plugins/workers/definition.js.map +1 -1
  363. package/dist/plugins/workers/index.d.ts +4 -4
  364. package/dist/plugins/workers/index.d.ts.map +1 -1
  365. package/dist/plugins/workers/index.js +2 -2
  366. package/dist/plugins/workers/index.js.map +1 -1
  367. package/dist/plugins/workers/plugin.d.ts +10 -57
  368. package/dist/plugins/workers/plugin.d.ts.map +1 -1
  369. package/dist/plugins/workers/plugin.js +385 -123
  370. package/dist/plugins/workers/plugin.js.map +1 -1
  371. package/dist/plugins/workers/state.d.ts +69 -0
  372. package/dist/plugins/workers/state.d.ts.map +1 -0
  373. package/dist/plugins/workers/state.js +52 -0
  374. package/dist/plugins/workers/state.js.map +1 -0
  375. package/dist/plugins/workers/worker.d.ts +15 -4
  376. package/dist/plugins/workers/worker.d.ts.map +1 -1
  377. package/dist/testing/conformance.d.ts +106 -0
  378. package/dist/testing/conformance.d.ts.map +1 -0
  379. package/dist/testing/conformance.js +1463 -0
  380. package/dist/testing/conformance.js.map +1 -0
  381. package/dist/testing/node-platform.d.ts.map +1 -1
  382. package/dist/testing/node-platform.js +5 -0
  383. package/dist/testing/node-platform.js.map +1 -1
  384. package/dist/testing/test-harness.d.ts +11 -1
  385. package/dist/testing/test-harness.d.ts.map +1 -1
  386. package/dist/testing/test-harness.js +17 -37
  387. package/dist/testing/test-harness.js.map +1 -1
  388. package/dist/testing/wait-helpers.d.ts.map +1 -1
  389. package/dist/testing/wait-helpers.js +1 -3
  390. package/dist/testing/wait-helpers.js.map +1 -1
  391. package/dist/transport/adapter/client-adapter.d.ts +6 -0
  392. package/dist/transport/adapter/client-adapter.d.ts.map +1 -1
  393. package/dist/transport/adapter/client-adapter.js +50 -3
  394. package/dist/transport/adapter/client-adapter.js.map +1 -1
  395. package/dist/transport/adapter/heartbeat.d.ts +16 -0
  396. package/dist/transport/adapter/heartbeat.d.ts.map +1 -0
  397. package/dist/transport/adapter/heartbeat.js +41 -0
  398. package/dist/transport/adapter/heartbeat.js.map +1 -0
  399. package/dist/transport/adapter/server-adapter.d.ts.map +1 -1
  400. package/dist/transport/adapter/server-adapter.js +6 -0
  401. package/dist/transport/adapter/server-adapter.js.map +1 -1
  402. package/dist/transport/http/app.d.ts +3 -30
  403. package/dist/transport/http/app.d.ts.map +1 -1
  404. package/dist/transport/http/app.js +3 -7
  405. package/dist/transport/http/app.js.map +1 -1
  406. package/dist/transport/http/context.d.ts +40 -0
  407. package/dist/transport/http/context.d.ts.map +1 -0
  408. package/dist/transport/http/context.js +17 -0
  409. package/dist/transport/http/context.js.map +1 -0
  410. package/dist/transport/http/fetch-guard.d.ts +49 -0
  411. package/dist/transport/http/fetch-guard.d.ts.map +1 -0
  412. package/dist/transport/http/fetch-guard.js +312 -0
  413. package/dist/transport/http/fetch-guard.js.map +1 -0
  414. package/dist/transport/http/index.d.ts +1 -1
  415. package/dist/transport/http/index.d.ts.map +1 -1
  416. package/dist/transport/http/middleware/bearer-auth.d.ts +1 -1
  417. package/dist/transport/http/middleware/bearer-auth.d.ts.map +1 -1
  418. package/dist/transport/http/middleware/error-handler.d.ts +2 -2
  419. package/dist/transport/http/middleware/error-handler.d.ts.map +1 -1
  420. package/dist/transport/http/path-containment.d.ts +20 -0
  421. package/dist/transport/http/path-containment.d.ts.map +1 -0
  422. package/dist/transport/http/path-containment.js +31 -0
  423. package/dist/transport/http/path-containment.js.map +1 -0
  424. package/dist/transport/http/responses.d.ts +30 -0
  425. package/dist/transport/http/responses.d.ts.map +1 -0
  426. package/dist/transport/http/responses.js +5 -0
  427. package/dist/transport/http/responses.js.map +1 -0
  428. package/dist/transport/http/routes/files.d.ts +1 -1
  429. package/dist/transport/http/routes/files.d.ts.map +1 -1
  430. package/dist/transport/http/routes/files.js +54 -155
  431. package/dist/transport/http/routes/files.js.map +1 -1
  432. package/dist/transport/http/routes/resources.d.ts +1 -1
  433. package/dist/transport/http/routes/resources.d.ts.map +1 -1
  434. package/dist/transport/http/routes/resources.js +92 -57
  435. package/dist/transport/http/routes/resources.js.map +1 -1
  436. package/dist/transport/http/routes/rpc.d.ts +6 -1
  437. package/dist/transport/http/routes/rpc.d.ts.map +1 -1
  438. package/dist/transport/http/routes/rpc.js +51 -21
  439. package/dist/transport/http/routes/rpc.js.map +1 -1
  440. package/dist/transport/http/routes/upload.d.ts +1 -1
  441. package/dist/transport/http/routes/upload.d.ts.map +1 -1
  442. package/dist/transport/http/routes/upload.js +256 -169
  443. package/dist/transport/http/routes/upload.js.map +1 -1
  444. package/dist/user-config.d.ts +34 -7
  445. package/dist/user-config.d.ts.map +1 -1
  446. package/dist/user-config.js +71 -0
  447. package/dist/user-config.js.map +1 -1
  448. package/package.json +17 -7
  449. package/src/bootstrap.ts +119 -35
  450. package/src/bun-platform/fs.ts +1 -0
  451. package/src/bun-platform/index.ts +18 -1
  452. package/src/bun-platform/server-lifecycle.ts +218 -0
  453. package/src/bun-platform/shell.ts +362 -0
  454. package/src/config.ts +130 -0
  455. package/src/core/agents/agent.ts +210 -92
  456. package/src/core/agents/config.ts +8 -0
  457. package/src/core/agents/retry.ts +16 -17
  458. package/src/core/agents/state.ts +2 -0
  459. package/src/core/events/base-event-store.ts +24 -16
  460. package/src/core/events/file.ts +198 -22
  461. package/src/core/file-store/containment.ts +75 -0
  462. package/src/core/file-store/file-store.ts +106 -25
  463. package/src/core/file-store/types.ts +14 -1
  464. package/src/core/image/image-processor.ts +3 -1
  465. package/src/core/image/types.ts +2 -0
  466. package/src/core/image/vips-resizer.ts +102 -37
  467. package/src/core/llm/anthropic.ts +63 -79
  468. package/src/core/llm/logger.ts +175 -37
  469. package/src/core/llm/openrouter.ts +57 -72
  470. package/src/core/llm/provider-request.ts +40 -0
  471. package/src/core/llm/provider.ts +28 -0
  472. package/src/core/plugins/plugin-builder.ts +106 -14
  473. package/src/core/preset/preset-builder.ts +12 -22
  474. package/src/core/sessions/context.ts +18 -0
  475. package/src/core/sessions/runtime-activity.ts +78 -0
  476. package/src/core/sessions/schema.ts +29 -3
  477. package/src/core/sessions/session-manager.ts +560 -140
  478. package/src/core/sessions/session-store.ts +38 -0
  479. package/src/core/sessions/session.ts +187 -47
  480. package/src/core/sessions/state.ts +11 -0
  481. package/src/core/system.ts +15 -0
  482. package/src/core/wake-key.ts +65 -0
  483. package/src/index.ts +30 -12
  484. package/src/lib/archive/archive-inspection.fixtures.ts +138 -0
  485. package/src/lib/archive/archive-inspection.ts +359 -0
  486. package/src/lib/archive/index.ts +17 -0
  487. package/src/lib/logger/console.ts +7 -57
  488. package/src/lib/logger/file.ts +28 -50
  489. package/src/lib/logger/index.ts +3 -1
  490. package/src/lib/logger/jsonl.ts +36 -0
  491. package/src/lib/logger/logger.ts +48 -0
  492. package/src/lib/logger/session-log.ts +42 -0
  493. package/src/lib/utils/concurrency.ts +37 -8
  494. package/src/lib/utils/fs-batch.ts +49 -0
  495. package/src/lib/utils/result.ts +7 -31
  496. package/src/lib/utils/sleep.ts +23 -0
  497. package/src/platform/fs-revision.ts +21 -0
  498. package/src/platform/fs.ts +109 -1
  499. package/src/platform/git.ts +67 -0
  500. package/src/platform/index.ts +51 -1
  501. package/src/platform/llm-call-log.ts +86 -0
  502. package/src/platform/scheduler.ts +71 -0
  503. package/src/platform/session-log.ts +39 -0
  504. package/src/platform/shell.ts +89 -0
  505. package/src/plugins/agent-status/plugin.ts +1 -0
  506. package/src/plugins/agents/plugin.ts +134 -81
  507. package/src/plugins/filesystem/listing.ts +70 -12
  508. package/src/plugins/filesystem/plugin.ts +8 -6
  509. package/src/plugins/git-status/plugin.ts +204 -77
  510. package/src/plugins/llm-debug/plugin.ts +1 -0
  511. package/src/plugins/logs/plugin.ts +9 -0
  512. package/src/plugins/mailbox/plugin.ts +46 -64
  513. package/src/plugins/mailbox/query.ts +15 -7
  514. package/src/plugins/mailbox/state.ts +1 -0
  515. package/src/plugins/resources/filename.ts +19 -0
  516. package/src/plugins/resources/plugin.ts +111 -59
  517. package/src/plugins/result-eviction/plugin.ts +6 -1
  518. package/src/plugins/services/plugin.ts +254 -98
  519. package/src/plugins/services/prompt.ts +1 -6
  520. package/src/plugins/services/schema.ts +17 -3
  521. package/src/plugins/services/service.ts +702 -252
  522. package/src/plugins/session-lifecycle/plugin.ts +56 -41
  523. package/src/plugins/session-state/plugin.ts +242 -88
  524. package/src/plugins/session-stats/plugin.ts +1 -0
  525. package/src/plugins/shell/executor.ts +144 -226
  526. package/src/plugins/shell/index.ts +1 -4
  527. package/src/plugins/shell/plugin.ts +7 -9
  528. package/src/plugins/skills/discovery.ts +10 -8
  529. package/src/plugins/skills/index.ts +1 -1
  530. package/src/plugins/skills/plugin.ts +19 -27
  531. package/src/plugins/skills/prompts.ts +3 -3
  532. package/src/plugins/skills/schema.ts +5 -2
  533. package/src/plugins/uploads/plugin.ts +991 -273
  534. package/src/plugins/uploads/preprocessor.ts +25 -0
  535. package/src/plugins/uploads/preprocessors/image-classifier.ts +56 -25
  536. package/src/plugins/uploads/preprocessors/markitdown-preprocessor.ts +41 -15
  537. package/src/plugins/uploads/preprocessors/pdf-preprocessor.ts +32 -16
  538. package/src/plugins/uploads/preprocessors/zip-preprocessor.ts +67 -38
  539. package/src/plugins/uploads/schema.ts +30 -3
  540. package/src/plugins/uploads/state.ts +12 -0
  541. package/src/plugins/user-chat/plugin.ts +196 -40
  542. package/src/plugins/workers/context.ts +102 -39
  543. package/src/plugins/workers/definition.ts +7 -0
  544. package/src/plugins/workers/index.ts +4 -4
  545. package/src/plugins/workers/plugin.ts +461 -151
  546. package/src/plugins/workers/state.ts +64 -0
  547. package/src/plugins/workers/worker.ts +15 -4
  548. package/src/testing/conformance.ts +1751 -0
  549. package/src/testing/node-platform.ts +5 -0
  550. package/src/testing/test-harness.ts +21 -38
  551. package/src/testing/wait-helpers.ts +1 -4
  552. package/src/transport/adapter/client-adapter.ts +60 -3
  553. package/src/transport/adapter/heartbeat.ts +50 -0
  554. package/src/transport/adapter/server-adapter.ts +6 -0
  555. package/src/transport/http/app.ts +7 -35
  556. package/src/transport/http/context.ts +46 -0
  557. package/src/transport/http/fetch-guard.ts +318 -0
  558. package/src/transport/http/index.ts +1 -1
  559. package/src/transport/http/middleware/bearer-auth.ts +1 -1
  560. package/src/transport/http/middleware/error-handler.ts +1 -1
  561. package/src/transport/http/path-containment.ts +44 -0
  562. package/src/transport/http/responses.ts +20 -0
  563. package/src/transport/http/routes/files.ts +69 -159
  564. package/src/transport/http/routes/resources.ts +124 -93
  565. package/src/transport/http/routes/rpc.ts +63 -26
  566. package/src/transport/http/routes/upload.ts +327 -258
  567. package/src/user-config.ts +93 -7
  568. package/dist/config.test.d.ts +0 -2
  569. package/dist/config.test.d.ts.map +0 -1
  570. package/dist/config.test.js +0 -155
  571. package/dist/config.test.js.map +0 -1
  572. package/dist/core/agent-loop.integration.test.d.ts +0 -2
  573. package/dist/core/agent-loop.integration.test.d.ts.map +0 -1
  574. package/dist/core/agent-loop.integration.test.js +0 -414
  575. package/dist/core/agent-loop.integration.test.js.map +0 -1
  576. package/dist/core/agents/agent-config.test.d.ts +0 -2
  577. package/dist/core/agents/agent-config.test.d.ts.map +0 -1
  578. package/dist/core/agents/agent-config.test.js +0 -194
  579. package/dist/core/agents/agent-config.test.js.map +0 -1
  580. package/dist/core/agents/agent-shutdown.test.d.ts +0 -6
  581. package/dist/core/agents/agent-shutdown.test.d.ts.map +0 -1
  582. package/dist/core/agents/agent-shutdown.test.js +0 -180
  583. package/dist/core/agents/agent-shutdown.test.js.map +0 -1
  584. package/dist/core/agents/agent.test.d.ts +0 -2
  585. package/dist/core/agents/agent.test.d.ts.map +0 -1
  586. package/dist/core/agents/agent.test.js +0 -313
  587. package/dist/core/agents/agent.test.js.map +0 -1
  588. package/dist/core/agents/communicator.d.ts +0 -3
  589. package/dist/core/agents/communicator.d.ts.map +0 -1
  590. package/dist/core/agents/communicator.js +0 -13
  591. package/dist/core/agents/communicator.js.map +0 -1
  592. package/dist/core/agents/handler-events.test.d.ts +0 -5
  593. package/dist/core/agents/handler-events.test.d.ts.map +0 -1
  594. package/dist/core/agents/handler-events.test.js +0 -115
  595. package/dist/core/agents/handler-events.test.js.map +0 -1
  596. package/dist/core/agents/response-sanitizer.test.d.ts +0 -2
  597. package/dist/core/agents/response-sanitizer.test.d.ts.map +0 -1
  598. package/dist/core/agents/response-sanitizer.test.js +0 -101
  599. package/dist/core/agents/response-sanitizer.test.js.map +0 -1
  600. package/dist/core/error-recovery.integration.test.d.ts +0 -2
  601. package/dist/core/error-recovery.integration.test.d.ts.map +0 -1
  602. package/dist/core/error-recovery.integration.test.js +0 -288
  603. package/dist/core/error-recovery.integration.test.js.map +0 -1
  604. package/dist/core/event-sourcing.integration.test.d.ts +0 -2
  605. package/dist/core/event-sourcing.integration.test.d.ts.map +0 -1
  606. package/dist/core/event-sourcing.integration.test.js +0 -154
  607. package/dist/core/event-sourcing.integration.test.js.map +0 -1
  608. package/dist/core/events/file.test.d.ts +0 -2
  609. package/dist/core/events/file.test.d.ts.map +0 -1
  610. package/dist/core/events/file.test.js +0 -284
  611. package/dist/core/events/file.test.js.map +0 -1
  612. package/dist/core/events/memory.test.d.ts +0 -2
  613. package/dist/core/events/memory.test.d.ts.map +0 -1
  614. package/dist/core/events/memory.test.js +0 -502
  615. package/dist/core/events/memory.test.js.map +0 -1
  616. package/dist/core/image/image-processor.test.d.ts +0 -2
  617. package/dist/core/image/image-processor.test.d.ts.map +0 -1
  618. package/dist/core/image/image-processor.test.js +0 -171
  619. package/dist/core/image/image-processor.test.js.map +0 -1
  620. package/dist/core/image/vips-resizer.test.d.ts +0 -2
  621. package/dist/core/image/vips-resizer.test.d.ts.map +0 -1
  622. package/dist/core/image/vips-resizer.test.js +0 -336
  623. package/dist/core/image/vips-resizer.test.js.map +0 -1
  624. package/dist/core/llm/anthropic.test.d.ts +0 -2
  625. package/dist/core/llm/anthropic.test.d.ts.map +0 -1
  626. package/dist/core/llm/anthropic.test.js +0 -464
  627. package/dist/core/llm/anthropic.test.js.map +0 -1
  628. package/dist/core/llm/cache-breakpoints.test.d.ts +0 -2
  629. package/dist/core/llm/cache-breakpoints.test.d.ts.map +0 -1
  630. package/dist/core/llm/cache-breakpoints.test.js +0 -69
  631. package/dist/core/llm/cache-breakpoints.test.js.map +0 -1
  632. package/dist/core/llm/cache-live.test.d.ts +0 -16
  633. package/dist/core/llm/cache-live.test.d.ts.map +0 -1
  634. package/dist/core/llm/cache-live.test.js +0 -137
  635. package/dist/core/llm/cache-live.test.js.map +0 -1
  636. package/dist/core/llm/logger.test.d.ts +0 -7
  637. package/dist/core/llm/logger.test.d.ts.map +0 -1
  638. package/dist/core/llm/logger.test.js +0 -228
  639. package/dist/core/llm/logger.test.js.map +0 -1
  640. package/dist/core/llm/message-sanitization.test.d.ts +0 -2
  641. package/dist/core/llm/message-sanitization.test.d.ts.map +0 -1
  642. package/dist/core/llm/message-sanitization.test.js +0 -181
  643. package/dist/core/llm/message-sanitization.test.js.map +0 -1
  644. package/dist/core/llm/mock.test.d.ts +0 -2
  645. package/dist/core/llm/mock.test.d.ts.map +0 -1
  646. package/dist/core/llm/mock.test.js +0 -318
  647. package/dist/core/llm/mock.test.js.map +0 -1
  648. package/dist/core/llm/model-shortlist-live.test.d.ts +0 -35
  649. package/dist/core/llm/model-shortlist-live.test.d.ts.map +0 -1
  650. package/dist/core/llm/model-shortlist-live.test.js +0 -452
  651. package/dist/core/llm/model-shortlist-live.test.js.map +0 -1
  652. package/dist/core/llm/openrouter-mapping.test.d.ts +0 -2
  653. package/dist/core/llm/openrouter-mapping.test.d.ts.map +0 -1
  654. package/dist/core/llm/openrouter-mapping.test.js +0 -190
  655. package/dist/core/llm/openrouter-mapping.test.js.map +0 -1
  656. package/dist/core/llm/openrouter.test.d.ts +0 -2
  657. package/dist/core/llm/openrouter.test.d.ts.map +0 -1
  658. package/dist/core/llm/openrouter.test.js +0 -377
  659. package/dist/core/llm/openrouter.test.js.map +0 -1
  660. package/dist/core/llm/provider-integration.test.d.ts +0 -12
  661. package/dist/core/llm/provider-integration.test.d.ts.map +0 -1
  662. package/dist/core/llm/provider-integration.test.js +0 -350
  663. package/dist/core/llm/provider-integration.test.js.map +0 -1
  664. package/dist/core/llm/reasoning-details.test.d.ts +0 -2
  665. package/dist/core/llm/reasoning-details.test.d.ts.map +0 -1
  666. package/dist/core/llm/reasoning-details.test.js +0 -144
  667. package/dist/core/llm/reasoning-details.test.js.map +0 -1
  668. package/dist/core/llm/routing-provider.test.d.ts +0 -2
  669. package/dist/core/llm/routing-provider.test.d.ts.map +0 -1
  670. package/dist/core/llm/routing-provider.test.js +0 -94
  671. package/dist/core/llm/routing-provider.test.js.map +0 -1
  672. package/dist/core/llm/snapshot-middleware.test.d.ts +0 -2
  673. package/dist/core/llm/snapshot-middleware.test.d.ts.map +0 -1
  674. package/dist/core/llm/snapshot-middleware.test.js +0 -144
  675. package/dist/core/llm/snapshot-middleware.test.js.map +0 -1
  676. package/dist/core/llm/thinking-blocks.test.d.ts +0 -2
  677. package/dist/core/llm/thinking-blocks.test.d.ts.map +0 -1
  678. package/dist/core/llm/thinking-blocks.test.js +0 -291
  679. package/dist/core/llm/thinking-blocks.test.js.map +0 -1
  680. package/dist/core/multi-agent.integration.test.d.ts +0 -2
  681. package/dist/core/multi-agent.integration.test.d.ts.map +0 -1
  682. package/dist/core/multi-agent.integration.test.js +0 -298
  683. package/dist/core/multi-agent.integration.test.js.map +0 -1
  684. package/dist/core/plugin-hooks.integration.test.d.ts +0 -2
  685. package/dist/core/plugin-hooks.integration.test.d.ts.map +0 -1
  686. package/dist/core/plugin-hooks.integration.test.js +0 -458
  687. package/dist/core/plugin-hooks.integration.test.js.map +0 -1
  688. package/dist/core/reasoning-round-trip.integration.test.d.ts +0 -2
  689. package/dist/core/reasoning-round-trip.integration.test.d.ts.map +0 -1
  690. package/dist/core/reasoning-round-trip.integration.test.js +0 -150
  691. package/dist/core/reasoning-round-trip.integration.test.js.map +0 -1
  692. package/dist/core/session-lifecycle.integration.test.d.ts +0 -2
  693. package/dist/core/session-lifecycle.integration.test.d.ts.map +0 -1
  694. package/dist/core/session-lifecycle.integration.test.js +0 -159
  695. package/dist/core/session-lifecycle.integration.test.js.map +0 -1
  696. package/dist/core/sessions/fork-utils.test.d.ts +0 -2
  697. package/dist/core/sessions/fork-utils.test.d.ts.map +0 -1
  698. package/dist/core/sessions/fork-utils.test.js +0 -129
  699. package/dist/core/sessions/fork-utils.test.js.map +0 -1
  700. package/dist/core/sessions/session-overrides.integration.test.d.ts +0 -2
  701. package/dist/core/sessions/session-overrides.integration.test.d.ts.map +0 -1
  702. package/dist/core/sessions/session-overrides.integration.test.js +0 -154
  703. package/dist/core/sessions/session-overrides.integration.test.js.map +0 -1
  704. package/dist/core/sessions/session.test.d.ts +0 -2
  705. package/dist/core/sessions/session.test.d.ts.map +0 -1
  706. package/dist/core/sessions/session.test.js +0 -1100
  707. package/dist/core/sessions/session.test.js.map +0 -1
  708. package/dist/core/tools/executor.test.d.ts +0 -2
  709. package/dist/core/tools/executor.test.d.ts.map +0 -1
  710. package/dist/core/tools/executor.test.js +0 -144
  711. package/dist/core/tools/executor.test.js.map +0 -1
  712. package/dist/lib/logger/console.test.d.ts +0 -2
  713. package/dist/lib/logger/console.test.d.ts.map +0 -1
  714. package/dist/lib/logger/console.test.js +0 -258
  715. package/dist/lib/logger/console.test.js.map +0 -1
  716. package/dist/lib/never.d.ts +0 -2
  717. package/dist/lib/never.d.ts.map +0 -1
  718. package/dist/lib/never.js +0 -4
  719. package/dist/lib/never.js.map +0 -1
  720. package/dist/lib/utils/concurrency.test.d.ts +0 -2
  721. package/dist/lib/utils/concurrency.test.d.ts.map +0 -1
  722. package/dist/lib/utils/concurrency.test.js +0 -135
  723. package/dist/lib/utils/concurrency.test.js.map +0 -1
  724. package/dist/plugins/agent-status/agent-status.test.d.ts +0 -2
  725. package/dist/plugins/agent-status/agent-status.test.d.ts.map +0 -1
  726. package/dist/plugins/agent-status/agent-status.test.js +0 -136
  727. package/dist/plugins/agent-status/agent-status.test.js.map +0 -1
  728. package/dist/plugins/agents/agents.integration.test.d.ts +0 -2
  729. package/dist/plugins/agents/agents.integration.test.d.ts.map +0 -1
  730. package/dist/plugins/agents/agents.integration.test.js +0 -830
  731. package/dist/plugins/agents/agents.integration.test.js.map +0 -1
  732. package/dist/plugins/agents/supervision.integration.test.d.ts +0 -2
  733. package/dist/plugins/agents/supervision.integration.test.d.ts.map +0 -1
  734. package/dist/plugins/agents/supervision.integration.test.js +0 -215
  735. package/dist/plugins/agents/supervision.integration.test.js.map +0 -1
  736. package/dist/plugins/context-compact/compaction-live.test.d.ts +0 -17
  737. package/dist/plugins/context-compact/compaction-live.test.d.ts.map +0 -1
  738. package/dist/plugins/context-compact/compaction-live.test.js +0 -177
  739. package/dist/plugins/context-compact/compaction-live.test.js.map +0 -1
  740. package/dist/plugins/context-compact/context-compact.integration.test.d.ts +0 -2
  741. package/dist/plugins/context-compact/context-compact.integration.test.d.ts.map +0 -1
  742. package/dist/plugins/context-compact/context-compact.integration.test.js +0 -364
  743. package/dist/plugins/context-compact/context-compact.integration.test.js.map +0 -1
  744. package/dist/plugins/context-compact/context-compactor.test.d.ts +0 -2
  745. package/dist/plugins/context-compact/context-compactor.test.d.ts.map +0 -1
  746. package/dist/plugins/context-compact/context-compactor.test.js +0 -858
  747. package/dist/plugins/context-compact/context-compactor.test.js.map +0 -1
  748. package/dist/plugins/context-compact/history-offloader.test.d.ts +0 -2
  749. package/dist/plugins/context-compact/history-offloader.test.d.ts.map +0 -1
  750. package/dist/plugins/context-compact/history-offloader.test.js +0 -77
  751. package/dist/plugins/context-compact/history-offloader.test.js.map +0 -1
  752. package/dist/plugins/filesystem/filesystem.integration.test.d.ts +0 -2
  753. package/dist/plugins/filesystem/filesystem.integration.test.d.ts.map +0 -1
  754. package/dist/plugins/filesystem/filesystem.integration.test.js +0 -447
  755. package/dist/plugins/filesystem/filesystem.integration.test.js.map +0 -1
  756. package/dist/plugins/filesystem/schema.d.ts +0 -7
  757. package/dist/plugins/filesystem/schema.d.ts.map +0 -1
  758. package/dist/plugins/filesystem/schema.js +0 -2
  759. package/dist/plugins/filesystem/schema.js.map +0 -1
  760. package/dist/plugins/limits-guard/limit-guard.test.d.ts +0 -2
  761. package/dist/plugins/limits-guard/limit-guard.test.d.ts.map +0 -1
  762. package/dist/plugins/limits-guard/limit-guard.test.js +0 -194
  763. package/dist/plugins/limits-guard/limit-guard.test.js.map +0 -1
  764. package/dist/plugins/limits-guard/limits-guard.integration.test.d.ts +0 -2
  765. package/dist/plugins/limits-guard/limits-guard.integration.test.d.ts.map +0 -1
  766. package/dist/plugins/limits-guard/limits-guard.integration.test.js +0 -887
  767. package/dist/plugins/limits-guard/limits-guard.integration.test.js.map +0 -1
  768. package/dist/plugins/llm-debug/llm-debug.integration.test.d.ts +0 -2
  769. package/dist/plugins/llm-debug/llm-debug.integration.test.d.ts.map +0 -1
  770. package/dist/plugins/llm-debug/llm-debug.integration.test.js +0 -157
  771. package/dist/plugins/llm-debug/llm-debug.integration.test.js.map +0 -1
  772. package/dist/plugins/mailbox/mailbox.integration.test.d.ts +0 -2
  773. package/dist/plugins/mailbox/mailbox.integration.test.d.ts.map +0 -1
  774. package/dist/plugins/mailbox/mailbox.integration.test.js +0 -678
  775. package/dist/plugins/mailbox/mailbox.integration.test.js.map +0 -1
  776. package/dist/plugins/resources/resources.integration.test.d.ts +0 -2
  777. package/dist/plugins/resources/resources.integration.test.d.ts.map +0 -1
  778. package/dist/plugins/resources/resources.integration.test.js +0 -62
  779. package/dist/plugins/resources/resources.integration.test.js.map +0 -1
  780. package/dist/plugins/result-eviction/result-eviction.integration.test.d.ts +0 -2
  781. package/dist/plugins/result-eviction/result-eviction.integration.test.d.ts.map +0 -1
  782. package/dist/plugins/result-eviction/result-eviction.integration.test.js +0 -294
  783. package/dist/plugins/result-eviction/result-eviction.integration.test.js.map +0 -1
  784. package/dist/plugins/services/pid-registry.test.d.ts +0 -2
  785. package/dist/plugins/services/pid-registry.test.d.ts.map +0 -1
  786. package/dist/plugins/services/pid-registry.test.js +0 -161
  787. package/dist/plugins/services/pid-registry.test.js.map +0 -1
  788. package/dist/plugins/services/services.integration.test.d.ts +0 -2
  789. package/dist/plugins/services/services.integration.test.d.ts.map +0 -1
  790. package/dist/plugins/services/services.integration.test.js +0 -1057
  791. package/dist/plugins/services/services.integration.test.js.map +0 -1
  792. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.d.ts +0 -2
  793. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.d.ts.map +0 -1
  794. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js +0 -498
  795. package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js.map +0 -1
  796. package/dist/plugins/session-stats/plugin.test.d.ts +0 -2
  797. package/dist/plugins/session-stats/plugin.test.d.ts.map +0 -1
  798. package/dist/plugins/session-stats/plugin.test.js +0 -145
  799. package/dist/plugins/session-stats/plugin.test.js.map +0 -1
  800. package/dist/plugins/shell/shell.integration.test.d.ts +0 -2
  801. package/dist/plugins/shell/shell.integration.test.d.ts.map +0 -1
  802. package/dist/plugins/shell/shell.integration.test.js +0 -234
  803. package/dist/plugins/shell/shell.integration.test.js.map +0 -1
  804. package/dist/plugins/shell/shell.test.d.ts +0 -2
  805. package/dist/plugins/shell/shell.test.d.ts.map +0 -1
  806. package/dist/plugins/shell/shell.test.js +0 -236
  807. package/dist/plugins/shell/shell.test.js.map +0 -1
  808. package/dist/plugins/skills/discovery.test.d.ts +0 -2
  809. package/dist/plugins/skills/discovery.test.d.ts.map +0 -1
  810. package/dist/plugins/skills/discovery.test.js +0 -312
  811. package/dist/plugins/skills/discovery.test.js.map +0 -1
  812. package/dist/plugins/skills/skills.integration.test.d.ts +0 -2
  813. package/dist/plugins/skills/skills.integration.test.d.ts.map +0 -1
  814. package/dist/plugins/skills/skills.integration.test.js +0 -475
  815. package/dist/plugins/skills/skills.integration.test.js.map +0 -1
  816. package/dist/plugins/todo/todo.integration.test.d.ts +0 -2
  817. package/dist/plugins/todo/todo.integration.test.d.ts.map +0 -1
  818. package/dist/plugins/todo/todo.integration.test.js +0 -605
  819. package/dist/plugins/todo/todo.integration.test.js.map +0 -1
  820. package/dist/plugins/uploads/preprocessors/image-classifier.test.d.ts +0 -2
  821. package/dist/plugins/uploads/preprocessors/image-classifier.test.d.ts.map +0 -1
  822. package/dist/plugins/uploads/preprocessors/image-classifier.test.js +0 -113
  823. package/dist/plugins/uploads/preprocessors/image-classifier.test.js.map +0 -1
  824. package/dist/plugins/uploads/uploads.integration.test.d.ts +0 -2
  825. package/dist/plugins/uploads/uploads.integration.test.d.ts.map +0 -1
  826. package/dist/plugins/uploads/uploads.integration.test.js +0 -639
  827. package/dist/plugins/uploads/uploads.integration.test.js.map +0 -1
  828. package/dist/plugins/user-chat/user-chat.integration.test.d.ts +0 -2
  829. package/dist/plugins/user-chat/user-chat.integration.test.d.ts.map +0 -1
  830. package/dist/plugins/user-chat/user-chat.integration.test.js +0 -754
  831. package/dist/plugins/user-chat/user-chat.integration.test.js.map +0 -1
  832. package/dist/plugins/workers/workers.integration.test.d.ts +0 -2
  833. package/dist/plugins/workers/workers.integration.test.d.ts.map +0 -1
  834. package/dist/plugins/workers/workers.integration.test.js +0 -629
  835. package/dist/plugins/workers/workers.integration.test.js.map +0 -1
  836. package/dist/prompts/macros.test.d.ts +0 -2
  837. package/dist/prompts/macros.test.d.ts.map +0 -1
  838. package/dist/prompts/macros.test.js +0 -80
  839. package/dist/prompts/macros.test.js.map +0 -1
  840. package/dist/testing/test-harness.test.d.ts +0 -2
  841. package/dist/testing/test-harness.test.d.ts.map +0 -1
  842. package/dist/testing/test-harness.test.js +0 -92
  843. package/dist/testing/test-harness.test.js.map +0 -1
  844. package/dist/transport/http/routes/rpc.integration.test.d.ts +0 -2
  845. package/dist/transport/http/routes/rpc.integration.test.d.ts.map +0 -1
  846. package/dist/transport/http/routes/rpc.integration.test.js +0 -189
  847. package/dist/transport/http/routes/rpc.integration.test.js.map +0 -1
  848. package/dist/transport/http/routes/rpc.test.d.ts +0 -2
  849. package/dist/transport/http/routes/rpc.test.d.ts.map +0 -1
  850. package/dist/transport/http/routes/rpc.test.js +0 -316
  851. package/dist/transport/http/routes/rpc.test.js.map +0 -1
  852. package/src/config.test.ts +0 -174
  853. package/src/core/agent-loop.integration.test.ts +0 -503
  854. package/src/core/agents/agent-config.test.ts +0 -240
  855. package/src/core/agents/agent-shutdown.test.ts +0 -236
  856. package/src/core/agents/agent.test.ts +0 -387
  857. package/src/core/agents/communicator.ts +0 -16
  858. package/src/core/agents/handler-events.test.ts +0 -167
  859. package/src/core/agents/response-sanitizer.test.ts +0 -137
  860. package/src/core/error-recovery.integration.test.ts +0 -343
  861. package/src/core/event-sourcing.integration.test.ts +0 -191
  862. package/src/core/events/file.test.ts +0 -436
  863. package/src/core/events/memory.test.ts +0 -741
  864. package/src/core/image/image-processor.test.ts +0 -218
  865. package/src/core/image/vips-resizer.test.ts +0 -388
  866. package/src/core/llm/anthropic.test.ts +0 -546
  867. package/src/core/llm/cache-breakpoints.test.ts +0 -85
  868. package/src/core/llm/cache-live.test.ts +0 -155
  869. package/src/core/llm/logger.test.ts +0 -270
  870. package/src/core/llm/message-sanitization.test.ts +0 -217
  871. package/src/core/llm/mock.test.ts +0 -402
  872. package/src/core/llm/model-shortlist-live.test.ts +0 -577
  873. package/src/core/llm/openrouter-mapping.test.ts +0 -234
  874. package/src/core/llm/openrouter.test.ts +0 -499
  875. package/src/core/llm/provider-integration.test.ts +0 -408
  876. package/src/core/llm/reasoning-details.test.ts +0 -177
  877. package/src/core/llm/routing-provider.test.ts +0 -113
  878. package/src/core/llm/snapshot-middleware.test.ts +0 -168
  879. package/src/core/llm/thinking-blocks.test.ts +0 -345
  880. package/src/core/multi-agent.integration.test.ts +0 -340
  881. package/src/core/plugin-hooks.integration.test.ts +0 -568
  882. package/src/core/reasoning-round-trip.integration.test.ts +0 -188
  883. package/src/core/session-lifecycle.integration.test.ts +0 -202
  884. package/src/core/sessions/fork-utils.test.ts +0 -158
  885. package/src/core/sessions/session-overrides.integration.test.ts +0 -210
  886. package/src/core/sessions/session.test.ts +0 -1736
  887. package/src/core/tools/executor.test.ts +0 -161
  888. package/src/lib/logger/console.test.ts +0 -348
  889. package/src/lib/never.ts +0 -3
  890. package/src/lib/utils/concurrency.test.ts +0 -169
  891. package/src/plugins/agent-status/agent-status.test.ts +0 -164
  892. package/src/plugins/agents/agents.integration.test.ts +0 -976
  893. package/src/plugins/agents/supervision.integration.test.ts +0 -249
  894. package/src/plugins/context-compact/compaction-live.test.ts +0 -221
  895. package/src/plugins/context-compact/context-compact.integration.test.ts +0 -418
  896. package/src/plugins/context-compact/context-compactor.test.ts +0 -1036
  897. package/src/plugins/context-compact/history-offloader.test.ts +0 -100
  898. package/src/plugins/filesystem/filesystem.integration.test.ts +0 -529
  899. package/src/plugins/filesystem/schema.ts +0 -6
  900. package/src/plugins/limits-guard/limit-guard.test.ts +0 -253
  901. package/src/plugins/limits-guard/limits-guard.integration.test.ts +0 -1012
  902. package/src/plugins/llm-debug/llm-debug.integration.test.ts +0 -192
  903. package/src/plugins/mailbox/mailbox.integration.test.ts +0 -794
  904. package/src/plugins/resources/resources.integration.test.ts +0 -68
  905. package/src/plugins/result-eviction/result-eviction.integration.test.ts +0 -332
  906. package/src/plugins/services/pid-registry.test.ts +0 -180
  907. package/src/plugins/services/services.integration.test.ts +0 -1223
  908. package/src/plugins/session-lifecycle/session-lifecycle.integration.test.ts +0 -639
  909. package/src/plugins/session-stats/plugin.test.ts +0 -160
  910. package/src/plugins/shell/shell.integration.test.ts +0 -273
  911. package/src/plugins/shell/shell.test.ts +0 -314
  912. package/src/plugins/skills/discovery.test.ts +0 -395
  913. package/src/plugins/skills/skills.integration.test.ts +0 -580
  914. package/src/plugins/todo/todo.integration.test.ts +0 -687
  915. package/src/plugins/uploads/preprocessors/image-classifier.test.ts +0 -142
  916. package/src/plugins/uploads/uploads.integration.test.ts +0 -831
  917. package/src/plugins/user-chat/user-chat.integration.test.ts +0 -893
  918. package/src/plugins/workers/workers.integration.test.ts +0 -778
  919. package/src/prompts/macros.test.ts +0 -107
  920. package/src/testing/test-harness.test.ts +0 -114
  921. package/src/transport/http/routes/rpc.integration.test.ts +0 -243
  922. package/src/transport/http/routes/rpc.test.ts +0 -372
@@ -1,8 +1,9 @@
1
1
  import { dirname, join } from 'node:path'
2
2
  import z from 'zod/v4'
3
3
  import type { DomainEvent } from '~/core/events/types.js'
4
- import type { FileSystem } from '~/platform/fs.js'
5
- import { domainEventSchema, SessionId, sessionMetadataSchema } from '~/core/sessions/schema.js'
4
+ import { silentLogger, type Logger } from '~/lib/logger/logger.js'
5
+ import type { Dirent, FileSystem } from '~/platform/fs.js'
6
+ import { domainEventSchema, isValidSessionId, SessionId, sessionMetadataSchema } from '~/core/sessions/schema.js'
6
7
  import type { SessionMetadata } from '~/core/sessions/schema.js'
7
8
  import { BaseEventStore } from './base-event-store.js'
8
9
  import type { LoadRangeOptions, LoadRangeResult } from './event-store.js'
@@ -99,6 +100,40 @@ async function readLastLines(fs: FileSystem, filePath: string, lineCount: number
99
100
  }
100
101
  }
101
102
 
103
+ /** Identity of the meta.json bytes a cached verdict was taken from. */
104
+ interface MetadataSource {
105
+ mtimeMs: number
106
+ size: number
107
+ }
108
+
109
+ /** A parsed record, or the verdict that the bytes it was read from do not parse. */
110
+ type MetadataCacheEntry =
111
+ | { kind: 'record'; record: SessionMetadata }
112
+ | { kind: 'invalid'; source: MetadataSource }
113
+
114
+ function isSameSource(a: MetadataSource, b: MetadataSource): boolean {
115
+ return a.mtimeMs === b.mtimeMs && a.size === b.size
116
+ }
117
+
118
+ function errorCode(error: unknown): string | undefined {
119
+ return error instanceof Error && 'code' in error && typeof error.code === 'string' ? error.code : undefined
120
+ }
121
+
122
+ function isNotFound(error: unknown): boolean {
123
+ return errorCode(error) === 'ENOENT'
124
+ }
125
+
126
+ /** Before the cache every read parsed fresh JSON — keep that, so a mutating caller cannot corrupt it. */
127
+ function copyMetadata(metadata: SessionMetadata | null): SessionMetadata | null {
128
+ if (!metadata) return null
129
+
130
+ const copy: SessionMetadata = { ...metadata }
131
+ if (metadata.metrics) copy.metrics = { ...metadata.metrics }
132
+ if (metadata.tags) copy.tags = [...metadata.tags]
133
+ if (metadata.custom) copy.custom = { ...metadata.custom }
134
+ return copy
135
+ }
136
+
102
137
  /**
103
138
  * FileEventStore - Persists domain events to JSONL files.
104
139
  *
@@ -121,7 +156,28 @@ async function readLastLines(fs: FileSystem, filePath: string, lineCount: number
121
156
  export class FileEventStore extends BaseEventStore {
122
157
  private readonly sessionLocks = new Map<SessionId, AsyncMutex>()
123
158
 
124
- constructor(private readonly basePath: string, private readonly fs: FileSystem) {
159
+ /**
160
+ * Parsed meta.json per session, so a `/status` poll costs one readdir instead of
161
+ * one readFile per session directory that ever existed. An `invalid` entry records
162
+ * bytes that exist but do not parse, so a corrupt record is reported once rather
163
+ * than once per poll, and is re-read as soon as those bytes change.
164
+ *
165
+ * Coherence rule: writes win. writeMetadata is the only writer, and a read stores
166
+ * its result only if the entry did not move while the read was in flight — a read
167
+ * is a snapshot of older bytes, so it must never overwrite a newer write. A full
168
+ * listing prunes the map to the readdir set, which keeps deletion and out-of-band
169
+ * creation self-healing.
170
+ */
171
+ private readonly metadataCache = new Map<SessionId, MetadataCacheEntry>()
172
+
173
+ /** Last reported read failure per session, so a permanent EACCES is not logged on every poll. */
174
+ private readonly reportedReadFailures = new Map<SessionId, string>()
175
+
176
+ constructor(
177
+ private readonly basePath: string,
178
+ private readonly fs: FileSystem,
179
+ private readonly logger: Logger = silentLogger,
180
+ ) {
125
181
  super()
126
182
  }
127
183
 
@@ -242,11 +298,12 @@ export class FileEventStore extends BaseEventStore {
242
298
 
243
299
  try {
244
300
  const entries = await this.fs.readdir(sessionsDir, { withFileTypes: true })
301
+ // A directory whose name is not a valid id is not a session — the metadata listing drops it too.
245
302
  return entries
246
- .filter((entry) => entry.isDirectory())
247
- .map((entry) => entry.name as SessionId)
303
+ .filter((entry) => entry.isDirectory() && isValidSessionId(entry.name))
304
+ .map((entry) => SessionId(entry.name))
248
305
  } catch (error) {
249
- if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
306
+ if (isNotFound(error)) {
250
307
  return []
251
308
  }
252
309
  throw error
@@ -326,47 +383,166 @@ export class FileEventStore extends BaseEventStore {
326
383
  // =========================================================================
327
384
 
328
385
  protected async readMetadata(sessionId: SessionId): Promise<SessionMetadata | null> {
386
+ const cached = this.metadataCache.get(sessionId)
387
+ if (cached?.kind === 'record') return copyMetadata(cached.record)
388
+
329
389
  const path = this.getMetaPath(sessionId)
330
390
 
331
391
  try {
392
+ // Stat before the read, so a verdict is never keyed to bytes newer than the ones it judged.
393
+ const source = await this.readMetadataSource(path)
394
+ // A rejected record stays rejected only for the bytes that were rejected, so a repair is picked up.
395
+ if (cached && isSameSource(cached.source, source)) return null
396
+
332
397
  const content = await this.fs.readFile(path, 'utf-8')
333
- const parsed = JSON.parse(content)
334
- const validated = sessionMetadataSchema.parse(parsed)
335
- return validated as SessionMetadata
398
+ const record = this.parseMetadata(sessionId, content)
399
+ this.reportedReadFailures.delete(sessionId)
400
+
401
+ return copyMetadata(
402
+ this.commitRead(sessionId, cached, record ? { kind: 'record', record } : { kind: 'invalid', source }),
403
+ )
336
404
  } catch (error) {
337
- if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
405
+ if (isNotFound(error)) {
406
+ // A missing file is never cached — unknown ids must not be able to grow the map.
338
407
  return null
339
408
  }
409
+ this.reportReadFailure(sessionId, error)
340
410
  throw error
341
411
  }
342
412
  }
343
413
 
414
+ /**
415
+ * Cache what the read found, unless a write landed while it was in flight.
416
+ *
417
+ * A read only ever sees the bytes it started from, so the concurrent writer holds the
418
+ * newer record and the reader reports that one instead of overwriting it with its own.
419
+ */
420
+ private commitRead(
421
+ sessionId: SessionId,
422
+ before: MetadataCacheEntry | undefined,
423
+ entry: MetadataCacheEntry,
424
+ ): SessionMetadata | null {
425
+ const current = this.metadataCache.get(sessionId)
426
+ if (current !== before) return current?.kind === 'record' ? current.record : null
427
+
428
+ this.metadataCache.set(sessionId, entry)
429
+ return entry.kind === 'record' ? entry.record : null
430
+ }
431
+
432
+ private async readMetadataSource(path: string): Promise<MetadataSource> {
433
+ const stats = await this.fs.stat(path)
434
+ return { mtimeMs: stats.mtimeMs, size: stats.size }
435
+ }
436
+
437
+ /** Reports a read that failed for anything but a missing file, once per failure kind. */
438
+ private reportReadFailure(sessionId: SessionId, error: unknown): void {
439
+ const code = errorCode(error) ?? 'unknown'
440
+ if (this.reportedReadFailures.get(sessionId) === code) return
441
+
442
+ this.reportedReadFailures.set(sessionId, code)
443
+ this.logger.error(
444
+ 'Failed to read session metadata',
445
+ error instanceof Error ? error : new Error(String(error)),
446
+ { sessionId },
447
+ )
448
+ }
449
+
450
+ /**
451
+ * Strict on write, tolerant on read.
452
+ *
453
+ * meta.json is written non-atomically and its schema tightened over time, so a
454
+ * single truncated or legacy record must not take the whole listing down with it.
455
+ */
456
+ private parseMetadata(sessionId: SessionId, content: string): SessionMetadata | null {
457
+ let raw: unknown
458
+ try {
459
+ raw = JSON.parse(content)
460
+ } catch (error) {
461
+ this.logger.warn('Skipping unreadable session metadata', { sessionId, reason: String(error) })
462
+ return null
463
+ }
464
+
465
+ const parsed = sessionMetadataSchema.safeParse(raw)
466
+ if (!parsed.success) {
467
+ this.logger.warn('Skipping invalid session metadata', { sessionId, reason: parsed.error.message })
468
+ return null
469
+ }
470
+
471
+ return parsed.data
472
+ }
473
+
344
474
  protected async writeMetadata(sessionId: SessionId, metadata: SessionMetadata): Promise<void> {
345
475
  const path = this.getMetaPath(sessionId)
346
476
  await this.fs.mkdir(dirname(path), { recursive: true })
347
477
  await this.fs.writeFile(path, JSON.stringify(metadata, null, 2))
478
+
479
+ // The cache may only hold what a read would return, so the record goes in through the same schema.
480
+ const parsed = sessionMetadataSchema.safeParse(metadata)
481
+ if (!parsed.success) {
482
+ this.logger.warn('Not caching invalid session metadata', { sessionId, reason: parsed.error.message })
483
+ this.metadataCache.delete(sessionId)
484
+ return
485
+ }
486
+
487
+ // Cached only once the write lands, so a failed write leaves no phantom value.
488
+ this.metadataCache.set(sessionId, { kind: 'record', record: parsed.data })
489
+ this.reportedReadFailures.delete(sessionId)
348
490
  }
349
491
 
350
492
  protected async getAllSessionMetadata(): Promise<SessionMetadata[]> {
351
493
  const sessionsDir = join(this.basePath, 'sessions')
352
494
 
495
+ let entries: Dirent[]
353
496
  try {
354
- const entries = await this.fs.readdir(sessionsDir, { withFileTypes: true })
355
- const sessions: SessionMetadata[] = []
356
-
357
- for (const entry of entries) {
358
- if (!entry.isDirectory()) continue
359
-
360
- const metadata = await this.readMetadata(entry.name as SessionId)
361
- if (metadata) sessions.push(metadata)
362
- }
363
-
364
- return sessions
497
+ entries = await this.fs.readdir(sessionsDir, { withFileTypes: true })
365
498
  } catch (error) {
366
- if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
499
+ if (isNotFound(error)) {
500
+ // The data root is gone, so every session cached from it is gone with it.
501
+ this.forgetAll()
367
502
  return []
368
503
  }
369
504
  throw error
370
505
  }
506
+
507
+ const sessions: SessionMetadata[] = []
508
+ const present = new Set<SessionId>()
509
+
510
+ for (const entry of entries) {
511
+ if (!entry.isDirectory()) continue
512
+
513
+ const sessionId = SessionId(entry.name)
514
+ present.add(sessionId)
515
+
516
+ const metadata = await this.readMetadataOrSkip(sessionId)
517
+ if (metadata) sessions.push(metadata)
518
+ }
519
+
520
+ // The directory listing is the only thing that can remove a session, so prune here.
521
+ this.forgetMissing(present)
522
+
523
+ return sessions
524
+ }
525
+
526
+ /** One unreadable session must not take the listing down for every other one. */
527
+ private async readMetadataOrSkip(sessionId: SessionId): Promise<SessionMetadata | null> {
528
+ try {
529
+ return await this.readMetadata(sessionId)
530
+ } catch {
531
+ return null // already reported by readMetadata
532
+ }
533
+ }
534
+
535
+ private forgetMissing(present: Set<SessionId>): void {
536
+ for (const sessionId of this.metadataCache.keys()) {
537
+ if (!present.has(sessionId)) this.metadataCache.delete(sessionId)
538
+ }
539
+ for (const sessionId of this.reportedReadFailures.keys()) {
540
+ if (!present.has(sessionId)) this.reportedReadFailures.delete(sessionId)
541
+ }
542
+ }
543
+
544
+ private forgetAll(): void {
545
+ this.metadataCache.clear()
546
+ this.reportedReadFailures.clear()
371
547
  }
372
548
  }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Containment check for paths that are about to be handed to the filesystem.
3
+ *
4
+ * A lexical check (`resolve()` then a prefix compare) only sees the path string,
5
+ * so a link inside a root can still point anywhere the process can reach. Both
6
+ * ends are canonicalized here instead. Links are not banned — one whose target
7
+ * lands back inside a root stays usable.
8
+ */
9
+
10
+ import { basename, dirname, isAbsolute, join, relative, sep } from 'node:path'
11
+ import type { FileSystem } from '~/platform/fs.js'
12
+
13
+ /**
14
+ * Where a path's real target sits.
15
+ *
16
+ * `unresolvable` is a path that exists but cannot be canonicalized — a link with
17
+ * no target, a link loop. Only an operation that would create through it has to
18
+ * refuse; the ones that merely follow it fail on their own.
19
+ */
20
+ export type Containment = 'inside' | 'outside' | 'unresolvable'
21
+
22
+ export async function containmentOf(
23
+ fs: FileSystem,
24
+ roots: readonly string[],
25
+ path: string,
26
+ ): Promise<Containment> {
27
+ // A path that is one of its own roots is inside it whatever it resolves to.
28
+ if (roots.includes(path)) return 'inside'
29
+
30
+ const target = await canonicalize(fs, path)
31
+ if (target === null) return 'unresolvable'
32
+
33
+ for (const root of roots) {
34
+ const canonicalRoot = await canonicalize(fs, root)
35
+ if (canonicalRoot !== null && isUnder(canonicalRoot, target)) return 'inside'
36
+ }
37
+ return 'outside'
38
+ }
39
+
40
+ function isUnder(root: string, target: string): boolean {
41
+ const rel = relative(root, target)
42
+ return rel === '' || (!isAbsolute(rel) && rel !== '..' && !rel.startsWith(`..${sep}`))
43
+ }
44
+
45
+ /**
46
+ * Canonical form of `path`, resolving through its deepest existing ancestor so
47
+ * a not-yet-created file is judged by the directory it would land in.
48
+ * Null when a component exists but cannot be resolved.
49
+ */
50
+ async function canonicalize(fs: FileSystem, path: string): Promise<string | null> {
51
+ const missing: string[] = []
52
+ let current = path
53
+ for (;;) {
54
+ try {
55
+ const real = await fs.realpath(current)
56
+ return missing.length > 0 ? join(real, ...missing) : real
57
+ } catch {
58
+ if (await entryExists(fs, current)) return null
59
+ const parent = dirname(current)
60
+ if (parent === current) return null
61
+ missing.unshift(basename(current))
62
+ current = parent
63
+ }
64
+ }
65
+ }
66
+
67
+ /** Anything `lstat` rejects counts as absent, an unreadable parent included — the caller's own operation then reports it. */
68
+ async function entryExists(fs: FileSystem, path: string): Promise<boolean> {
69
+ try {
70
+ await fs.lstat(path)
71
+ return true
72
+ } catch {
73
+ return false
74
+ }
75
+ }
@@ -5,6 +5,11 @@
5
5
  * validation, agent-visible path mapping). Replaces the separate path-resolver
6
6
  * functions for FileStore consumers.
7
7
  *
8
+ * Every operation resolves the path lexically and then checks that its real
9
+ * target is still inside the area the store may touch — session and workspace
10
+ * together, or whatever root a `scoped()` sub-store was carved out of. Links
11
+ * are not banned: one whose target lands back inside stays usable.
12
+ *
8
13
  * Three scopes:
9
14
  * - 'full': accepts agent-visible paths (/home/user/session/... or real paths)
10
15
  * - 'session': paths relative to sessionDir
@@ -12,8 +17,9 @@
12
17
  */
13
18
 
14
19
  import { dirname, join, normalize, resolve } from 'node:path'
20
+ import { containmentOf } from '~/core/file-store/containment.js'
15
21
  import type { FileEntry, FileStore } from '~/core/file-store/types.js'
16
- import type { FileSystem } from '~/platform/fs.js'
22
+ import type { FileSystem, WalkEntry } from '~/platform/fs.js'
17
23
  import { Err, Ok } from '~/lib/utils/result.js'
18
24
  import type { Result } from '~/lib/utils/result.js'
19
25
 
@@ -23,6 +29,19 @@ const VIRTUAL_WORKSPACE = '/home/user/workspace'
23
29
 
24
30
  type FileStoreScope = 'full' | 'session' | 'workspace'
25
31
 
32
+ /** A lexically resolved path plus the roots its real target must stay inside. */
33
+ interface ResolvedPath {
34
+ absolute: string
35
+ roots: readonly string[]
36
+ }
37
+
38
+ /**
39
+ * What the operation does with the final link, which decides what an
40
+ * unresolvable one means: `follow` leaves it to the operation, `create` refuses
41
+ * it because writing would create the target, `entry` checks the parent instead.
42
+ */
43
+ type ContainmentMode = 'follow' | 'create' | 'entry'
44
+
26
45
  export class SessionFileStore implements FileStore {
27
46
  constructor(
28
47
  private readonly sessionDir: string,
@@ -30,25 +49,31 @@ export class SessionFileStore implements FileStore {
30
49
  private readonly sandboxed: boolean,
31
50
  private readonly fs: FileSystem,
32
51
  private readonly scope: FileStoreScope = 'full',
52
+ /** Set by `scoped()` so a sub-store cannot escape the roots it was carved out of. */
53
+ private readonly containmentRoots?: readonly string[],
33
54
  ) {}
34
55
 
35
56
  /** Create a session-scoped FileStore (relative paths → sessionDir) */
36
57
  get session(): SessionFileStore {
37
- return new SessionFileStore(this.sessionDir, this.workspaceDir, this.sandboxed, this.fs, 'session')
58
+ return new SessionFileStore(this.sessionDir, this.workspaceDir, this.sandboxed, this.fs, 'session', this.containmentRoots)
38
59
  }
39
60
 
40
61
  /** Create a workspace-scoped FileStore (relative paths → workspaceDir), or undefined if no workspace */
41
62
  get workspace(): SessionFileStore | undefined {
42
63
  if (!this.workspaceDir) return undefined
43
- return new SessionFileStore(this.sessionDir, this.workspaceDir, this.sandboxed, this.fs, 'workspace')
64
+ return new SessionFileStore(this.sessionDir, this.workspaceDir, this.sandboxed, this.fs, 'workspace', this.containmentRoots)
44
65
  }
45
66
 
46
67
  async write(path: string, content: string | Buffer): Promise<Result<{ path: string }, string>> {
47
- const resolved = this.resolvePath(path)
68
+ const resolved = await this.resolveContained(path, 'create')
48
69
  if (!resolved.ok) return resolved
49
70
 
50
- await this.fs.mkdir(dirname(resolved.value), { recursive: true })
51
- await this.fs.writeFile(resolved.value, content)
71
+ try {
72
+ await this.fs.mkdir(dirname(resolved.value), { recursive: true })
73
+ await this.fs.writeFile(resolved.value, content)
74
+ } catch {
75
+ return Err(`Failed to write: ${path}`)
76
+ }
52
77
 
53
78
  return Ok({ path: this.toAgentPath(resolved.value) })
54
79
  }
@@ -56,7 +81,7 @@ export class SessionFileStore implements FileStore {
56
81
  async read(path: string): Promise<Result<string, string>>
57
82
  async read(path: string, opts: { type: 'buffer' }): Promise<Result<Buffer, string>>
58
83
  async read(path: string, opts?: { type: 'buffer' }): Promise<Result<string | Buffer, string>> {
59
- const resolved = this.resolvePath(path)
84
+ const resolved = await this.resolveContained(path, 'follow')
60
85
  if (!resolved.ok) return resolved
61
86
 
62
87
  try {
@@ -70,21 +95,22 @@ export class SessionFileStore implements FileStore {
70
95
  }
71
96
 
72
97
  async exists(path: string): Promise<Result<boolean, string>> {
73
- const resolved = this.resolvePath(path)
98
+ const resolved = await this.resolveContained(path, 'follow')
74
99
  if (!resolved.ok) return resolved
75
100
 
76
101
  return Ok(await this.fs.exists(resolved.value))
77
102
  }
78
103
 
79
104
  async stat(path: string): Promise<Result<FileEntry, string>> {
80
- const resolved = this.resolvePath(path)
105
+ const resolved = await this.resolveContained(path, 'follow')
81
106
  if (!resolved.ok) return resolved
82
107
 
83
108
  try {
109
+ // `stat` follows links on purpose — a link to a file inside the root is a file here.
84
110
  const s = await this.fs.stat(resolved.value)
85
111
  return Ok({
86
112
  size: s.size,
87
- type: s.isFile() ? 'file' : s.isDirectory() ? 'directory' : s.isSymbolicLink() ? 'symlink' : 'other',
113
+ type: s.isFile() ? 'file' : s.isDirectory() ? 'directory' : 'other',
88
114
  name: resolved.value.split('/').pop() || '',
89
115
  })
90
116
  } catch {
@@ -96,15 +122,24 @@ export class SessionFileStore implements FileStore {
96
122
  path: string,
97
123
  options?: { maxDepth?: number; gitIgnore?: boolean },
98
124
  ): Promise<Result<FileEntry[], string>> {
99
- const resolved = this.resolvePath(path)
125
+ const resolved = await this.resolveContained(path, 'follow')
100
126
  if (!resolved.ok) return resolved
101
127
 
102
128
  const maxDepth = options?.maxDepth ?? 1
103
129
  if (maxDepth < 1) return Ok([])
104
130
 
105
131
  try {
132
+ // A readdir plus a stat per file is one question asked in pieces. Where
133
+ // the platform takes it whole, ask it whole.
134
+ if (this.fs.walk) {
135
+ const base = resolved.value
136
+ const found = await this.fs.walk(base, { depth: maxDepth })
137
+ return Ok(found.map((entry) => toFileEntry(entry, base)))
138
+ }
139
+
106
140
  const entries: FileEntry[] = []
107
- await this.walkInto(resolved.value, '', maxDepth, entries)
141
+ const readAll = (): Promise<void> => this.walkInto(resolved.value, '', maxDepth, entries)
142
+ await (this.fs.scopeReads ? this.fs.scopeReads(readAll) : readAll())
108
143
  return Ok(entries)
109
144
  } catch {
110
145
  return Err(`Directory not found: ${path}`)
@@ -142,7 +177,7 @@ export class SessionFileStore implements FileStore {
142
177
  }
143
178
 
144
179
  async remove(path: string): Promise<Result<void, string>> {
145
- const resolved = this.resolvePath(path)
180
+ const resolved = await this.resolveContained(path, 'entry')
146
181
  if (!resolved.ok) return resolved
147
182
 
148
183
  try {
@@ -166,24 +201,60 @@ export class SessionFileStore implements FileStore {
166
201
  }
167
202
  }
168
203
 
204
+ /** Lexical resolution only — despite the name it never follows a symlink. See FileStore.realPath. */
169
205
  realPath(path: string): Result<string, string> {
170
- return this.resolvePath(path)
206
+ const resolved = this.resolveScoped(path)
207
+ return resolved.ok ? Ok(resolved.value.absolute) : resolved
171
208
  }
172
209
 
210
+ /** See FileStore.containedPath. */
211
+ containedPath(path: string): Promise<Result<string, string>> {
212
+ return this.resolveContained(path, 'create')
213
+ }
214
+
215
+ /** Throws on a path it cannot resolve — never hand it unvalidated request data; use `realPath` there. */
173
216
  scoped(basePath: string): SessionFileStore {
174
217
  // Resolve basePath relative to current scope
175
- const resolved = this.resolvePath(basePath)
218
+ const resolved = this.resolveScoped(basePath)
176
219
  if (!resolved.ok) {
177
220
  throw new Error(`Cannot scope to invalid path: ${basePath}`)
178
221
  }
179
- return new SessionFileStore(resolved.value, undefined, false, this.fs, 'session')
222
+ return new SessionFileStore(resolved.value.absolute, undefined, false, this.fs, 'session', resolved.value.roots)
180
223
  }
181
224
 
182
225
  // ============================================================================
183
226
  // Path resolution
184
227
  // ============================================================================
185
228
 
186
- private resolvePath(path: string): Result<string, string> {
229
+ /**
230
+ * Lexical resolution, plus a check that the real target has not left the roots.
231
+ * `mode` says what the operation does with the final link — see ContainmentMode.
232
+ */
233
+ private async resolveContained(path: string, mode: ContainmentMode): Promise<Result<string, string>> {
234
+ const resolved = this.resolveScoped(path)
235
+ if (!resolved.ok) return resolved
236
+
237
+ const { absolute, roots } = resolved.value
238
+ const subject = mode === 'entry' ? dirname(absolute) : absolute
239
+ switch (await containmentOf(this.fs, roots, subject)) {
240
+ case 'outside':
241
+ return Err(`Path '${path}' resolves outside allowed directories`)
242
+ case 'unresolvable':
243
+ return mode === 'create' ? Err(`Path '${path}' cannot be resolved`) : Ok(absolute)
244
+ case 'inside':
245
+ return Ok(absolute)
246
+ }
247
+ }
248
+
249
+ /** The area this store may touch — both roots where a workspace is configured. */
250
+ private allowedRoots(): readonly string[] {
251
+ if (this.containmentRoots) return this.containmentRoots
252
+ const roots = [resolve(this.sessionDir)]
253
+ if (this.workspaceDir) roots.push(resolve(this.workspaceDir))
254
+ return roots
255
+ }
256
+
257
+ private resolveScoped(path: string): Result<ResolvedPath, string> {
187
258
  switch (this.scope) {
188
259
  case 'full':
189
260
  return this.resolveAgentPath(path)
@@ -196,7 +267,7 @@ export class SessionFileStore implements FileStore {
196
267
  }
197
268
 
198
269
  /** Resolve a relative path within a root directory */
199
- private resolveRelativePath(path: string, rootDir: string): Result<string, string> {
270
+ private resolveRelativePath(path: string, rootDir: string): Result<ResolvedPath, string> {
200
271
  const normalized = normalize(path)
201
272
  if (normalized.startsWith('..') || normalized.startsWith('/')) {
202
273
  return Err(`Path traversal not allowed: ${path}`)
@@ -205,18 +276,18 @@ export class SessionFileStore implements FileStore {
205
276
  if (!absolute.startsWith(rootDir)) {
206
277
  return Err(`Path traversal not allowed: ${path}`)
207
278
  }
208
- return Ok(absolute)
279
+ return Ok({ absolute, roots: this.allowedRoots() })
209
280
  }
210
281
 
211
282
  /** Resolve an agent-visible path to real filesystem path (handles sandboxed virtual paths) */
212
- private resolveAgentPath(agentPath: string): Result<string, string> {
283
+ private resolveAgentPath(agentPath: string): Result<ResolvedPath, string> {
213
284
  if (this.sandboxed) {
214
285
  return this.resolveSandboxedPath(agentPath)
215
286
  }
216
287
  return this.resolveNonSandboxedPath(agentPath)
217
288
  }
218
289
 
219
- private resolveSandboxedPath(agentPath: string): Result<string, string> {
290
+ private resolveSandboxedPath(agentPath: string): Result<ResolvedPath, string> {
220
291
  if (agentPath.startsWith(VIRTUAL_SESSION + '/') || agentPath === VIRTUAL_SESSION) {
221
292
  const relative = agentPath.slice(VIRTUAL_SESSION.length)
222
293
  const absolutePath = resolve(this.sessionDir, relative.slice(1) || '.')
@@ -239,7 +310,7 @@ export class SessionFileStore implements FileStore {
239
310
  return Err(`Path must start with ${validPrefixes}. Got: '${agentPath}'`)
240
311
  }
241
312
 
242
- private resolveNonSandboxedPath(agentPath: string): Result<string, string> {
313
+ private resolveNonSandboxedPath(agentPath: string): Result<ResolvedPath, string> {
243
314
  const absolutePath = resolve(agentPath)
244
315
  const normalizedSession = resolve(this.sessionDir)
245
316
  const normalizedWorkspace = this.workspaceDir ? resolve(this.workspaceDir) : null
@@ -252,10 +323,10 @@ export class SessionFileStore implements FileStore {
252
323
  return Err(`Path '${agentPath}' is outside allowed directories`)
253
324
  }
254
325
 
255
- return Ok(absolutePath)
326
+ return Ok({ absolute: absolutePath, roots: this.allowedRoots() })
256
327
  }
257
328
 
258
- private validateWithinRoot(absolutePath: string, rootDir: string, originalPath: string): Result<string, string> {
329
+ private validateWithinRoot(absolutePath: string, rootDir: string, originalPath: string): Result<ResolvedPath, string> {
259
330
  const normalizedRoot = resolve(rootDir)
260
331
  const isWithin = absolutePath === normalizedRoot || absolutePath.startsWith(normalizedRoot + '/')
261
332
 
@@ -263,7 +334,7 @@ export class SessionFileStore implements FileStore {
263
334
  return Err(`Path '${originalPath}' resolves outside allowed directories`)
264
335
  }
265
336
 
266
- return Ok(absolutePath)
337
+ return Ok({ absolute: absolutePath, roots: this.allowedRoots() })
267
338
  }
268
339
 
269
340
  // ============================================================================
@@ -293,3 +364,13 @@ export class SessionFileStore implements FileStore {
293
364
  return realPath
294
365
  }
295
366
  }
367
+
368
+ /** A walked entry as the store reports it: name relative to the listed directory. */
369
+ function toFileEntry(entry: WalkEntry, baseDir: string): FileEntry {
370
+ const prefixLength = baseDir.endsWith('/') ? baseDir.length : baseDir.length + 1
371
+ return {
372
+ name: entry.path.slice(prefixLength),
373
+ type: entry.type,
374
+ size: entry.type === 'file' ? entry.size : undefined,
375
+ }
376
+ }
@@ -39,9 +39,22 @@ export interface FileStore {
39
39
  /** Remove a file. */
40
40
  remove(path: string): Promise<Result<void, string>>
41
41
 
42
- /** Resolve an agent-visible path to real filesystem path. */
42
+ /**
43
+ * Resolve an agent-visible path to a real filesystem path, lexically.
44
+ *
45
+ * Does not follow symlinks, so it cannot decide containment on its own. Use
46
+ * it only where the path is never handed to the filesystem — everything that
47
+ * goes on to read, write or spawn wants `containedPath` instead.
48
+ */
43
49
  realPath(path: string): Result<string, string>
44
50
 
51
+ /**
52
+ * Resolve to a real filesystem path, refusing one whose real target leaves
53
+ * the store's roots. What a caller that reaches the filesystem itself, rather
54
+ * than through this store, should ask for.
55
+ */
56
+ containedPath(path: string): Promise<Result<string, string>>
57
+
45
58
  /** Get the agent-visible root paths (virtual when sandboxed, real otherwise) */
46
59
  getRoots(): { session: string; workspace?: string }
47
60
 
@@ -80,7 +80,9 @@ export class DefaultImageProcessor implements ImageProcessor {
80
80
  return { type: 'text', text: `[Image unavailable: ${path} - unsupported format]` }
81
81
  }
82
82
 
83
- const resolved = fileStore.realPath(path)
83
+ // Not `realPath`: the URL comes back from conversation history, and what it
84
+ // names may have become a link out of the store since it was first read.
85
+ const resolved = await fileStore.containedPath(path)
84
86
  if (!resolved.ok) {
85
87
  return { type: 'text', text: `[Image unavailable: ${path} - ${resolved.error}]` }
86
88
  }