@namzu/sdk 0.4.2 → 0.4.4

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 (310) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/advisory/context.test.d.ts +16 -0
  3. package/dist/advisory/context.test.d.ts.map +1 -0
  4. package/dist/advisory/context.test.js +92 -0
  5. package/dist/advisory/context.test.js.map +1 -0
  6. package/dist/advisory/evaluator.test.d.ts +34 -0
  7. package/dist/advisory/evaluator.test.d.ts.map +1 -0
  8. package/dist/advisory/evaluator.test.js +172 -0
  9. package/dist/advisory/evaluator.test.js.map +1 -0
  10. package/dist/advisory/executor.test.d.ts +35 -0
  11. package/dist/advisory/executor.test.d.ts.map +1 -0
  12. package/dist/advisory/executor.test.js +233 -0
  13. package/dist/advisory/executor.test.js.map +1 -0
  14. package/dist/advisory/registry.test.d.ts +16 -0
  15. package/dist/advisory/registry.test.d.ts.map +1 -0
  16. package/dist/advisory/registry.test.js +62 -0
  17. package/dist/advisory/registry.test.js.map +1 -0
  18. package/dist/bridge/a2a/agent-card.test.d.ts +24 -0
  19. package/dist/bridge/a2a/agent-card.test.d.ts.map +1 -0
  20. package/dist/bridge/a2a/agent-card.test.js +118 -0
  21. package/dist/bridge/a2a/agent-card.test.js.map +1 -0
  22. package/dist/bridge/a2a/mapper.test.d.ts +29 -0
  23. package/dist/bridge/a2a/mapper.test.d.ts.map +1 -0
  24. package/dist/bridge/a2a/mapper.test.js +265 -0
  25. package/dist/bridge/a2a/mapper.test.js.map +1 -0
  26. package/dist/bridge/a2a/message.test.d.ts +20 -0
  27. package/dist/bridge/a2a/message.test.d.ts.map +1 -0
  28. package/dist/bridge/a2a/message.test.js +116 -0
  29. package/dist/bridge/a2a/message.test.js.map +1 -0
  30. package/dist/bridge/a2a/task.test.d.ts +29 -0
  31. package/dist/bridge/a2a/task.test.d.ts.map +1 -0
  32. package/dist/bridge/a2a/task.test.js +198 -0
  33. package/dist/bridge/a2a/task.test.js.map +1 -0
  34. package/dist/bridge/mcp/connector/adapter.test.d.ts +27 -0
  35. package/dist/bridge/mcp/connector/adapter.test.d.ts.map +1 -0
  36. package/dist/bridge/mcp/connector/adapter.test.js +203 -0
  37. package/dist/bridge/mcp/connector/adapter.test.js.map +1 -0
  38. package/dist/bridge/sse/mapper.test.d.ts +27 -0
  39. package/dist/bridge/sse/mapper.test.d.ts.map +1 -0
  40. package/dist/bridge/sse/mapper.test.js +271 -0
  41. package/dist/bridge/sse/mapper.test.js.map +1 -0
  42. package/dist/bridge/tools/connector/adapter.d.ts +2 -2
  43. package/dist/bridge/tools/connector/adapter.test.d.ts +28 -0
  44. package/dist/bridge/tools/connector/adapter.test.d.ts.map +1 -0
  45. package/dist/bridge/tools/connector/adapter.test.js +182 -0
  46. package/dist/bridge/tools/connector/adapter.test.js.map +1 -0
  47. package/dist/bridge/tools/connector/definitions.test.d.ts +23 -0
  48. package/dist/bridge/tools/connector/definitions.test.d.ts.map +1 -0
  49. package/dist/bridge/tools/connector/definitions.test.js +158 -0
  50. package/dist/bridge/tools/connector/definitions.test.js.map +1 -0
  51. package/dist/bridge/tools/connector/router.test.d.ts +21 -0
  52. package/dist/bridge/tools/connector/router.test.d.ts.map +1 -0
  53. package/dist/bridge/tools/connector/router.test.js +139 -0
  54. package/dist/bridge/tools/connector/router.test.js.map +1 -0
  55. package/dist/bus/breaker.test.d.ts +41 -0
  56. package/dist/bus/breaker.test.d.ts.map +1 -0
  57. package/dist/bus/breaker.test.js +242 -0
  58. package/dist/bus/breaker.test.js.map +1 -0
  59. package/dist/bus/index.d.ts +3 -1
  60. package/dist/bus/index.d.ts.map +1 -1
  61. package/dist/bus/index.js +18 -11
  62. package/dist/bus/index.js.map +1 -1
  63. package/dist/bus/index.test.d.ts +25 -0
  64. package/dist/bus/index.test.d.ts.map +1 -0
  65. package/dist/bus/index.test.js +151 -0
  66. package/dist/bus/index.test.js.map +1 -0
  67. package/dist/bus/lock.test.d.ts +44 -0
  68. package/dist/bus/lock.test.d.ts.map +1 -0
  69. package/dist/bus/lock.test.js +226 -0
  70. package/dist/bus/lock.test.js.map +1 -0
  71. package/dist/bus/ownership.test.d.ts +26 -0
  72. package/dist/bus/ownership.test.d.ts.map +1 -0
  73. package/dist/bus/ownership.test.js +205 -0
  74. package/dist/bus/ownership.test.js.map +1 -0
  75. package/dist/config/runtime.d.ts +28 -28
  76. package/dist/connector/BaseConnector.test.d.ts +21 -0
  77. package/dist/connector/BaseConnector.test.d.ts.map +1 -0
  78. package/dist/connector/BaseConnector.test.js +108 -0
  79. package/dist/connector/BaseConnector.test.js.map +1 -0
  80. package/dist/connector/builtins/http.test.d.ts +30 -0
  81. package/dist/connector/builtins/http.test.d.ts.map +1 -0
  82. package/dist/connector/builtins/http.test.js +232 -0
  83. package/dist/connector/builtins/http.test.js.map +1 -0
  84. package/dist/connector/builtins/webhook.test.d.ts +20 -0
  85. package/dist/connector/builtins/webhook.test.d.ts.map +1 -0
  86. package/dist/connector/builtins/webhook.test.js +113 -0
  87. package/dist/connector/builtins/webhook.test.js.map +1 -0
  88. package/dist/connector/execution/factory.test.d.ts +16 -0
  89. package/dist/connector/execution/factory.test.d.ts.map +1 -0
  90. package/dist/connector/execution/factory.test.js +64 -0
  91. package/dist/connector/execution/factory.test.js.map +1 -0
  92. package/dist/connector/execution/remote.test.d.ts +16 -0
  93. package/dist/connector/execution/remote.test.d.ts.map +1 -0
  94. package/dist/connector/execution/remote.test.js +53 -0
  95. package/dist/connector/execution/remote.test.js.map +1 -0
  96. package/dist/connector/mcp/adapter.test.d.ts +34 -0
  97. package/dist/connector/mcp/adapter.test.d.ts.map +1 -0
  98. package/dist/connector/mcp/adapter.test.js +199 -0
  99. package/dist/connector/mcp/adapter.test.js.map +1 -0
  100. package/dist/probe/context.d.ts +8 -0
  101. package/dist/probe/context.d.ts.map +1 -0
  102. package/dist/probe/context.js +7 -0
  103. package/dist/probe/context.js.map +1 -0
  104. package/dist/probe/errors.d.ts +12 -0
  105. package/dist/probe/errors.d.ts.map +1 -0
  106. package/dist/probe/errors.js +21 -0
  107. package/dist/probe/errors.js.map +1 -0
  108. package/dist/probe/index.d.ts +5 -0
  109. package/dist/probe/index.d.ts.map +1 -0
  110. package/dist/probe/index.js +4 -0
  111. package/dist/probe/index.js.map +1 -0
  112. package/dist/probe/registry.d.ts +24 -0
  113. package/dist/probe/registry.d.ts.map +1 -0
  114. package/dist/probe/registry.js +228 -0
  115. package/dist/probe/registry.js.map +1 -0
  116. package/dist/probe/registry.test.d.ts +7 -0
  117. package/dist/probe/registry.test.d.ts.map +1 -0
  118. package/dist/probe/registry.test.js +310 -0
  119. package/dist/probe/registry.test.js.map +1 -0
  120. package/dist/provider/instrumentation.d.ts +9 -0
  121. package/dist/provider/instrumentation.d.ts.map +1 -0
  122. package/dist/provider/instrumentation.js +104 -0
  123. package/dist/provider/instrumentation.js.map +1 -0
  124. package/dist/provider/instrumentation.test.d.ts +2 -0
  125. package/dist/provider/instrumentation.test.d.ts.map +1 -0
  126. package/dist/provider/instrumentation.test.js +152 -0
  127. package/dist/provider/instrumentation.test.js.map +1 -0
  128. package/dist/public-runtime.d.ts +5 -0
  129. package/dist/public-runtime.d.ts.map +1 -1
  130. package/dist/public-runtime.js +4 -0
  131. package/dist/public-runtime.js.map +1 -1
  132. package/dist/public-types.d.ts +3 -0
  133. package/dist/public-types.d.ts.map +1 -1
  134. package/dist/rag/chunking.test.d.ts +20 -0
  135. package/dist/rag/chunking.test.d.ts.map +1 -0
  136. package/dist/rag/chunking.test.js +92 -0
  137. package/dist/rag/chunking.test.js.map +1 -0
  138. package/dist/rag/context-assembler.test.d.ts +19 -0
  139. package/dist/rag/context-assembler.test.d.ts.map +1 -0
  140. package/dist/rag/context-assembler.test.js +98 -0
  141. package/dist/rag/context-assembler.test.js.map +1 -0
  142. package/dist/rag/embedding.test.d.ts +19 -0
  143. package/dist/rag/embedding.test.d.ts.map +1 -0
  144. package/dist/rag/embedding.test.js +115 -0
  145. package/dist/rag/embedding.test.js.map +1 -0
  146. package/dist/rag/ingestion.test.d.ts +22 -0
  147. package/dist/rag/ingestion.test.d.ts.map +1 -0
  148. package/dist/rag/ingestion.test.js +99 -0
  149. package/dist/rag/ingestion.test.js.map +1 -0
  150. package/dist/rag/knowledge-base.test.d.ts +17 -0
  151. package/dist/rag/knowledge-base.test.d.ts.map +1 -0
  152. package/dist/rag/knowledge-base.test.js +77 -0
  153. package/dist/rag/knowledge-base.test.js.map +1 -0
  154. package/dist/rag/rag-tool.test.d.ts +21 -0
  155. package/dist/rag/rag-tool.test.d.ts.map +1 -0
  156. package/dist/rag/rag-tool.test.js +149 -0
  157. package/dist/rag/rag-tool.test.js.map +1 -0
  158. package/dist/rag/retriever.test.d.ts +26 -0
  159. package/dist/rag/retriever.test.d.ts.map +1 -0
  160. package/dist/rag/retriever.test.js +180 -0
  161. package/dist/rag/retriever.test.js.map +1 -0
  162. package/dist/rag/vector-store.test.d.ts +38 -0
  163. package/dist/rag/vector-store.test.d.ts.map +1 -0
  164. package/dist/rag/vector-store.test.js +175 -0
  165. package/dist/rag/vector-store.test.js.map +1 -0
  166. package/dist/registry/ManagedRegistry.test.d.ts +21 -0
  167. package/dist/registry/ManagedRegistry.test.d.ts.map +1 -0
  168. package/dist/registry/ManagedRegistry.test.js +98 -0
  169. package/dist/registry/ManagedRegistry.test.js.map +1 -0
  170. package/dist/registry/Registry.test.d.ts +18 -0
  171. package/dist/registry/Registry.test.d.ts.map +1 -0
  172. package/dist/registry/Registry.test.js +79 -0
  173. package/dist/registry/Registry.test.js.map +1 -0
  174. package/dist/registry/agent/definitions.test.d.ts +15 -0
  175. package/dist/registry/agent/definitions.test.d.ts.map +1 -0
  176. package/dist/registry/agent/definitions.test.js +84 -0
  177. package/dist/registry/agent/definitions.test.js.map +1 -0
  178. package/dist/registry/connector/definitions.test.d.ts +13 -0
  179. package/dist/registry/connector/definitions.test.d.ts.map +1 -0
  180. package/dist/registry/connector/definitions.test.js +41 -0
  181. package/dist/registry/connector/definitions.test.js.map +1 -0
  182. package/dist/registry/connector/scoped.test.d.ts +21 -0
  183. package/dist/registry/connector/scoped.test.d.ts.map +1 -0
  184. package/dist/registry/connector/scoped.test.js +115 -0
  185. package/dist/registry/connector/scoped.test.js.map +1 -0
  186. package/dist/registry/plugin/index.test.d.ts +12 -0
  187. package/dist/registry/plugin/index.test.d.ts.map +1 -0
  188. package/dist/registry/plugin/index.test.js +69 -0
  189. package/dist/registry/plugin/index.test.js.map +1 -0
  190. package/dist/registry/tool/execute.test.d.ts +42 -0
  191. package/dist/registry/tool/execute.test.d.ts.map +1 -0
  192. package/dist/registry/tool/execute.test.js +281 -0
  193. package/dist/registry/tool/execute.test.js.map +1 -0
  194. package/dist/runtime/query/events.d.ts +3 -1
  195. package/dist/runtime/query/events.d.ts.map +1 -1
  196. package/dist/runtime/query/events.js +6 -1
  197. package/dist/runtime/query/events.js.map +1 -1
  198. package/dist/runtime/query/executor.d.ts +3 -1
  199. package/dist/runtime/query/executor.d.ts.map +1 -1
  200. package/dist/runtime/query/executor.js +30 -1
  201. package/dist/runtime/query/executor.js.map +1 -1
  202. package/dist/runtime/query/iteration/phases/advisory.test.d.ts +42 -0
  203. package/dist/runtime/query/iteration/phases/advisory.test.d.ts.map +1 -0
  204. package/dist/runtime/query/iteration/phases/advisory.test.js +334 -0
  205. package/dist/runtime/query/iteration/phases/advisory.test.js.map +1 -0
  206. package/dist/test-setup.d.ts +22 -0
  207. package/dist/test-setup.d.ts.map +1 -0
  208. package/dist/test-setup.js +23 -0
  209. package/dist/test-setup.js.map +1 -0
  210. package/dist/types/bus/index.d.ts +46 -2
  211. package/dist/types/bus/index.d.ts.map +1 -1
  212. package/dist/types/doctor/check.d.ts +41 -0
  213. package/dist/types/doctor/check.d.ts.map +1 -0
  214. package/dist/types/doctor/check.js +2 -0
  215. package/dist/types/doctor/check.js.map +1 -0
  216. package/dist/types/doctor/index.d.ts +2 -0
  217. package/dist/types/doctor/index.d.ts.map +1 -0
  218. package/dist/types/doctor/index.js +2 -0
  219. package/dist/types/doctor/index.js.map +1 -0
  220. package/dist/types/probe/event-kind.d.ts +6 -0
  221. package/dist/types/probe/event-kind.d.ts.map +1 -0
  222. package/dist/types/probe/event-kind.js +2 -0
  223. package/dist/types/probe/event-kind.js.map +1 -0
  224. package/dist/types/probe/event-of.d.ts +5 -0
  225. package/dist/types/probe/event-of.d.ts.map +1 -0
  226. package/dist/types/probe/event-of.js +2 -0
  227. package/dist/types/probe/event-of.js.map +1 -0
  228. package/dist/types/probe/index.d.ts +4 -0
  229. package/dist/types/probe/index.d.ts.map +1 -0
  230. package/dist/types/probe/index.js +2 -0
  231. package/dist/types/probe/index.js.map +1 -0
  232. package/dist/types/probe/registry.d.ts +27 -0
  233. package/dist/types/probe/registry.d.ts.map +1 -0
  234. package/dist/types/probe/registry.js +2 -0
  235. package/dist/types/probe/registry.js.map +1 -0
  236. package/dist/utils/logger.d.ts +1 -1
  237. package/dist/utils/logger.d.ts.map +1 -1
  238. package/dist/utils/logger.js +5 -0
  239. package/dist/utils/logger.js.map +1 -1
  240. package/dist/vault/instrumentation.d.ts +11 -0
  241. package/dist/vault/instrumentation.d.ts.map +1 -0
  242. package/dist/vault/instrumentation.js +32 -0
  243. package/dist/vault/instrumentation.js.map +1 -0
  244. package/dist/vault/instrumentation.test.d.ts +2 -0
  245. package/dist/vault/instrumentation.test.d.ts.map +1 -0
  246. package/dist/vault/instrumentation.test.js +80 -0
  247. package/dist/vault/instrumentation.test.js.map +1 -0
  248. package/package.json +4 -1
  249. package/src/advisory/context.test.ts +109 -0
  250. package/src/advisory/evaluator.test.ts +192 -0
  251. package/src/advisory/executor.test.ts +272 -0
  252. package/src/advisory/registry.test.ts +75 -0
  253. package/src/bridge/a2a/agent-card.test.ts +140 -0
  254. package/src/bridge/a2a/mapper.test.ts +293 -0
  255. package/src/bridge/a2a/message.test.ts +138 -0
  256. package/src/bridge/a2a/task.test.ts +235 -0
  257. package/src/bridge/mcp/connector/adapter.test.ts +230 -0
  258. package/src/bridge/sse/mapper.test.ts +422 -0
  259. package/src/bridge/tools/connector/adapter.test.ts +224 -0
  260. package/src/bridge/tools/connector/definitions.test.ts +183 -0
  261. package/src/bridge/tools/connector/router.test.ts +159 -0
  262. package/src/bus/breaker.test.ts +274 -0
  263. package/src/bus/index.test.ts +183 -0
  264. package/src/bus/index.ts +21 -10
  265. package/src/bus/lock.test.ts +265 -0
  266. package/src/bus/ownership.test.ts +243 -0
  267. package/src/connector/BaseConnector.test.ts +130 -0
  268. package/src/connector/builtins/http.test.ts +290 -0
  269. package/src/connector/builtins/webhook.test.ts +138 -0
  270. package/src/connector/execution/factory.test.ts +75 -0
  271. package/src/connector/execution/remote.test.ts +63 -0
  272. package/src/connector/mcp/adapter.test.ts +249 -0
  273. package/src/probe/context.ts +14 -0
  274. package/src/probe/errors.ts +27 -0
  275. package/src/probe/index.ts +4 -0
  276. package/src/probe/registry.test.ts +480 -0
  277. package/src/probe/registry.ts +276 -0
  278. package/src/provider/instrumentation.test.ts +192 -0
  279. package/src/provider/instrumentation.ts +139 -0
  280. package/src/public-runtime.ts +17 -0
  281. package/src/public-types.ts +3 -0
  282. package/src/rag/chunking.test.ts +107 -0
  283. package/src/rag/context-assembler.test.ts +114 -0
  284. package/src/rag/embedding.test.ts +130 -0
  285. package/src/rag/ingestion.test.ts +114 -0
  286. package/src/rag/knowledge-base.test.ts +106 -0
  287. package/src/rag/rag-tool.test.ts +167 -0
  288. package/src/rag/retriever.test.ts +210 -0
  289. package/src/rag/vector-store.test.ts +196 -0
  290. package/src/registry/ManagedRegistry.test.ts +118 -0
  291. package/src/registry/Registry.test.ts +91 -0
  292. package/src/registry/agent/definitions.test.ts +100 -0
  293. package/src/registry/connector/definitions.test.ts +51 -0
  294. package/src/registry/connector/scoped.test.ts +129 -0
  295. package/src/registry/plugin/index.test.ts +85 -0
  296. package/src/registry/tool/execute.test.ts +330 -0
  297. package/src/runtime/query/events.ts +6 -1
  298. package/src/runtime/query/executor.ts +34 -0
  299. package/src/runtime/query/iteration/phases/advisory.test.ts +412 -0
  300. package/src/test-setup.ts +24 -0
  301. package/src/types/bus/index.ts +54 -2
  302. package/src/types/doctor/check.ts +53 -0
  303. package/src/types/doctor/index.ts +9 -0
  304. package/src/types/probe/event-kind.ts +8 -0
  305. package/src/types/probe/event-of.ts +3 -0
  306. package/src/types/probe/index.ts +11 -0
  307. package/src/types/probe/registry.ts +36 -0
  308. package/src/utils/logger.ts +6 -1
  309. package/src/vault/instrumentation.test.ts +98 -0
  310. package/src/vault/instrumentation.ts +56 -0
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 3):
3
+ *
4
+ * - `ConnectorRegistry` extends `ManagedRegistry<ConnectorDefinition>`
5
+ * with `idField: 'id'` — it keys by the top-level `id` field, NOT
6
+ * a nested path.
7
+ * - `listByType(connectionType)` filters by `connectionType`.
8
+ * - As a global (non-tenant-scoped) registry, ConnectorRegistry is
9
+ * shared across tenants; tenant isolation lives in
10
+ * `TenantConnectorManager` per Codex #5.
11
+ */
12
+ import { describe, expect, it } from 'vitest';
13
+ import { z } from 'zod';
14
+ import { ConnectorRegistry } from './definitions.js';
15
+ function makeDef(id, connectionType) {
16
+ return {
17
+ id: id,
18
+ name: id,
19
+ description: `${id} connector`,
20
+ connectionType,
21
+ configSchema: z.object({}),
22
+ methods: [],
23
+ };
24
+ }
25
+ describe('ConnectorRegistry', () => {
26
+ it('keys by top-level id', () => {
27
+ const r = new ConnectorRegistry();
28
+ r.register(makeDef('conn_a', 'http'));
29
+ expect(r.get('conn_a')).toBeDefined();
30
+ });
31
+ it('listByType filters by connectionType', () => {
32
+ const r = new ConnectorRegistry();
33
+ r.register(makeDef('conn_a', 'http'));
34
+ r.register(makeDef('conn_b', 'webhook'));
35
+ r.register(makeDef('conn_c', 'http'));
36
+ expect(r.listByType('http').map((d) => d.id)).toEqual(['conn_a', 'conn_c']);
37
+ expect(r.listByType('webhook').map((d) => d.id)).toEqual(['conn_b']);
38
+ expect(r.listByType('custom')).toEqual([]);
39
+ });
40
+ });
41
+ //# sourceMappingURL=definitions.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.test.js","sourceRoot":"","sources":["../../../src/registry/connector/definitions.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAKvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEpD,SAAS,OAAO,CACf,EAAU,EACV,cAAqD;IAErD,OAAO;QACN,EAAE,EAAE,EAAiB;QACrB,IAAI,EAAE,EAAE;QACR,WAAW,EAAE,GAAG,EAAE,YAAY;QAC9B,cAAc;QACd,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,EAAE;KACX,CAAA;AACF,CAAC;AAED,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,GAAG,IAAI,iBAAiB,EAAE,CAAA;QACjC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;QACrC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;IACtC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,GAAG,IAAI,iBAAiB,EAAE,CAAA;QACjC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;QACrC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAA;QACxC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;QACrC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAA;QAC3E,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;QACpE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC3C,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 3):
3
+ *
4
+ * - `ScopedConnectorRegistry` stores per-scope config by a composite
5
+ * key `<scope>:<scopeId>:<connectorId>`. Multiple configs at
6
+ * different scopes for the same connector coexist.
7
+ * - `set`, `remove`, `getAt` round-trip through the same key.
8
+ * - `resolve(connectorId, chain)` iterates in `CONNECTOR_SCOPE_ORDER`
9
+ * (org → environment → team → project → agent) and merges layers
10
+ * — later scopes override earlier ones. Specifically:
11
+ * - `options` are shallow-merged across layers.
12
+ * - `auth` is last-wins (any layer with an explicit auth replaces).
13
+ * - `enabled` is last-wins (defaulting to true when no layer sets it).
14
+ * - The final `ConnectorConfig.name` falls back to `connectorId`
15
+ * when no layer sets a name.
16
+ * - `resolve` returns undefined when no layer matches the chain.
17
+ * - `listForConnector` returns every config for a connector across
18
+ * all scopes; `listAtScope` returns every connector at a given scope.
19
+ */
20
+ export {};
21
+ //# sourceMappingURL=scoped.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoped.test.d.ts","sourceRoot":"","sources":["../../../src/registry/connector/scoped.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 3):
3
+ *
4
+ * - `ScopedConnectorRegistry` stores per-scope config by a composite
5
+ * key `<scope>:<scopeId>:<connectorId>`. Multiple configs at
6
+ * different scopes for the same connector coexist.
7
+ * - `set`, `remove`, `getAt` round-trip through the same key.
8
+ * - `resolve(connectorId, chain)` iterates in `CONNECTOR_SCOPE_ORDER`
9
+ * (org → environment → team → project → agent) and merges layers
10
+ * — later scopes override earlier ones. Specifically:
11
+ * - `options` are shallow-merged across layers.
12
+ * - `auth` is last-wins (any layer with an explicit auth replaces).
13
+ * - `enabled` is last-wins (defaulting to true when no layer sets it).
14
+ * - The final `ConnectorConfig.name` falls back to `connectorId`
15
+ * when no layer sets a name.
16
+ * - `resolve` returns undefined when no layer matches the chain.
17
+ * - `listForConnector` returns every config for a connector across
18
+ * all scopes; `listAtScope` returns every connector at a given scope.
19
+ */
20
+ import { describe, expect, it } from 'vitest';
21
+ import { ScopedConnectorRegistry } from './scoped.js';
22
+ const CID = 'conn_http';
23
+ describe('ScopedConnectorRegistry', () => {
24
+ describe('set + getAt + remove', () => {
25
+ it('round-trips via the composite key', () => {
26
+ const r = new ScopedConnectorRegistry();
27
+ r.set({
28
+ scope: { scope: 'org', scopeId: 'org_1' },
29
+ connectorId: CID,
30
+ options: { k: 'v' },
31
+ });
32
+ expect(r.getAt({ scope: 'org', scopeId: 'org_1' }, CID)?.options).toEqual({ k: 'v' });
33
+ });
34
+ it('remove returns true iff an entry existed', () => {
35
+ const r = new ScopedConnectorRegistry();
36
+ r.set({ scope: { scope: 'org', scopeId: 'org_1' }, connectorId: CID });
37
+ expect(r.remove({ scope: 'org', scopeId: 'org_1' }, CID)).toBe(true);
38
+ expect(r.remove({ scope: 'org', scopeId: 'org_1' }, CID)).toBe(false);
39
+ });
40
+ it('different scopes coexist for the same connector', () => {
41
+ const r = new ScopedConnectorRegistry();
42
+ r.set({ scope: { scope: 'org', scopeId: 'org_1' }, connectorId: CID });
43
+ r.set({ scope: { scope: 'project', scopeId: 'proj_1' }, connectorId: CID });
44
+ expect(r.listForConnector(CID)).toHaveLength(2);
45
+ });
46
+ });
47
+ describe('resolve layering', () => {
48
+ it('merges options shallow; later scopes override', () => {
49
+ const r = new ScopedConnectorRegistry();
50
+ r.set({
51
+ scope: { scope: 'org', scopeId: 'org_1' },
52
+ connectorId: CID,
53
+ options: { host: 'api.org', timeout: 30 },
54
+ });
55
+ r.set({
56
+ scope: { scope: 'project', scopeId: 'proj_1' },
57
+ connectorId: CID,
58
+ options: { host: 'api.project' },
59
+ });
60
+ const resolved = r.resolve(CID, { org: 'org_1', project: 'proj_1' });
61
+ expect(resolved?.options).toEqual({ host: 'api.project', timeout: 30 });
62
+ });
63
+ it('auth is last-wins (CONNECTOR_SCOPE_ORDER)', () => {
64
+ const r = new ScopedConnectorRegistry();
65
+ r.set({
66
+ scope: { scope: 'org', scopeId: 'org_1' },
67
+ connectorId: CID,
68
+ auth: { type: 'none' },
69
+ });
70
+ r.set({
71
+ scope: { scope: 'project', scopeId: 'proj_1' },
72
+ connectorId: CID,
73
+ auth: { type: 'api_key', credentials: { apiKey: 'secret' } },
74
+ });
75
+ const resolved = r.resolve(CID, { org: 'org_1', project: 'proj_1' });
76
+ expect(resolved?.auth).toEqual({ type: 'api_key', credentials: { apiKey: 'secret' } });
77
+ });
78
+ it('enabled defaults to true and is last-wins', () => {
79
+ const r = new ScopedConnectorRegistry();
80
+ r.set({ scope: { scope: 'org', scopeId: 'org_1' }, connectorId: CID, enabled: false });
81
+ const resolved = r.resolve(CID, { org: 'org_1' });
82
+ expect(resolved?.enabled).toBe(false);
83
+ });
84
+ it('config.name falls back to connectorId when no layer sets a name', () => {
85
+ const r = new ScopedConnectorRegistry();
86
+ r.set({ scope: { scope: 'org', scopeId: 'org_1' }, connectorId: CID });
87
+ const resolved = r.resolve(CID, { org: 'org_1' });
88
+ expect(resolved?.config.name).toBe(CID);
89
+ });
90
+ it('resolvedFrom preserves layer order by CONNECTOR_SCOPE_ORDER', () => {
91
+ const r = new ScopedConnectorRegistry();
92
+ r.set({ scope: { scope: 'project', scopeId: 'proj_1' }, connectorId: CID });
93
+ r.set({ scope: { scope: 'org', scopeId: 'org_1' }, connectorId: CID });
94
+ const resolved = r.resolve(CID, { org: 'org_1', project: 'proj_1' });
95
+ expect(resolved?.resolvedFrom.map((s) => s.scope)).toEqual(['org', 'project']);
96
+ });
97
+ it('returns undefined when no layer matches the chain', () => {
98
+ const r = new ScopedConnectorRegistry();
99
+ expect(r.resolve(CID, { org: 'org_none' })).toBeUndefined();
100
+ });
101
+ });
102
+ describe('list operations', () => {
103
+ it('listAtScope filters by scope prefix', () => {
104
+ const r = new ScopedConnectorRegistry();
105
+ r.set({ scope: { scope: 'org', scopeId: 'org_1' }, connectorId: CID });
106
+ r.set({
107
+ scope: { scope: 'org', scopeId: 'org_1' },
108
+ connectorId: 'conn_other',
109
+ });
110
+ r.set({ scope: { scope: 'project', scopeId: 'proj_1' }, connectorId: CID });
111
+ expect(r.listAtScope({ scope: 'org', scopeId: 'org_1' })).toHaveLength(2);
112
+ });
113
+ });
114
+ });
115
+ //# sourceMappingURL=scoped.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoped.test.js","sourceRoot":"","sources":["../../../src/registry/connector/scoped.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 3):
3
+ *
4
+ * - `PluginRegistry` extends `ManagedRegistry<PluginDefinition>`
5
+ * with `idField: 'id'`.
6
+ * - `listByScope(scope)` filters by `def.scope`.
7
+ * - `listByStatus(status)` filters by `def.status`.
8
+ * - `findByName(name)` does a linear scan through `getAll()` and
9
+ * returns the first match by `manifest.name`, or undefined.
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/registry/plugin/index.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 3):
3
+ *
4
+ * - `PluginRegistry` extends `ManagedRegistry<PluginDefinition>`
5
+ * with `idField: 'id'`.
6
+ * - `listByScope(scope)` filters by `def.scope`.
7
+ * - `listByStatus(status)` filters by `def.status`.
8
+ * - `findByName(name)` does a linear scan through `getAll()` and
9
+ * returns the first match by `manifest.name`, or undefined.
10
+ */
11
+ import { describe, expect, it } from 'vitest';
12
+ import { PluginRegistry } from './index.js';
13
+ function makeDef(id, scope, status, name = id) {
14
+ return {
15
+ id: id,
16
+ manifest: {
17
+ name,
18
+ version: '1.0.0',
19
+ description: `${name} plugin`,
20
+ },
21
+ scope,
22
+ status,
23
+ rootDir: `/plugins/${id}`,
24
+ installedAt: Date.now(),
25
+ };
26
+ }
27
+ describe('PluginRegistry', () => {
28
+ it('keys by top-level id', () => {
29
+ const r = new PluginRegistry();
30
+ r.register(makeDef('plugin_a', 'project', 'installed'));
31
+ expect(r.get('plugin_a')).toBeDefined();
32
+ });
33
+ it('listByScope filters by scope', () => {
34
+ const r = new PluginRegistry();
35
+ r.register(makeDef('a', 'project', 'installed'));
36
+ r.register(makeDef('b', 'user', 'enabled'));
37
+ r.register(makeDef('c', 'project', 'disabled'));
38
+ expect(r.listByScope('project').map((d) => d.id)).toEqual(['a', 'c']);
39
+ expect(r.listByScope('user').map((d) => d.id)).toEqual(['b']);
40
+ });
41
+ it('listByStatus filters by status', () => {
42
+ const r = new PluginRegistry();
43
+ r.register(makeDef('a', 'project', 'installed'));
44
+ r.register(makeDef('b', 'project', 'enabled'));
45
+ r.register(makeDef('c', 'project', 'enabled'));
46
+ expect(r.listByStatus('enabled').map((d) => d.id)).toEqual(['b', 'c']);
47
+ expect(r.listByStatus('error')).toEqual([]);
48
+ });
49
+ describe('findByName', () => {
50
+ it('returns the first def with matching manifest.name', () => {
51
+ const r = new PluginRegistry();
52
+ r.register(makeDef('id_1', 'project', 'installed', 'alpha'));
53
+ r.register(makeDef('id_2', 'project', 'installed', 'beta'));
54
+ expect(r.findByName('beta')?.id).toBe('id_2');
55
+ });
56
+ it('returns undefined when no match', () => {
57
+ const r = new PluginRegistry();
58
+ r.register(makeDef('id_1', 'project', 'installed', 'alpha'));
59
+ expect(r.findByName('missing')).toBeUndefined();
60
+ });
61
+ it('is case-sensitive (exact string match)', () => {
62
+ const r = new PluginRegistry();
63
+ r.register(makeDef('id_1', 'project', 'installed', 'Alpha'));
64
+ expect(r.findByName('alpha')).toBeUndefined();
65
+ expect(r.findByName('Alpha')?.id).toBe('id_1');
66
+ });
67
+ });
68
+ });
69
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../src/registry/plugin/index.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAK7C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C,SAAS,OAAO,CACf,EAAU,EACV,KAAkB,EAClB,MAAoB,EACpB,IAAI,GAAG,EAAE;IAET,OAAO;QACN,EAAE,EAAE,EAAc;QAClB,QAAQ,EAAE;YACT,IAAI;YACJ,OAAO,EAAE,OAAO;YAChB,WAAW,EAAE,GAAG,IAAI,SAAS;SAC7B;QACD,KAAK;QACL,MAAM;QACN,OAAO,EAAE,YAAY,EAAE,EAAE;QACzB,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;KACvB,CAAA;AACF,CAAC;AAED,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,GAAG,IAAI,cAAc,EAAE,CAAA;QAC9B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAA;QACvD,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,GAAG,IAAI,cAAc,EAAE,CAAA;QAC9B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAA;QAChD,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;QAC3C,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAA;QAC/C,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;QACrE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAC9D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,GAAG,IAAI,cAAc,EAAE,CAAA;QAC9B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAA;QAChD,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAA;QAC9C,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAA;QAC9C,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;QACtE,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC5C,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC5D,MAAM,CAAC,GAAG,IAAI,cAAc,EAAE,CAAA;YAC9B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAA;YAC5D,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC,CAAA;YAC3D,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC9C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YAC1C,MAAM,CAAC,GAAG,IAAI,cAAc,EAAE,CAAA;YAC9B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAA;YAC5D,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;QAChD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YACjD,MAAM,CAAC,GAAG,IAAI,cAAc,EAAE,CAAA;YAC9B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAA;YAC5D,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;YAC7C,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC/C,CAAC,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 3):
3
+ *
4
+ * - `ToolRegistry` extends `ManagedRegistry<ToolDefinition>` with
5
+ * `idField: 'name'` and an additional `availability` map keyed by
6
+ * tool name.
7
+ * - `register(tool)` defaults availability to 'active'; the array
8
+ * overload uses the second arg (if it's a string) as the initial
9
+ * state for all tools.
10
+ * - Tier validation: if `tool.tier` is set AND `tierConfig` is
11
+ * configured, the tier id must be in `tierConfig.tiers`; otherwise
12
+ * register throws. Tools without a tier (even with tierConfig
13
+ * configured) are always accepted.
14
+ * - `unregister` + `clear` drop both the Registry entry and the
15
+ * availability entry.
16
+ * - `activate` / `defer` take a list of names; each throws (via
17
+ * `getOrThrow`) if the name is unknown, then toggles availability.
18
+ * - `suspendAll` flips every `active` tool to `suspended`;
19
+ * `deferred` / `suspended` tools are left alone. `hasSuspended`
20
+ * reports true iff at least one tool is suspended.
21
+ * - `getAvailability(name)` returns 'active' as a default even for
22
+ * unknown names (this is non-obvious but is the current behavior).
23
+ * - `searchDeferred(q)` is a case-insensitive filter against name OR
24
+ * description of every DEFERRED tool.
25
+ * - `assignTiers(mapping)` mutates `tool.tier` on existing tools;
26
+ * throws via `getOrThrow` on unknown name; throws if the tier id
27
+ * is not in `tierConfig.tiers`.
28
+ * - `toTierGuidance` returns null without a guidanceTemplate; calls
29
+ * the template with every defined tier otherwise.
30
+ * - `toPromptSection`: returns '' when no active or deferred tools;
31
+ * otherwise produces `<available_tools>` + `<deferred_tools>`
32
+ * fragments.
33
+ * - `toLLMTools`: converts active + suspended tools (filtered by
34
+ * `toolNames` if provided) into LLM tool schemas via
35
+ * `zodToJsonSchema`. When `tierConfig.labelInDescription` is true,
36
+ * the description is prefixed with the tier label.
37
+ * - `execute`: validates availability → permissionMode plan gate →
38
+ * zod.safeParse → calls tool.execute inside an OTEL span; wraps
39
+ * thrown errors as `{success:false, error}`.
40
+ */
41
+ export {};
42
+ //# sourceMappingURL=execute.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execute.test.d.ts","sourceRoot":"","sources":["../../../src/registry/tool/execute.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG"}
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 3):
3
+ *
4
+ * - `ToolRegistry` extends `ManagedRegistry<ToolDefinition>` with
5
+ * `idField: 'name'` and an additional `availability` map keyed by
6
+ * tool name.
7
+ * - `register(tool)` defaults availability to 'active'; the array
8
+ * overload uses the second arg (if it's a string) as the initial
9
+ * state for all tools.
10
+ * - Tier validation: if `tool.tier` is set AND `tierConfig` is
11
+ * configured, the tier id must be in `tierConfig.tiers`; otherwise
12
+ * register throws. Tools without a tier (even with tierConfig
13
+ * configured) are always accepted.
14
+ * - `unregister` + `clear` drop both the Registry entry and the
15
+ * availability entry.
16
+ * - `activate` / `defer` take a list of names; each throws (via
17
+ * `getOrThrow`) if the name is unknown, then toggles availability.
18
+ * - `suspendAll` flips every `active` tool to `suspended`;
19
+ * `deferred` / `suspended` tools are left alone. `hasSuspended`
20
+ * reports true iff at least one tool is suspended.
21
+ * - `getAvailability(name)` returns 'active' as a default even for
22
+ * unknown names (this is non-obvious but is the current behavior).
23
+ * - `searchDeferred(q)` is a case-insensitive filter against name OR
24
+ * description of every DEFERRED tool.
25
+ * - `assignTiers(mapping)` mutates `tool.tier` on existing tools;
26
+ * throws via `getOrThrow` on unknown name; throws if the tier id
27
+ * is not in `tierConfig.tiers`.
28
+ * - `toTierGuidance` returns null without a guidanceTemplate; calls
29
+ * the template with every defined tier otherwise.
30
+ * - `toPromptSection`: returns '' when no active or deferred tools;
31
+ * otherwise produces `<available_tools>` + `<deferred_tools>`
32
+ * fragments.
33
+ * - `toLLMTools`: converts active + suspended tools (filtered by
34
+ * `toolNames` if provided) into LLM tool schemas via
35
+ * `zodToJsonSchema`. When `tierConfig.labelInDescription` is true,
36
+ * the description is prefixed with the tier label.
37
+ * - `execute`: validates availability → permissionMode plan gate →
38
+ * zod.safeParse → calls tool.execute inside an OTEL span; wraps
39
+ * thrown errors as `{success:false, error}`.
40
+ */
41
+ import { describe, expect, it, vi } from 'vitest';
42
+ import { z } from 'zod';
43
+ import { ToolRegistry } from './execute.js';
44
+ function makeTool(name, overrides = {}) {
45
+ return {
46
+ name,
47
+ description: `${name} tool`,
48
+ inputSchema: z.object({ k: z.string().optional() }),
49
+ async execute() {
50
+ return { success: true, output: `${name}-ran` };
51
+ },
52
+ ...overrides,
53
+ };
54
+ }
55
+ function makeContext(overrides = {}) {
56
+ return {
57
+ runId: 'run_1',
58
+ workingDirectory: '/tmp',
59
+ abortSignal: new AbortController().signal,
60
+ env: {},
61
+ log: () => { },
62
+ ...overrides,
63
+ };
64
+ }
65
+ describe('ToolRegistry — register + availability', () => {
66
+ it('single-tool register: default availability is active', () => {
67
+ const r = new ToolRegistry();
68
+ r.register(makeTool('read'));
69
+ expect(r.getAvailability('read')).toBe('active');
70
+ });
71
+ it('array-register: second arg sets availability for all', () => {
72
+ const r = new ToolRegistry();
73
+ r.register([makeTool('a'), makeTool('b')], 'deferred');
74
+ expect(r.getAvailability('a')).toBe('deferred');
75
+ expect(r.getAvailability('b')).toBe('deferred');
76
+ });
77
+ it('getAvailability returns active for unknown names (current default)', () => {
78
+ const r = new ToolRegistry();
79
+ expect(r.getAvailability('never-registered')).toBe('active');
80
+ });
81
+ it('unregister drops both the tool + the availability entry', () => {
82
+ const r = new ToolRegistry();
83
+ r.register(makeTool('a'));
84
+ expect(r.unregister('a')).toBe(true);
85
+ expect(r.get('a')).toBeUndefined();
86
+ expect(r.listIds()).toEqual([]);
87
+ });
88
+ it('clear empties both maps', () => {
89
+ const r = new ToolRegistry();
90
+ r.register(makeTool('a'));
91
+ r.clear();
92
+ expect(r.listIds()).toEqual([]);
93
+ });
94
+ });
95
+ describe('ToolRegistry — tier validation', () => {
96
+ const tierConfig = {
97
+ tiers: [
98
+ { id: 'safe', label: 'Safe', priority: 1 },
99
+ { id: 'danger', label: 'Danger', priority: 10 },
100
+ ],
101
+ };
102
+ it('accepts tools without a tier even when tierConfig is configured', () => {
103
+ const r = new ToolRegistry({ tierConfig });
104
+ expect(() => r.register(makeTool('a'))).not.toThrow();
105
+ });
106
+ it('accepts tools whose tier is in the config', () => {
107
+ const r = new ToolRegistry({ tierConfig });
108
+ expect(() => r.register(makeTool('a', { tier: 'safe' }))).not.toThrow();
109
+ });
110
+ it('throws when tier id is unknown', () => {
111
+ const r = new ToolRegistry({ tierConfig });
112
+ expect(() => r.register(makeTool('a', { tier: 'bogus' }))).toThrow(/not defined/);
113
+ });
114
+ });
115
+ describe('ToolRegistry — activate / defer / suspend', () => {
116
+ it('activate + defer throw via getOrThrow on unknown name', () => {
117
+ const r = new ToolRegistry();
118
+ expect(() => r.activate(['unknown'])).toThrow(/Not found/);
119
+ expect(() => r.defer(['unknown'])).toThrow(/Not found/);
120
+ });
121
+ it('activate sets state to active', () => {
122
+ const r = new ToolRegistry();
123
+ r.register([makeTool('a')], 'deferred');
124
+ r.activate(['a']);
125
+ expect(r.getAvailability('a')).toBe('active');
126
+ });
127
+ it('defer sets state to deferred', () => {
128
+ const r = new ToolRegistry();
129
+ r.register(makeTool('a'));
130
+ r.defer(['a']);
131
+ expect(r.getAvailability('a')).toBe('deferred');
132
+ });
133
+ it('suspendAll flips active → suspended; leaves deferred / suspended alone', () => {
134
+ const r = new ToolRegistry();
135
+ r.register(makeTool('a'));
136
+ r.register(makeTool('b'));
137
+ r.register([makeTool('c')], 'deferred');
138
+ r.suspendAll();
139
+ expect(r.getAvailability('a')).toBe('suspended');
140
+ expect(r.getAvailability('b')).toBe('suspended');
141
+ expect(r.getAvailability('c')).toBe('deferred');
142
+ expect(r.hasSuspended()).toBe(true);
143
+ });
144
+ it('hasSuspended returns false when none are suspended', () => {
145
+ const r = new ToolRegistry();
146
+ r.register(makeTool('a'));
147
+ expect(r.hasSuspended()).toBe(false);
148
+ });
149
+ });
150
+ describe('ToolRegistry — searchDeferred', () => {
151
+ it('filters only deferred tools by name OR description (case-insensitive)', () => {
152
+ const r = new ToolRegistry();
153
+ r.register([makeTool('alpha', { description: 'does alpha' })], 'deferred');
154
+ r.register([makeTool('beta', { description: 'does BETA' })], 'deferred');
155
+ r.register(makeTool('gamma'));
156
+ expect(r.searchDeferred('alpha').map((t) => t.name)).toEqual(['alpha']);
157
+ expect(r.searchDeferred('beta').map((t) => t.name)).toEqual(['beta']);
158
+ expect(r.searchDeferred('does').map((t) => t.name)).toEqual(['alpha', 'beta']);
159
+ expect(r.searchDeferred('gamma')).toEqual([]);
160
+ });
161
+ });
162
+ describe('ToolRegistry — tier mutation + guidance', () => {
163
+ const tierConfig = {
164
+ tiers: [
165
+ { id: 'safe', label: 'Safe', priority: 1 },
166
+ { id: 'danger', label: 'Danger', priority: 10 },
167
+ ],
168
+ guidanceTemplate: (tiers) => `tiers: ${tiers.map((t) => t.id).join(',')}`,
169
+ labelInDescription: true,
170
+ };
171
+ it('assignTiers sets the tier on each mapped tool', () => {
172
+ const r = new ToolRegistry({ tierConfig });
173
+ r.register(makeTool('a'));
174
+ r.assignTiers({ a: 'safe' });
175
+ expect(r.get('a')?.tier).toBe('safe');
176
+ });
177
+ it('assignTiers throws when the tier is unknown', () => {
178
+ const r = new ToolRegistry({ tierConfig });
179
+ r.register(makeTool('a'));
180
+ expect(() => r.assignTiers({ a: 'bogus' })).toThrow(/not defined/);
181
+ });
182
+ it('toTierGuidance returns null without a template', () => {
183
+ const r = new ToolRegistry();
184
+ expect(r.toTierGuidance()).toBeNull();
185
+ });
186
+ it('toTierGuidance renders via the template', () => {
187
+ const r = new ToolRegistry({ tierConfig });
188
+ expect(r.toTierGuidance()).toBe('tiers: safe,danger');
189
+ });
190
+ });
191
+ describe('ToolRegistry — toPromptSection + toLLMTools', () => {
192
+ it('toPromptSection returns empty when the registry is empty', () => {
193
+ const r = new ToolRegistry();
194
+ expect(r.toPromptSection()).toBe('');
195
+ });
196
+ it('toPromptSection renders available + deferred fragments', () => {
197
+ const r = new ToolRegistry();
198
+ r.register(makeTool('a'));
199
+ r.register([makeTool('b')], 'deferred');
200
+ const s = r.toPromptSection();
201
+ expect(s).toContain('<available_tools>');
202
+ expect(s).toContain('- a: a tool');
203
+ expect(s).toContain('<deferred_tools>');
204
+ expect(s).toContain('- b');
205
+ });
206
+ it('toLLMTools: converts active + suspended tools', () => {
207
+ const r = new ToolRegistry();
208
+ r.register(makeTool('a'));
209
+ r.register([makeTool('b')], 'deferred');
210
+ r.register([makeTool('c')], 'suspended');
211
+ const schemas = r.toLLMTools();
212
+ const names = schemas.map((t) => t.function.name).sort();
213
+ expect(names).toEqual(['a', 'c']);
214
+ });
215
+ it('toLLMTools: prefixes description with tier label when labelInDescription is true', () => {
216
+ const tierConfig = {
217
+ tiers: [{ id: 'safe', label: 'Safe', priority: 1 }],
218
+ labelInDescription: true,
219
+ };
220
+ const r = new ToolRegistry({ tierConfig });
221
+ r.register(makeTool('a', { tier: 'safe' }));
222
+ const schemas = r.toLLMTools();
223
+ expect(schemas[0]?.function.description).toBe('[Safe] a tool');
224
+ });
225
+ });
226
+ describe('ToolRegistry — execute', () => {
227
+ it('returns error when tool is not active (e.g. deferred)', async () => {
228
+ const r = new ToolRegistry();
229
+ r.register([makeTool('a')], 'deferred');
230
+ const result = await r.execute('a', {}, makeContext());
231
+ expect(result.success).toBe(false);
232
+ expect(result.error).toMatch(/deferred and cannot be executed/);
233
+ });
234
+ it('blocks non-read-only tools in plan mode', async () => {
235
+ const r = new ToolRegistry();
236
+ r.register(makeTool('write', { isReadOnly: () => false }));
237
+ const result = await r.execute('write', {}, makeContext({
238
+ permissionContext: { mode: 'plan', runId: 'run_1', workingDirectory: '/tmp' },
239
+ }));
240
+ expect(result.success).toBe(false);
241
+ expect(result.permissionDenied).toBe(true);
242
+ });
243
+ it('allows read-only tools in plan mode', async () => {
244
+ const r = new ToolRegistry();
245
+ const execute = vi.fn(async () => ({ success: true, output: 'ok' }));
246
+ r.register(makeTool('read', { isReadOnly: () => true, execute }));
247
+ const result = await r.execute('read', {}, makeContext({
248
+ permissionContext: { mode: 'plan', runId: 'run_1', workingDirectory: '/tmp' },
249
+ }));
250
+ expect(result.success).toBe(true);
251
+ expect(execute).toHaveBeenCalled();
252
+ });
253
+ it('returns error when input fails zod validation', async () => {
254
+ const r = new ToolRegistry();
255
+ r.register(makeTool('strict', {
256
+ inputSchema: z.object({ required: z.string() }),
257
+ }));
258
+ const result = await r.execute('strict', { required: 123 }, makeContext());
259
+ expect(result.success).toBe(false);
260
+ expect(result.error).toMatch(/Invalid input/);
261
+ });
262
+ it('wraps thrown errors in the execute function', async () => {
263
+ const r = new ToolRegistry();
264
+ r.register(makeTool('bad', {
265
+ async execute() {
266
+ throw new Error('boom');
267
+ },
268
+ }));
269
+ const result = await r.execute('bad', {}, makeContext());
270
+ expect(result.success).toBe(false);
271
+ expect(result.error).toMatch(/execution failed: boom/);
272
+ });
273
+ it('returns the tool result on happy path', async () => {
274
+ const r = new ToolRegistry();
275
+ r.register(makeTool('good'));
276
+ const result = await r.execute('good', {}, makeContext());
277
+ expect(result.success).toBe(true);
278
+ expect(result.output).toBe('good-ran');
279
+ });
280
+ });
281
+ //# sourceMappingURL=execute.test.js.map