specli 0.0.11 → 0.0.13

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/README.md +216 -325
  2. package/bin/cli.sh +27 -0
  3. package/dist/{src/ai → ai}/tools.d.ts +0 -1
  4. package/dist/ai/tools.js +161 -0
  5. package/dist/ai/tools.test.d.ts +1 -0
  6. package/dist/ai/tools.test.js +56 -0
  7. package/dist/{src/cli → cli}/auth-requirements.d.ts +0 -1
  8. package/dist/cli/auth-requirements.js +65 -0
  9. package/dist/cli/auth-requirements.test.d.ts +1 -0
  10. package/dist/cli/auth-requirements.test.js +16 -0
  11. package/dist/{src/cli → cli}/auth-schemes.d.ts +0 -1
  12. package/dist/cli/auth-schemes.js +112 -0
  13. package/dist/cli/auth-schemes.test.d.ts +1 -0
  14. package/dist/cli/auth-schemes.test.js +56 -0
  15. package/dist/{src/cli → cli}/capabilities.d.ts +0 -1
  16. package/dist/cli/capabilities.js +41 -0
  17. package/dist/cli/capabilities.test.d.ts +1 -0
  18. package/dist/cli/capabilities.test.js +84 -0
  19. package/dist/{src/cli → cli}/command-id.d.ts +0 -1
  20. package/dist/cli/command-id.js +8 -0
  21. package/dist/cli/command-id.test.d.ts +1 -0
  22. package/dist/cli/command-id.test.js +27 -0
  23. package/dist/{src/cli → cli}/command-index.d.ts +0 -1
  24. package/dist/cli/command-index.js +9 -0
  25. package/dist/{src/cli → cli}/command-model.d.ts +0 -1
  26. package/dist/cli/command-model.js +53 -0
  27. package/dist/cli/command-model.test.d.ts +1 -0
  28. package/dist/cli/command-model.test.js +40 -0
  29. package/dist/{src/cli → cli}/compile.d.ts +0 -1
  30. package/dist/cli/compile.js +79 -0
  31. package/dist/{src/cli → cli}/crypto.d.ts +0 -1
  32. package/dist/cli/crypto.js +9 -0
  33. package/dist/{src/cli → cli}/derive-name.d.ts +0 -1
  34. package/dist/cli/derive-name.js +96 -0
  35. package/dist/{src/cli → cli}/exec.d.ts +0 -1
  36. package/dist/cli/exec.js +50 -0
  37. package/dist/{src/cli → cli}/main.d.ts +0 -1
  38. package/dist/cli/main.js +177 -0
  39. package/dist/{src/cli → cli}/naming.d.ts +0 -1
  40. package/dist/cli/naming.js +191 -0
  41. package/dist/cli/naming.test.d.ts +1 -0
  42. package/dist/cli/naming.test.js +75 -0
  43. package/dist/{src/cli → cli}/operations.d.ts +0 -1
  44. package/dist/cli/operations.js +100 -0
  45. package/dist/cli/operations.test.d.ts +1 -0
  46. package/dist/cli/operations.test.js +51 -0
  47. package/dist/{src/cli → cli}/params.d.ts +0 -1
  48. package/dist/cli/params.js +36 -0
  49. package/dist/cli/params.test.d.ts +1 -0
  50. package/dist/cli/params.test.js +62 -0
  51. package/dist/{src/cli → cli}/pluralize.d.ts +0 -1
  52. package/dist/cli/pluralize.js +38 -0
  53. package/dist/{src/cli → cli}/positional.d.ts +0 -1
  54. package/dist/cli/positional.js +35 -0
  55. package/dist/cli/positional.test.d.ts +1 -0
  56. package/dist/cli/positional.test.js +60 -0
  57. package/dist/{src/cli → cli}/request-body.d.ts +0 -1
  58. package/dist/cli/request-body.js +44 -0
  59. package/dist/cli/request-body.test.d.ts +1 -0
  60. package/dist/cli/request-body.test.js +31 -0
  61. package/dist/{src/cli → cli}/runtime/argv.d.ts +0 -1
  62. package/dist/cli/runtime/argv.js +15 -0
  63. package/dist/{src/cli → cli}/runtime/auth/resolve.d.ts +0 -1
  64. package/dist/cli/runtime/auth/resolve.js +39 -0
  65. package/dist/{src/cli → cli}/runtime/body-flags.d.ts +0 -1
  66. package/dist/cli/runtime/body-flags.js +117 -0
  67. package/dist/cli/runtime/body-flags.test.d.ts +1 -0
  68. package/dist/cli/runtime/body-flags.test.js +192 -0
  69. package/dist/{src/cli → cli}/runtime/body.d.ts +0 -1
  70. package/dist/cli/runtime/body.js +16 -0
  71. package/dist/{src/cli → cli}/runtime/collect.d.ts +0 -1
  72. package/dist/cli/runtime/collect.js +3 -0
  73. package/dist/{src/cli → cli}/runtime/compat.d.ts +0 -1
  74. package/dist/cli/runtime/compat.js +78 -0
  75. package/dist/{src/cli → cli}/runtime/context.d.ts +0 -1
  76. package/dist/cli/runtime/context.js +44 -0
  77. package/dist/{src/cli → cli}/runtime/execute.d.ts +0 -1
  78. package/dist/cli/runtime/execute.js +106 -0
  79. package/dist/{src/cli → cli}/runtime/generated.d.ts +0 -1
  80. package/dist/cli/runtime/generated.js +168 -0
  81. package/dist/{src/cli → cli}/runtime/headers.d.ts +0 -1
  82. package/dist/cli/runtime/headers.js +30 -0
  83. package/dist/{src/cli → cli}/runtime/index.d.ts +0 -1
  84. package/dist/cli/runtime/index.js +3 -0
  85. package/dist/{src/cli → cli}/runtime/profile/secrets.d.ts +0 -1
  86. package/dist/cli/runtime/profile/secrets.js +53 -0
  87. package/dist/{src/cli → cli}/runtime/profile/store.d.ts +0 -1
  88. package/dist/cli/runtime/profile/store.js +63 -0
  89. package/dist/{src/cli → cli}/runtime/request.d.ts +0 -1
  90. package/dist/cli/runtime/request.js +283 -0
  91. package/dist/cli/runtime/request.test.d.ts +1 -0
  92. package/dist/cli/runtime/request.test.js +332 -0
  93. package/dist/{src/cli → cli}/runtime/server-url.d.ts +0 -1
  94. package/dist/cli/runtime/server-url.js +28 -0
  95. package/dist/{src/cli → cli}/runtime/template.d.ts +0 -1
  96. package/dist/cli/runtime/template.js +22 -0
  97. package/dist/cli/runtime/validate/ajv.d.ts +2 -0
  98. package/dist/cli/runtime/validate/ajv.js +11 -0
  99. package/dist/{src/cli → cli}/runtime/validate/coerce.d.ts +0 -1
  100. package/dist/cli/runtime/validate/coerce.js +63 -0
  101. package/dist/cli/runtime/validate/coerce.test.d.ts +1 -0
  102. package/dist/cli/runtime/validate/coerce.test.js +75 -0
  103. package/dist/{src/cli → cli}/runtime/validate/error.d.ts +0 -1
  104. package/dist/cli/runtime/validate/error.js +19 -0
  105. package/dist/{src/cli → cli}/runtime/validate/index.d.ts +0 -1
  106. package/dist/cli/runtime/validate/index.js +4 -0
  107. package/dist/{src/cli → cli}/runtime/validate/schema.d.ts +0 -1
  108. package/dist/cli/runtime/validate/schema.js +38 -0
  109. package/dist/{src/cli → cli}/schema-shape.d.ts +0 -1
  110. package/dist/cli/schema-shape.js +34 -0
  111. package/dist/{src/cli → cli}/schema.d.ts +0 -1
  112. package/dist/cli/schema.js +31 -0
  113. package/dist/{src/cli → cli}/server.d.ts +0 -1
  114. package/dist/cli/server.js +130 -0
  115. package/dist/cli/server.test.d.ts +1 -0
  116. package/dist/cli/server.test.js +49 -0
  117. package/dist/{src/cli → cli}/spec-id.d.ts +0 -1
  118. package/dist/cli/spec-id.js +8 -0
  119. package/dist/{src/cli → cli}/spec-loader.d.ts +0 -1
  120. package/dist/cli/spec-loader.js +40 -0
  121. package/dist/{src/cli → cli}/stable-json.d.ts +0 -1
  122. package/dist/cli/stable-json.js +29 -0
  123. package/dist/{src/cli → cli}/strings.d.ts +0 -1
  124. package/dist/cli/strings.js +20 -0
  125. package/dist/{src/cli → cli}/types.d.ts +0 -1
  126. package/dist/cli/types.js +3 -0
  127. package/dist/cli.d.ts +0 -1
  128. package/dist/cli.js +51 -2324
  129. package/dist/compiled.d.ts +2 -0
  130. package/{src/compiled.ts → dist/compiled.js} +8 -11
  131. package/dist/macros/env.d.ts +10 -0
  132. package/dist/macros/env.js +22 -0
  133. package/dist/macros/spec.d.ts +5 -0
  134. package/dist/macros/spec.js +16 -0
  135. package/package.json +17 -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
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { buildCommandId } from "./command-id.js";
3
+ describe("buildCommandId", () => {
4
+ test("includes spec/resource/action/op", () => {
5
+ expect(buildCommandId({
6
+ specId: "contacts-api",
7
+ resource: "contacts",
8
+ action: "get",
9
+ operationKey: "GET /contacts/{id}",
10
+ })).toBe("contacts-api:contacts:get:get-contacts-id");
11
+ });
12
+ test("disambiguates by operationKey", () => {
13
+ const a = buildCommandId({
14
+ specId: "x",
15
+ resource: "contacts",
16
+ action: "list",
17
+ operationKey: "GET /contacts",
18
+ });
19
+ const b = buildCommandId({
20
+ specId: "x",
21
+ resource: "contacts",
22
+ action: "list",
23
+ operationKey: "GET /contacts/search",
24
+ });
25
+ expect(a).not.toBe(b);
26
+ });
27
+ });
@@ -3,4 +3,3 @@ export type CommandsIndex = {
3
3
  byId: Record<string, CommandAction>;
4
4
  };
