@namzu/sdk 0.4.1 → 0.4.3

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 (685) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/dist/__tests__/replay-public-surface.test.d.ts +2 -0
  3. package/dist/__tests__/replay-public-surface.test.d.ts.map +1 -0
  4. package/dist/__tests__/replay-public-surface.test.js +45 -0
  5. package/dist/__tests__/replay-public-surface.test.js.map +1 -0
  6. package/dist/advisory/context.test.d.ts +16 -0
  7. package/dist/advisory/context.test.d.ts.map +1 -0
  8. package/dist/advisory/context.test.js +92 -0
  9. package/dist/advisory/context.test.js.map +1 -0
  10. package/dist/advisory/evaluator.test.d.ts +34 -0
  11. package/dist/advisory/evaluator.test.d.ts.map +1 -0
  12. package/dist/advisory/evaluator.test.js +172 -0
  13. package/dist/advisory/evaluator.test.js.map +1 -0
  14. package/dist/advisory/executor.test.d.ts +35 -0
  15. package/dist/advisory/executor.test.d.ts.map +1 -0
  16. package/dist/advisory/executor.test.js +233 -0
  17. package/dist/advisory/executor.test.js.map +1 -0
  18. package/dist/advisory/registry.test.d.ts +16 -0
  19. package/dist/advisory/registry.test.d.ts.map +1 -0
  20. package/dist/advisory/registry.test.js +62 -0
  21. package/dist/advisory/registry.test.js.map +1 -0
  22. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  23. package/dist/agents/SupervisorAgent.js.map +1 -1
  24. package/dist/bridge/a2a/agent-card.test.d.ts +24 -0
  25. package/dist/bridge/a2a/agent-card.test.d.ts.map +1 -0
  26. package/dist/bridge/a2a/agent-card.test.js +118 -0
  27. package/dist/bridge/a2a/agent-card.test.js.map +1 -0
  28. package/dist/bridge/a2a/mapper.test.d.ts +29 -0
  29. package/dist/bridge/a2a/mapper.test.d.ts.map +1 -0
  30. package/dist/bridge/a2a/mapper.test.js +265 -0
  31. package/dist/bridge/a2a/mapper.test.js.map +1 -0
  32. package/dist/bridge/a2a/message.test.d.ts +20 -0
  33. package/dist/bridge/a2a/message.test.d.ts.map +1 -0
  34. package/dist/bridge/a2a/message.test.js +116 -0
  35. package/dist/bridge/a2a/message.test.js.map +1 -0
  36. package/dist/bridge/a2a/task.d.ts +2 -2
  37. package/dist/bridge/a2a/task.d.ts.map +1 -1
  38. package/dist/bridge/a2a/task.js.map +1 -1
  39. package/dist/bridge/a2a/task.test.d.ts +29 -0
  40. package/dist/bridge/a2a/task.test.d.ts.map +1 -0
  41. package/dist/bridge/a2a/task.test.js +198 -0
  42. package/dist/bridge/a2a/task.test.js.map +1 -0
  43. package/dist/bridge/mcp/connector/adapter.test.d.ts +27 -0
  44. package/dist/bridge/mcp/connector/adapter.test.d.ts.map +1 -0
  45. package/dist/bridge/mcp/connector/adapter.test.js +203 -0
  46. package/dist/bridge/mcp/connector/adapter.test.js.map +1 -0
  47. package/dist/bridge/sse/mapper.test.d.ts +27 -0
  48. package/dist/bridge/sse/mapper.test.d.ts.map +1 -0
  49. package/dist/bridge/sse/mapper.test.js +271 -0
  50. package/dist/bridge/sse/mapper.test.js.map +1 -0
  51. package/dist/bridge/tools/connector/adapter.test.d.ts +28 -0
  52. package/dist/bridge/tools/connector/adapter.test.d.ts.map +1 -0
  53. package/dist/bridge/tools/connector/adapter.test.js +182 -0
  54. package/dist/bridge/tools/connector/adapter.test.js.map +1 -0
  55. package/dist/bridge/tools/connector/definitions.test.d.ts +23 -0
  56. package/dist/bridge/tools/connector/definitions.test.d.ts.map +1 -0
  57. package/dist/bridge/tools/connector/definitions.test.js +158 -0
  58. package/dist/bridge/tools/connector/definitions.test.js.map +1 -0
  59. package/dist/bridge/tools/connector/router.test.d.ts +21 -0
  60. package/dist/bridge/tools/connector/router.test.d.ts.map +1 -0
  61. package/dist/bridge/tools/connector/router.test.js +139 -0
  62. package/dist/bridge/tools/connector/router.test.js.map +1 -0
  63. package/dist/bus/breaker.test.d.ts +41 -0
  64. package/dist/bus/breaker.test.d.ts.map +1 -0
  65. package/dist/bus/breaker.test.js +242 -0
  66. package/dist/bus/breaker.test.js.map +1 -0
  67. package/dist/bus/index.test.d.ts +25 -0
  68. package/dist/bus/index.test.d.ts.map +1 -0
  69. package/dist/bus/index.test.js +151 -0
  70. package/dist/bus/index.test.js.map +1 -0
  71. package/dist/bus/lock.test.d.ts +44 -0
  72. package/dist/bus/lock.test.d.ts.map +1 -0
  73. package/dist/bus/lock.test.js +226 -0
  74. package/dist/bus/lock.test.js.map +1 -0
  75. package/dist/bus/ownership.test.d.ts +26 -0
  76. package/dist/bus/ownership.test.d.ts.map +1 -0
  77. package/dist/bus/ownership.test.js +205 -0
  78. package/dist/bus/ownership.test.js.map +1 -0
  79. package/dist/config/runtime.d.ts +24 -25
  80. package/dist/config/runtime.d.ts.map +1 -1
  81. package/dist/config/runtime.js.map +1 -1
  82. package/dist/connector/BaseConnector.test.d.ts +21 -0
  83. package/dist/connector/BaseConnector.test.d.ts.map +1 -0
  84. package/dist/connector/BaseConnector.test.js +108 -0
  85. package/dist/connector/BaseConnector.test.js.map +1 -0
  86. package/dist/connector/builtins/http.test.d.ts +30 -0
  87. package/dist/connector/builtins/http.test.d.ts.map +1 -0
  88. package/dist/connector/builtins/http.test.js +232 -0
  89. package/dist/connector/builtins/http.test.js.map +1 -0
  90. package/dist/connector/builtins/webhook.test.d.ts +20 -0
  91. package/dist/connector/builtins/webhook.test.d.ts.map +1 -0
  92. package/dist/connector/builtins/webhook.test.js +113 -0
  93. package/dist/connector/builtins/webhook.test.js.map +1 -0
  94. package/dist/connector/execution/factory.test.d.ts +16 -0
  95. package/dist/connector/execution/factory.test.d.ts.map +1 -0
  96. package/dist/connector/execution/factory.test.js +64 -0
  97. package/dist/connector/execution/factory.test.js.map +1 -0
  98. package/dist/connector/execution/remote.test.d.ts +16 -0
  99. package/dist/connector/execution/remote.test.d.ts.map +1 -0
  100. package/dist/connector/execution/remote.test.js +53 -0
  101. package/dist/connector/execution/remote.test.js.map +1 -0
  102. package/dist/connector/mcp/adapter.test.d.ts +34 -0
  103. package/dist/connector/mcp/adapter.test.d.ts.map +1 -0
  104. package/dist/connector/mcp/adapter.test.js +199 -0
  105. package/dist/connector/mcp/adapter.test.js.map +1 -0
  106. package/dist/contracts/api.d.ts +2 -2
  107. package/dist/contracts/api.d.ts.map +1 -1
  108. package/dist/contracts/index.d.ts +1 -2
  109. package/dist/contracts/index.d.ts.map +1 -1
  110. package/dist/contracts/index.js.map +1 -1
  111. package/dist/contracts/schemas.d.ts +10 -10
  112. package/dist/index.d.ts +3 -103
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.js +9 -89
  115. package/dist/index.js.map +1 -1
  116. package/dist/manager/agent/__tests__/lifecycle.test.js.map +1 -1
  117. package/dist/manager/agent/lifecycle.d.ts +1 -1
  118. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  119. package/dist/manager/agent/lifecycle.js +1 -1
  120. package/dist/manager/agent/lifecycle.js.map +1 -1
  121. package/dist/manager/run/persistence.d.ts +3 -3
  122. package/dist/manager/run/persistence.d.ts.map +1 -1
  123. package/dist/manager/run/persistence.js.map +1 -1
  124. package/dist/manager/thread/__tests__/lifecycle.test.js.map +1 -1
  125. package/dist/manager/thread/lifecycle.d.ts +1 -1
  126. package/dist/manager/thread/lifecycle.d.ts.map +1 -1
  127. package/dist/plugin/loader.d.ts +0 -5
  128. package/dist/plugin/loader.d.ts.map +1 -1
  129. package/dist/plugin/loader.js +1 -13
  130. package/dist/plugin/loader.js.map +1 -1
  131. package/dist/public-runtime.d.ts +70 -0
  132. package/dist/public-runtime.d.ts.map +1 -0
  133. package/dist/public-runtime.js +108 -0
  134. package/dist/public-runtime.js.map +1 -0
  135. package/dist/public-tools.d.ts +19 -0
  136. package/dist/public-tools.d.ts.map +1 -0
  137. package/dist/public-tools.js +34 -0
  138. package/dist/public-tools.js.map +1 -0
  139. package/dist/public-types.d.ts +55 -0
  140. package/dist/public-types.d.ts.map +1 -0
  141. package/dist/public-types.js +14 -0
  142. package/dist/public-types.js.map +1 -0
  143. package/dist/rag/chunking.test.d.ts +20 -0
  144. package/dist/rag/chunking.test.d.ts.map +1 -0
  145. package/dist/rag/chunking.test.js +92 -0
  146. package/dist/rag/chunking.test.js.map +1 -0
  147. package/dist/rag/context-assembler.test.d.ts +19 -0
  148. package/dist/rag/context-assembler.test.d.ts.map +1 -0
  149. package/dist/rag/context-assembler.test.js +98 -0
  150. package/dist/rag/context-assembler.test.js.map +1 -0
  151. package/dist/rag/embedding.test.d.ts +19 -0
  152. package/dist/rag/embedding.test.d.ts.map +1 -0
  153. package/dist/rag/embedding.test.js +115 -0
  154. package/dist/rag/embedding.test.js.map +1 -0
  155. package/dist/rag/ingestion.test.d.ts +22 -0
  156. package/dist/rag/ingestion.test.d.ts.map +1 -0
  157. package/dist/rag/ingestion.test.js +99 -0
  158. package/dist/rag/ingestion.test.js.map +1 -0
  159. package/dist/rag/knowledge-base.test.d.ts +17 -0
  160. package/dist/rag/knowledge-base.test.d.ts.map +1 -0
  161. package/dist/rag/knowledge-base.test.js +77 -0
  162. package/dist/rag/knowledge-base.test.js.map +1 -0
  163. package/dist/rag/rag-tool.d.ts +1 -1
  164. package/dist/rag/rag-tool.test.d.ts +21 -0
  165. package/dist/rag/rag-tool.test.d.ts.map +1 -0
  166. package/dist/rag/rag-tool.test.js +149 -0
  167. package/dist/rag/rag-tool.test.js.map +1 -0
  168. package/dist/rag/retriever.test.d.ts +26 -0
  169. package/dist/rag/retriever.test.d.ts.map +1 -0
  170. package/dist/rag/retriever.test.js +180 -0
  171. package/dist/rag/retriever.test.js.map +1 -0
  172. package/dist/rag/vector-store.test.d.ts +38 -0
  173. package/dist/rag/vector-store.test.d.ts.map +1 -0
  174. package/dist/rag/vector-store.test.js +175 -0
  175. package/dist/rag/vector-store.test.js.map +1 -0
  176. package/dist/registry/ManagedRegistry.test.d.ts +21 -0
  177. package/dist/registry/ManagedRegistry.test.d.ts.map +1 -0
  178. package/dist/registry/ManagedRegistry.test.js +98 -0
  179. package/dist/registry/ManagedRegistry.test.js.map +1 -0
  180. package/dist/registry/Registry.test.d.ts +18 -0
  181. package/dist/registry/Registry.test.d.ts.map +1 -0
  182. package/dist/registry/Registry.test.js +79 -0
  183. package/dist/registry/Registry.test.js.map +1 -0
  184. package/dist/registry/agent/definitions.test.d.ts +15 -0
  185. package/dist/registry/agent/definitions.test.d.ts.map +1 -0
  186. package/dist/registry/agent/definitions.test.js +84 -0
  187. package/dist/registry/agent/definitions.test.js.map +1 -0
  188. package/dist/registry/connector/definitions.test.d.ts +13 -0
  189. package/dist/registry/connector/definitions.test.d.ts.map +1 -0
  190. package/dist/registry/connector/definitions.test.js +41 -0
  191. package/dist/registry/connector/definitions.test.js.map +1 -0
  192. package/dist/registry/connector/scoped.test.d.ts +21 -0
  193. package/dist/registry/connector/scoped.test.d.ts.map +1 -0
  194. package/dist/registry/connector/scoped.test.js +115 -0
  195. package/dist/registry/connector/scoped.test.js.map +1 -0
  196. package/dist/registry/plugin/index.test.d.ts +12 -0
  197. package/dist/registry/plugin/index.test.d.ts.map +1 -0
  198. package/dist/registry/plugin/index.test.js +69 -0
  199. package/dist/registry/plugin/index.test.js.map +1 -0
  200. package/dist/registry/tool/execute.test.d.ts +42 -0
  201. package/dist/registry/tool/execute.test.d.ts.map +1 -0
  202. package/dist/registry/tool/execute.test.js +281 -0
  203. package/dist/registry/tool/execute.test.js.map +1 -0
  204. package/dist/run/LimitChecker.d.ts +0 -1
  205. package/dist/run/LimitChecker.d.ts.map +1 -1
  206. package/dist/run/LimitChecker.js +0 -6
  207. package/dist/run/LimitChecker.js.map +1 -1
  208. package/dist/run/reporter.d.ts +2 -2
  209. package/dist/run/reporter.d.ts.map +1 -1
  210. package/dist/run/reporter.js.map +1 -1
  211. package/dist/runtime/query/__tests__/checkpoint.test.d.ts +2 -0
  212. package/dist/runtime/query/__tests__/checkpoint.test.d.ts.map +1 -0
  213. package/dist/runtime/query/__tests__/checkpoint.test.js +150 -0
  214. package/dist/runtime/query/__tests__/checkpoint.test.js.map +1 -0
  215. package/dist/runtime/query/checkpoint.d.ts +23 -0
  216. package/dist/runtime/query/checkpoint.d.ts.map +1 -1
  217. package/dist/runtime/query/checkpoint.js +49 -0
  218. package/dist/runtime/query/checkpoint.js.map +1 -1
  219. package/dist/runtime/query/context.d.ts +0 -2
  220. package/dist/runtime/query/context.d.ts.map +1 -1
  221. package/dist/runtime/query/context.js +0 -4
  222. package/dist/runtime/query/context.js.map +1 -1
  223. package/dist/runtime/query/index.d.ts +3 -3
  224. package/dist/runtime/query/index.d.ts.map +1 -1
  225. package/dist/runtime/query/iteration/phases/advisory.test.d.ts +42 -0
  226. package/dist/runtime/query/iteration/phases/advisory.test.d.ts.map +1 -0
  227. package/dist/runtime/query/iteration/phases/advisory.test.js +334 -0
  228. package/dist/runtime/query/iteration/phases/advisory.test.js.map +1 -0
  229. package/dist/runtime/query/replay/__tests__/mutate.test.d.ts +2 -0
  230. package/dist/runtime/query/replay/__tests__/mutate.test.d.ts.map +1 -0
  231. package/dist/runtime/query/replay/__tests__/mutate.test.js +123 -0
  232. package/dist/runtime/query/replay/__tests__/mutate.test.js.map +1 -0
  233. package/dist/runtime/query/replay/__tests__/prepare.test.d.ts +2 -0
  234. package/dist/runtime/query/replay/__tests__/prepare.test.d.ts.map +1 -0
  235. package/dist/runtime/query/replay/__tests__/prepare.test.js +171 -0
  236. package/dist/runtime/query/replay/__tests__/prepare.test.js.map +1 -0
  237. package/dist/runtime/query/replay/list.d.ts +24 -0
  238. package/dist/runtime/query/replay/list.d.ts.map +1 -0
  239. package/dist/runtime/query/replay/list.js +21 -0
  240. package/dist/runtime/query/replay/list.js.map +1 -0
  241. package/dist/runtime/query/replay/mutate.d.ts +17 -0
  242. package/dist/runtime/query/replay/mutate.d.ts.map +1 -0
  243. package/dist/runtime/query/replay/mutate.js +62 -0
  244. package/dist/runtime/query/replay/mutate.js.map +1 -0
  245. package/dist/runtime/query/replay/prepare.d.ts +56 -0
  246. package/dist/runtime/query/replay/prepare.d.ts.map +1 -0
  247. package/dist/runtime/query/replay/prepare.js +65 -0
  248. package/dist/runtime/query/replay/prepare.js.map +1 -0
  249. package/dist/runtime/query/result.d.ts +2 -2
  250. package/dist/runtime/query/result.d.ts.map +1 -1
  251. package/dist/session/__tests__/integration/_fixtures.d.ts +4 -4
  252. package/dist/session/__tests__/integration/_fixtures.d.ts.map +1 -1
  253. package/dist/session/__tests__/integration/_fixtures.js.map +1 -1
  254. package/dist/session/__tests__/integration/archive-gate.test.js.map +1 -1
  255. package/dist/session/__tests__/integration/capacity-caps.test.js.map +1 -1
  256. package/dist/session/__tests__/integration/e2e-spawn.test.js.map +1 -1
  257. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js.map +1 -1
  258. package/dist/session/__tests__/integration/handoff-single-e2e.test.js.map +1 -1
  259. package/dist/session/__tests__/integration/prev-artifact-dag.test.js.map +1 -1
  260. package/dist/session/__tests__/integration/retention-archive.test.js.map +1 -1
  261. package/dist/session/__tests__/integration/spawn-rollback.test.js.map +1 -1
  262. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js +1 -1
  263. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js.map +1 -1
  264. package/dist/session/errors.d.ts +1 -1
  265. package/dist/session/errors.d.ts.map +1 -1
  266. package/dist/session/events/index.d.ts +3 -3
  267. package/dist/session/events/index.d.ts.map +1 -1
  268. package/dist/session/events/index.js +3 -2
  269. package/dist/session/events/index.js.map +1 -1
  270. package/dist/session/handoff/__tests__/broadcast.test.js.map +1 -1
  271. package/dist/session/handoff/__tests__/capacity.test.js.map +1 -1
  272. package/dist/session/handoff/__tests__/single.test.js.map +1 -1
  273. package/dist/session/handoff/assignment.d.ts +1 -1
  274. package/dist/session/handoff/assignment.d.ts.map +1 -1
  275. package/dist/session/handoff/broadcast.d.ts.map +1 -1
  276. package/dist/session/handoff/broadcast.js.map +1 -1
  277. package/dist/session/handoff/single.d.ts.map +1 -1
  278. package/dist/session/handoff/single.js.map +1 -1
  279. package/dist/session/index.d.ts +0 -1
  280. package/dist/session/index.d.ts.map +1 -1
  281. package/dist/session/index.js +7 -6
  282. package/dist/session/index.js.map +1 -1
  283. package/dist/session/intervention/__tests__/prev-artifact.test.js.map +1 -1
  284. package/dist/session/intervention/prev-artifact.d.ts +1 -1
  285. package/dist/session/intervention/prev-artifact.d.ts.map +1 -1
  286. package/dist/session/retention/__tests__/archive.test.js.map +1 -1
  287. package/dist/session/retention/__tests__/disk-backend.test.js.map +1 -1
  288. package/dist/session/retention/archive.d.ts +1 -1
  289. package/dist/session/retention/archive.d.ts.map +1 -1
  290. package/dist/session/retention/backend.d.ts +4 -4
  291. package/dist/session/retention/backend.d.ts.map +1 -1
  292. package/dist/session/retention/disk-backend.d.ts +1 -1
  293. package/dist/session/retention/disk-backend.d.ts.map +1 -1
  294. package/dist/session/retention/index.d.ts +3 -3
  295. package/dist/session/retention/index.d.ts.map +1 -1
  296. package/dist/session/retention/index.js +4 -2
  297. package/dist/session/retention/index.js.map +1 -1
  298. package/dist/session/status/__tests__/derive.test.d.ts +2 -0
  299. package/dist/session/status/__tests__/derive.test.d.ts.map +1 -0
  300. package/dist/session/{hierarchy/__tests__/session.test.js → status/__tests__/derive.test.js} +2 -2
  301. package/dist/session/status/__tests__/derive.test.js.map +1 -0
  302. package/dist/session/status/derive.d.ts +33 -0
  303. package/dist/session/status/derive.d.ts.map +1 -0
  304. package/dist/session/{hierarchy/session.js → status/derive.js} +6 -1
  305. package/dist/session/status/derive.js.map +1 -0
  306. package/dist/session/summary/__tests__/materialize.test.js +2 -1
  307. package/dist/session/summary/__tests__/materialize.test.js.map +1 -1
  308. package/dist/session/summary/errors.d.ts +43 -0
  309. package/dist/session/summary/errors.d.ts.map +1 -0
  310. package/dist/session/summary/errors.js +37 -0
  311. package/dist/session/summary/errors.js.map +1 -0
  312. package/dist/session/summary/index.d.ts +4 -3
  313. package/dist/session/summary/index.d.ts.map +1 -1
  314. package/dist/session/summary/index.js +5 -4
  315. package/dist/session/summary/index.js.map +1 -1
  316. package/dist/session/summary/materialize.d.ts +2 -2
  317. package/dist/session/summary/materialize.d.ts.map +1 -1
  318. package/dist/session/summary/materialize.js +2 -1
  319. package/dist/session/summary/materialize.js.map +1 -1
  320. package/dist/session/workspace/__tests__/git-worktree.test.js.map +1 -1
  321. package/dist/session/workspace/driver.d.ts +2 -2
  322. package/dist/session/workspace/driver.d.ts.map +1 -1
  323. package/dist/session/workspace/git-worktree.d.ts +1 -1
  324. package/dist/session/workspace/git-worktree.d.ts.map +1 -1
  325. package/dist/session/workspace/git-worktree.js.map +1 -1
  326. package/dist/session/workspace/index.d.ts +1 -1
  327. package/dist/session/workspace/index.d.ts.map +1 -1
  328. package/dist/session/workspace/index.js +3 -2
  329. package/dist/session/workspace/index.js.map +1 -1
  330. package/dist/store/run/disk.d.ts +4 -4
  331. package/dist/store/run/disk.d.ts.map +1 -1
  332. package/dist/store/run/disk.js.map +1 -1
  333. package/dist/store/session/__tests__/disk.test.js.map +1 -1
  334. package/dist/store/session/__tests__/memory.test.js.map +1 -1
  335. package/dist/store/session/disk.d.ts +6 -6
  336. package/dist/store/session/disk.d.ts.map +1 -1
  337. package/dist/store/session/disk.js +1 -1
  338. package/dist/store/session/disk.js.map +1 -1
  339. package/dist/store/session/index.d.ts +1 -1
  340. package/dist/store/session/index.d.ts.map +1 -1
  341. package/dist/store/session/index.js +2 -1
  342. package/dist/store/session/index.js.map +1 -1
  343. package/dist/store/session/linkage.d.ts +1 -1
  344. package/dist/store/session/linkage.d.ts.map +1 -1
  345. package/dist/store/session/memory.d.ts +5 -5
  346. package/dist/store/session/memory.d.ts.map +1 -1
  347. package/dist/store/session/memory.js +1 -1
  348. package/dist/store/session/memory.js.map +1 -1
  349. package/dist/store/thread/disk.d.ts +1 -1
  350. package/dist/store/thread/disk.d.ts.map +1 -1
  351. package/dist/store/thread/memory.d.ts +1 -1
  352. package/dist/store/thread/memory.d.ts.map +1 -1
  353. package/dist/telemetry/attributes.d.ts +0 -1
  354. package/dist/telemetry/attributes.d.ts.map +1 -1
  355. package/dist/telemetry/attributes.js +0 -3
  356. package/dist/telemetry/attributes.js.map +1 -1
  357. package/dist/telemetry/runtime-accessors.d.ts +1 -2
  358. package/dist/telemetry/runtime-accessors.d.ts.map +1 -1
  359. package/dist/telemetry/runtime-accessors.js +1 -4
  360. package/dist/telemetry/runtime-accessors.js.map +1 -1
  361. package/dist/test-setup.d.ts +22 -0
  362. package/dist/test-setup.d.ts.map +1 -0
  363. package/dist/test-setup.js +23 -0
  364. package/dist/test-setup.js.map +1 -0
  365. package/dist/tools/builtins/bash.d.ts +1 -1
  366. package/dist/tools/builtins/computer-use.d.ts +4 -4
  367. package/dist/tools/builtins/edit.d.ts +1 -1
  368. package/dist/tools/builtins/glob.d.ts +1 -1
  369. package/dist/tools/builtins/grep.d.ts +1 -1
  370. package/dist/tools/builtins/ls.d.ts +1 -1
  371. package/dist/tools/builtins/read-file.d.ts +1 -1
  372. package/dist/tools/builtins/search-tools.d.ts +1 -1
  373. package/dist/tools/builtins/write-file.d.ts +1 -1
  374. package/dist/types/agent/task.d.ts +2 -2
  375. package/dist/types/agent/task.d.ts.map +1 -1
  376. package/dist/{session/hierarchy/project.d.ts → types/project/entity.d.ts} +4 -4
  377. package/dist/types/project/entity.d.ts.map +1 -0
  378. package/dist/types/project/entity.js +2 -0
  379. package/dist/types/project/entity.js.map +1 -0
  380. package/dist/types/project/index.d.ts +2 -0
  381. package/dist/types/project/index.d.ts.map +1 -0
  382. package/dist/types/project/index.js +4 -0
  383. package/dist/types/project/index.js.map +1 -0
  384. package/dist/types/retention/archive-backend-ref.d.ts.map +1 -0
  385. package/dist/types/retention/archive-backend-ref.js.map +1 -0
  386. package/dist/types/retention/index.d.ts +4 -0
  387. package/dist/types/retention/index.d.ts.map +1 -0
  388. package/dist/types/retention/index.js +4 -0
  389. package/dist/types/retention/index.js.map +1 -0
  390. package/dist/types/retention/policy.d.ts.map +1 -0
  391. package/dist/types/retention/policy.js.map +1 -0
  392. package/dist/types/run/entity.d.ts +56 -0
  393. package/dist/types/run/entity.d.ts.map +1 -0
  394. package/dist/types/run/entity.js +2 -0
  395. package/dist/types/run/entity.js.map +1 -0
  396. package/dist/types/run/events.d.ts +2 -2
  397. package/dist/types/run/events.d.ts.map +1 -1
  398. package/dist/types/run/index.d.ts +7 -1
  399. package/dist/types/run/index.d.ts.map +1 -1
  400. package/dist/types/run/index.js +8 -9
  401. package/dist/types/run/index.js.map +1 -1
  402. package/dist/{session/hierarchy → types/run}/lineage.d.ts +1 -1
  403. package/dist/types/run/lineage.d.ts.map +1 -0
  404. package/dist/types/run/lineage.js.map +1 -0
  405. package/dist/types/run/replay.d.ts +53 -0
  406. package/dist/types/run/replay.d.ts.map +1 -0
  407. package/dist/types/run/replay.js +15 -0
  408. package/dist/types/run/replay.js.map +1 -0
  409. package/dist/types/run/schema-version.d.ts.map +1 -0
  410. package/dist/types/run/schema-version.js.map +1 -0
  411. package/dist/{session/events/types.d.ts → types/run/subsession-events.d.ts} +5 -5
  412. package/dist/types/run/subsession-events.d.ts.map +1 -0
  413. package/dist/types/run/subsession-events.js +2 -0
  414. package/dist/types/run/subsession-events.js.map +1 -0
  415. package/dist/{session/hierarchy → types/session}/actor.d.ts +1 -1
  416. package/dist/types/session/actor.d.ts.map +1 -0
  417. package/dist/{session/hierarchy → types/session}/actor.js.map +1 -1
  418. package/dist/types/session/entity.d.ts +51 -0
  419. package/dist/types/session/entity.d.ts.map +1 -0
  420. package/dist/types/session/entity.js +2 -0
  421. package/dist/types/session/entity.js.map +1 -0
  422. package/dist/types/session/index.d.ts +4 -0
  423. package/dist/types/session/index.d.ts.map +1 -1
  424. package/dist/{store → types}/session/messages.d.ts +2 -2
  425. package/dist/{store → types}/session/messages.d.ts.map +1 -1
  426. package/dist/types/session/messages.js.map +1 -0
  427. package/dist/types/session/store.d.ts +6 -6
  428. package/dist/types/session/store.d.ts.map +1 -1
  429. package/dist/{session/hierarchy → types/session}/sub-session.d.ts +9 -9
  430. package/dist/types/session/sub-session.d.ts.map +1 -0
  431. package/dist/types/session/sub-session.js.map +1 -0
  432. package/dist/{session → types}/summary/deliverable.d.ts +2 -2
  433. package/dist/types/summary/deliverable.d.ts.map +1 -0
  434. package/dist/types/summary/deliverable.js.map +1 -0
  435. package/dist/types/summary/index.d.ts +4 -0
  436. package/dist/types/summary/index.d.ts.map +1 -0
  437. package/dist/types/summary/index.js +4 -0
  438. package/dist/types/summary/index.js.map +1 -0
  439. package/dist/{session → types}/summary/ref.d.ts +9 -36
  440. package/dist/types/summary/ref.d.ts.map +1 -0
  441. package/dist/types/summary/ref.js +28 -0
  442. package/dist/types/summary/ref.js.map +1 -0
  443. package/dist/{session/hierarchy/tenant.d.ts → types/tenant/entity.d.ts} +2 -2
  444. package/dist/types/tenant/entity.d.ts.map +1 -0
  445. package/dist/types/tenant/entity.js +2 -0
  446. package/dist/types/tenant/entity.js.map +1 -0
  447. package/dist/types/tenant/index.d.ts +2 -0
  448. package/dist/types/tenant/index.d.ts.map +1 -0
  449. package/dist/types/tenant/index.js +4 -0
  450. package/dist/types/tenant/index.js.map +1 -0
  451. package/dist/{session/hierarchy/thread.d.ts → types/thread/entity.d.ts} +31 -7
  452. package/dist/types/thread/entity.d.ts.map +1 -0
  453. package/dist/types/thread/entity.js +2 -0
  454. package/dist/types/thread/entity.js.map +1 -0
  455. package/dist/types/thread/index.d.ts +1 -0
  456. package/dist/types/thread/index.d.ts.map +1 -1
  457. package/dist/types/thread/store.d.ts +1 -1
  458. package/dist/types/thread/store.d.ts.map +1 -1
  459. package/dist/types/workspace/index.d.ts +2 -0
  460. package/dist/types/workspace/index.d.ts.map +1 -0
  461. package/dist/types/workspace/index.js +7 -0
  462. package/dist/types/workspace/index.js.map +1 -0
  463. package/dist/{session → types}/workspace/ref.d.ts +1 -1
  464. package/dist/types/workspace/ref.d.ts.map +1 -0
  465. package/dist/types/workspace/ref.js.map +1 -0
  466. package/dist/utils/logger.d.ts +1 -1
  467. package/dist/utils/logger.d.ts.map +1 -1
  468. package/dist/utils/logger.js +5 -0
  469. package/dist/utils/logger.js.map +1 -1
  470. package/package.json +4 -1
  471. package/src/__tests__/replay-public-surface.test.ts +54 -0
  472. package/src/advisory/context.test.ts +109 -0
  473. package/src/advisory/evaluator.test.ts +192 -0
  474. package/src/advisory/executor.test.ts +272 -0
  475. package/src/advisory/registry.test.ts +75 -0
  476. package/src/agents/SupervisorAgent.ts +1 -1
  477. package/src/bridge/a2a/agent-card.test.ts +140 -0
  478. package/src/bridge/a2a/mapper.test.ts +293 -0
  479. package/src/bridge/a2a/message.test.ts +138 -0
  480. package/src/bridge/a2a/task.test.ts +235 -0
  481. package/src/bridge/a2a/task.ts +4 -4
  482. package/src/bridge/mcp/connector/adapter.test.ts +230 -0
  483. package/src/bridge/sse/mapper.test.ts +422 -0
  484. package/src/bridge/tools/connector/adapter.test.ts +224 -0
  485. package/src/bridge/tools/connector/definitions.test.ts +183 -0
  486. package/src/bridge/tools/connector/router.test.ts +159 -0
  487. package/src/bus/breaker.test.ts +274 -0
  488. package/src/bus/index.test.ts +183 -0
  489. package/src/bus/lock.test.ts +265 -0
  490. package/src/bus/ownership.test.ts +243 -0
  491. package/src/config/runtime.ts +0 -2
  492. package/src/connector/BaseConnector.test.ts +130 -0
  493. package/src/connector/builtins/http.test.ts +290 -0
  494. package/src/connector/builtins/webhook.test.ts +138 -0
  495. package/src/connector/execution/factory.test.ts +75 -0
  496. package/src/connector/execution/remote.test.ts +63 -0
  497. package/src/connector/mcp/adapter.test.ts +249 -0
  498. package/src/contracts/api.ts +2 -2
  499. package/src/contracts/index.ts +1 -3
  500. package/src/index.ts +11 -362
  501. package/src/manager/agent/__tests__/lifecycle.test.ts +2 -2
  502. package/src/manager/agent/lifecycle.ts +5 -5
  503. package/src/manager/run/persistence.ts +4 -4
  504. package/src/manager/thread/__tests__/lifecycle.test.ts +1 -1
  505. package/src/manager/thread/lifecycle.ts +2 -2
  506. package/src/plugin/loader.ts +0 -16
  507. package/src/public-runtime.ts +373 -0
  508. package/src/public-tools.ts +63 -0
  509. package/src/public-types.ts +156 -0
  510. package/src/rag/chunking.test.ts +107 -0
  511. package/src/rag/context-assembler.test.ts +114 -0
  512. package/src/rag/embedding.test.ts +130 -0
  513. package/src/rag/ingestion.test.ts +114 -0
  514. package/src/rag/knowledge-base.test.ts +106 -0
  515. package/src/rag/rag-tool.test.ts +167 -0
  516. package/src/rag/retriever.test.ts +210 -0
  517. package/src/rag/vector-store.test.ts +196 -0
  518. package/src/registry/ManagedRegistry.test.ts +118 -0
  519. package/src/registry/Registry.test.ts +91 -0
  520. package/src/registry/agent/definitions.test.ts +100 -0
  521. package/src/registry/connector/definitions.test.ts +51 -0
  522. package/src/registry/connector/scoped.test.ts +129 -0
  523. package/src/registry/plugin/index.test.ts +85 -0
  524. package/src/registry/tool/execute.test.ts +330 -0
  525. package/src/run/LimitChecker.ts +0 -9
  526. package/src/run/reporter.ts +3 -3
  527. package/src/runtime/query/__tests__/checkpoint.test.ts +169 -0
  528. package/src/runtime/query/checkpoint.ts +54 -0
  529. package/src/runtime/query/context.ts +0 -5
  530. package/src/runtime/query/index.ts +4 -4
  531. package/src/runtime/query/iteration/phases/advisory.test.ts +412 -0
  532. package/src/runtime/query/replay/__tests__/mutate.test.ts +134 -0
  533. package/src/runtime/query/replay/__tests__/prepare.test.ts +207 -0
  534. package/src/runtime/query/replay/list.ts +32 -0
  535. package/src/runtime/query/replay/mutate.ts +76 -0
  536. package/src/runtime/query/replay/prepare.ts +114 -0
  537. package/src/runtime/query/result.ts +2 -2
  538. package/src/session/__tests__/integration/_fixtures.ts +2 -2
  539. package/src/session/__tests__/integration/archive-gate.test.ts +1 -1
  540. package/src/session/__tests__/integration/capacity-caps.test.ts +1 -1
  541. package/src/session/__tests__/integration/e2e-spawn.test.ts +1 -1
  542. package/src/session/__tests__/integration/handoff-broadcast-e2e.test.ts +1 -1
  543. package/src/session/__tests__/integration/handoff-single-e2e.test.ts +1 -1
  544. package/src/session/__tests__/integration/prev-artifact-dag.test.ts +4 -1
  545. package/src/session/__tests__/integration/retention-archive.test.ts +1 -1
  546. package/src/session/__tests__/integration/spawn-rollback.test.ts +2 -2
  547. package/src/session/__tests__/integration/summary-materialization-e2e.test.ts +1 -1
  548. package/src/session/errors.ts +1 -1
  549. package/src/session/events/index.ts +5 -4
  550. package/src/session/handoff/__tests__/broadcast.test.ts +1 -1
  551. package/src/session/handoff/__tests__/capacity.test.ts +1 -1
  552. package/src/session/handoff/__tests__/single.test.ts +1 -1
  553. package/src/session/handoff/assignment.ts +1 -1
  554. package/src/session/handoff/broadcast.ts +2 -2
  555. package/src/session/handoff/single.ts +2 -2
  556. package/src/session/index.ts +7 -6
  557. package/src/session/intervention/__tests__/prev-artifact.test.ts +4 -1
  558. package/src/session/intervention/prev-artifact.ts +1 -1
  559. package/src/session/retention/__tests__/archive.test.ts +3 -3
  560. package/src/session/retention/__tests__/disk-backend.test.ts +4 -4
  561. package/src/session/retention/archive.ts +2 -2
  562. package/src/session/retention/backend.ts +4 -4
  563. package/src/session/retention/disk-backend.ts +4 -4
  564. package/src/session/retention/index.ts +6 -4
  565. package/src/session/{hierarchy/__tests__/session.test.ts → status/__tests__/derive.test.ts} +3 -2
  566. package/src/session/{hierarchy/session.ts → status/derive.ts} +9 -55
  567. package/src/session/summary/__tests__/materialize.test.ts +4 -7
  568. package/src/session/summary/errors.ts +51 -0
  569. package/src/session/summary/index.ts +7 -10
  570. package/src/session/summary/materialize.ts +4 -5
  571. package/src/session/workspace/__tests__/git-worktree.test.ts +1 -1
  572. package/src/session/workspace/driver.ts +2 -2
  573. package/src/session/workspace/git-worktree.ts +1 -1
  574. package/src/session/workspace/index.ts +7 -6
  575. package/src/store/run/disk.ts +4 -4
  576. package/src/store/session/__tests__/disk.test.ts +2 -2
  577. package/src/store/session/__tests__/memory.test.ts +2 -2
  578. package/src/store/session/disk.ts +12 -12
  579. package/src/store/session/index.ts +3 -2
  580. package/src/store/session/linkage.ts +1 -1
  581. package/src/store/session/memory.ts +6 -6
  582. package/src/store/thread/disk.ts +1 -1
  583. package/src/store/thread/memory.ts +1 -1
  584. package/src/telemetry/attributes.ts +0 -4
  585. package/src/telemetry/runtime-accessors.ts +1 -5
  586. package/src/test-setup.ts +24 -0
  587. package/src/types/agent/task.ts +2 -2
  588. package/src/{session/hierarchy/project.ts → types/project/entity.ts} +3 -3
  589. package/src/types/project/index.ts +4 -0
  590. package/src/types/retention/index.ts +6 -0
  591. package/src/types/run/entity.ts +63 -0
  592. package/src/types/run/events.ts +6 -6
  593. package/src/types/run/index.ts +16 -9
  594. package/src/{session/hierarchy → types/run}/lineage.ts +1 -1
  595. package/src/types/run/replay.ts +61 -0
  596. package/src/{session/events/types.ts → types/run/subsession-events.ts} +4 -4
  597. package/src/{session/hierarchy → types/session}/actor.ts +1 -1
  598. package/src/types/session/entity.ts +59 -0
  599. package/src/types/session/index.ts +15 -0
  600. package/src/{store → types}/session/messages.ts +2 -2
  601. package/src/types/session/store.ts +6 -6
  602. package/src/{session/hierarchy → types/session}/sub-session.ts +9 -9
  603. package/src/{session → types}/summary/deliverable.ts +2 -2
  604. package/src/types/summary/index.ts +18 -0
  605. package/src/{session → types}/summary/ref.ts +9 -44
  606. package/src/{session/hierarchy/tenant.ts → types/tenant/entity.ts} +1 -1
  607. package/src/types/tenant/index.ts +4 -0
  608. package/src/{session/hierarchy/thread.ts → types/thread/entity.ts} +30 -6
  609. package/src/types/thread/index.ts +1 -0
  610. package/src/types/thread/store.ts +1 -1
  611. package/src/types/workspace/index.ts +12 -0
  612. package/src/{session → types}/workspace/ref.ts +1 -1
  613. package/src/utils/logger.ts +6 -1
  614. package/dist/contracts/ids.d.ts +0 -2
  615. package/dist/contracts/ids.d.ts.map +0 -1
  616. package/dist/contracts/ids.js +0 -2
  617. package/dist/contracts/ids.js.map +0 -1
  618. package/dist/session/events/schema-version.d.ts.map +0 -1
  619. package/dist/session/events/schema-version.js.map +0 -1
  620. package/dist/session/events/types.d.ts.map +0 -1
  621. package/dist/session/events/types.js +0 -2
  622. package/dist/session/events/types.js.map +0 -1
  623. package/dist/session/hierarchy/__tests__/session.test.d.ts +0 -2
  624. package/dist/session/hierarchy/__tests__/session.test.d.ts.map +0 -1
  625. package/dist/session/hierarchy/__tests__/session.test.js.map +0 -1
  626. package/dist/session/hierarchy/actor.d.ts.map +0 -1
  627. package/dist/session/hierarchy/index.d.ts +0 -9
  628. package/dist/session/hierarchy/index.d.ts.map +0 -1
  629. package/dist/session/hierarchy/index.js +0 -4
  630. package/dist/session/hierarchy/index.js.map +0 -1
  631. package/dist/session/hierarchy/lineage.d.ts.map +0 -1
  632. package/dist/session/hierarchy/lineage.js.map +0 -1
  633. package/dist/session/hierarchy/project.d.ts.map +0 -1
  634. package/dist/session/hierarchy/project.js +0 -2
  635. package/dist/session/hierarchy/project.js.map +0 -1
  636. package/dist/session/hierarchy/session.d.ts +0 -71
  637. package/dist/session/hierarchy/session.d.ts.map +0 -1
  638. package/dist/session/hierarchy/session.js.map +0 -1
  639. package/dist/session/hierarchy/sub-session.d.ts.map +0 -1
  640. package/dist/session/hierarchy/sub-session.js.map +0 -1
  641. package/dist/session/hierarchy/tenant.d.ts.map +0 -1
  642. package/dist/session/hierarchy/tenant.js +0 -2
  643. package/dist/session/hierarchy/tenant.js.map +0 -1
  644. package/dist/session/hierarchy/thread.d.ts.map +0 -1
  645. package/dist/session/hierarchy/thread.js +0 -2
  646. package/dist/session/hierarchy/thread.js.map +0 -1
  647. package/dist/session/retention/archive-backend-ref.d.ts.map +0 -1
  648. package/dist/session/retention/archive-backend-ref.js.map +0 -1
  649. package/dist/session/retention/policy.d.ts.map +0 -1
  650. package/dist/session/retention/policy.js.map +0 -1
  651. package/dist/session/summary/deliverable.d.ts.map +0 -1
  652. package/dist/session/summary/deliverable.js.map +0 -1
  653. package/dist/session/summary/ref.d.ts.map +0 -1
  654. package/dist/session/summary/ref.js +0 -51
  655. package/dist/session/summary/ref.js.map +0 -1
  656. package/dist/session/workspace/ref.d.ts.map +0 -1
  657. package/dist/session/workspace/ref.js.map +0 -1
  658. package/dist/store/session/messages.js.map +0 -1
  659. package/dist/tools/builtins/__tests__/structuredOutput.example.d.ts +0 -140
  660. package/dist/tools/builtins/__tests__/structuredOutput.example.d.ts.map +0 -1
  661. package/dist/tools/builtins/__tests__/structuredOutput.example.js +0 -183
  662. package/dist/tools/builtins/__tests__/structuredOutput.example.js.map +0 -1
  663. package/dist/types/run/state.d.ts +0 -30
  664. package/dist/types/run/state.d.ts.map +0 -1
  665. package/dist/types/run/state.js +0 -2
  666. package/dist/types/run/state.js.map +0 -1
  667. package/src/contracts/ids.ts +0 -1
  668. package/src/session/hierarchy/index.ts +0 -18
  669. package/src/tools/builtins/__tests__/structuredOutput.example.ts +0 -221
  670. package/src/types/run/state.ts +0 -35
  671. /package/dist/{session → types}/retention/archive-backend-ref.d.ts +0 -0
  672. /package/dist/{session → types}/retention/archive-backend-ref.js +0 -0
  673. /package/dist/{session → types}/retention/policy.d.ts +0 -0
  674. /package/dist/{session → types}/retention/policy.js +0 -0
  675. /package/dist/{session/hierarchy → types/run}/lineage.js +0 -0
  676. /package/dist/{session/events → types/run}/schema-version.d.ts +0 -0
  677. /package/dist/{session/events → types/run}/schema-version.js +0 -0
  678. /package/dist/{session/hierarchy → types/session}/actor.js +0 -0
  679. /package/dist/{store → types}/session/messages.js +0 -0
  680. /package/dist/{session/hierarchy → types/session}/sub-session.js +0 -0
  681. /package/dist/{session → types}/summary/deliverable.js +0 -0
  682. /package/dist/{session → types}/workspace/ref.js +0 -0
  683. /package/src/{session → types}/retention/archive-backend-ref.ts +0 -0
  684. /package/src/{session → types}/retention/policy.ts +0 -0
  685. /package/src/{session/events → types/run}/schema-version.ts +0 -0
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 1):
3
+ *
4
+ * - `AgentBus` composes a `FileLockManager`, `EditOwnershipTracker`,
5
+ * and `CircuitBreaker`; every event each of them emits is
6
+ * broadcast to bus-level listeners.
7
+ * - `on(listener)` returns an unsubscribe function; invoking it
8
+ * removes the listener, and subsequent events skip it.
9
+ * - Listeners receive events in the order they are emitted
10
+ * (preserved by `Set` insertion-order iteration). Multi-listener
11
+ * fan-out: every listener sees every event.
12
+ * - A throwing listener does NOT cascade — other listeners still
13
+ * receive the same event, and the bus logs the error via
14
+ * `log.error`.
15
+ * - No per-tenant routing — events are global to the bus instance
16
+ * (design.md §2.1 aspirational per-tenant ordering does not
17
+ * exist; see §2.7).
18
+ * - `cleanupAgent(runId)` releases every lock + every ownership +
19
+ * resets the breaker for that runId. Counts are logged; the
20
+ * method does not return them.
21
+ * - `maintenance()` expires stale locks via `locks.expireStale()`
22
+ * and logs the count when non-zero.
23
+ */
24
+
25
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
26
+
27
+ import type { AgentBusEvent } from '../types/bus/index.js'
28
+ import type { RunId } from '../types/ids/index.js'
29
+ import type { Logger } from '../utils/logger.js'
30
+
31
+ import { AgentBus } from './index.js'
32
+
33
+ function makeLogger(): Logger {
34
+ // Recursive self-returning child — AgentBus nests FileLockManager /
35
+ // EditOwnershipTracker / CircuitBreaker, each of which chains a
36
+ // `log.child(...)` call in its constructor.
37
+ const self = {
38
+ info: vi.fn(),
39
+ warn: vi.fn(),
40
+ error: vi.fn(),
41
+ debug: vi.fn(),
42
+ child: vi.fn(),
43
+ } as unknown as Logger
44
+ ;(self as { child: (ctx: unknown) => Logger }).child = vi.fn(() => self)
45
+ return self
46
+ }
47
+
48
+ function runId(n: number): RunId {
49
+ return `run_${n}` as RunId
50
+ }
51
+
52
+ describe('AgentBus', () => {
53
+ let bus: AgentBus
54
+ let log: Logger
55
+
56
+ beforeEach(() => {
57
+ log = makeLogger()
58
+ bus = new AgentBus(log, { lockTimeoutMs: 60_000, lockAcquireTimeoutMs: 60 })
59
+ })
60
+
61
+ afterEach(() => {
62
+ vi.useRealTimers()
63
+ })
64
+
65
+ describe('listener lifecycle', () => {
66
+ it('broadcasts events to every registered listener', async () => {
67
+ const a: AgentBusEvent[] = []
68
+ const b: AgentBusEvent[] = []
69
+ bus.on((e) => a.push(e))
70
+ bus.on((e) => b.push(e))
71
+
72
+ await bus.locks.acquire('/tmp/f.txt', runId(1))
73
+
74
+ expect(a.length).toBeGreaterThan(0)
75
+ expect(b).toEqual(a)
76
+ })
77
+
78
+ it('unsubscribe removes the listener; later events skip it', async () => {
79
+ const seen: AgentBusEvent[] = []
80
+ const off = bus.on((e) => seen.push(e))
81
+
82
+ await bus.locks.acquire('/tmp/a.txt', runId(1))
83
+ const countAfterFirst = seen.length
84
+ expect(countAfterFirst).toBeGreaterThan(0)
85
+
86
+ off()
87
+ await bus.locks.acquire('/tmp/b.txt', runId(1))
88
+ expect(seen.length).toBe(countAfterFirst)
89
+ })
90
+
91
+ it('preserves emission order per listener (Set insertion-order iteration)', async () => {
92
+ const seen: string[] = []
93
+ bus.on((e) => seen.push(e.type))
94
+
95
+ await bus.locks.acquire('/tmp/a.txt', runId(1))
96
+ bus.ownership.claim('/tmp/a.txt', runId(1))
97
+ bus.ownership.release('/tmp/a.txt', runId(1))
98
+ bus.locks.release('/tmp/a.txt', runId(1))
99
+
100
+ expect(seen).toEqual([
101
+ 'lock_acquired',
102
+ 'ownership_claimed',
103
+ 'ownership_released',
104
+ 'lock_released',
105
+ ])
106
+ })
107
+
108
+ it('a throwing listener does not cascade — other listeners still fire', async () => {
109
+ const good: AgentBusEvent[] = []
110
+ bus.on(() => {
111
+ throw new Error('boom')
112
+ })
113
+ bus.on((e) => good.push(e))
114
+
115
+ await bus.locks.acquire('/tmp/a.txt', runId(1))
116
+ expect(good.length).toBeGreaterThan(0)
117
+ })
118
+ })
119
+
120
+ describe('composed sub-components', () => {
121
+ it('CircuitBreaker events flow through the bus listener', () => {
122
+ const seen: AgentBusEvent[] = []
123
+ bus.on((e) => seen.push(e))
124
+
125
+ for (let i = 0; i < 5; i++) bus.breaker.recordFailure(runId(1))
126
+ expect(seen.filter((e) => e.type === 'breaker_tripped')).toHaveLength(1)
127
+ })
128
+
129
+ it('EditOwnershipTracker events flow through the bus listener', () => {
130
+ const seen: AgentBusEvent[] = []
131
+ bus.on((e) => seen.push(e))
132
+
133
+ bus.ownership.claim('/tmp/a.txt', runId(1))
134
+ bus.ownership.transfer('/tmp/a.txt', runId(1), runId(2))
135
+ bus.ownership.release('/tmp/a.txt', runId(2))
136
+
137
+ expect(seen.map((e) => e.type)).toEqual([
138
+ 'ownership_claimed',
139
+ 'ownership_transferred',
140
+ 'ownership_released',
141
+ ])
142
+ })
143
+ })
144
+
145
+ describe('cleanupAgent', () => {
146
+ it('releases locks + ownerships + resets breaker for the runId', async () => {
147
+ await bus.locks.acquire('/tmp/a.txt', runId(1))
148
+ bus.ownership.claim('/tmp/a.txt', runId(1))
149
+ for (let i = 0; i < 5; i++) bus.breaker.recordFailure(runId(1))
150
+ expect(bus.breaker.getSnapshot(runId(1))?.state).toBe('open')
151
+ expect(bus.locks.isLocked('/tmp/a.txt')).toBe(true)
152
+
153
+ bus.cleanupAgent(runId(1))
154
+
155
+ expect(bus.locks.isLocked('/tmp/a.txt')).toBe(false)
156
+ expect(bus.ownership.getOwner('/tmp/a.txt')).toBeUndefined()
157
+ expect(bus.breaker.getSnapshot(runId(1))?.state).toBe('closed')
158
+ })
159
+
160
+ it('does not affect other runIds', async () => {
161
+ await bus.locks.acquire('/tmp/a.txt', runId(1))
162
+ await bus.locks.acquire('/tmp/b.txt', runId(2))
163
+
164
+ bus.cleanupAgent(runId(1))
165
+
166
+ expect(bus.locks.isLocked('/tmp/a.txt')).toBe(false)
167
+ expect(bus.locks.isLocked('/tmp/b.txt')).toBe(true)
168
+ expect(bus.locks.getHolder('/tmp/b.txt')).toBe(runId(2))
169
+ })
170
+ })
171
+
172
+ describe('maintenance', () => {
173
+ it('sweeps expired locks', async () => {
174
+ vi.useFakeTimers()
175
+ const b = new AgentBus(makeLogger(), { lockTimeoutMs: 500, lockAcquireTimeoutMs: 30 })
176
+ await b.locks.acquire('/tmp/a.txt', runId(1))
177
+ vi.advanceTimersByTime(501)
178
+
179
+ b.maintenance()
180
+ expect(b.locks.isLocked('/tmp/a.txt')).toBe(false)
181
+ })
182
+ })
183
+ })
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 1):
3
+ *
4
+ * - `acquire(path, owner)` returns immediately when the file is
5
+ * unlocked; creates a lock with `lockId = lock_<uuid>`,
6
+ * `expiresAt = now + lockTimeoutMs`, emits `lock_acquired`.
7
+ * - `acquire` on a file already held by the SAME owner is idempotent
8
+ * — returns `{acquired: true, lock}` (the existing lock) and emits
9
+ * nothing.
10
+ * - `acquire` on a file held by a DIFFERENT owner emits `lock_denied`
11
+ * and then polls at `LOCK_ACQUIRE_POLL_INTERVAL_MS` (100ms) intervals
12
+ * until either the holder releases, the lock expires, or
13
+ * `acquireTimeoutMs` elapses. No FIFO queue; retries race.
14
+ * - When the holder releases before the deadline, the waiting acquire
15
+ * succeeds on its next poll.
16
+ * - When `acquireTimeoutMs` elapses, acquire returns
17
+ * `{acquired: false, holder, filePath}` — holder is the current
18
+ * lock holder's owner if the lock still exists, else empty string.
19
+ * - `maxLocksPerAgent` blocks further acquisitions by the same owner.
20
+ * The internal `tryAcquire` returns `{holder: owner}` (a
21
+ * "yourself" sentinel) but the public `acquire()` swallows that and
22
+ * keeps polling for `acquireTimeoutMs` (there's no short-circuit
23
+ * for cap-exceeded). When the deadline expires and no lock exists
24
+ * on the file, the final `holder` is `''` (empty `RunId`) because
25
+ * the fallback reads `this.locks.get(filePath)?.owner ?? ''`.
26
+ * - `release(path, owner)` deletes the lock + emits `lock_released`
27
+ * when the current lock's owner matches; cleans up the per-owner
28
+ * lock set (and prunes the set entry when it becomes empty).
29
+ * Returns false without emitting when no lock or owner mismatch.
30
+ * - `releaseAll(owner)` drops every lock owned by `owner`, emits
31
+ * `lock_released` per lock, returns the count, and prunes the
32
+ * per-owner set.
33
+ * - `isLocked(path)` + `getHolder(path)` auto-expire any stale lock
34
+ * they observe (and emit `lock_expired`) before returning the
35
+ * current state.
36
+ * - `expireStale()` sweeps every lock; expired ones are deleted and
37
+ * emit `lock_expired`; returns the count.
38
+ * - Re-acquiring a path after its lock expires succeeds and assigns
39
+ * a FRESH `lockId` (the old id is never reused).
40
+ * - Lock state is per-`RunId`; no tenant dimension (design.md §2.1
41
+ * aspirational).
42
+ */
43
+
44
+ import { afterEach, describe, expect, it, vi } from 'vitest'
45
+
46
+ import type { AgentBusEvent } from '../types/bus/index.js'
47
+ import type { RunId } from '../types/ids/index.js'
48
+ import type { Logger } from '../utils/logger.js'
49
+
50
+ import { FileLockManager } from './lock.js'
51
+
52
+ function makeLogger(): Logger {
53
+ const stub = { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }
54
+ return { ...stub, child: vi.fn(() => ({ ...stub, child: vi.fn() })) } as unknown as Logger
55
+ }
56
+
57
+ function runId(n: number): RunId {
58
+ return `run_${n}` as RunId
59
+ }
60
+
61
+ function makeManager(
62
+ overrides: Partial<{
63
+ lockTimeoutMs: number
64
+ acquireTimeoutMs: number
65
+ maxLocksPerAgent: number
66
+ }> = {},
67
+ ) {
68
+ const events: AgentBusEvent[] = []
69
+ const mgr = new FileLockManager(makeLogger(), (e) => events.push(e), {
70
+ // short defaults keep acquire-retry tests under a second total
71
+ lockTimeoutMs: 60_000,
72
+ acquireTimeoutMs: 200,
73
+ maxLocksPerAgent: 10,
74
+ ...overrides,
75
+ })
76
+ return { mgr, events }
77
+ }
78
+
79
+ describe('FileLockManager', () => {
80
+ afterEach(() => {
81
+ vi.useRealTimers()
82
+ })
83
+
84
+ describe('acquire (happy path)', () => {
85
+ it('acquires an unheld lock immediately + emits lock_acquired', async () => {
86
+ const { mgr, events } = makeManager()
87
+ const before = Date.now()
88
+ const result = await mgr.acquire('/tmp/a.txt', runId(1))
89
+ expect(result.acquired).toBe(true)
90
+ if (result.acquired) {
91
+ expect(result.lock.owner).toBe(runId(1))
92
+ expect(result.lock.filePath).toBe('/tmp/a.txt')
93
+ expect(result.lock.lockId).toMatch(/^lock_[0-9a-f-]+$/)
94
+ expect(result.lock.acquiredAt).toBeGreaterThanOrEqual(before)
95
+ expect(result.lock.expiresAt).toBeGreaterThan(result.lock.acquiredAt)
96
+ }
97
+ const acquired = events.filter((e) => e.type === 'lock_acquired')
98
+ expect(acquired).toHaveLength(1)
99
+ })
100
+
101
+ it('is idempotent for the same owner — returns the existing lock, emits nothing', async () => {
102
+ const { mgr, events } = makeManager()
103
+ const first = await mgr.acquire('/tmp/a.txt', runId(1))
104
+ events.length = 0
105
+ const second = await mgr.acquire('/tmp/a.txt', runId(1))
106
+ expect(second.acquired).toBe(true)
107
+ if (first.acquired && second.acquired) {
108
+ expect(second.lock.lockId).toBe(first.lock.lockId)
109
+ }
110
+ expect(events).toEqual([])
111
+ })
112
+ })
113
+
114
+ describe('acquire (contention)', () => {
115
+ it('emits lock_denied when another owner holds the lock and no release happens', async () => {
116
+ const { mgr, events } = makeManager({ acquireTimeoutMs: 120 })
117
+ await mgr.acquire('/tmp/a.txt', runId(1))
118
+ events.length = 0
119
+
120
+ const result = await mgr.acquire('/tmp/a.txt', runId(2))
121
+ expect(result.acquired).toBe(false)
122
+ if (!result.acquired) {
123
+ expect(result.holder).toBe(runId(1))
124
+ expect(result.filePath).toBe('/tmp/a.txt')
125
+ }
126
+ expect(events.some((e) => e.type === 'lock_denied')).toBe(true)
127
+ })
128
+
129
+ it('succeeds on a retry once the holder releases before the deadline', async () => {
130
+ const { mgr } = makeManager({ acquireTimeoutMs: 500 })
131
+ await mgr.acquire('/tmp/a.txt', runId(1))
132
+
133
+ const contender = mgr.acquire('/tmp/a.txt', runId(2))
134
+ setTimeout(() => mgr.release('/tmp/a.txt', runId(1)), 120)
135
+
136
+ const result = await contender
137
+ expect(result.acquired).toBe(true)
138
+ if (result.acquired) expect(result.lock.owner).toBe(runId(2))
139
+ })
140
+ })
141
+
142
+ describe('maxLocksPerAgent cap', () => {
143
+ it('denies a new acquisition when the owner is at cap — acquire polls to deadline then returns empty holder', async () => {
144
+ const { mgr } = makeManager({ maxLocksPerAgent: 2, acquireTimeoutMs: 60 })
145
+ await mgr.acquire('/tmp/a.txt', runId(1))
146
+ await mgr.acquire('/tmp/b.txt', runId(1))
147
+
148
+ const over = await mgr.acquire('/tmp/c.txt', runId(1))
149
+ expect(over.acquired).toBe(false)
150
+ if (!over.acquired) {
151
+ // No lock exists on /tmp/c.txt, so the fallback holder is ''.
152
+ expect(over.holder).toBe('' as RunId)
153
+ expect(over.filePath).toBe('/tmp/c.txt')
154
+ }
155
+ })
156
+ })
157
+
158
+ describe('release', () => {
159
+ it('releases an owned lock + emits lock_released', async () => {
160
+ const { mgr, events } = makeManager()
161
+ await mgr.acquire('/tmp/a.txt', runId(1))
162
+ events.length = 0
163
+
164
+ expect(mgr.release('/tmp/a.txt', runId(1))).toBe(true)
165
+ expect(mgr.isLocked('/tmp/a.txt')).toBe(false)
166
+ expect(events.some((e) => e.type === 'lock_released')).toBe(true)
167
+ })
168
+
169
+ it('returns false + emits nothing when the caller is not the holder', async () => {
170
+ const { mgr, events } = makeManager()
171
+ await mgr.acquire('/tmp/a.txt', runId(1))
172
+ events.length = 0
173
+
174
+ expect(mgr.release('/tmp/a.txt', runId(2))).toBe(false)
175
+ expect(mgr.isLocked('/tmp/a.txt')).toBe(true)
176
+ expect(events).toEqual([])
177
+ })
178
+
179
+ it('returns false when no lock exists', () => {
180
+ const { mgr, events } = makeManager()
181
+ expect(mgr.release('/tmp/never.txt', runId(1))).toBe(false)
182
+ expect(events).toEqual([])
183
+ })
184
+ })
185
+
186
+ describe('releaseAll', () => {
187
+ it('drops every lock owned by the runId, emits one event per lock, returns count', async () => {
188
+ const { mgr, events } = makeManager()
189
+ await mgr.acquire('/tmp/a.txt', runId(1))
190
+ await mgr.acquire('/tmp/b.txt', runId(1))
191
+ await mgr.acquire('/tmp/c.txt', runId(2))
192
+ events.length = 0
193
+
194
+ const count = mgr.releaseAll(runId(1))
195
+ expect(count).toBe(2)
196
+ expect(mgr.isLocked('/tmp/a.txt')).toBe(false)
197
+ expect(mgr.isLocked('/tmp/b.txt')).toBe(false)
198
+ expect(mgr.isLocked('/tmp/c.txt')).toBe(true)
199
+ expect(events.filter((e) => e.type === 'lock_released')).toHaveLength(2)
200
+ })
201
+
202
+ it('returns 0 when the owner has no locks', () => {
203
+ const { mgr } = makeManager()
204
+ expect(mgr.releaseAll(runId(99))).toBe(0)
205
+ })
206
+ })
207
+
208
+ describe('expiry', () => {
209
+ it('expireStale drops expired locks + emits lock_expired per drop', async () => {
210
+ vi.useFakeTimers()
211
+ const { mgr, events } = makeManager({ lockTimeoutMs: 10_000 })
212
+ await mgr.acquire('/tmp/a.txt', runId(1))
213
+ await mgr.acquire('/tmp/b.txt', runId(2))
214
+ events.length = 0
215
+
216
+ vi.advanceTimersByTime(10_001)
217
+ const expired = mgr.expireStale()
218
+ expect(expired).toBe(2)
219
+ expect(events.filter((e) => e.type === 'lock_expired')).toHaveLength(2)
220
+ })
221
+
222
+ it('isLocked / getHolder auto-expire a stale lock before answering', async () => {
223
+ vi.useFakeTimers()
224
+ const { mgr, events } = makeManager({ lockTimeoutMs: 5_000 })
225
+ await mgr.acquire('/tmp/a.txt', runId(1))
226
+
227
+ vi.advanceTimersByTime(5_001)
228
+ events.length = 0
229
+ expect(mgr.isLocked('/tmp/a.txt')).toBe(false)
230
+ expect(events.some((e) => e.type === 'lock_expired')).toBe(true)
231
+
232
+ events.length = 0
233
+ expect(mgr.getHolder('/tmp/a.txt')).toBeUndefined()
234
+ // already expired by the previous call; no second emit
235
+ expect(events).toEqual([])
236
+ })
237
+
238
+ it('a fresh acquire after expiry assigns a new lockId', async () => {
239
+ vi.useFakeTimers()
240
+ const { mgr } = makeManager({ lockTimeoutMs: 1_000 })
241
+ const first = await mgr.acquire('/tmp/a.txt', runId(1))
242
+ vi.advanceTimersByTime(1_001)
243
+ mgr.expireStale()
244
+
245
+ vi.useRealTimers()
246
+ const second = await mgr.acquire('/tmp/a.txt', runId(2))
247
+ expect(first.acquired && second.acquired).toBe(true)
248
+ if (first.acquired && second.acquired) {
249
+ expect(second.lock.lockId).not.toBe(first.lock.lockId)
250
+ expect(second.lock.owner).toBe(runId(2))
251
+ }
252
+ })
253
+ })
254
+
255
+ describe('per-runId isolation', () => {
256
+ it('different runIds can hold locks on different files concurrently', async () => {
257
+ const { mgr } = makeManager()
258
+ const a = await mgr.acquire('/tmp/a.txt', runId(1))
259
+ const b = await mgr.acquire('/tmp/b.txt', runId(2))
260
+ expect(a.acquired && b.acquired).toBe(true)
261
+ expect(mgr.getHolder('/tmp/a.txt')).toBe(runId(1))
262
+ expect(mgr.getHolder('/tmp/b.txt')).toBe(runId(2))
263
+ })
264
+ })
265
+ })
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 1):
3
+ *
4
+ * - `claim(path, owner)` on an unowned file creates ownership, emits
5
+ * `ownership_claimed`, returns `{claimed: true, ownership}`.
6
+ * - `claim(path, owner)` by the same owner is idempotent — returns
7
+ * `{claimed: true, ownership}` WITHOUT re-emitting.
8
+ * - `claim(path, owner)` by a different owner is denied — emits
9
+ * `ownership_denied`, returns `{claimed: false, currentOwner, filePath}`.
10
+ * - `release(path, owner)` on the current owner deletes + emits; returns
11
+ * true. On mismatch or missing entry: returns false; no emit.
12
+ * - `transfer(path, from, to)` requires the current owner to equal
13
+ * `from`. Success replaces the entry with a new `claimedAt`, emits
14
+ * `ownership_transferred`; no intervening `ownership_released` or
15
+ * `ownership_claimed` events. Failure returns false; no emit.
16
+ * - `releaseAll(owner)` sweeps every ownership for `owner`, emits
17
+ * `ownership_released` per entry, returns the count. Other owners'
18
+ * entries are untouched.
19
+ * - File paths are normalised via `path.resolve` before keying —
20
+ * `./foo/bar` and the absolute resolution of the same path collide
21
+ * into one ownership slot.
22
+ * - Ownership is not per-tenant; only per-`RunId`. There is no tenant
23
+ * isolation at this layer (design.md §2.1 aspirational; see §2.7).
24
+ */
25
+
26
+ import path from 'node:path'
27
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
28
+
29
+ import type { AgentBusEvent } from '../types/bus/index.js'
30
+ import type { RunId } from '../types/ids/index.js'
31
+ import type { Logger } from '../utils/logger.js'
32
+
33
+ import { EditOwnershipTracker } from './ownership.js'
34
+
35
+ function makeLogger(): Logger {
36
+ const stub = { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }
37
+ return { ...stub, child: vi.fn(() => ({ ...stub, child: vi.fn() })) } as unknown as Logger
38
+ }
39
+
40
+ function runId(n: number): RunId {
41
+ return `run_${n}` as RunId
42
+ }
43
+
44
+ describe('EditOwnershipTracker', () => {
45
+ let events: AgentBusEvent[]
46
+ let tracker: EditOwnershipTracker
47
+
48
+ beforeEach(() => {
49
+ events = []
50
+ tracker = new EditOwnershipTracker(makeLogger(), (e) => events.push(e))
51
+ })
52
+
53
+ describe('claim', () => {
54
+ it('claims an unowned file, emits ownership_claimed, returns ownership', () => {
55
+ const before = Date.now()
56
+ const result = tracker.claim('/tmp/file.txt', runId(1))
57
+ const after = Date.now()
58
+
59
+ expect(result.claimed).toBe(true)
60
+ if (result.claimed) {
61
+ expect(result.ownership.owner).toBe(runId(1))
62
+ expect(result.ownership.filePath).toBe(path.resolve('/tmp/file.txt'))
63
+ expect(result.ownership.claimedAt).toBeGreaterThanOrEqual(before)
64
+ expect(result.ownership.claimedAt).toBeLessThanOrEqual(after)
65
+ }
66
+ expect(events).toEqual([
67
+ { type: 'ownership_claimed', filePath: path.resolve('/tmp/file.txt'), owner: runId(1) },
68
+ ])
69
+ })
70
+
71
+ it('is idempotent when the same owner re-claims — no re-emit', () => {
72
+ tracker.claim('/tmp/file.txt', runId(1))
73
+ events.length = 0
74
+
75
+ const result = tracker.claim('/tmp/file.txt', runId(1))
76
+ expect(result.claimed).toBe(true)
77
+ expect(events).toEqual([])
78
+ })
79
+
80
+ it('denies a claim by a different owner, emits ownership_denied', () => {
81
+ tracker.claim('/tmp/file.txt', runId(1))
82
+ events.length = 0
83
+
84
+ const result = tracker.claim('/tmp/file.txt', runId(2))
85
+ expect(result.claimed).toBe(false)
86
+ if (!result.claimed) {
87
+ expect(result.currentOwner).toBe(runId(1))
88
+ expect(result.filePath).toBe(path.resolve('/tmp/file.txt'))
89
+ }
90
+ expect(events).toEqual([
91
+ {
92
+ type: 'ownership_denied',
93
+ filePath: path.resolve('/tmp/file.txt'),
94
+ requester: runId(2),
95
+ currentOwner: runId(1),
96
+ },
97
+ ])
98
+ })
99
+
100
+ it('normalises file paths — equivalent paths collide', () => {
101
+ tracker.claim('/tmp/foo/../file.txt', runId(1))
102
+ const result = tracker.claim('/tmp/file.txt', runId(2))
103
+ expect(result.claimed).toBe(false)
104
+ })
105
+ })
106
+
107
+ describe('release', () => {
108
+ it('releases an owned file, emits ownership_released, returns true', () => {
109
+ tracker.claim('/tmp/file.txt', runId(1))
110
+ events.length = 0
111
+
112
+ const ok = tracker.release('/tmp/file.txt', runId(1))
113
+ expect(ok).toBe(true)
114
+ expect(tracker.getOwner('/tmp/file.txt')).toBeUndefined()
115
+ expect(events).toEqual([
116
+ {
117
+ type: 'ownership_released',
118
+ filePath: path.resolve('/tmp/file.txt'),
119
+ previousOwner: runId(1),
120
+ },
121
+ ])
122
+ })
123
+
124
+ it('returns false when no ownership exists — no emit', () => {
125
+ const ok = tracker.release('/tmp/never-claimed.txt', runId(1))
126
+ expect(ok).toBe(false)
127
+ expect(events).toEqual([])
128
+ })
129
+
130
+ it('returns false when owner mismatches — no emit', () => {
131
+ tracker.claim('/tmp/file.txt', runId(1))
132
+ events.length = 0
133
+
134
+ const ok = tracker.release('/tmp/file.txt', runId(2))
135
+ expect(ok).toBe(false)
136
+ expect(tracker.getOwner('/tmp/file.txt')).toBe(runId(1))
137
+ expect(events).toEqual([])
138
+ })
139
+ })
140
+
141
+ describe('transfer', () => {
142
+ it('transfers ownership from current owner to another — atomic, single event', () => {
143
+ tracker.claim('/tmp/file.txt', runId(1))
144
+ events.length = 0
145
+
146
+ const ok = tracker.transfer('/tmp/file.txt', runId(1), runId(2))
147
+ expect(ok).toBe(true)
148
+ expect(tracker.getOwner('/tmp/file.txt')).toBe(runId(2))
149
+ expect(events).toEqual([
150
+ {
151
+ type: 'ownership_transferred',
152
+ filePath: path.resolve('/tmp/file.txt'),
153
+ from: runId(1),
154
+ to: runId(2),
155
+ },
156
+ ])
157
+ })
158
+
159
+ it('returns false when the `from` argument is not the current owner — no emit', () => {
160
+ tracker.claim('/tmp/file.txt', runId(1))
161
+ events.length = 0
162
+
163
+ const ok = tracker.transfer('/tmp/file.txt', runId(99), runId(2))
164
+ expect(ok).toBe(false)
165
+ expect(tracker.getOwner('/tmp/file.txt')).toBe(runId(1))
166
+ expect(events).toEqual([])
167
+ })
168
+
169
+ it('returns false when no ownership exists — no emit', () => {
170
+ const ok = tracker.transfer('/tmp/file.txt', runId(1), runId(2))
171
+ expect(ok).toBe(false)
172
+ expect(events).toEqual([])
173
+ })
174
+
175
+ it('refreshes claimedAt on successful transfer', async () => {
176
+ tracker.claim('/tmp/file.txt', runId(1))
177
+ const t0 = tracker.getOwner('/tmp/file.txt')
178
+ expect(t0).toBe(runId(1))
179
+
180
+ await new Promise((r) => setTimeout(r, 2))
181
+ tracker.transfer('/tmp/file.txt', runId(1), runId(2))
182
+ const list = tracker.listByOwner(runId(2))
183
+ expect(list).toHaveLength(1)
184
+ const after = list[0]
185
+ expect(after?.claimedAt).toBeGreaterThan(0)
186
+ expect(after?.owner).toBe(runId(2))
187
+ })
188
+ })
189
+
190
+ describe('releaseAll', () => {
191
+ it('releases every ownership for the owner, returns count, emits per-entry', () => {
192
+ tracker.claim('/tmp/a.txt', runId(1))
193
+ tracker.claim('/tmp/b.txt', runId(1))
194
+ tracker.claim('/tmp/c.txt', runId(2))
195
+ events.length = 0
196
+
197
+ const count = tracker.releaseAll(runId(1))
198
+ expect(count).toBe(2)
199
+ expect(tracker.getOwner('/tmp/a.txt')).toBeUndefined()
200
+ expect(tracker.getOwner('/tmp/b.txt')).toBeUndefined()
201
+ expect(tracker.getOwner('/tmp/c.txt')).toBe(runId(2))
202
+
203
+ const released = events.filter((e) => e.type === 'ownership_released')
204
+ expect(released.length).toBe(2)
205
+ for (const e of released) {
206
+ if (e.type === 'ownership_released') {
207
+ expect(e.previousOwner).toBe(runId(1))
208
+ }
209
+ }
210
+ })
211
+
212
+ it('returns 0 when the owner has no entries', () => {
213
+ const count = tracker.releaseAll(runId(99))
214
+ expect(count).toBe(0)
215
+ expect(events).toEqual([])
216
+ })
217
+ })
218
+
219
+ describe('read helpers', () => {
220
+ it('getOwner returns undefined for unclaimed paths', () => {
221
+ expect(tracker.getOwner('/tmp/anything.txt')).toBeUndefined()
222
+ })
223
+
224
+ it('listByOwner returns all ownerships for a given owner', () => {
225
+ tracker.claim('/tmp/a.txt', runId(1))
226
+ tracker.claim('/tmp/b.txt', runId(1))
227
+ tracker.claim('/tmp/c.txt', runId(2))
228
+
229
+ const list = tracker.listByOwner(runId(1))
230
+ expect(list.length).toBe(2)
231
+ expect(new Set(list.map((o) => o.filePath))).toEqual(
232
+ new Set([path.resolve('/tmp/a.txt'), path.resolve('/tmp/b.txt')]),
233
+ )
234
+ })
235
+
236
+ it('checkConflict returns the current owner iff a different owner holds the file', () => {
237
+ tracker.claim('/tmp/file.txt', runId(1))
238
+ expect(tracker.checkConflict('/tmp/file.txt', runId(1))).toBeUndefined()
239
+ expect(tracker.checkConflict('/tmp/file.txt', runId(2))).toBe(runId(1))
240
+ expect(tracker.checkConflict('/tmp/other.txt', runId(2))).toBeUndefined()
241
+ })
242
+ })
243
+ })
@@ -51,8 +51,6 @@ export const PromptCacheConfigSchema = z.object({
51
51
  strategy: z.enum(['auto', 'disabled']).default('auto'),
52
52
  })
53
53
 
54
- export type PromptCacheConfig = z.infer<typeof PromptCacheConfigSchema>
55
-
56
54
  export const PluginRuntimeConfigSchema = z.object({
57
55
  enabled: z.boolean().default(false),
58
56
  autoDiscovery: z.boolean().default(true),