@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,1057 +0,0 @@
1
- import { afterEach, describe, expect, it } from 'bun:test';
2
- import { mkdir, mkdtemp, readFile, rm } from 'node:fs/promises';
3
- import { tmpdir } from 'node:os';
4
- import { join } from 'node:path';
5
- import { MemoryEventStore } from '../../core/events/memory.js';
6
- import { MockLLMProvider } from '../../core/llm/mock.js';
7
- import { selectPluginState } from '../../core/sessions/reducer.js';
8
- import { SessionId } from '../../core/sessions/schema.js';
9
- import { ToolCallId } from '../../core/tools/schema.js';
10
- import { silentLogger } from '../../lib/logger/logger.js';
11
- import { createNodePlatform } from '../../testing/node-platform.js';
12
- import { createTestPreset, TestHarness } from '../../testing/index.js';
13
- import { serviceEvents, servicePlugin } from './plugin.js';
14
- import { PortPool } from './port-pool.js';
15
- import { buildServiceStatusMessage } from './prompt.js';
16
- import { ServiceExecutor } from './service.js';
17
- // ============================================================================
18
- // Test Service Configs
19
- // ============================================================================
20
- const quickService = {
21
- type: 'quick',
22
- description: 'Quick service that becomes ready immediately',
23
- command: 'echo "service output" && sleep 60',
24
- };
25
- const readyPatternService = {
26
- type: 'ready-service',
27
- description: 'Service with ready pattern',
28
- command: 'echo "Listening READY" && sleep 60',
29
- readyPattern: 'READY',
30
- };
31
- const commandCallbackService = {
32
- type: 'callback-service',
33
- description: 'Service with command callback that uses allocated port',
34
- command: ({ port }) => `echo "Server on port ${port}" && sleep 60`,
35
- readyPattern: 'Server on port',
36
- };
37
- const failingService = {
38
- type: 'failing',
39
- description: 'Service that exits immediately',
40
- command: 'exit 1',
41
- };
42
- const autoStartService = {
43
- type: 'auto-start',
44
- description: 'Auto-starting service',
45
- command: 'sleep 60',
46
- autoStart: true,
47
- };
48
- // ============================================================================
49
- // Helpers
50
- // ============================================================================
51
- let currentHarness;
52
- afterEach(async () => {
53
- if (currentHarness) {
54
- await currentHarness.shutdown();
55
- currentHarness = undefined;
56
- }
57
- });
58
- function createServicesPreset(services, agentServices, portPool, overrides) {
59
- return createTestPreset({
60
- ...overrides,
61
- plugins: [
62
- servicePlugin.configure({ services, portPool }),
63
- ...(overrides?.plugins ?? []),
64
- ],
65
- orchestratorPlugins: [
66
- servicePlugin.configureAgent({ services: agentServices }),
67
- ...(overrides?.orchestratorPlugins ?? []),
68
- ],
69
- });
70
- }
71
- function createServicesHarness(options) {
72
- const harness = new TestHarness({ ...options, systemPlugins: [servicePlugin] });
73
- currentHarness = harness;
74
- return harness;
75
- }
76
- /** Wait for a service status change event of a specific type */
77
- async function waitForServiceStatus(session, serviceType, targetStatus, timeoutMs = 5000) {
78
- const deadline = Date.now() + timeoutMs;
79
- while (Date.now() < deadline) {
80
- const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
81
- if (events.some((e) => e.serviceType === serviceType && e.toStatus === targetStatus)) {
82
- return;
83
- }
84
- await new Promise((r) => setTimeout(r, 50));
85
- }
86
- }
87
- /** Wait for the services plugin state slice to reflect a given status for a serviceType */
88
- async function waitForServiceStateStatus(session, serviceType, targetStatus, timeoutMs = 5000) {
89
- const deadline = Date.now() + timeoutMs;
90
- while (Date.now() < deadline) {
91
- const entry = selectPluginState(session.state, 'services')?.get(serviceType);
92
- if (entry?.status === targetStatus)
93
- return;
94
- await new Promise((r) => setTimeout(r, 20));
95
- }
96
- }
97
- // ============================================================================
98
- // Tests
99
- // ============================================================================
100
- describe('services plugin', () => {
101
- // =========================================================================
102
- // Service lifecycle via methods
103
- // =========================================================================
104
- describe('service lifecycle via methods', () => {
105
- it('start → status_changed events (starting, ready) → state updated', async () => {
106
- const portPool = new PortPool();
107
- const harness = createServicesHarness({
108
- presets: [createServicesPreset([quickService], ['quick'], portPool)],
109
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
110
- });
111
- const session = await harness.createSession('test');
112
- await session.sendAndWaitForIdle('Hi');
113
- const entryAgentId = session.getEntryAgentId();
114
- const result = await session.callPluginMethod('services.start', {
115
- sessionId: String(session.sessionId),
116
- agentId: String(entryAgentId),
117
- serviceType: 'quick',
118
- });
119
- expect(result.ok).toBe(true);
120
- // Wait for ready (no readyPattern = immediately ready)
121
- await waitForServiceStatus(session, 'quick', 'ready');
122
- const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
123
- const quickEvents = events.filter((e) => e.serviceType === 'quick');
124
- const statuses = quickEvents.map((e) => e.toStatus);
125
- expect(statuses).toContain('starting');
126
- expect(statuses).toContain('ready');
127
- // Verify state has port from pool
128
- const serviceState = selectPluginState(session.state, 'services')?.get('quick');
129
- expect(serviceState).toBeDefined();
130
- expect(serviceState.status).toBe('ready');
131
- expect(serviceState.port).toBeGreaterThanOrEqual(10000);
132
- expect(serviceState.port).toBeLessThanOrEqual(49151);
133
- });
134
- it('stop running service → status stopped', async () => {
135
- const portPool = new PortPool();
136
- const harness = createServicesHarness({
137
- presets: [createServicesPreset([quickService], ['quick'], portPool)],
138
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
139
- });
140
- const session = await harness.createSession('test');
141
- await session.sendAndWaitForIdle('Hi');
142
- const entryAgentId = session.getEntryAgentId();
143
- await session.callPluginMethod('services.start', {
144
- sessionId: String(session.sessionId),
145
- agentId: String(entryAgentId),
146
- serviceType: 'quick',
147
- });
148
- await waitForServiceStatus(session, 'quick', 'ready');
149
- const stopResult = await session.callPluginMethod('services.stop', {
150
- sessionId: String(session.sessionId),
151
- agentId: String(entryAgentId),
152
- serviceType: 'quick',
153
- });
154
- expect(stopResult.ok).toBe(true);
155
- await waitForServiceStatus(session, 'quick', 'stopped');
156
- const serviceState = selectPluginState(session.state, 'services')?.get('quick');
157
- expect(serviceState.status).toBe('stopped');
158
- });
159
- it('start already running service → idempotent', async () => {
160
- const portPool = new PortPool();
161
- const harness = createServicesHarness({
162
- presets: [createServicesPreset([quickService], ['quick'], portPool)],
163
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
164
- });
165
- const session = await harness.createSession('test');
166
- await session.sendAndWaitForIdle('Hi');
167
- const entryAgentId = session.getEntryAgentId();
168
- await session.callPluginMethod('services.start', {
169
- sessionId: String(session.sessionId),
170
- agentId: String(entryAgentId),
171
- serviceType: 'quick',
172
- });
173
- await waitForServiceStatus(session, 'quick', 'ready');
174
- // Start again — should be idempotent
175
- const result = await session.callPluginMethod('services.start', {
176
- sessionId: String(session.sessionId),
177
- agentId: String(entryAgentId),
178
- serviceType: 'quick',
179
- });
180
- expect(result.ok).toBe(true);
181
- });
182
- });
183
- // =========================================================================
184
- // Port pool allocation
185
- // =========================================================================
186
- describe('port pool allocation', () => {
187
- it('starting event includes allocated port', async () => {
188
- const portPool = new PortPool();
189
- const harness = createServicesHarness({
190
- presets: [createServicesPreset([quickService], ['quick'], portPool)],
191
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
192
- });
193
- const session = await harness.createSession('test');
194
- await session.sendAndWaitForIdle('Hi');
195
- const entryAgentId = session.getEntryAgentId();
196
- await session.callPluginMethod('services.start', {
197
- sessionId: String(session.sessionId),
198
- agentId: String(entryAgentId),
199
- serviceType: 'quick',
200
- });
201
- await waitForServiceStatus(session, 'quick', 'ready');
202
- const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
203
- const startingEvent = events.find((e) => e.serviceType === 'quick' && e.toStatus === 'starting');
204
- expect(startingEvent).toBeDefined();
205
- expect(startingEvent.port).toBeGreaterThanOrEqual(10000);
206
- });
207
- it('command callback receives allocated port', async () => {
208
- const portPool = new PortPool();
209
- const harness = createServicesHarness({
210
- presets: [createServicesPreset([commandCallbackService], ['callback-service'], portPool)],
211
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
212
- });
213
- const session = await harness.createSession('test');
214
- await session.sendAndWaitForIdle('Hi');
215
- const entryAgentId = session.getEntryAgentId();
216
- await session.callPluginMethod('services.start', {
217
- sessionId: String(session.sessionId),
218
- agentId: String(entryAgentId),
219
- serviceType: 'callback-service',
220
- });
221
- await waitForServiceStatus(session, 'callback-service', 'ready');
222
- // Port should be in state from starting event
223
- const serviceState = selectPluginState(session.state, 'services')?.get('callback-service');
224
- expect(serviceState.port).toBeGreaterThanOrEqual(10000);
225
- });
226
- it('resolves cwd, command, and env callbacks with runtime context', async () => {
227
- const workspaceDir = await mkdtemp(join(tmpdir(), 'roj-svc-runtime-'));
228
- const webDir = join(workspaceDir, 'packages', 'web');
229
- await mkdir(webDir, { recursive: true });
230
- let cwdArgs;
231
- let commandArgs;
232
- let envArgs;
233
- const runtimeService = {
234
- type: 'runtime',
235
- description: 'Service with runtime resolvers',
236
- cwd: (args) => {
237
- cwdArgs = args;
238
- return 'packages/web';
239
- },
240
- command: async (args) => {
241
- commandArgs = args;
242
- return `printf "%s" "$RUNTIME_MARKER" > marker.txt && echo "READY ${args.port}" && sleep 60`;
243
- },
244
- env: (args) => {
245
- envArgs = args;
246
- return {
247
- RUNTIME_MARKER: `${args.sessionId}|${args.workspaceDir}|${args.cwd}|${args.port}`,
248
- };
249
- },
250
- readyPattern: 'READY',
251
- };
252
- try {
253
- const portPool = new PortPool();
254
- const harness = createServicesHarness({
255
- presets: [createServicesPreset([runtimeService], ['runtime'], portPool, { workspaceDir })],
256
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
257
- });
258
- const session = await harness.createSession('test');
259
- const entryAgentId = session.getEntryAgentId();
260
- const startResult = await session.callPluginMethod('services.start', {
261
- sessionId: String(session.sessionId),
262
- agentId: String(entryAgentId),
263
- serviceType: 'runtime',
264
- });
265
- expect(startResult.ok).toBe(true);
266
- await waitForServiceStatus(session, 'runtime', 'ready');
267
- const serviceState = selectPluginState(session.state, 'services')?.get('runtime');
268
- expect(cwdArgs?.workspaceDir).toBe(workspaceDir);
269
- expect(cwdArgs?.sessionId).toBe(String(session.sessionId));
270
- expect(commandArgs?.cwd).toBe(webDir);
271
- expect(commandArgs?.workspaceDir).toBe(workspaceDir);
272
- expect(envArgs?.cwd).toBe(webDir);
273
- expect(serviceState?.cwd).toBe(webDir);
274
- expect(serviceState?.command).toContain('RUNTIME_MARKER');
275
- const marker = await readFile(join(webDir, 'marker.txt'), 'utf-8');
276
- expect(marker).toContain(String(session.sessionId));
277
- expect(marker).toContain(workspaceDir);
278
- expect(marker).toContain(webDir);
279
- const statusResult = await session.callPluginMethod('services.status', {
280
- sessionId: String(session.sessionId),
281
- agentId: String(entryAgentId),
282
- serviceType: 'runtime',
283
- });
284
- expect(statusResult).toMatchObject({
285
- ok: true,
286
- value: {
287
- status: 'ready',
288
- cwd: webDir,
289
- command: serviceState?.command,
290
- },
291
- });
292
- }
293
- finally {
294
- await rm(workspaceDir, { recursive: true, force: true });
295
- }
296
- });
297
- });
298
- // =========================================================================
299
- // Service tools
300
- // =========================================================================
301
- describe('service tools', () => {
302
- it('agent calls service_start tool → service starts', async () => {
303
- const portPool = new PortPool();
304
- const harness = createServicesHarness({
305
- presets: [createServicesPreset([quickService], ['quick'], portPool)],
306
- llmProvider: MockLLMProvider.withSequence([
307
- {
308
- toolCalls: [{
309
- id: ToolCallId('tc1'),
310
- name: 'service_start',
311
- input: { serviceType: 'quick' },
312
- }],
313
- },
314
- { content: 'Done', toolCalls: [] },
315
- ]),
316
- });
317
- const session = await harness.createSession('test');
318
- await session.sendAndWaitForIdle('Start service');
319
- await waitForServiceStatus(session, 'quick', 'ready');
320
- const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
321
- const quickEvents = events.filter((e) => e.serviceType === 'quick');
322
- expect(quickEvents.length).toBeGreaterThanOrEqual(1);
323
- });
324
- it('agent calls service_status → returns status info', async () => {
325
- const portPool = new PortPool();
326
- const harness = createServicesHarness({
327
- presets: [createServicesPreset([quickService], ['quick'], portPool)],
328
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
329
- });
330
- const session = await harness.createSession('test');
331
- await session.sendAndWaitForIdle('Hi');
332
- const entryAgentId = session.getEntryAgentId();
333
- // Start service
334
- await session.callPluginMethod('services.start', {
335
- sessionId: String(session.sessionId),
336
- agentId: String(entryAgentId),
337
- serviceType: 'quick',
338
- });
339
- await waitForServiceStatus(session, 'quick', 'ready');
340
- // Get status
341
- const statusResult = await session.callPluginMethod('services.status', {
342
- sessionId: String(session.sessionId),
343
- agentId: String(entryAgentId),
344
- serviceType: 'quick',
345
- });
346
- expect(statusResult).toMatchObject({ ok: true, value: { status: 'ready' } });
347
- });
348
- it('service not in agent visible list → error', async () => {
349
- const portPool = new PortPool();
350
- const harness = createServicesHarness({
351
- presets: [createServicesPreset([quickService], [], portPool)], // empty visible list
352
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
353
- });
354
- const session = await harness.createSession('test');
355
- await session.sendAndWaitForIdle('Hi');
356
- // No service tools should be available
357
- const lastRequest = harness.llmProvider.getLastRequest();
358
- const toolNames = lastRequest?.tools?.map((t) => t.name) ?? [];
359
- expect(toolNames).not.toContain('service_start');
360
- expect(toolNames).not.toContain('service_stop');
361
- });
362
- });
363
- // =========================================================================
364
- // Auto-start on session ready
365
- // =========================================================================
366
- describe('auto-start on session ready', () => {
367
- it('service with autoStart: true → started on session creation', async () => {
368
- const portPool = new PortPool();
369
- const harness = createServicesHarness({
370
- presets: [createServicesPreset([autoStartService], ['auto-start'], portPool)],
371
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
372
- });
373
- const session = await harness.createSession('test');
374
- // Session creation triggers onSessionReady → autoStart services
375
- await waitForServiceStatus(session, 'auto-start', 'ready');
376
- const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
377
- const autoEvents = events.filter((e) => e.serviceType === 'auto-start');
378
- expect(autoEvents.length).toBeGreaterThanOrEqual(1);
379
- });
380
- it('availableWhen false skips auto-start and explicit start returns an error', async () => {
381
- const unavailableService = {
382
- type: 'unavailable',
383
- description: 'Unavailable service',
384
- command: 'sleep 60',
385
- autoStart: true,
386
- availableWhen: () => false,
387
- };
388
- const portPool = new PortPool();
389
- const harness = createServicesHarness({
390
- presets: [createServicesPreset([unavailableService], ['unavailable'], portPool)],
391
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
392
- });
393
- const session = await harness.createSession('test');
394
- await new Promise((resolve) => setTimeout(resolve, 100));
395
- const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
396
- expect(events.some((event) => event.serviceType === 'unavailable')).toBe(false);
397
- const entryAgentId = session.getEntryAgentId();
398
- const result = await session.callPluginMethod('services.start', {
399
- sessionId: String(session.sessionId),
400
- agentId: String(entryAgentId),
401
- serviceType: 'unavailable',
402
- });
403
- expect(result.ok).toBe(false);
404
- });
405
- });
406
- // =========================================================================
407
- // Service failure
408
- // =========================================================================
409
- describe('service failure', () => {
410
- it('service that exits immediately → status failed with error', async () => {
411
- const portPool = new PortPool();
412
- const harness = createServicesHarness({
413
- presets: [createServicesPreset([failingService], ['failing'], portPool)],
414
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
415
- });
416
- const session = await harness.createSession('test');
417
- await session.sendAndWaitForIdle('Hi');
418
- const entryAgentId = session.getEntryAgentId();
419
- await session.callPluginMethod('services.start', {
420
- sessionId: String(session.sessionId),
421
- agentId: String(entryAgentId),
422
- serviceType: 'failing',
423
- });
424
- await waitForServiceStatus(session, 'failing', 'failed');
425
- const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
426
- const failEvent = events.find((e) => e.serviceType === 'failing' && e.toStatus === 'failed');
427
- expect(failEvent).toBeDefined();
428
- expect(failEvent.error).toBeDefined();
429
- });
430
- });
431
- // =========================================================================
432
- // Ready pattern
433
- // =========================================================================
434
- describe('ready pattern', () => {
435
- it('service with readyPattern → status ready when pattern matches', async () => {
436
- const portPool = new PortPool();
437
- const harness = createServicesHarness({
438
- presets: [createServicesPreset([readyPatternService], ['ready-service'], portPool)],
439
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
440
- });
441
- const session = await harness.createSession('test');
442
- await session.sendAndWaitForIdle('Hi');
443
- const entryAgentId = session.getEntryAgentId();
444
- await session.callPluginMethod('services.start', {
445
- sessionId: String(session.sessionId),
446
- agentId: String(entryAgentId),
447
- serviceType: 'ready-service',
448
- });
449
- await waitForServiceStatus(session, 'ready-service', 'ready');
450
- const serviceState = selectPluginState(session.state, 'services')?.get('ready-service');
451
- expect(serviceState.status).toBe('ready');
452
- });
453
- it('readyWhen can mark a service ready without output pattern', async () => {
454
- let checks = 0;
455
- const readyWhenService = {
456
- type: 'ready-when',
457
- description: 'Service with callback readiness',
458
- command: 'sleep 60',
459
- readyWhen: () => {
460
- checks += 1;
461
- return checks > 1;
462
- },
463
- readyCheckIntervalMs: 20,
464
- startupTimeoutMs: 1000,
465
- };
466
- const portPool = new PortPool();
467
- const harness = createServicesHarness({
468
- presets: [createServicesPreset([readyWhenService], ['ready-when'], portPool)],
469
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
470
- });
471
- const session = await harness.createSession('test');
472
- const entryAgentId = session.getEntryAgentId();
473
- const result = await session.callPluginMethod('services.start', {
474
- sessionId: String(session.sessionId),
475
- agentId: String(entryAgentId),
476
- serviceType: 'ready-when',
477
- });
478
- expect(result.ok).toBe(true);
479
- await waitForServiceStatus(session, 'ready-when', 'ready');
480
- expect(checks).toBeGreaterThan(1);
481
- });
482
- });
483
- // =========================================================================
484
- // Server restart reconcile
485
- // =========================================================================
486
- describe('onSessionReady reconcile after server restart', () => {
487
- it('preserves port in state when service transitions to stopped', async () => {
488
- const portPool = new PortPool();
489
- const harness = createServicesHarness({
490
- presets: [createServicesPreset([quickService], ['quick'], portPool)],
491
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
492
- });
493
- const session = await harness.createSession('test');
494
- await session.sendAndWaitForIdle('Hi');
495
- const entryAgentId = session.getEntryAgentId();
496
- await session.callPluginMethod('services.start', {
497
- sessionId: String(session.sessionId),
498
- agentId: String(entryAgentId),
499
- serviceType: 'quick',
500
- });
501
- await waitForServiceStateStatus(session, 'quick', 'ready');
502
- const portBefore = selectPluginState(session.state, 'services')?.get('quick')?.port;
503
- expect(portBefore).toBeDefined();
504
- await session.callPluginMethod('services.stop', {
505
- sessionId: String(session.sessionId),
506
- agentId: String(entryAgentId),
507
- serviceType: 'quick',
508
- });
509
- await waitForServiceStateStatus(session, 'quick', 'stopped');
510
- const stopped = selectPluginState(session.state, 'services')?.get('quick');
511
- expect(stopped?.status).toBe('stopped');
512
- expect(stopped?.port).toBe(portBefore);
513
- expect(stopped?.pid).toBeUndefined();
514
- });
515
- it('kills orphaned process group from previous server instance', async () => {
516
- const eventStore = new MemoryEventStore();
517
- // Harness 1: start service, capture pid + port, then "crash" (shutdown
518
- // without running onSessionClose — matches session.shutdown() behavior).
519
- const harness1 = new TestHarness({
520
- presets: [createServicesPreset([quickService], ['quick'], new PortPool())],
521
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
522
- systemPlugins: [servicePlugin],
523
- eventStore,
524
- });
525
- const session1 = await harness1.createSession('test');
526
- await session1.sendAndWaitForIdle('Hi');
527
- const entryAgentId = session1.getEntryAgentId();
528
- await session1.callPluginMethod('services.start', {
529
- sessionId: String(session1.sessionId),
530
- agentId: String(entryAgentId),
531
- serviceType: 'quick',
532
- });
533
- await waitForServiceStateStatus(session1, 'quick', 'ready');
534
- const stateBefore = selectPluginState(session1.state, 'services')?.get('quick');
535
- const orphanPid = stateBefore?.pid;
536
- const orphanPort = stateBefore?.port;
537
- expect(orphanPid).toBeDefined();
538
- expect(orphanPort).toBeDefined();
539
- // Process should be alive before restart
540
- expect(() => process.kill(orphanPid, 0)).not.toThrow();
541
- const sessionId = session1.sessionId;
542
- // Simulate server crash: sessionManager.shutdown() clears in-memory state
543
- // but does NOT run onSessionClose, so the detached service process survives.
544
- await harness1.sessionManager.shutdown();
545
- // Orphan must still be alive after "crash"
546
- expect(() => process.kill(orphanPid, 0)).not.toThrow();
547
- // Harness 2: fresh SessionManager over the same event store
548
- const harness2 = new TestHarness({
549
- presets: [createServicesPreset([quickService], ['quick'], new PortPool())],
550
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
551
- systemPlugins: [servicePlugin],
552
- eventStore,
553
- });
554
- currentHarness = harness2;
555
- // Opening the session fires onSessionReady → reconcile kills the orphan
556
- const session2 = await harness2.openSession(sessionId);
557
- await waitForServiceStateStatus(session2, 'quick', 'stopped', 3000);
558
- // Give the OS a beat to reap the killed process
559
- for (let i = 0; i < 20; i++) {
560
- try {
561
- process.kill(orphanPid, 0);
562
- }
563
- catch {
564
- break;
565
- }
566
- await new Promise((r) => setTimeout(r, 50));
567
- }
568
- let isAlive = true;
569
- try {
570
- process.kill(orphanPid, 0);
571
- }
572
- catch {
573
- isAlive = false;
574
- }
575
- // Safety net in case reconcile didn't kill it — don't leave zombies behind
576
- if (isAlive) {
577
- try {
578
- process.kill(-orphanPid, 'SIGKILL');
579
- }
580
- catch {
581
- // already gone
582
- }
583
- }
584
- expect(isAlive).toBe(false);
585
- // Port preserved in state — next start() would receive it via preferredPort
586
- const stateAfter = selectPluginState(session2.state, 'services')?.get('quick');
587
- expect(stateAfter?.status).toBe('stopped');
588
- expect(stateAfter?.port).toBe(orphanPort);
589
- expect(stateAfter?.pid).toBeUndefined();
590
- });
591
- });
592
- describe('session close cleanup', () => {
593
- it('closing session stops running services', async () => {
594
- const portPool = new PortPool();
595
- const harness = createServicesHarness({
596
- presets: [createServicesPreset([quickService], ['quick'], portPool)],
597
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
598
- });
599
- const session = await harness.createSession('test');
600
- await session.sendAndWaitForIdle('Hi');
601
- const entryAgentId = session.getEntryAgentId();
602
- await session.callPluginMethod('services.start', {
603
- sessionId: String(session.sessionId),
604
- agentId: String(entryAgentId),
605
- serviceType: 'quick',
606
- });
607
- await waitForServiceStatus(session, 'quick', 'ready');
608
- // Close session → should stop services
609
- await session.close();
610
- // Wait for stopped event
611
- await waitForServiceStatus(session, 'quick', 'stopped', 10000);
612
- const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
613
- const stoppedEvent = events.find((e) => e.serviceType === 'quick' && e.toStatus === 'stopped');
614
- expect(stoppedEvent).toBeDefined();
615
- });
616
- });
617
- // =========================================================================
618
- // Port conflict recovery + concurrent start (ServiceExecutor unit-level)
619
- // =========================================================================
620
- describe('port conflict recovery and concurrent start', () => {
621
- const waitUntil = async (predicate, timeoutMs = 8000) => {
622
- const deadline = Date.now() + timeoutMs;
623
- while (Date.now() < deadline) {
624
- if (predicate())
625
- return;
626
- await new Promise((r) => setTimeout(r, 20));
627
- }
628
- };
629
- it('collapses concurrent start() calls onto a single process', async () => {
630
- const platform = createNodePlatform();
631
- const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
632
- const marker = join(tmpdir(), `roj-svc-mutex-${Date.now()}-${Math.floor(Math.random() * 1e6)}`);
633
- const config = {
634
- type: 'concurrent',
635
- description: 'appends one line per spawned process',
636
- command: `echo spawned >> ${marker} && sleep 30`,
637
- };
638
- try {
639
- const [r1, r2] = await Promise.all([
640
- executor.start(config, SessionId('s-concurrent')),
641
- executor.start(config, SessionId('s-concurrent')),
642
- ]);
643
- expect(r1.ok).toBe(true);
644
- expect(r2.ok).toBe(true);
645
- // Let the shell flush its append.
646
- await new Promise((r) => setTimeout(r, 400));
647
- const lines = (await readFile(marker, 'utf-8')).split('\n').filter((l) => l.length > 0);
648
- // Without the in-flight lock both starts spawn and the file gets two lines.
649
- expect(lines.length).toBe(1);
650
- }
651
- finally {
652
- await executor.shutdown();
653
- await rm(marker, { force: true });
654
- }
655
- });
656
- it('recovers on a fresh port when the chosen port is in use (EADDRINUSE)', async () => {
657
- const platform = createNodePlatform();
658
- const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
659
- const marker = join(tmpdir(), `roj-svc-eaddr-${Date.now()}-${Math.floor(Math.random() * 1e6)}`);
660
- // First spawn fails with an EADDRINUSE-style message; the marker makes the
661
- // retry (a fresh process) succeed and match the ready pattern.
662
- const config = {
663
- type: 'flaky-port',
664
- description: 'EADDRINUSE on first attempt, ready on retry',
665
- command: `if [ -f ${marker} ]; then echo "listening READY"; sleep 30; else touch ${marker}; echo "error: listen EADDRINUSE: address already in use" 1>&2; exit 1; fi`,
666
- readyPattern: 'READY',
667
- startupTimeoutMs: 5000,
668
- };
669
- const observed = [];
670
- executor.onStatusChanged = (_sessionId, _serviceType, status, details) => {
671
- observed.push({ status, port: details.port });
672
- };
673
- try {
674
- const result = await executor.start(config, SessionId('s-flaky'));
675
- expect(result.ok).toBe(true);
676
- await waitUntil(() => executor.getStatus('flaky-port') === 'ready');
677
- expect(executor.getStatus('flaky-port')).toBe('ready');
678
- // Two 'starting' events: the conflicted port, then a fresh, different one.
679
- const startingPorts = observed.filter((e) => e.status === 'starting').map((e) => e.port);
680
- expect(startingPorts.length).toBe(2);
681
- expect(startingPorts[0]).not.toBe(startingPorts[1]);
682
- // The transient EADDRINUSE must NOT surface as a terminal failure.
683
- expect(observed.some((e) => e.status === 'failed')).toBe(false);
684
- }
685
- finally {
686
- await executor.shutdown();
687
- await rm(marker, { force: true });
688
- }
689
- });
690
- });
691
- // =========================================================================
692
- // restartPolicy — reviving a service that exited on its own
693
- // =========================================================================
694
- describe('restartPolicy', () => {
695
- const waitUntil = async (predicate, timeoutMs = 8000) => {
696
- const deadline = Date.now() + timeoutMs;
697
- while (Date.now() < deadline) {
698
- if (predicate())
699
- return;
700
- await new Promise((r) => setTimeout(r, 20));
701
- }
702
- };
703
- const waitUntilAsync = async (predicate, timeoutMs = 8000) => {
704
- const deadline = Date.now() + timeoutMs;
705
- while (Date.now() < deadline) {
706
- if (await predicate())
707
- return;
708
- await new Promise((r) => setTimeout(r, 20));
709
- }
710
- };
711
- const marker = (name) => join(tmpdir(), `roj-restart-${name}-${Date.now()}-${Math.floor(Math.random() * 1e6)}`);
712
- /** Records every spawn, then crashes or stays up depending on the run count. */
713
- const crashCommand = (path, crashRuns) => `echo x >> ${path}; runs=$(wc -l < ${path} | tr -d ' '); if [ "$runs" -le ${crashRuns} ]; then exit 1; fi; echo "listening READY"; sleep 30`;
714
- const spawnCount = async (path) => {
715
- try {
716
- return (await readFile(path, 'utf-8')).split('\n').filter((l) => l.length > 0).length;
717
- }
718
- catch {
719
- return 0;
720
- }
721
- };
722
- it('revives a crashed service on the port it already holds', async () => {
723
- const platform = createNodePlatform();
724
- const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
725
- const path = marker('revive');
726
- const config = {
727
- type: 'revive-svc',
728
- description: 'crashes once, then stays up',
729
- command: crashCommand(path, 1),
730
- readyPattern: 'READY',
731
- startupTimeoutMs: 5000,
732
- restartPolicy: { maxRetries: 3, initialDelayMs: 20 },
733
- };
734
- const ports = [];
735
- executor.onStatusChanged = (_s, _t, status, details) => {
736
- if (status === 'starting' && details.port !== undefined)
737
- ports.push(details.port);
738
- };
739
- try {
740
- await executor.start(config, SessionId('s-revive'));
741
- await waitUntil(() => executor.getStatus('revive-svc') === 'ready');
742
- expect(executor.getStatus('revive-svc')).toBe('ready');
743
- expect(await spawnCount(path)).toBe(2);
744
- // The preview URL must survive the bounce.
745
- expect(new Set(ports).size).toBe(1);
746
- }
747
- finally {
748
- await executor.shutdown();
749
- await rm(path, { force: true });
750
- }
751
- });
752
- it('leaves the service failed once the retry budget is spent', async () => {
753
- const platform = createNodePlatform();
754
- const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
755
- const path = marker('budget');
756
- const config = {
757
- type: 'budget-svc',
758
- description: 'always crashes',
759
- command: crashCommand(path, 99),
760
- readyPattern: 'READY',
761
- startupTimeoutMs: 5000,
762
- restartPolicy: { maxRetries: 2, initialDelayMs: 20 },
763
- };
764
- try {
765
- await executor.start(config, SessionId('s-budget'));
766
- // One initial spawn plus two retries, then it stays down.
767
- await waitUntilAsync(async () => (await spawnCount(path)) >= 3 && executor.getStatus('budget-svc') === 'failed');
768
- await new Promise((r) => setTimeout(r, 300));
769
- expect(await spawnCount(path)).toBe(3);
770
- expect(executor.getStatus('budget-svc')).toBe('failed');
771
- }
772
- finally {
773
- await executor.shutdown();
774
- await rm(path, { force: true });
775
- }
776
- });
777
- it('without a policy a crash stays a crash', async () => {
778
- const platform = createNodePlatform();
779
- const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
780
- const path = marker('nopolicy');
781
- const config = {
782
- type: 'nopolicy-svc',
783
- description: 'always crashes, no restartPolicy',
784
- command: crashCommand(path, 99),
785
- readyPattern: 'READY',
786
- startupTimeoutMs: 5000,
787
- };
788
- try {
789
- await executor.start(config, SessionId('s-nopolicy'));
790
- await waitUntil(() => executor.getStatus('nopolicy-svc') === 'failed');
791
- await new Promise((r) => setTimeout(r, 300));
792
- expect(await spawnCount(path)).toBe(1);
793
- }
794
- finally {
795
- await executor.shutdown();
796
- await rm(path, { force: true });
797
- }
798
- });
799
- it('a queued revival rides along on the failed status change', async () => {
800
- const platform = createNodePlatform();
801
- const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
802
- const path = marker('event');
803
- const config = {
804
- type: 'event-svc',
805
- description: 'crashes once, then stays up',
806
- command: crashCommand(path, 1),
807
- readyPattern: 'READY',
808
- startupTimeoutMs: 5000,
809
- restartPolicy: { maxRetries: 3, initialDelayMs: 20 },
810
- };
811
- const changes = [];
812
- executor.onStatusChanged = (_s, _t, status, details) => {
813
- changes.push({ status, details });
814
- };
815
- try {
816
- await executor.start(config, SessionId('s-event'));
817
- await waitUntil(() => executor.getStatus('event-svc') === 'ready');
818
- const failedIndex = changes.findIndex((c) => c.status === 'failed');
819
- expect(failedIndex).toBeGreaterThanOrEqual(0);
820
- const failed = changes[failedIndex];
821
- expect(failed.details.restartAttempt).toBe(1);
822
- expect(failed.details.restartMaxRetries).toBe(3);
823
- expect(failed.details.restartAt).toBeGreaterThan(0);
824
- // The revival's own start must not carry the intent it just honoured.
825
- const revivalStart = changes.slice(failedIndex + 1).find((c) => c.status === 'starting');
826
- expect(revivalStart).toBeDefined();
827
- expect(revivalStart.details.restartAt).toBeUndefined();
828
- }
829
- finally {
830
- await executor.shutdown();
831
- await rm(path, { force: true });
832
- }
833
- });
834
- it('the failure that spends the budget carries no revival', async () => {
835
- const platform = createNodePlatform();
836
- const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
837
- const path = marker('terminal');
838
- const config = {
839
- type: 'terminal-svc',
840
- description: 'always crashes',
841
- command: crashCommand(path, 99),
842
- readyPattern: 'READY',
843
- startupTimeoutMs: 5000,
844
- restartPolicy: { maxRetries: 1, initialDelayMs: 20 },
845
- };
846
- const failures = [];
847
- executor.onStatusChanged = (_s, _t, status, details) => {
848
- if (status === 'failed')
849
- failures.push(details);
850
- };
851
- try {
852
- await executor.start(config, SessionId('s-terminal'));
853
- await waitUntilAsync(async () => (await spawnCount(path)) >= 2 && failures.length >= 2);
854
- expect(failures[0]?.restartAttempt).toBe(1);
855
- expect(failures[1]?.restartAt).toBeUndefined();
856
- expect(failures[1]?.restartAttempt).toBeUndefined();
857
- }
858
- finally {
859
- await executor.shutdown();
860
- await rm(path, { force: true });
861
- }
862
- });
863
- it('session state shows the queued revival and drops it once called off', async () => {
864
- const portPool = new PortPool();
865
- const config = {
866
- type: 'reviving',
867
- description: 'crashes early, revival queued behind a long delay',
868
- // The sleep keeps the exit from beating the executor's close listener.
869
- command: 'sleep 0.2; exit 1',
870
- restartPolicy: { maxRetries: 3, initialDelayMs: 3000 },
871
- };
872
- const harness = createServicesHarness({
873
- presets: [createServicesPreset([config], ['reviving'], portPool)],
874
- });
875
- const session = await harness.createSession('test');
876
- await session.callPluginMethod('services.start', { serviceType: 'reviving' });
877
- await waitForServiceStateStatus(session, 'reviving', 'failed');
878
- const entry = selectPluginState(session.state, 'services')?.get('reviving');
879
- expect(entry?.status).toBe('failed');
880
- expect(entry?.restartAt).toBeGreaterThan(Date.now());
881
- expect(entry?.restartAttempt).toBe(1);
882
- expect(entry?.restartMaxRetries).toBe(3);
883
- const stopped = await session.callPluginMethod('services.stop', { serviceType: 'reviving' });
884
- expect(stopped.ok).toBe(true);
885
- await waitForServiceStateStatus(session, 'reviving', 'stopped');
886
- const after = selectPluginState(session.state, 'services')?.get('reviving');
887
- expect(after?.status).toBe('stopped');
888
- expect(after?.restartAt).toBeUndefined();
889
- expect(after?.restartAttempt).toBeUndefined();
890
- });
891
- it('closing the session calls off a queued revival', async () => {
892
- const portPool = new PortPool();
893
- const path = marker('close');
894
- const config = {
895
- type: 'close-svc',
896
- description: 'crashes early, revival queued behind a delay',
897
- // The sleep keeps the exit from beating the executor's close listener.
898
- command: `echo x >> ${path}; sleep 0.2; exit 1`,
899
- restartPolicy: { maxRetries: 3, initialDelayMs: 800 },
900
- };
901
- const harness = createServicesHarness({
902
- presets: [createServicesPreset([config], ['close-svc'], portPool)],
903
- });
904
- const session = await harness.createSession('test');
905
- try {
906
- await session.callPluginMethod('services.start', { serviceType: 'close-svc' });
907
- await waitForServiceStateStatus(session, 'close-svc', 'failed');
908
- expect(await spawnCount(path)).toBe(1);
909
- await session.close();
910
- // Long enough for the revival to have fired had nothing called it off.
911
- await new Promise((r) => setTimeout(r, 1500));
912
- expect(await spawnCount(path)).toBe(1);
913
- }
914
- finally {
915
- await rm(path, { force: true });
916
- }
917
- });
918
- it('an explicit stop calls off a queued revival', async () => {
919
- const platform = createNodePlatform();
920
- const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
921
- const path = marker('stop');
922
- const config = {
923
- type: 'stop-svc',
924
- description: 'always crashes, revival queued behind a long delay',
925
- command: crashCommand(path, 99),
926
- readyPattern: 'READY',
927
- startupTimeoutMs: 5000,
928
- restartPolicy: { maxRetries: 3, initialDelayMs: 1500 },
929
- };
930
- try {
931
- await executor.start(config, SessionId('s-stop'));
932
- await waitUntil(() => executor.getStatus('stop-svc') === 'failed');
933
- const stopped = await executor.stop('stop-svc', SessionId('s-stop'));
934
- expect(stopped.ok).toBe(true);
935
- expect(executor.getStatus('stop-svc')).toBe('stopped');
936
- await new Promise((r) => setTimeout(r, 2000));
937
- expect(await spawnCount(path)).toBe(1);
938
- }
939
- finally {
940
- await executor.shutdown();
941
- await rm(path, { force: true });
942
- }
943
- });
944
- });
945
- // =========================================================================
946
- // agentVisible: false — infrastructure services hidden from agents
947
- // =========================================================================
948
- describe('agentVisible: false services', () => {
949
- const hiddenService = {
950
- type: 'hidden-svc',
951
- description: 'Infra service driven by the platform, not agents',
952
- command: 'sleep 60',
953
- agentVisible: false,
954
- };
955
- it('auto-wired agent visibility excludes it: no tool mention, no status line, still method-controllable', async () => {
956
- const portPool = new PortPool();
957
- const base = createTestPreset({
958
- plugins: [servicePlugin.configure({ services: [quickService, hiddenService], portPool })],
959
- });
960
- // Services attached on the agent definition (defineAgent-style auto-wiring),
961
- // NOT via explicit configureAgent — exercises the getAgentConfig filter.
962
- const preset = { ...base, orchestrator: { ...base.orchestrator, services: [quickService, hiddenService] } };
963
- const harness = createServicesHarness({
964
- presets: [preset],
965
- llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
966
- });
967
- const session = await harness.createSession('test');
968
- await session.sendAndWaitForIdle('Hi');
969
- // Service tools exist (quick is visible) but never mention the hidden service
970
- const lastRequest = harness.llmProvider.getLastRequest();
971
- const serviceStart = lastRequest?.tools?.find((t) => t.name === 'service_start');
972
- expect(serviceStart).toBeDefined();
973
- expect(serviceStart?.description).toContain('quick');
974
- expect(serviceStart?.description).not.toContain('hidden-svc');
975
- // The session-context status block skips it too
976
- const serialized = JSON.stringify(lastRequest?.messages ?? []);
977
- expect(serialized).not.toContain('hidden-svc');
978
- // Still fully controllable at the session level via services.* methods
979
- const entryAgentId = session.getEntryAgentId();
980
- const startResult = await session.callPluginMethod('services.start', {
981
- sessionId: String(session.sessionId),
982
- agentId: String(entryAgentId),
983
- serviceType: 'hidden-svc',
984
- });
985
- expect(startResult).toMatchObject({ ok: true });
986
- await waitForServiceStatus(session, 'hidden-svc', 'ready');
987
- const statusResult = await session.callPluginMethod('services.status', {
988
- sessionId: String(session.sessionId),
989
- agentId: String(entryAgentId),
990
- serviceType: 'hidden-svc',
991
- });
992
- expect(statusResult).toMatchObject({ ok: true, value: { status: 'ready' } });
993
- });
994
- });
995
- // =========================================================================
996
- // Real host paths must not leak into agent-facing surfaces
997
- // =========================================================================
998
- describe('host path hygiene', () => {
999
- it('status block omits cwd even when the entry tracks one', () => {
1000
- const message = buildServiceStatusMessage([{
1001
- serviceType: 'quick',
1002
- status: 'ready',
1003
- port: 4321,
1004
- cwd: '/home/user/sessions/0000-real-host-path/packages/web',
1005
- }], [quickService]);
1006
- expect(message).toContain('quick');
1007
- expect(message).toContain('port 4321');
1008
- expect(message).not.toContain('real-host-path');
1009
- expect(message).not.toContain('cwd');
1010
- });
1011
- it('service_status tool output strips cwd', async () => {
1012
- const portPool = new PortPool();
1013
- // Absolute cwd so the tracked entry actually carries a host path to leak.
1014
- const cwdService = {
1015
- type: 'cwd-svc',
1016
- description: 'Service with a resolved host cwd',
1017
- command: 'sleep 60',
1018
- cwd: tmpdir(),
1019
- };
1020
- const harness = createServicesHarness({
1021
- presets: [createServicesPreset([cwdService], ['cwd-svc'], portPool)],
1022
- llmProvider: MockLLMProvider.withSequence([
1023
- {
1024
- toolCalls: [{
1025
- id: ToolCallId('tc-start'),
1026
- name: 'service_start',
1027
- input: { serviceType: 'cwd-svc' },
1028
- }],
1029
- },
1030
- {
1031
- toolCalls: [{
1032
- id: ToolCallId('tc-status'),
1033
- name: 'service_status',
1034
- input: { serviceType: 'cwd-svc' },
1035
- }],
1036
- },
1037
- { content: 'Done', toolCalls: [] },
1038
- ]),
1039
- });
1040
- const session = await harness.createSession('test');
1041
- await session.sendAndWaitForIdle('Check the service');
1042
- await waitForServiceStatus(session, 'cwd-svc', 'ready');
1043
- // The service_status tool result (fed back as a message) must not carry cwd,
1044
- // while the session-level method keeps returning it for platform callers.
1045
- const serialized = JSON.stringify(harness.llmProvider.getLastRequest()?.messages ?? []);
1046
- expect(serialized).not.toContain('"cwd"');
1047
- const entryAgentId = session.getEntryAgentId();
1048
- const statusResult = await session.callPluginMethod('services.status', {
1049
- sessionId: String(session.sessionId),
1050
- agentId: String(entryAgentId),
1051
- serviceType: 'cwd-svc',
1052
- });
1053
- expect(statusResult).toMatchObject({ ok: true, value: { cwd: expect.any(String) } });
1054
- });
1055
- });
1056
- });
1057
- //# sourceMappingURL=services.integration.test.js.map