5
5
  export declare function buildCommandsIndex(commands: CommandModel | undefined): CommandsIndex;
6
- //# sourceMappingURL=command-index.d.ts.map
@@ -0,0 +1,9 @@
1
+ export function buildCommandsIndex(commands) {
2
+ const byId = {};
3
+ for (const resource of commands?.resources ?? []) {
4
+ for (const action of resource.actions) {
5
+ byId[action.id] = action;
6
+ }
7
+ }
8
+ return { byId };
9
+ }
@@ -37,4 +37,3 @@ export type BuildCommandModelOptions = {
37
37
  authSchemes?: AuthScheme[];
38
38
  };
39
39
  export declare function buildCommandModel(planned: PlannedOperation[], options: BuildCommandModelOptions): CommandModel;
40
- //# sourceMappingURL=command-model.d.ts.map
@@ -0,0 +1,53 @@
1
+ import { summarizeAuth } from "./auth-requirements.js";
2
+ import { buildCommandId } from "./command-id.js";
3
+ import { deriveParamSpecs } from "./params.js";
4
+ import { deriveFlags, derivePositionals } from "./positional.js";
5
+ import { deriveRequestBodyInfo } from "./request-body.js";
6
+ export function buildCommandModel(planned, options) {
7
+ const byResource = new Map();
8
+ for (const op of planned) {
9
+ const list = byResource.get(op.resource) ?? [];
10
+ const params = deriveParamSpecs(op);
11
+ const positionals = derivePositionals({ pathArgs: op.pathArgs, params });
12
+ const flags = deriveFlags({ pathArgs: op.pathArgs, params });
13
+ list.push({
14
+ id: buildCommandId({
15
+ specId: options.specId,
16
+ resource: op.resource,
17
+ action: op.action,
18
+ operationKey: op.key,
19
+ }),
20
+ key: op.key,
21
+ action: op.action,
22
+ pathArgs: op.pathArgs,
23
+ method: op.method,
24
+ path: op.path,
25
+ operationId: op.operationId,
26
+ tags: op.tags,
27
+ summary: op.summary,
28
+ description: op.description,
29
+ deprecated: op.deprecated,
30
+ style: op.style,
31
+ params,
32
+ positionals,
33
+ flags: flags.flags,
34
+ auth: summarizeAuth(op.security, options.globalSecurity, options.authSchemes ?? []),
35
+ requestBody: deriveRequestBodyInfo(op),
36
+ requestBodySchema: deriveRequestBodyInfo(op)?.preferredSchema,
37
+ });
38
+ byResource.set(op.resource, list);
39
+ }
40
+ const resources = [];
41
+ for (const [resource, actions] of byResource.entries()) {
42
+ actions.sort((a, b) => {
43
+ if (a.action !== b.action)
44
+ return a.action.localeCompare(b.action);
45
+ if (a.path !== b.path)
46
+ return a.path.localeCompare(b.path);
47
+ return a.method.localeCompare(b.method);
48
+ });
49
+ resources.push({ resource, actions });
50
+ }
51
+ resources.sort((a, b) => a.resource.localeCompare(b.resource));
52
+ return { resources };
53
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { buildCommandModel } from "./command-model.js";
3
+ describe("buildCommandModel", () => {
4
+ test("groups operations by resource", () => {
5
+ const planned = [
6
+ {
7
+ key: "GET /contacts",
8
+ method: "GET",
9
+ path: "/contacts",
10
+ tags: ["Contacts"],
11
+ parameters: [],
12
+ resource: "contacts",
13
+ action: "list",
14
+ canonicalAction: "list",
15
+ pathArgs: [],
16
+ style: "rest",
17
+ },
18
+ {
19
+ key: "GET /contacts/{id}",
20
+ method: "GET",
21
+ path: "/contacts/{id}",
22
+ tags: ["Contacts"],
23
+ parameters: [],
24
+ resource: "contacts",
25
+ action: "get",
26
+ canonicalAction: "get",
27
+ pathArgs: ["id"],
28
+ style: "rest",
29
+ },
30
+ ];
31
+ const model = buildCommandModel(planned, { specId: "contacts-api" });
32
+ expect(model.resources).toHaveLength(1);
33
+ expect(model.resources[0]?.resource).toBe("contacts");
34
+ expect(model.resources[0]?.actions).toHaveLength(2);
35
+ expect(model.resources[0]?.actions.map((a) => a.action)).toEqual([
36
+ "get",
37
+ "list",
38
+ ]);
39
+ });
40
+ });
@@ -12,4 +12,3 @@ export type CompileOptions = {
12
12
  auth?: string;
13
13
  };
14
14
  export declare function compileCommand(spec: string, options: CompileOptions): Promise<void>;
15
- //# sourceMappingURL=compile.d.ts.map
@@ -0,0 +1,79 @@
1
+ import { deriveBinaryName } from "./derive-name.js";
2
+ function parseKeyValue(input) {
3
+ const idx = input.indexOf("=");
4
+ if (idx === -1)
5
+ throw new Error(`Invalid --define '${input}', expected key=value`);
6
+ const key = input.slice(0, idx).trim();
7
+ const value = input.slice(idx + 1).trim();
8
+ if (!key)
9
+ throw new Error(`Invalid --define '${input}', missing key`);
10
+ return { key, value };
11
+ }
12
+ export async function compileCommand(spec, options) {
13
+ // Derive name from spec if not provided
14
+ const name = options.name ?? (await deriveBinaryName(spec));
15
+ const outfile = options.outfile ?? `./dist/${name}`;
16
+ const target = options.target
17
+ ? options.target
18
+ : `bun-${process.platform}-${process.arch}`;
19
+ // Parse --define pairs
20
+ const define = {};
21
+ if (options.define) {
22
+ for (const pair of options.define) {
23
+ const { key, value } = parseKeyValue(pair);
24
+ define[key] = JSON.stringify(value);
25
+ }
26
+ }
27
+ // Build command args
28
+ const buildArgs = [
29
+ "build",
30
+ "--compile",
31
+ `--outfile=${outfile}`,
32
+ `--target=${target}`,
33
+ ];
34
+ if (options.minify)
35
+ buildArgs.push("--minify");
36
+ if (options.bytecode)
37
+ buildArgs.push("--bytecode");
38
+ for (const [k, v] of Object.entries(define)) {
39
+ buildArgs.push("--define", `${k}=${v}`);
40
+ }
41
+ if (options.dotenv === false)
42
+ buildArgs.push("--no-compile-autoload-dotenv");
43
+ if (options.bunfig === false)
44
+ buildArgs.push("--no-compile-autoload-bunfig");
45
+ buildArgs.push("./src/compiled.ts");
46
+ // Only set env vars that have actual values - avoid empty strings
47
+ // because the macros will embed them and they will override defaults.
48
+ const buildEnv = {
49
+ ...process.env,
50
+ SPECLI_SPEC: spec,
51
+ SPECLI_NAME: name,
52
+ };
53
+ if (options.server)
54
+ buildEnv.SPECLI_SERVER = options.server;
55
+ if (options.serverVar?.length)
56
+ buildEnv.SPECLI_SERVER_VARS = options.serverVar.join(",");
57
+ if (options.auth)
58
+ buildEnv.SPECLI_AUTH = options.auth;
59
+ const proc = Bun.spawn({
60
+ cmd: ["bun", ...buildArgs],
61
+ stdout: "pipe",
62
+ stderr: "pipe",
63
+ env: buildEnv,
64
+ });
65
+ const output = await new Response(proc.stdout).text();
66
+ const error = await new Response(proc.stderr).text();
67
+ const code = await proc.exited;
68
+ if (output)
69
+ process.stdout.write(output);
70
+ if (error)
71
+ process.stderr.write(error);
72
+ if (code !== 0) {
73
+ process.exitCode = code;
74
+ return;
75
+ }
76
+ process.stdout.write(`ok: built ${outfile}\n`);
77
+ process.stdout.write(`target: ${target}\n`);
78
+ process.stdout.write(`name: ${name}\n`);
79
+ }
@@ -1,2 +1 @@
1
1
  export declare function sha256Hex(text: string): Promise<string>;
2
- //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1,9 @@
1
+ export async function sha256Hex(text) {
2
+ const data = new TextEncoder().encode(text);
3
+ const hash = await crypto.subtle.digest("SHA-256", data);
4
+ const bytes = new Uint8Array(hash);
5
+ let out = "";
6
+ for (const b of bytes)
7
+ out += b.toString(16).padStart(2, "0");
8
+ return out;
9
+ }
@@ -6,4 +6,3 @@
6
6
  * 3. Fallback to "specli"
7
7
  */
8
8
  export declare function deriveBinaryName(spec: string): Promise<string>;
9
- //# sourceMappingURL=derive-name.d.ts.map
@@ -0,0 +1,96 @@
1
+ const RESERVED_NAMES = [
2
+ "exec",
3
+ "compile",
4
+ "profile",
5
+ "auth",
6
+ "help",
7
+ "version",
8
+ ];
9
+ /**
10
+ * Derives a clean binary name from an OpenAPI spec.
11
+ * Priority:
12
+ * 1. info.title (kebab-cased, sanitized)
13
+ * 2. Host from spec URL (if URL provided)
14
+ * 3. Fallback to "specli"
15
+ */
16
+ export async function deriveBinaryName(spec) {
17
+ try {
18
+ // Load spec to extract title
19
+ const text = await loadSpecText(spec);
20
+ const doc = parseSpec(text);
21
+ const title = doc?.info?.title;
22
+ if (title && typeof title === "string") {
23
+ const name = sanitizeName(title);
24
+ if (name)
25
+ return name;
26
+ }
27
+ }
28
+ catch {
29
+ // Fall through to URL-based derivation
30
+ }
31
+ // Try to derive from URL host
32
+ if (/^https?:\/\//i.test(spec)) {
33
+ try {
34
+ const url = new URL(spec);
35
+ const hostParts = url.hostname.split(".");
36
+ // Use first meaningful segment (skip www, api prefixes)
37
+ const meaningful = hostParts.find((p) => p !== "www" && p !== "api" && p.length > 2);
38
+ if (meaningful) {
39
+ const name = sanitizeName(meaningful);
40
+ if (name)
41
+ return name;
42
+ }
43
+ }
44
+ catch {
45
+ // Invalid URL, fall through
46
+ }
47
+ }
48
+ // Fallback
49
+ return "specli";
50
+ }
51
+ async function loadSpecText(spec) {
52
+ if (/^https?:\/\//i.test(spec)) {
53
+ const res = await fetch(spec);
54
+ if (!res.ok)
55
+ throw new Error(`Failed to fetch: ${res.status}`);
56
+ return res.text();
57
+ }
58
+ return Bun.file(spec).text();
59
+ }
60
+ function parseSpec(text) {
61
+ try {
62
+ const trimmed = text.trimStart();
63
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
64
+ return JSON.parse(text);
65
+ }
66
+ // Use Bun's YAML parser
67
+ const { YAML } = globalThis.Bun ?? {};
68
+ if (YAML?.parse) {
69
+ return YAML.parse(text);
70
+ }
71
+ // Fallback: only JSON supported
72
+ return null;
73
+ }
74
+ catch {
75
+ return null;
76
+ }
77
+ }
78
+ /**
79
+ * Convert title to valid binary name:
80
+ * - kebab-case
81
+ * - lowercase
82
+ * - remove invalid chars
83
+ * - max 32 chars
84
+ * - avoid reserved names
85
+ */
86
+ function sanitizeName(input) {
87
+ let name = input
88
+ .toLowerCase()
89
+ .replace(/[^a-z0-9]+/g, "-") // Replace non-alphanumeric with dash
90
+ .replace(/^-+|-+$/g, "") // Trim leading/trailing dashes
91
+ .slice(0, 32); // Limit length
92
+ if (RESERVED_NAMES.includes(name)) {
93
+ name = `${name}-cli`;
94
+ }
95
+ return name;
96
+ }
@@ -11,4 +11,3 @@ export type ExecOptions = {
11
11
  json?: boolean;
12
12
  };
