specli 0.0.11 → 0.0.12

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 (335) hide show
  1. package/bin/cli.sh +27 -0
  2. package/dist/{src/ai → ai}/tools.d.ts +0 -1
  3. package/dist/ai/tools.js +161 -0
  4. package/dist/ai/tools.test.d.ts +1 -0
  5. package/dist/ai/tools.test.js +56 -0
  6. package/dist/{src/cli → cli}/auth-requirements.d.ts +0 -1
  7. package/dist/cli/auth-requirements.js +65 -0
  8. package/dist/cli/auth-requirements.test.d.ts +1 -0
  9. package/dist/cli/auth-requirements.test.js +16 -0
  10. package/dist/{src/cli → cli}/auth-schemes.d.ts +0 -1
  11. package/dist/cli/auth-schemes.js +112 -0
  12. package/dist/cli/auth-schemes.test.d.ts +1 -0
  13. package/dist/cli/auth-schemes.test.js +56 -0
  14. package/dist/{src/cli → cli}/capabilities.d.ts +0 -1
  15. package/dist/cli/capabilities.js +41 -0
  16. package/dist/cli/capabilities.test.d.ts +1 -0
  17. package/dist/cli/capabilities.test.js +84 -0
  18. package/dist/{src/cli → cli}/command-id.d.ts +0 -1
  19. package/dist/cli/command-id.js +8 -0
  20. package/dist/cli/command-id.test.d.ts +1 -0
  21. package/dist/cli/command-id.test.js +27 -0
  22. package/dist/{src/cli → cli}/command-index.d.ts +0 -1
  23. package/dist/cli/command-index.js +9 -0
  24. package/dist/{src/cli → cli}/command-model.d.ts +0 -1
  25. package/dist/cli/command-model.js +53 -0
  26. package/dist/cli/command-model.test.d.ts +1 -0
  27. package/dist/cli/command-model.test.js +40 -0
  28. package/dist/{src/cli → cli}/compile.d.ts +0 -1
  29. package/dist/cli/compile.js +79 -0
  30. package/dist/{src/cli → cli}/crypto.d.ts +0 -1
  31. package/dist/cli/crypto.js +9 -0
  32. package/dist/{src/cli → cli}/derive-name.d.ts +0 -1
  33. package/dist/cli/derive-name.js +96 -0
  34. package/dist/{src/cli → cli}/exec.d.ts +0 -1
  35. package/dist/cli/exec.js +50 -0
  36. package/dist/{src/cli → cli}/main.d.ts +0 -1
  37. package/dist/cli/main.js +177 -0
  38. package/dist/{src/cli → cli}/naming.d.ts +0 -1
  39. package/dist/cli/naming.js +191 -0
  40. package/dist/cli/naming.test.d.ts +1 -0
  41. package/dist/cli/naming.test.js +75 -0
  42. package/dist/{src/cli → cli}/operations.d.ts +0 -1
  43. package/dist/cli/operations.js +100 -0
  44. package/dist/cli/operations.test.d.ts +1 -0
  45. package/dist/cli/operations.test.js +51 -0
  46. package/dist/{src/cli → cli}/params.d.ts +0 -1
  47. package/dist/cli/params.js +36 -0
  48. package/dist/cli/params.test.d.ts +1 -0
  49. package/dist/cli/params.test.js +62 -0
  50. package/dist/{src/cli → cli}/pluralize.d.ts +0 -1
  51. package/dist/cli/pluralize.js +38 -0
  52. package/dist/{src/cli → cli}/positional.d.ts +0 -1
  53. package/dist/cli/positional.js +35 -0
  54. package/dist/cli/positional.test.d.ts +1 -0
  55. package/dist/cli/positional.test.js +60 -0
  56. package/dist/{src/cli → cli}/request-body.d.ts +0 -1
  57. package/dist/cli/request-body.js +44 -0
  58. package/dist/cli/request-body.test.d.ts +1 -0
  59. package/dist/cli/request-body.test.js +31 -0
  60. package/dist/{src/cli → cli}/runtime/argv.d.ts +0 -1
  61. package/dist/cli/runtime/argv.js +15 -0
  62. package/dist/{src/cli → cli}/runtime/auth/resolve.d.ts +0 -1
  63. package/dist/cli/runtime/auth/resolve.js +39 -0
  64. package/dist/{src/cli → cli}/runtime/body-flags.d.ts +0 -1
  65. package/dist/cli/runtime/body-flags.js +117 -0
  66. package/dist/cli/runtime/body-flags.test.d.ts +1 -0
  67. package/dist/cli/runtime/body-flags.test.js +192 -0
  68. package/dist/{src/cli → cli}/runtime/body.d.ts +0 -1
  69. package/dist/cli/runtime/body.js +16 -0
  70. package/dist/{src/cli → cli}/runtime/collect.d.ts +0 -1
  71. package/dist/cli/runtime/collect.js +3 -0
  72. package/dist/{src/cli → cli}/runtime/compat.d.ts +0 -1
  73. package/dist/cli/runtime/compat.js +78 -0
  74. package/dist/{src/cli → cli}/runtime/context.d.ts +0 -1
  75. package/dist/cli/runtime/context.js +44 -0
  76. package/dist/{src/cli → cli}/runtime/execute.d.ts +0 -1
  77. package/dist/cli/runtime/execute.js +106 -0
  78. package/dist/{src/cli → cli}/runtime/generated.d.ts +0 -1
  79. package/dist/cli/runtime/generated.js +168 -0
  80. package/dist/{src/cli → cli}/runtime/headers.d.ts +0 -1
  81. package/dist/cli/runtime/headers.js +30 -0
  82. package/dist/{src/cli → cli}/runtime/index.d.ts +0 -1
  83. package/dist/cli/runtime/index.js +3 -0
  84. package/dist/{src/cli → cli}/runtime/profile/secrets.d.ts +0 -1
  85. package/dist/cli/runtime/profile/secrets.js +53 -0
  86. package/dist/{src/cli → cli}/runtime/profile/store.d.ts +0 -1
  87. package/dist/cli/runtime/profile/store.js +63 -0
  88. package/dist/{src/cli → cli}/runtime/request.d.ts +0 -1
  89. package/dist/cli/runtime/request.js +283 -0
  90. package/dist/cli/runtime/request.test.d.ts +1 -0
  91. package/dist/cli/runtime/request.test.js +332 -0
  92. package/dist/{src/cli → cli}/runtime/server-url.d.ts +0 -1
  93. package/dist/cli/runtime/server-url.js +28 -0
  94. package/dist/{src/cli → cli}/runtime/template.d.ts +0 -1
  95. package/dist/cli/runtime/template.js +22 -0
  96. package/dist/cli/runtime/validate/ajv.d.ts +2 -0
  97. package/dist/cli/runtime/validate/ajv.js +11 -0
  98. package/dist/{src/cli → cli}/runtime/validate/coerce.d.ts +0 -1
  99. package/dist/cli/runtime/validate/coerce.js +63 -0
  100. package/dist/cli/runtime/validate/coerce.test.d.ts +1 -0
  101. package/dist/cli/runtime/validate/coerce.test.js +75 -0
  102. package/dist/{src/cli → cli}/runtime/validate/error.d.ts +0 -1
  103. package/dist/cli/runtime/validate/error.js +19 -0
  104. package/dist/{src/cli → cli}/runtime/validate/index.d.ts +0 -1
  105. package/dist/cli/runtime/validate/index.js +4 -0
  106. package/dist/{src/cli → cli}/runtime/validate/schema.d.ts +0 -1
  107. package/dist/cli/runtime/validate/schema.js +38 -0
  108. package/dist/{src/cli → cli}/schema-shape.d.ts +0 -1
  109. package/dist/cli/schema-shape.js +34 -0
  110. package/dist/{src/cli → cli}/schema.d.ts +0 -1
  111. package/dist/cli/schema.js +31 -0
  112. package/dist/{src/cli → cli}/server.d.ts +0 -1
  113. package/dist/cli/server.js +130 -0
  114. package/dist/cli/server.test.d.ts +1 -0
  115. package/dist/cli/server.test.js +49 -0
  116. package/dist/{src/cli → cli}/spec-id.d.ts +0 -1
  117. package/dist/cli/spec-id.js +8 -0
  118. package/dist/{src/cli → cli}/spec-loader.d.ts +0 -1
  119. package/dist/cli/spec-loader.js +40 -0
  120. package/dist/{src/cli → cli}/stable-json.d.ts +0 -1
  121. package/dist/cli/stable-json.js +29 -0
  122. package/dist/{src/cli → cli}/strings.d.ts +0 -1
  123. package/dist/cli/strings.js +20 -0
  124. package/dist/{src/cli → cli}/types.d.ts +0 -1
  125. package/dist/cli/types.js +3 -0
  126. package/dist/cli.d.ts +0 -1
  127. package/dist/cli.js +51 -2324
  128. package/dist/compiled.d.ts +2 -0
  129. package/{src/compiled.ts → dist/compiled.js} +8 -11
  130. package/dist/macros/env.d.ts +10 -0
  131. package/dist/macros/env.js +22 -0
  132. package/dist/macros/spec.d.ts +5 -0
  133. package/dist/macros/spec.js +16 -0
  134. package/dist/weather +0 -0
  135. package/package.json +12 -25
  136. package/bin/specli.js +0 -26
  137. package/cli.ts +0 -77
  138. package/dist/cli.d.ts.map +0 -1
  139. package/dist/cli.js.map +0 -53
  140. package/dist/index.d.ts +0 -2
  141. package/dist/index.d.ts.map +0 -1
  142. package/dist/index.js +0 -2032
  143. package/dist/index.js.map +0 -48
  144. package/dist/src/ai/tools.d.ts.map +0 -1
  145. package/dist/src/ai/tools.js +0 -1656
  146. package/dist/src/ai/tools.js.map +0 -45
  147. package/dist/src/cli/auth-requirements.d.ts.map +0 -1
  148. package/dist/src/cli/auth-requirements.js +0 -66
  149. package/dist/src/cli/auth-requirements.js.map +0 -10
  150. package/dist/src/cli/auth-schemes.d.ts.map +0 -1
  151. package/dist/src/cli/auth-schemes.js +0 -116
  152. package/dist/src/cli/auth-schemes.js.map +0 -11
  153. package/dist/src/cli/capabilities.d.ts.map +0 -1
  154. package/dist/src/cli/capabilities.js +0 -45
  155. package/dist/src/cli/capabilities.js.map +0 -10
  156. package/dist/src/cli/command-id.d.ts.map +0 -1
  157. package/dist/src/cli/command-id.js +0 -18
  158. package/dist/src/cli/command-id.js.map +0 -11
  159. package/dist/src/cli/command-index.d.ts.map +0 -1
  160. package/dist/src/cli/command-index.js +0 -15
  161. package/dist/src/cli/command-index.js.map +0 -10
  162. package/dist/src/cli/command-model.d.ts.map +0 -1
  163. package/dist/src/cli/command-model.js +0 -274
  164. package/dist/src/cli/command-model.js.map +0 -18
  165. package/dist/src/cli/compile.d.ts.map +0 -1
  166. package/dist/src/cli/compile.js +0 -146
  167. package/dist/src/cli/compile.js.map +0 -11
  168. package/dist/src/cli/crypto.d.ts.map +0 -1
  169. package/dist/src/cli/crypto.js +0 -15
  170. package/dist/src/cli/crypto.js.map +0 -10
  171. package/dist/src/cli/derive-name.d.ts.map +0 -1
  172. package/dist/src/cli/derive-name.js +0 -70
  173. package/dist/src/cli/derive-name.js.map +0 -10
  174. package/dist/src/cli/exec.d.ts.map +0 -1
  175. package/dist/src/cli/exec.js +0 -2077
  176. package/dist/src/cli/exec.js.map +0 -49
  177. package/dist/src/cli/main.d.ts.map +0 -1
  178. package/dist/src/cli/main.js +0 -2032
  179. package/dist/src/cli/main.js.map +0 -48
  180. package/dist/src/cli/naming.d.ts.map +0 -1
  181. package/dist/src/cli/naming.js +0 -216
  182. package/dist/src/cli/naming.js.map +0 -12
  183. package/dist/src/cli/operations.d.ts.map +0 -1
  184. package/dist/src/cli/operations.js +0 -103
  185. package/dist/src/cli/operations.js.map +0 -10
  186. package/dist/src/cli/params.d.ts.map +0 -1
  187. package/dist/src/cli/params.js +0 -79
  188. package/dist/src/cli/params.js.map +0 -12
  189. package/dist/src/cli/pluralize.d.ts.map +0 -1
  190. package/dist/src/cli/pluralize.js +0 -43
  191. package/dist/src/cli/pluralize.js.map +0 -10
  192. package/dist/src/cli/positional.d.ts.map +0 -1
  193. package/dist/src/cli/positional.js +0 -39
  194. package/dist/src/cli/positional.js.map +0 -10
  195. package/dist/src/cli/request-body.d.ts.map +0 -1
  196. package/dist/src/cli/request-body.js +0 -82
  197. package/dist/src/cli/request-body.js.map +0 -12
  198. package/dist/src/cli/runtime/argv.d.ts.map +0 -1
  199. package/dist/src/cli/runtime/argv.js +0 -22
  200. package/dist/src/cli/runtime/argv.js.map +0 -10
  201. package/dist/src/cli/runtime/auth/resolve.d.ts.map +0 -1
  202. package/dist/src/cli/runtime/auth/resolve.js +0 -38
  203. package/dist/src/cli/runtime/auth/resolve.js.map +0 -10
  204. package/dist/src/cli/runtime/body-flags.d.ts.map +0 -1
  205. package/dist/src/cli/runtime/body-flags.js +0 -86
  206. package/dist/src/cli/runtime/body-flags.js.map +0 -10
  207. package/dist/src/cli/runtime/body.d.ts.map +0 -1
  208. package/dist/src/cli/runtime/body.js +0 -40
  209. package/dist/src/cli/runtime/body.js.map +0 -11
  210. package/dist/src/cli/runtime/collect.d.ts.map +0 -1
  211. package/dist/src/cli/runtime/collect.js +0 -9
  212. package/dist/src/cli/runtime/collect.js.map +0 -10
  213. package/dist/src/cli/runtime/compat.d.ts.map +0 -1
  214. package/dist/src/cli/runtime/compat.js +0 -62
  215. package/dist/src/cli/runtime/compat.js.map +0 -10
  216. package/dist/src/cli/runtime/context.d.ts.map +0 -1
  217. package/dist/src/cli/runtime/context.js +0 -936
  218. package/dist/src/cli/runtime/context.js.map +0 -32
  219. package/dist/src/cli/runtime/execute.d.ts.map +0 -1
  220. package/dist/src/cli/runtime/execute.js +0 -670
  221. package/dist/src/cli/runtime/execute.js.map +0 -22
  222. package/dist/src/cli/runtime/generated.d.ts.map +0 -1
  223. package/dist/src/cli/runtime/generated.js +0 -869
  224. package/dist/src/cli/runtime/generated.js.map +0 -23
  225. package/dist/src/cli/runtime/headers.d.ts.map +0 -1
  226. package/dist/src/cli/runtime/headers.js +0 -36
  227. package/dist/src/cli/runtime/headers.js.map +0 -10
  228. package/dist/src/cli/runtime/index.d.ts.map +0 -1
  229. package/dist/src/cli/runtime/index.js +0 -1808
  230. package/dist/src/cli/runtime/index.js.map +0 -46
  231. package/dist/src/cli/runtime/profile/secrets.d.ts.map +0 -1
  232. package/dist/src/cli/runtime/profile/secrets.js +0 -51
  233. package/dist/src/cli/runtime/profile/secrets.js.map +0 -11
  234. package/dist/src/cli/runtime/profile/store.d.ts.map +0 -1
  235. package/dist/src/cli/runtime/profile/store.js +0 -102
  236. package/dist/src/cli/runtime/profile/store.js.map +0 -11
  237. package/dist/src/cli/runtime/request.d.ts.map +0 -1
  238. package/dist/src/cli/runtime/request.js +0 -571
  239. package/dist/src/cli/runtime/request.js.map +0 -21
  240. package/dist/src/cli/runtime/server-url.d.ts.map +0 -1
  241. package/dist/src/cli/runtime/server-url.js +0 -55
  242. package/dist/src/cli/runtime/server-url.js.map +0 -11
  243. package/dist/src/cli/runtime/template.d.ts.map +0 -1
  244. package/dist/src/cli/runtime/template.js +0 -29
  245. package/dist/src/cli/runtime/template.js.map +0 -10
  246. package/dist/src/cli/runtime/validate/ajv.d.ts +0 -3
  247. package/dist/src/cli/runtime/validate/ajv.d.ts.map +0 -1
  248. package/dist/src/cli/runtime/validate/ajv.js +0 -17
  249. package/dist/src/cli/runtime/validate/ajv.js.map +0 -10
  250. package/dist/src/cli/runtime/validate/coerce.d.ts.map +0 -1
  251. package/dist/src/cli/runtime/validate/coerce.js +0 -60
  252. package/dist/src/cli/runtime/validate/coerce.js.map +0 -10
  253. package/dist/src/cli/runtime/validate/error.d.ts.map +0 -1
  254. package/dist/src/cli/runtime/validate/error.js +0 -21
  255. package/dist/src/cli/runtime/validate/error.js.map +0 -10
  256. package/dist/src/cli/runtime/validate/index.d.ts.map +0 -1
  257. package/dist/src/cli/runtime/validate/index.js +0 -122
  258. package/dist/src/cli/runtime/validate/index.js.map +0 -13
  259. package/dist/src/cli/runtime/validate/schema.d.ts.map +0 -1
  260. package/dist/src/cli/runtime/validate/schema.js +0 -36
  261. package/dist/src/cli/runtime/validate/schema.js.map +0 -10
  262. package/dist/src/cli/schema-shape.d.ts.map +0 -1
  263. package/dist/src/cli/schema-shape.js +0 -41
  264. package/dist/src/cli/schema-shape.js.map +0 -10
  265. package/dist/src/cli/schema.d.ts.map +0 -1
  266. package/dist/src/cli/schema.js +0 -38
  267. package/dist/src/cli/schema.js.map +0 -10
  268. package/dist/src/cli/server.d.ts.map +0 -1
  269. package/dist/src/cli/server.js +0 -64
  270. package/dist/src/cli/server.js.map +0 -11
  271. package/dist/src/cli/spec-id.d.ts.map +0 -1
  272. package/dist/src/cli/spec-id.js +0 -21
  273. package/dist/src/cli/spec-id.js.map +0 -11
  274. package/dist/src/cli/spec-loader.d.ts.map +0 -1
  275. package/dist/src/cli/spec-loader.js +0 -110
  276. package/dist/src/cli/spec-loader.js.map +0 -15
  277. package/dist/src/cli/stable-json.d.ts.map +0 -1
  278. package/dist/src/cli/stable-json.js +0 -35
  279. package/dist/src/cli/stable-json.js.map +0 -10
  280. package/dist/src/cli/strings.d.ts.map +0 -1
  281. package/dist/src/cli/strings.js +0 -16
  282. package/dist/src/cli/strings.js.map +0 -10
  283. package/dist/src/cli/types.d.ts.map +0 -1
  284. package/dist/src/cli/types.js +0 -9
  285. package/dist/src/cli/types.js.map +0 -10
  286. package/index.ts +0 -1
  287. package/src/ai/tools.ts +0 -211
  288. package/src/cli/auth-requirements.ts +0 -91
  289. package/src/cli/auth-schemes.ts +0 -187
  290. package/src/cli/capabilities.ts +0 -88
  291. package/src/cli/command-id.ts +0 -16
  292. package/src/cli/command-index.ts +0 -19
  293. package/src/cli/command-model.ts +0 -128
  294. package/src/cli/compile.ts +0 -101
  295. package/src/cli/crypto.ts +0 -9
  296. package/src/cli/derive-name.ts +0 -101
  297. package/src/cli/exec.ts +0 -72
  298. package/src/cli/main.ts +0 -231
  299. package/src/cli/naming.ts +0 -224
  300. package/src/cli/operations.ts +0 -152
  301. package/src/cli/params.ts +0 -71
  302. package/src/cli/pluralize.ts +0 -41
  303. package/src/cli/positional.ts +0 -75
  304. package/src/cli/request-body.ts +0 -94
  305. package/src/cli/runtime/argv.ts +0 -14
  306. package/src/cli/runtime/auth/resolve.ts +0 -59
  307. package/src/cli/runtime/body-flags.ts +0 -176
  308. package/src/cli/runtime/body.ts +0 -24
  309. package/src/cli/runtime/collect.ts +0 -6
  310. package/src/cli/runtime/compat.ts +0 -89
  311. package/src/cli/runtime/context.ts +0 -62
  312. package/src/cli/runtime/execute.ts +0 -147
  313. package/src/cli/runtime/generated.ts +0 -242
  314. package/src/cli/runtime/headers.ts +0 -37
  315. package/src/cli/runtime/index.ts +0 -3
  316. package/src/cli/runtime/profile/secrets.ts +0 -83
  317. package/src/cli/runtime/profile/store.ts +0 -100
  318. package/src/cli/runtime/request.ts +0 -390
  319. package/src/cli/runtime/server-url.ts +0 -45
  320. package/src/cli/runtime/template.ts +0 -26
  321. package/src/cli/runtime/validate/ajv.ts +0 -13
  322. package/src/cli/runtime/validate/coerce.ts +0 -71
  323. package/src/cli/runtime/validate/error.ts +0 -29
  324. package/src/cli/runtime/validate/index.ts +0 -4
  325. package/src/cli/runtime/validate/schema.ts +0 -54
  326. package/src/cli/schema-shape.ts +0 -36
  327. package/src/cli/schema.ts +0 -76
  328. package/src/cli/server.ts +0 -88
  329. package/src/cli/spec-id.ts +0 -12
  330. package/src/cli/spec-loader.ts +0 -58
  331. package/src/cli/stable-json.ts +0 -35
  332. package/src/cli/strings.ts +0 -21
  333. package/src/cli/types.ts +0 -59
  334. package/src/macros/env.ts +0 -21
  335. package/src/macros/spec.ts +0 -17