13
13
  export declare function execCommand(spec: string, options: ExecOptions, commandArgs: string[]): Promise<void>;
14
- //# sourceMappingURL=exec.d.ts.map
@@ -0,0 +1,50 @@
1
+ import { main } from "./main.js";
2
+ export async function execCommand(spec, options, commandArgs) {
3
+ // commandArgs includes the spec as first element, filter it out
4
+ // to get the remaining args (resource, action, etc.)
5
+ const remainingArgs = commandArgs.slice(1);
6
+ // Reconstruct argv for main():
7
+ // [node, script, --spec, <spec>, ...options, ...remainingArgs]
8
+ const argv = [
9
+ process.argv[0] ?? "bun",
10
+ process.argv[1] ?? "specli",
11
+ "--spec",
12
+ spec,
13
+ ];
14
+ // Add common options back as flags
15
+ if (options.server) {
16
+ argv.push("--server", options.server);
17
+ }
18
+ if (options.serverVar) {
19
+ for (const v of options.serverVar) {
20
+ argv.push("--server-var", v);
21
+ }
22
+ }
23
+ if (options.auth) {
24
+ argv.push("--auth", options.auth);
25
+ }
26
+ if (options.bearerToken) {
27
+ argv.push("--bearer-token", options.bearerToken);
28
+ }
29
+ if (options.oauthToken) {
30
+ argv.push("--oauth-token", options.oauthToken);
31
+ }
32
+ if (options.username) {
33
+ argv.push("--username", options.username);
34
+ }
35
+ if (options.password) {
36
+ argv.push("--password", options.password);
37
+ }
38
+ if (options.apiKey) {
39
+ argv.push("--api-key", options.apiKey);
40
+ }
41
+ if (options.profile) {
42
+ argv.push("--profile", options.profile);
43
+ }
44
+ if (options.json) {
45
+ argv.push("--json");
46
+ }
47
+ // Append remaining args (subcommand + its args)
48
+ argv.push(...remainingArgs);
49
+ await main(argv);
50
+ }
@@ -7,4 +7,3 @@ type MainOptions = {
7
7
  };
8
8
  export declare function main(argv: string[], options?: MainOptions): Promise<void>;
9
9
  export {};
10
- //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1,177 @@
1
+ import { Command } from "commander";
2
+ import { getArgValue, hasAnyArg } from "./runtime/argv.js";
3
+ import { collectRepeatable } from "./runtime/collect.js";
4
+ import { readStdinText } from "./runtime/compat.js";
5
+ import { buildRuntimeContext } from "./runtime/context.js";
6
+ import { addGeneratedCommands } from "./runtime/generated.js";
7
+ import { deleteToken, getToken, setToken } from "./runtime/profile/secrets.js";
8
+ import { readProfiles, upsertProfile, writeProfiles, } from "./runtime/profile/store.js";
9
+ import { toMinimalSchemaOutput } from "./schema.js";
10
+ import { stableStringify } from "./stable-json.js";
11
+ export async function main(argv, options = {}) {
12
+ const program = new Command();
13
+ program
14
+ .name(options.cliName ?? "specli")
15
+ .description("Generate a CLI from an OpenAPI spec")
16
+ .option("--spec <urlOrPath>", "OpenAPI URL or file path")
17
+ .option("--server <url>", "Override server/base URL")
18
+ .option("--server-var <name=value>", "Server URL template variable (repeatable)", collectRepeatable)
19
+ .option("--auth <scheme>", "Select auth scheme by key")
20
+ .option("--bearer-token <token>", "Bearer token (Authorization: Bearer)")
21
+ .option("--oauth-token <token>", "OAuth token (alias of bearer)")
22
+ .option("--username <username>", "Basic auth username")
23
+ .option("--password <password>", "Basic auth password")
24
+ .option("--api-key <key>", "API key value")
25
+ .option("--json", "Machine-readable output")
26
+ .showHelpAfterError();
27
+ // If user asks for help and we have no embedded spec and no --spec, show minimal help.
28
+ const spec = getArgValue(argv, "--spec");
29
+ const wantsHelp = hasAnyArg(argv, ["-h", "--help"]);
30
+ if (!spec && !options.embeddedSpecText && wantsHelp) {
31
+ program.addHelpText("after", "\nTo see generated commands, run with --spec <url|path>.\n");
32
+ program.parse(argv);
33
+ return;
34
+ }
35
+ const ctx = await buildRuntimeContext({
36
+ spec,
37
+ embeddedSpecText: options.embeddedSpecText,
38
+ });
39
+ // Simple auth commands
40
+ const defaultProfileName = "default";
41
+ program
42
+ .command("login [token]")
43
+ .description("Store a bearer token for authentication")
44
+ .action(async (tokenArg, _opts, command) => {
45
+ const globals = command.optsWithGlobals();
46
+ let token = tokenArg;
47
+ // If no token argument, try to read from stdin (for piping)
48
+ if (!token) {
49
+ const isTTY = process.stdin.isTTY;
50
+ if (isTTY) {
51
+ // Interactive mode - prompt user
52
+ process.stdout.write("Enter token: ");
53
+ const reader = process.stdin;
54
+ const chunks = [];
55
+ for await (const chunk of reader) {
56
+ chunks.push(chunk);
57
+ // Read one line only
58
+ if (chunk.includes(10))
59
+ break; // newline
60
+ }
61
+ token = Buffer.concat(chunks).toString().trim();
62
+ }
63
+ else {
64
+ // Piped input - use cross-runtime stdin reading
65
+ const text = await readStdinText();
66
+ token = text.trim();
67
+ }
68
+ }
69
+ if (!token) {
70
+ throw new Error("No token provided. Usage: login <token> or echo $TOKEN | login");
71
+ }
72
+ // Ensure default profile exists
73
+ const file = await readProfiles();
74
+ if (!file.profiles.find((p) => p.name === defaultProfileName)) {
75
+ const updated = upsertProfile(file, { name: defaultProfileName });
76
+ await writeProfiles({ ...updated, defaultProfile: defaultProfileName });
77
+ }
78
+ else if (!file.defaultProfile) {
79
+ await writeProfiles({ ...file, defaultProfile: defaultProfileName });
80
+ }
81
+ await setToken(ctx.loaded.id, defaultProfileName, token);
82
+ if (globals.json) {
83
+ process.stdout.write(`${JSON.stringify({ ok: true })}\n`);
84
+ return;
85
+ }
86
+ process.stdout.write("ok: logged in\n");
87
+ });
88
+ program
89
+ .command("logout")
90
+ .description("Clear stored authentication token")
91
+ .action(async (_opts, command) => {
92
+ const globals = command.optsWithGlobals();
93
+ const deleted = await deleteToken(ctx.loaded.id, defaultProfileName);
94
+ if (globals.json) {
95
+ process.stdout.write(`${JSON.stringify({ ok: deleted })}\n`);
96
+ return;
97
+ }
98
+ process.stdout.write(deleted ? "ok: logged out\n" : "ok: not logged in\n");
99
+ });
100
+ program
101
+ .command("whoami")
102
+ .description("Show current authentication status")
103
+ .action(async (_opts, command) => {
104
+ const globals = command.optsWithGlobals();
105
+ const token = await getToken(ctx.loaded.id, defaultProfileName);
106
+ const hasToken = Boolean(token);
107
+ // Mask the token for display (show first 8 and last 4 chars)
108
+ let maskedToken = null;
109
+ if (token && token.length > 16) {
110
+ maskedToken = `${token.slice(0, 8)}...${token.slice(-4)}`;
111
+ }
112
+ else if (token) {
113
+ maskedToken = `${token.slice(0, 4)}...`;
114
+ }
115
+ if (globals.json) {
116
+ process.stdout.write(`${JSON.stringify({ authenticated: hasToken, token: maskedToken })}\n`);
117
+ return;
118
+ }
119
+ if (hasToken) {
120
+ process.stdout.write(`authenticated: yes\n`);
121
+ process.stdout.write(`token: ${maskedToken}\n`);
122
+ }
123
+ else {
124
+ process.stdout.write(`authenticated: no\n`);
125
+ process.stdout.write(`Run 'login <token>' to authenticate.\n`);
126
+ }
127
+ });
128
+ program
129
+ .command("__schema")
130
+ .description("Print indexed operations (machine-readable when --json)")
131
+ .option("--pretty", "Pretty-print JSON when used with --json")
132
+ .option("--min", "Minimal JSON output (commands + metadata only)")
133
+ .action(async (_opts, command) => {
134
+ const flags = command.optsWithGlobals();
135
+ if (flags.json) {
136
+ const pretty = Boolean(flags.pretty);
137
+ const payload = flags.min
138
+ ? toMinimalSchemaOutput(ctx.schema)
139
+ : ctx.schema;
140
+ const text = stableStringify(payload, { space: pretty ? 2 : 0 });
141
+ process.stdout.write(`${text}\n`);
142
+ return;
143
+ }
144
+ process.stdout.write(`${ctx.schema.openapi.title ?? "(untitled)"}\n`);
145
+ process.stdout.write(`OpenAPI: ${ctx.schema.openapi.version}\n`);
146
+ process.stdout.write(`Spec: ${ctx.schema.spec.id} (${ctx.schema.spec.source})\n`);
147
+ process.stdout.write(`Fingerprint: ${ctx.schema.spec.fingerprint}\n`);
148
+ process.stdout.write(`Servers: ${ctx.schema.servers.length}\n`);
149
+ process.stdout.write(`Auth Schemes: ${ctx.schema.authSchemes.length}\n`);
150
+ process.stdout.write(`Operations: ${ctx.schema.operations.length}\n`);
151
+ for (const op of ctx.schema.operations) {
152
+ const id = op.operationId ? ` (${op.operationId})` : "";
153
+ process.stdout.write(`- ${op.method} ${op.path}${id}\n`);
154
+ }
155
+ if (ctx.schema.planned?.length) {
156
+ process.stdout.write("\nPlanned commands:\n");
157
+ for (const op of ctx.schema.planned) {
158
+ const args = op.pathArgs.length
159
+ ? ` ${op.pathArgs.map((a) => `<${a}>`).join(" ")}`
160
+ : "";
161
+ process.stdout.write(`- specli ${op.resource} ${op.action}${args}\n`);
162
+ }
163
+ }
164
+ });
165
+ addGeneratedCommands(program, {
166
+ servers: ctx.servers,
167
+ authSchemes: ctx.authSchemes,
168
+ commands: ctx.commands,
169
+ specId: ctx.loaded.id,
170
+ embeddedDefaults: {
171
+ server: options.server,
172
+ serverVars: options.serverVars,
173
+ auth: options.auth,
174
+ },
175
+ });
176
+ await program.parseAsync(argv);
177
+ }
@@ -9,4 +9,3 @@ export type PlannedOperation = NormalizedOperation & {
9
9
  };
10
10
  export declare function planOperation(op: NormalizedOperation): PlannedOperation;
11
11
  export declare function planOperations(ops: NormalizedOperation[]): PlannedOperation[];
12
- //# sourceMappingURL=naming.d.ts.map