package/bin/cli.sh ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+
4
+ SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
5
+ CLI_JS="$SCRIPT_DIR/../dist/cli.js"
6
+
7
+ is_compile=0
8
+ for arg in "$@"; do
9
+ if [ "$arg" = "compile" ]; then
10
+ is_compile=1
11
+ break
12
+ fi
13
+ done
14
+
15
+ # 1. Prefer Bun if installed
16
+ if command -v bun >/dev/null 2>&1; then
17
+ exec bun "$CLI_JS" "$@"
18
+ fi
19
+
20
+ # 2. Bun is required for compile
21
+ if [ "$is_compile" -eq 1 ]; then
22
+ printf '%s\n' "Error: The 'compile' command requires Bun." "Install Bun: https://bun.sh" >&2
23
+ exit 1
24
+ fi
25
+
26
+ # 3. Fallback to Node.js
27
+ exec node "$CLI_JS" "$@"
@@ -136,4 +136,3 @@ export declare function specli(options: SpecliToolOptions): import("ai").Tool<{
136
136
  }>;
137
137
  /** Clear cached spec context */
138
138
  export declare function clearSpecliCache(spec?: string): void;
139
- //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1,161 @@
1
+ /**
2
+ * AI SDK tools for specli
3
+ *
4
+ * Provides tools for AI agents to explore and execute OpenAPI specs.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { specli } from "specli/ai";
9
+ * import { generateText } from "ai";
10
+ *
11
+ * const result = await generateText({
12
+ * model: yourModel,
13
+ * tools: {
14
+ * api: specli({ spec: "https://api.example.com/openapi.json" }),
15
+ * },
16
+ * prompt: "List all users",
17
+ * });
18
+ * ```
19
+ */
20
+ import { tool } from "ai";
21
+ import { z } from "zod";
22
+ import { buildRuntimeContext } from "../cli/runtime/context.js";
23
+ import { execute } from "../cli/runtime/execute.js";
24
+ // Cache contexts to avoid reloading spec on every call
25
+ const contextCache = new Map();
26
+ async function getContext(spec) {
27
+ let ctx = contextCache.get(spec);
28
+ if (!ctx) {
29
+ ctx = await buildRuntimeContext({ spec });
30
+ contextCache.set(spec, ctx);
31
+ }
32
+ return ctx;
33
+ }
34
+ function findAction(ctx, resource, action) {
35
+ const r = ctx.commands.resources.find((r) => r.resource.toLowerCase() === resource.toLowerCase());
36
+ return r?.actions.find((a) => a.action.toLowerCase() === action.toLowerCase());
37
+ }
38
+ /**
39
+ * Create an AI SDK tool for interacting with an OpenAPI spec.
40
+ */
41
+ export function specli(options) {
42
+ const { spec, server, serverVars, bearerToken, apiKey, basicAuth, authScheme, } = options;
43
+ return tool({
44
+ description: `Execute API operations. Commands: "list" (show resources/actions), "help" (action details), "exec" (call API).`,
45
+ inputSchema: z.object({
46
+ command: z.enum(["list", "help", "exec"]).describe("Command to run"),
47
+ resource: z.string().optional().describe("Resource name (e.g. users)"),
48
+ action: z
49
+ .string()
50
+ .optional()
51
+ .describe("Action name (e.g. list, get, create)"),
52
+ args: z.array(z.string()).optional().describe("Positional arguments"),
53
+ flags: z
54
+ .record(z.string(), z.unknown())
55
+ .optional()
56
+ .describe("Named flags"),
57
+ }),
58
+ execute: async ({ command, resource, action, args, flags }) => {
59
+ const ctx = await getContext(spec);
60
+ if (command === "list") {
61
+ return {
62
+ resources: ctx.commands.resources.map((r) => ({
63
+ name: r.resource,
64
+ actions: r.actions.map((a) => ({
65
+ name: a.action,
66
+ summary: a.summary,
67
+ method: a.method,
68
+ path: a.path,
69
+ args: a.positionals.map((p) => p.name),
70
+ requiredFlags: a.flags
71
+ .filter((f) => f.required)
72
+ .map((f) => f.flag),
73
+ })),
74
+ })),
75
+ };
76
+ }
77
+ if (command === "help") {
78
+ if (!resource)
79
+ return { error: "Missing resource" };
80
+ const r = ctx.commands.resources.find((r) => r.resource.toLowerCase() === resource.toLowerCase());
81
+ if (!r)
82
+ return { error: `Unknown resource: ${resource}` };
83
+ if (!action) {
84
+ return {
85
+ resource: r.resource,
86
+ actions: r.actions.map((a) => a.action),
87
+ };
88
+ }
89
+ const a = r.actions.find((a) => a.action.toLowerCase() === action.toLowerCase());
90
+ if (!a)
91
+ return { error: `Unknown action: ${action}` };
92
+ return {
93
+ action: a.action,
94
+ method: a.method,
95
+ path: a.path,
96
+ summary: a.summary,
97
+ args: a.positionals.map((p) => ({
98
+ name: p.name,
99
+ description: p.description,
100
+ })),
101
+ flags: a.flags.map((f) => ({
102
+ name: f.flag,
103
+ type: f.type,
104
+ required: f.required,
105
+ description: f.description,
106
+ })),
107
+ };
108
+ }
109
+ if (command === "exec") {
110
+ if (!resource || !action)
111
+ return { error: "Missing resource or action" };
112
+ const actionDef = findAction(ctx, resource, action);
113
+ if (!actionDef)
114
+ return { error: `Unknown: ${resource} ${action}` };
115
+ const positionalValues = args ?? [];
116
+ if (positionalValues.length < actionDef.positionals.length) {
117
+ return {
118
+ error: `Missing args: ${actionDef.positionals
119
+ .slice(positionalValues.length)
120
+ .map((p) => p.name)
121
+ .join(", ")}`,
122
+ };
123
+ }
124
+ const globals = {
125
+ server,
126
+ serverVar: serverVars
127
+ ? Object.entries(serverVars).map(([k, v]) => `${k}=${v}`)
128
+ : undefined,
129
+ auth: authScheme,
130
+ bearerToken,
131
+ apiKey,
132
+ username: basicAuth?.username,
133
+ password: basicAuth?.password,
134
+ };
135
+ try {
136
+ const result = await execute({
137
+ specId: ctx.loaded.id,
138
+ action: actionDef,
139
+ positionalValues,
140
+ flagValues: flags ?? {},
141
+ globals,
142
+ servers: ctx.servers,
143
+ authSchemes: ctx.authSchemes,
144
+ });
145
+ return { status: result.status, ok: result.ok, body: result.body };
146
+ }
147
+ catch (err) {
148
+ return { error: err instanceof Error ? err.message : String(err) };
149
+ }
150
+ }
151
+ return { error: `Unknown command: ${command}` };
152
+ },
153
+ });
154
+ }
155
+ /** Clear cached spec context */
156
+ export function clearSpecliCache(spec) {
157
+ if (spec)
158
+ contextCache.delete(spec);
159
+ else
160
+ contextCache.clear();
161
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,56 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { clearSpecliCache, specli } from "./tools.js";
3
+ const mockOptions = {
4
+ toolCallId: "test-call-id",
5
+ abortSignal: new AbortController().signal,
6
+ messages: [],
7
+ };
8
+ describe("specli tool", () => {
9
+ test("creates a tool with correct structure", () => {
10
+ const tool = specli({
11
+ spec: "https://petstore3.swagger.io/api/v3/openapi.json",
12
+ });
13
+ expect(tool).toHaveProperty("description");
14
+ expect(tool).toHaveProperty("inputSchema");
15
+ expect(tool).toHaveProperty("execute");
16
+ expect(typeof tool.execute).toBe("function");
17
+ });
18
+ test("list command returns resources", async () => {
19
+ const tool = specli({
20
+ spec: "https://petstore3.swagger.io/api/v3/openapi.json",
21
+ });
22
+ const result = (await tool.execute?.({ command: "list" }, mockOptions));
23
+ expect(result).toHaveProperty("resources");
24
+ expect(Array.isArray(result.resources)).toBe(true);
25
+ });
26
+ test("help command returns action details", async () => {
27
+ const tool = specli({
28
+ spec: "https://petstore3.swagger.io/api/v3/openapi.json",
29
+ });
30
+ const result = (await tool.execute?.({ command: "help", resource: "pets", action: "get" }, mockOptions));
31
+ expect(result).toHaveProperty("action");
32
+ expect(result.action).toBe("get");
33
+ });
34
+ test("help command with missing resource returns error", async () => {
35
+ const tool = specli({
36
+ spec: "https://petstore3.swagger.io/api/v3/openapi.json",
37
+ });
38
+ const result = (await tool.execute?.({ command: "help" }, mockOptions));
39
+ expect(result).toHaveProperty("error");
40
+ });
41
+ test("exec command with missing args returns error", async () => {
42
+ const tool = specli({
43
+ spec: "https://petstore3.swagger.io/api/v3/openapi.json",
44
+ });
45
+ const result = (await tool.execute?.({ command: "exec", resource: "pets", action: "get" }, mockOptions));
46
+ expect(result).toHaveProperty("error");
47
+ expect(result.error).toContain("Missing args");
48
+ });
49
+ test("clearCache works", async () => {
50
+ const spec = "https://petstore3.swagger.io/api/v3/openapi.json";
51
+ const tool = specli({ spec });
52
+ await tool.execute?.({ command: "list" }, mockOptions);
53
+ clearSpecliCache(spec);
54
+ clearSpecliCache();
55
+ });
56
+ });
@@ -7,4 +7,3 @@ export type AuthSummary = {
7
7
  alternatives: AuthRequirement[][];
8
8
  };
9
9
  export declare function summarizeAuth(operationSecurity: unknown, globalSecurity: unknown, knownSchemes: AuthScheme[]): AuthSummary;
10
- //# sourceMappingURL=auth-requirements.d.ts.map
@@ -0,0 +1,65 @@
1
+ function isSecurityRequirement(value) {
2
+ if (!value || typeof value !== "object")
3
+ return false;
4
+ if (Array.isArray(value))
5
+ return false;
6
+ for (const [k, v] of Object.entries(value)) {
7
+ if (typeof k !== "string")
8
+ return false;
9
+ if (!Array.isArray(v))
10
+ return false;
11
+ if (!v.every((s) => typeof s === "string"))
12
+ return false;
13
+ }
14
+ return true;
15
+ }
16
+ function normalizeSecurity(value) {
17
+ if (value == null)
18
+ return { requirements: [], source: "none" };
19
+ if (!Array.isArray(value))
20
+ return { requirements: [], source: "none" };
21
+ const reqs = value.filter(isSecurityRequirement);
22
+ if (reqs.length === 0)
23
+ return { requirements: [], source: "empty" };
24
+ return { requirements: reqs, source: "non-empty" };
25
+ }
26
+ export function summarizeAuth(operationSecurity, globalSecurity, knownSchemes) {
27
+ // Per spec:
28
+ // - operation security overrides root
29
+ // - empty array [] means "no auth"
30
+ const op = normalizeSecurity(operationSecurity);
31
+ if (op.source === "non-empty") {
32
+ return { alternatives: toAlternatives(op.requirements, knownSchemes) };
33
+ }
34
+ if (op.source === "empty") {
35
+ return { alternatives: [] };
36
+ }
37
+ const global = normalizeSecurity(globalSecurity);
38
+ if (global.source === "non-empty") {
39
+ return { alternatives: toAlternatives(global.requirements, knownSchemes) };
40
+ }
41
+ return { alternatives: [] };
42
+ }
43
+ function toAlternatives(requirements, knownSchemes) {
44
+ const known = new Set(knownSchemes.map((s) => s.key));
45
+ return requirements.map((req) => {
46
+ const out = [];
47
+ for (const [key, scopes] of Object.entries(req)) {
48
+ out.push({
49
+ key,
50
+ scopes: Array.isArray(scopes) ? scopes : [],
51
+ });
52
+ }
53
+ // Stable order.
54
+ out.sort((a, b) => a.key.localeCompare(b.key));
55
+ // Prefer known schemes first.
56
+ out.sort((a, b) => {
57
+ const ak = known.has(a.key) ? 0 : 1;
58
+ const bk = known.has(b.key) ? 0 : 1;
59
+ if (ak !== bk)
60
+ return ak - bk;
61
+ return a.key.localeCompare(b.key);
62
+ });
63
+ return out;
64
+ });
65
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { summarizeAuth } from "./auth-requirements.js";
3
+ describe("summarizeAuth", () => {
4
+ test("uses operation-level security when present", () => {
5
+ const schemes = [{ key: "oauth", kind: "oauth2" }];
6
+ const summary = summarizeAuth([{ oauth: ["read:ping"] }], [{ oauth: ["read:other"] }], schemes);
7
+ expect(summary.alternatives).toEqual([
8
+ [{ key: "oauth", scopes: ["read:ping"] }],
9
+ ]);
10
+ });
11
+ test("empty operation security disables auth", () => {
12
+ const schemes = [{ key: "oauth", kind: "oauth2" }];
13
+ const summary = summarizeAuth([], [{ oauth: ["read:other"] }], schemes);
14
+ expect(summary.alternatives).toEqual([]);
15
+ });
16
+ });
@@ -19,4 +19,3 @@ export type OAuthFlow = {
19
19
  };
20
20
  export type OAuthFlows = Partial<Record<"implicit" | "password" | "clientCredentials" | "authorizationCode", OAuthFlow>>;
21
21
  export declare function listAuthSchemes(doc: OpenApiDoc): AuthScheme[];
22
- //# sourceMappingURL=auth-schemes.d.ts.map
@@ -0,0 +1,112 @@
1
+ import { kebabCase } from "./strings.js";
2
+ function parseOAuthFlow(flow) {
3
+ if (!flow)
4
+ return undefined;
5
+ const scopesObj = flow.scopes;
6
+ const scopes = scopesObj && typeof scopesObj === "object" && !Array.isArray(scopesObj)
7
+ ? Object.keys(scopesObj)
8
+ : [];
9
+ return {
10
+ authorizationUrl: typeof flow.authorizationUrl === "string"
11
+ ? flow.authorizationUrl
12
+ : undefined,
13
+ tokenUrl: typeof flow.tokenUrl === "string" ? flow.tokenUrl : undefined,
14
+ refreshUrl: typeof flow.refreshUrl === "string" ? flow.refreshUrl : undefined,
15
+ scopes: scopes.sort(),
16
+ };
17
+ }
18
+ function parseOAuthFlows(flows) {
19
+ if (!flows)
20
+ return undefined;
21
+ const out = {};
22
+ const implicit = parseOAuthFlow(flows.implicit);
23
+ if (implicit)
24
+ out.implicit = implicit;
25
+ const password = parseOAuthFlow(flows.password);
26
+ if (password)
27
+ out.password = password;
28
+ const clientCredentials = parseOAuthFlow(flows.clientCredentials);
29
+ if (clientCredentials)
30
+ out.clientCredentials = clientCredentials;
31
+ const authorizationCode = parseOAuthFlow(flows.authorizationCode);
32
+ if (authorizationCode)
33
+ out.authorizationCode = authorizationCode;
34
+ return Object.keys(out).length ? out : undefined;
35
+ }
36
+ export function listAuthSchemes(doc) {
37
+ const schemes = doc.components?.securitySchemes;
38
+ if (!schemes || typeof schemes !== "object")
39
+ return [];
40
+ const out = [];
41
+ for (const [key, raw] of Object.entries(schemes)) {
42
+ if (!raw || typeof raw !== "object")
43
+ continue;
44
+ const s = raw;
45
+ const type = s.type;
46
+ if (type === "http") {
47
+ const scheme = (s.scheme ?? "").toLowerCase();
48
+ if (scheme === "bearer") {
49
+ out.push({
50
+ key,
51
+ kind: "http-bearer",
52
+ scheme: scheme,
53
+ bearerFormat: s.bearerFormat,
54
+ description: s.description,
55
+ });
56
+ }
57
+ else if (scheme === "basic") {
58
+ out.push({
59
+ key,
60
+ kind: "http-basic",
61
+ scheme: scheme,
62
+ description: s.description,
63
+ });
64
+ }
65
+ else {
66
+ out.push({
67
+ key,
68
+ kind: "unknown",
69
+ scheme: s.scheme,
70
+ description: s.description,
71
+ });
72
+ }
73
+ continue;
74
+ }
75
+ if (type === "apiKey") {
76
+ const where = s.in;
77
+ const loc = where === "header" || where === "query" || where === "cookie"
78
+ ? where
79
+ : undefined;
80
+ out.push({
81
+ key,
82
+ kind: "api-key",
83
+ name: s.name,
84
+ in: loc,
85
+ description: s.description,
86
+ });
87
+ continue;
88
+ }
89
+ if (type === "oauth2") {
90
+ out.push({
91
+ key,
92
+ kind: "oauth2",
93
+ description: s.description,
94
+ oauthFlows: parseOAuthFlows(s.flows),
95
+ });
96
+ continue;
97
+ }
98
+ if (type === "openIdConnect") {
99
+ out.push({
100
+ key,
101
+ kind: "openIdConnect",
102
+ description: s.description,
103
+ openIdConnectUrl: s.openIdConnectUrl,
104
+ });
105
+ continue;
106
+ }
107
+ out.push({ key, kind: "unknown", description: s.description });
108
+ }
109
+ // Stable order.
110
+ out.sort((a, b) => kebabCase(a.key).localeCompare(kebabCase(b.key)));
111
+ return out;
112
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,56 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { listAuthSchemes } from "./auth-schemes.js";
3
+ describe("listAuthSchemes", () => {
4
+ test("parses bearer + apiKey", () => {
5
+ const doc = {
6
+ openapi: "3.0.3",
7
+ components: {
8
+ securitySchemes: {
9
+ bearerAuth: {
10
+ type: "http",
11
+ scheme: "bearer",
12
+ bearerFormat: "JWT",
13
+ },
14
+ apiKeyAuth: {
15
+ type: "apiKey",
16
+ in: "header",
17
+ name: "X-API-Key",
18
+ },
19
+ },
20
+ },
21
+ };
22
+ const schemes = listAuthSchemes(doc);
23
+ expect(schemes).toHaveLength(2);
24
+ const bearer = schemes.find((s) => s.key === "bearerAuth");
25
+ expect(bearer?.kind).toBe("http-bearer");
26
+ const apiKey = schemes.find((s) => s.key === "apiKeyAuth");
27
+ expect(apiKey?.kind).toBe("api-key");
28
+ expect(apiKey?.in).toBe("header");
29
+ expect(apiKey?.name).toBe("X-API-Key");
30
+ });
31
+ test("parses oauth2 flows", () => {
32
+ const doc = {
33
+ openapi: "3.0.3",
34
+ components: {
35
+ securitySchemes: {
36
+ oauth: {
37
+ type: "oauth2",
38
+ flows: {
39
+ clientCredentials: {
40
+ tokenUrl: "https://example.com/oauth/token",
41
+ scopes: {
42
+ "read:ping": "read ping",
43
+ },
44
+ },
45
+ },
46
+ },
47
+ },
48
+ },
49
+ };
50
+ const schemes = listAuthSchemes(doc);
51
+ const oauth = schemes.find((s) => s.key === "oauth");
52
+ expect(oauth?.kind).toBe("oauth2");
53
+ expect(oauth?.oauthFlows?.clientCredentials?.tokenUrl).toBe("https://example.com/oauth/token");
54
+ expect(oauth?.oauthFlows?.clientCredentials?.scopes).toEqual(["read:ping"]);
55
+ });
56
+ });
@@ -29,4 +29,3 @@ export declare function deriveCapabilities(input: {
29
29
  operations: NormalizedOperation[];
30
30
  commands?: CommandModel;
31
31
  }): Capabilities;
32
- //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1,41 @@
1
+ function uniqueSorted(items, compare) {
2
+ const out = [...items];
3
+ out.sort(compare);
4
+ return out.filter((v, i) => i === 0 || compare(out[i - 1], v) !== 0);
5
+ }
6
+ function hasSecurity(requirements) {
7
+ if (!requirements?.length)
8
+ return false;
9
+ // Treat any non-empty array as "auth exists", even if it contains `{}` to mean optional.
10
+ return true;
11
+ }
12
+ export function deriveCapabilities(input) {
13
+ const serverHasVars = input.servers.some((s) => s.variableNames.length > 0);
14
+ const authKinds = uniqueSorted(input.authSchemes.map((s) => s.kind), (a, b) => a.localeCompare(b));
15
+ const hasSecurityRequirements = hasSecurity(input.doc.security) ||
16
+ input.operations.some((op) => hasSecurity(op.security));
17
+ const opHasBodies = input.operations.some((op) => Boolean(op.requestBody));
18
+ const cmdResources = input.commands?.resources ?? [];
19
+ const cmdActions = cmdResources.flatMap((r) => r.actions);
20
+ const cmdHasBodies = cmdActions.some((a) => Boolean(a.requestBody));
21
+ return {
22
+ servers: {
23
+ count: input.servers.length,
24
+ hasVariables: serverHasVars,
25
+ },
26
+ auth: {
27
+ count: input.authSchemes.length,
28
+ kinds: authKinds,
29
+ hasSecurityRequirements,
30
+ },
31
+ operations: {
32
+ count: input.operations.length,
33
+ hasRequestBodies: opHasBodies,
34
+ },
35
+ commands: {
36
+ countResources: cmdResources.length,
37
+ countActions: cmdActions.length,
38
+ hasRequestBodies: cmdHasBodies,
39
+ },
40
+ };
41
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,84 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { deriveCapabilities } from "./capabilities.js";
3
+ describe("deriveCapabilities", () => {
4
+ test("reports requestBody + server vars", () => {
5
+ const doc = {
6
+ openapi: "3.0.3",
7
+ security: [{ bearerAuth: [] }],
8
+ };
9
+ const servers = [
10
+ {
11
+ url: "https://{region}.api.example.com",
12
+ variables: [],
13
+ variableNames: ["region"],
14
+ },
15
+ ];
16
+ const authSchemes = [
17
+ { key: "bearerAuth", kind: "http-bearer" },
18
+ ];
19
+ const operations = [
20
+ {
21
+ key: "POST /contacts",
22
+ method: "POST",
23
+ path: "/contacts",
24
+ tags: [],
25
+ parameters: [],
26
+ requestBody: {
27
+ required: true,
28
+ contentTypes: ["application/json"],
29
+ schemasByContentType: { "application/json": { type: "object" } },
30
+ },
31
+ },
32
+ ];
33
+ const commands = {
34
+ resources: [
35
+ {
36
+ resource: "contacts",
37
+ actions: [
38
+ {
39
+ id: "x",
40
+ key: "POST /contacts",
41
+ action: "create",
42
+ pathArgs: [],
43
+ method: "POST",
44
+ path: "/contacts",
45
+ tags: [],
46
+ style: "rest",
47
+ positionals: [],
48
+ flags: [],
49
+ params: [],
50
+ auth: { alternatives: [] },
51
+ requestBody: {
52
+ required: true,
53
+ content: [
54
+ {
55
+ contentType: "application/json",
56
+ required: true,
57
+ schemaType: "object",
58
+ },
59
+ ],
60
+ hasJson: true,
61
+ hasFormUrlEncoded: false,
62
+ hasMultipart: false,
63
+ bodyFlags: ["--data", "--file"],
64
+ preferredContentType: "application/json",
65
+ },
66
+ },
67
+ ],
68
+ },
69
+ ],
70
+ };
71
+ const caps = deriveCapabilities({
72
+ doc,
73
+ servers,
74
+ authSchemes,
75
+ operations,
76
+ commands,
77
+ });
78
+ expect(caps.servers.hasVariables).toBe(true);
79
+ expect(caps.operations.hasRequestBodies).toBe(true);
80
+ expect(caps.commands.hasRequestBodies).toBe(true);
81
+ expect(caps.auth.hasSecurityRequirements).toBe(true);
82
+ expect(caps.auth.kinds).toEqual(["http-bearer"]);
83
+ });
84
+ });
@@ -5,4 +5,3 @@ export type CommandIdParts = {
5
5
  operationKey: string;
6
6
  };
7
7
  export declare function buildCommandId(parts: CommandIdParts): string;
8
- //# sourceMappingURL=command-id.d.ts.map
@@ -0,0 +1,8 @@
1
+ import { kebabCase } from "./strings.js";
2
+ export function buildCommandId(parts) {
3
+ // operationKey is the ultimate disambiguator, but we keep the id readable.
4
+ // Example:
5
+ // contacts-api:contacts:get:GET-/contacts/{id}
6
+ const op = kebabCase(parts.operationKey.replace(/\s+/g, "-"));
7
+ return `${parts.specId}:${kebabCase(parts.resource)}:${kebabCase(parts.action)}:${op}`;
8
+ }