specli 0.0.4 → 0.0.7

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 (209) hide show
  1. package/cli.ts +13 -4
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +2331 -0
  5. package/dist/cli.js.map +53 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +2032 -0
  9. package/dist/index.js.map +48 -0
  10. package/dist/src/ai/tools.d.ts +139 -0
  11. package/dist/src/ai/tools.d.ts.map +1 -0
  12. package/dist/src/ai/tools.js +1656 -0
  13. package/dist/src/ai/tools.js.map +45 -0
  14. package/dist/src/cli/auth-requirements.d.ts +10 -0
  15. package/dist/src/cli/auth-requirements.d.ts.map +1 -0
  16. package/dist/src/cli/auth-requirements.js +66 -0
  17. package/dist/src/cli/auth-requirements.js.map +10 -0
  18. package/dist/src/cli/auth-schemes.d.ts +22 -0
  19. package/dist/src/cli/auth-schemes.d.ts.map +1 -0
  20. package/dist/src/cli/auth-schemes.js +116 -0
  21. package/dist/src/cli/auth-schemes.js.map +11 -0
  22. package/dist/src/cli/capabilities.d.ts +32 -0
  23. package/dist/src/cli/capabilities.d.ts.map +1 -0
  24. package/dist/src/cli/capabilities.js +45 -0
  25. package/dist/src/cli/capabilities.js.map +10 -0
  26. package/dist/src/cli/command-id.d.ts +8 -0
  27. package/dist/src/cli/command-id.d.ts.map +1 -0
  28. package/dist/src/cli/command-id.js +18 -0
  29. package/dist/src/cli/command-id.js.map +11 -0
  30. package/dist/src/cli/command-index.d.ts +6 -0
  31. package/dist/src/cli/command-index.d.ts.map +1 -0
  32. package/dist/src/cli/command-index.js +15 -0
  33. package/dist/src/cli/command-index.js.map +10 -0
  34. package/dist/src/cli/command-model.d.ts +40 -0
  35. package/dist/src/cli/command-model.d.ts.map +1 -0
  36. package/dist/src/cli/command-model.js +274 -0
  37. package/dist/src/cli/command-model.js.map +18 -0
  38. package/dist/src/cli/compile.d.ts +15 -0
  39. package/dist/src/cli/compile.d.ts.map +1 -0
  40. package/dist/src/cli/compile.js +146 -0
  41. package/dist/src/cli/compile.js.map +11 -0
  42. package/dist/src/cli/crypto.d.ts +2 -0
  43. package/dist/src/cli/crypto.d.ts.map +1 -0
  44. package/dist/src/cli/crypto.js +15 -0
  45. package/dist/src/cli/crypto.js.map +10 -0
  46. package/dist/src/cli/derive-name.d.ts +9 -0
  47. package/dist/src/cli/derive-name.d.ts.map +1 -0
  48. package/dist/src/cli/derive-name.js +70 -0
  49. package/dist/src/cli/derive-name.js.map +10 -0
  50. package/dist/src/cli/exec.d.ts +14 -0
  51. package/dist/src/cli/exec.d.ts.map +1 -0
  52. package/dist/src/cli/exec.js +2077 -0
  53. package/dist/src/cli/exec.js.map +49 -0
  54. package/dist/src/cli/main.d.ts +10 -0
  55. package/dist/src/cli/main.d.ts.map +1 -0
  56. package/dist/src/cli/main.js +2032 -0
  57. package/dist/src/cli/main.js.map +48 -0
  58. package/dist/src/cli/naming.d.ts +12 -0
  59. package/dist/src/cli/naming.d.ts.map +1 -0
  60. package/dist/src/cli/naming.js +216 -0
  61. package/dist/src/cli/naming.js.map +12 -0
  62. package/dist/src/cli/operations.d.ts +3 -0
  63. package/dist/src/cli/operations.d.ts.map +1 -0
  64. package/dist/src/cli/operations.js +103 -0
  65. package/dist/src/cli/operations.js.map +10 -0
  66. package/dist/src/cli/params.d.ts +19 -0
  67. package/dist/src/cli/params.d.ts.map +1 -0
  68. package/dist/src/cli/params.js +79 -0
  69. package/dist/src/cli/params.js.map +12 -0
  70. package/dist/src/cli/pluralize.d.ts +2 -0
  71. package/dist/src/cli/pluralize.d.ts.map +1 -0
  72. package/dist/src/cli/pluralize.js +43 -0
  73. package/dist/src/cli/pluralize.js.map +10 -0
  74. package/dist/src/cli/positional.d.ts +19 -0
  75. package/dist/src/cli/positional.d.ts.map +1 -0
  76. package/dist/src/cli/positional.js +39 -0
  77. package/dist/src/cli/positional.js.map +10 -0
  78. package/dist/src/cli/request-body.d.ts +20 -0
  79. package/dist/src/cli/request-body.d.ts.map +1 -0
  80. package/dist/src/cli/request-body.js +82 -0
  81. package/dist/src/cli/request-body.js.map +12 -0
  82. package/dist/src/cli/runtime/argv.d.ts +3 -0
  83. package/dist/src/cli/runtime/argv.d.ts.map +1 -0
  84. package/dist/src/cli/runtime/argv.js +22 -0
  85. package/dist/src/cli/runtime/argv.js.map +10 -0
  86. package/dist/src/cli/runtime/auth/resolve.d.ts +9 -0
  87. package/dist/src/cli/runtime/auth/resolve.d.ts.map +1 -0
  88. package/dist/src/cli/runtime/auth/resolve.js +38 -0
  89. package/dist/src/cli/runtime/auth/resolve.js.map +10 -0
  90. package/dist/src/cli/runtime/body-flags.d.ts +41 -0
  91. package/dist/src/cli/runtime/body-flags.d.ts.map +1 -0
  92. package/dist/src/cli/runtime/body-flags.js +86 -0
  93. package/dist/src/cli/runtime/body-flags.js.map +10 -0
  94. package/dist/src/cli/runtime/body.d.ts +15 -0
  95. package/dist/src/cli/runtime/body.d.ts.map +1 -0
  96. package/dist/src/cli/runtime/body.js +40 -0
  97. package/dist/src/cli/runtime/body.js.map +11 -0
  98. package/dist/src/cli/runtime/collect.d.ts +2 -0
  99. package/dist/src/cli/runtime/collect.d.ts.map +1 -0
  100. package/dist/src/cli/runtime/collect.js +9 -0
  101. package/dist/src/cli/runtime/collect.js.map +10 -0
  102. package/dist/src/cli/runtime/compat.d.ts +35 -0
  103. package/dist/src/cli/runtime/compat.d.ts.map +1 -0
  104. package/dist/src/cli/runtime/compat.js +62 -0
  105. package/dist/src/cli/runtime/compat.js.map +10 -0
  106. package/dist/src/cli/runtime/context.d.ts +16 -0
  107. package/dist/src/cli/runtime/context.d.ts.map +1 -0
  108. package/dist/src/cli/runtime/context.js +936 -0
  109. package/dist/src/cli/runtime/context.js.map +32 -0
  110. package/dist/src/cli/runtime/execute.d.ts +33 -0
  111. package/dist/src/cli/runtime/execute.d.ts.map +1 -0
  112. package/dist/src/cli/runtime/execute.js +670 -0
  113. package/dist/src/cli/runtime/execute.js.map +22 -0
  114. package/dist/src/cli/runtime/generated.d.ts +14 -0
  115. package/dist/src/cli/runtime/generated.d.ts.map +1 -0
  116. package/dist/src/cli/runtime/generated.js +869 -0
  117. package/dist/src/cli/runtime/generated.js.map +23 -0
  118. package/dist/src/cli/runtime/headers.d.ts +9 -0
  119. package/dist/src/cli/runtime/headers.d.ts.map +1 -0
  120. package/dist/src/cli/runtime/headers.js +36 -0
  121. package/dist/src/cli/runtime/headers.js.map +10 -0
  122. package/dist/src/cli/runtime/index.d.ts +4 -0
  123. package/dist/src/cli/runtime/index.d.ts.map +1 -0
  124. package/dist/src/cli/runtime/index.js +1808 -0
  125. package/dist/src/cli/runtime/index.js.map +46 -0
  126. package/dist/src/cli/runtime/profile/secrets.d.ts +25 -0
  127. package/dist/src/cli/runtime/profile/secrets.d.ts.map +1 -0
  128. package/dist/src/cli/runtime/profile/secrets.js +51 -0
  129. package/dist/src/cli/runtime/profile/secrets.js.map +11 -0
  130. package/dist/src/cli/runtime/profile/store.d.ts +15 -0
  131. package/dist/src/cli/runtime/profile/store.d.ts.map +1 -0
  132. package/dist/src/cli/runtime/profile/store.js +102 -0
  133. package/dist/src/cli/runtime/profile/store.js.map +11 -0
  134. package/dist/src/cli/runtime/request.d.ts +36 -0
  135. package/dist/src/cli/runtime/request.d.ts.map +1 -0
  136. package/dist/src/cli/runtime/request.js +571 -0
  137. package/dist/src/cli/runtime/request.js.map +21 -0
  138. package/dist/src/cli/runtime/server-url.d.ts +8 -0
  139. package/dist/src/cli/runtime/server-url.d.ts.map +1 -0
  140. package/dist/src/cli/runtime/server-url.js +55 -0
  141. package/dist/src/cli/runtime/server-url.js.map +11 -0
  142. package/dist/src/cli/runtime/template.d.ts +5 -0
  143. package/dist/src/cli/runtime/template.d.ts.map +1 -0
  144. package/dist/src/cli/runtime/template.js +29 -0
  145. package/dist/src/cli/runtime/template.js.map +10 -0
  146. package/dist/src/cli/runtime/validate/ajv.d.ts +3 -0
  147. package/dist/src/cli/runtime/validate/ajv.d.ts.map +1 -0
  148. package/dist/src/cli/runtime/validate/ajv.js +17 -0
  149. package/dist/src/cli/runtime/validate/ajv.js.map +10 -0
  150. package/dist/src/cli/runtime/validate/coerce.d.ts +4 -0
  151. package/dist/src/cli/runtime/validate/coerce.d.ts.map +1 -0
  152. package/dist/src/cli/runtime/validate/coerce.js +60 -0
  153. package/dist/src/cli/runtime/validate/coerce.js.map +10 -0
  154. package/dist/src/cli/runtime/validate/error.d.ts +3 -0
  155. package/dist/src/cli/runtime/validate/error.d.ts.map +1 -0
  156. package/dist/src/cli/runtime/validate/error.js +21 -0
  157. package/dist/src/cli/runtime/validate/error.js.map +10 -0
  158. package/dist/src/cli/runtime/validate/index.d.ts +5 -0
  159. package/dist/src/cli/runtime/validate/index.d.ts.map +1 -0
  160. package/dist/src/cli/runtime/validate/index.js +122 -0
  161. package/dist/src/cli/runtime/validate/index.js.map +13 -0
  162. package/dist/src/cli/runtime/validate/schema.d.ts +9 -0
  163. package/dist/src/cli/runtime/validate/schema.d.ts.map +1 -0
  164. package/dist/src/cli/runtime/validate/schema.js +36 -0
  165. package/dist/src/cli/runtime/validate/schema.js.map +10 -0
  166. package/dist/src/cli/schema-shape.d.ts +5 -0
  167. package/dist/src/cli/schema-shape.d.ts.map +1 -0
  168. package/dist/src/cli/schema-shape.js +41 -0
  169. package/dist/src/cli/schema-shape.js.map +10 -0
  170. package/dist/src/cli/schema.d.ts +30 -0
  171. package/dist/src/cli/schema.d.ts.map +1 -0
  172. package/dist/src/cli/schema.js +38 -0
  173. package/dist/src/cli/schema.js.map +10 -0
  174. package/dist/src/cli/server.d.ts +16 -0
  175. package/dist/src/cli/server.d.ts.map +1 -0
  176. package/dist/src/cli/server.js +64 -0
  177. package/dist/src/cli/server.js.map +11 -0
  178. package/dist/src/cli/spec-id.d.ts +3 -0
  179. package/dist/src/cli/spec-id.d.ts.map +1 -0
  180. package/dist/src/cli/spec-id.js +21 -0
  181. package/dist/src/cli/spec-id.js.map +11 -0
  182. package/dist/src/cli/spec-loader.d.ts +7 -0
  183. package/dist/src/cli/spec-loader.d.ts.map +1 -0
  184. package/dist/src/cli/spec-loader.js +110 -0
  185. package/dist/src/cli/spec-loader.js.map +15 -0
  186. package/dist/src/cli/stable-json.d.ts +4 -0
  187. package/dist/src/cli/stable-json.d.ts.map +1 -0
  188. package/dist/src/cli/stable-json.js +35 -0
  189. package/dist/src/cli/stable-json.js.map +10 -0
  190. package/dist/src/cli/strings.d.ts +3 -0
  191. package/dist/src/cli/strings.d.ts.map +1 -0
  192. package/dist/src/cli/strings.js +16 -0
  193. package/dist/src/cli/strings.js.map +10 -0
  194. package/dist/src/cli/types.d.ts +53 -0
  195. package/dist/src/cli/types.d.ts.map +1 -0
  196. package/dist/src/cli/types.js +9 -0
  197. package/dist/src/cli/types.js.map +10 -0
  198. package/package.json +31 -4
  199. package/src/ai/tools.ts +211 -0
  200. package/src/cli/main.ts +73 -163
  201. package/src/cli/runtime/auth/resolve.ts +20 -0
  202. package/src/cli/runtime/body.ts +3 -3
  203. package/src/cli/runtime/compat.ts +89 -0
  204. package/src/cli/runtime/execute.ts +98 -39
  205. package/src/cli/runtime/generated.ts +111 -4
  206. package/src/cli/runtime/profile/secrets.ts +42 -1
  207. package/src/cli/runtime/profile/store.ts +15 -13
  208. package/src/cli/runtime/request.ts +22 -11
  209. package/src/cli/spec-loader.ts +2 -2
package/dist/cli.js ADDED
@@ -0,0 +1,2331 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
+
14
+ // src/cli/runtime/argv.ts
15
+ function getArgValue(argv, key) {
16
+ for (let i = 0;i < argv.length; i++) {
17
+ const a = argv[i];
18
+ if (!a)
19
+ continue;
20
+ if (a === key)
21
+ return argv[i + 1];
22
+ if (a.startsWith(`${key}=`))
23
+ return a.slice(key.length + 1);
24
+ }
25
+ return;
26
+ }
27
+ function hasAnyArg(argv, names) {
28
+ return argv.some((a) => a && names.includes(a));
29
+ }
30
+
31
+ // src/cli/runtime/collect.ts
32
+ function collectRepeatable(value, previous) {
33
+ return [...previous ?? [], value];
34
+ }
35
+
36
+ // src/cli/runtime/compat.ts
37
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
38
+ import { parse as parseYaml } from "yaml";
39
+ async function readFileText(path) {
40
+ if (isBun) {
41
+ return Bun.file(path).text();
42
+ }
43
+ return readFileSync(path, "utf-8");
44
+ }
45
+ async function fileExists(path) {
46
+ if (isBun) {
47
+ return Bun.file(path).exists();
48
+ }
49
+ return existsSync(path);
50
+ }
51
+ async function writeFileText(path, content) {
52
+ if (isBun) {
53
+ await Bun.write(path, content);
54
+ return;
55
+ }
56
+ writeFileSync(path, content, "utf-8");
57
+ }
58
+ async function mkdirp(path) {
59
+ if (isBun) {
60
+ await Bun.$`mkdir -p ${path}`;
61
+ return;
62
+ }
63
+ mkdirSync(path, { recursive: true });
64
+ }
65
+ function parseYamlContent(text) {
66
+ if (isBun) {
67
+ const { YAML } = globalThis.Bun;
68
+ return YAML.parse(text);
69
+ }
70
+ return parseYaml(text);
71
+ }
72
+ async function readStdinText() {
73
+ if (isBun) {
74
+ return Bun.stdin.text();
75
+ }
76
+ return new Promise((resolve, reject) => {
77
+ let data = "";
78
+ process.stdin.setEncoding("utf8");
79
+ process.stdin.on("data", (chunk) => {
80
+ data += chunk;
81
+ });
82
+ process.stdin.on("end", () => resolve(data));
83
+ process.stdin.on("error", reject);
84
+ });
85
+ }
86
+ var isBun;
87
+ var init_compat = __esm(() => {
88
+ isBun = typeof globalThis.Bun !== "undefined";
89
+ });
90
+
91
+ // src/cli/strings.ts
92
+ function kebabCase(input) {
93
+ const trimmed = input.trim();
94
+ if (!trimmed)
95
+ return "";
96
+ return trimmed.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[\s_.:/]+/g, "-").replace(/[^a-zA-Z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").toLowerCase();
97
+ }
98
+
99
+ // src/cli/auth-schemes.ts
100
+ function parseOAuthFlow(flow) {
101
+ if (!flow)
102
+ return;
103
+ const scopesObj = flow.scopes;
104
+ const scopes = scopesObj && typeof scopesObj === "object" && !Array.isArray(scopesObj) ? Object.keys(scopesObj) : [];
105
+ return {
106
+ authorizationUrl: typeof flow.authorizationUrl === "string" ? flow.authorizationUrl : undefined,
107
+ tokenUrl: typeof flow.tokenUrl === "string" ? flow.tokenUrl : undefined,
108
+ refreshUrl: typeof flow.refreshUrl === "string" ? flow.refreshUrl : undefined,
109
+ scopes: scopes.sort()
110
+ };
111
+ }
112
+ function parseOAuthFlows(flows) {
113
+ if (!flows)
114
+ return;
115
+ const out = {};
116
+ const implicit = parseOAuthFlow(flows.implicit);
117
+ if (implicit)
118
+ out.implicit = implicit;
119
+ const password = parseOAuthFlow(flows.password);
120
+ if (password)
121
+ out.password = password;
122
+ const clientCredentials = parseOAuthFlow(flows.clientCredentials);
123
+ if (clientCredentials)
124
+ out.clientCredentials = clientCredentials;
125
+ const authorizationCode = parseOAuthFlow(flows.authorizationCode);
126
+ if (authorizationCode)
127
+ out.authorizationCode = authorizationCode;
128
+ return Object.keys(out).length ? out : undefined;
129
+ }
130
+ function listAuthSchemes(doc) {
131
+ const schemes = doc.components?.securitySchemes;
132
+ if (!schemes || typeof schemes !== "object")
133
+ return [];
134
+ const out = [];
135
+ for (const [key, raw] of Object.entries(schemes)) {
136
+ if (!raw || typeof raw !== "object")
137
+ continue;
138
+ const s = raw;
139
+ const type = s.type;
140
+ if (type === "http") {
141
+ const scheme = (s.scheme ?? "").toLowerCase();
142
+ if (scheme === "bearer") {
143
+ out.push({
144
+ key,
145
+ kind: "http-bearer",
146
+ scheme,
147
+ bearerFormat: s.bearerFormat,
148
+ description: s.description
149
+ });
150
+ } else if (scheme === "basic") {
151
+ out.push({
152
+ key,
153
+ kind: "http-basic",
154
+ scheme,
155
+ description: s.description
156
+ });
157
+ } else {
158
+ out.push({
159
+ key,
160
+ kind: "unknown",
161
+ scheme: s.scheme,
162
+ description: s.description
163
+ });
164
+ }
165
+ continue;
166
+ }
167
+ if (type === "apiKey") {
168
+ const where = s.in;
169
+ const loc = where === "header" || where === "query" || where === "cookie" ? where : undefined;
170
+ out.push({
171
+ key,
172
+ kind: "api-key",
173
+ name: s.name,
174
+ in: loc,
175
+ description: s.description
176
+ });
177
+ continue;
178
+ }
179
+ if (type === "oauth2") {
180
+ out.push({
181
+ key,
182
+ kind: "oauth2",
183
+ description: s.description,
184
+ oauthFlows: parseOAuthFlows(s.flows)
185
+ });
186
+ continue;
187
+ }
188
+ if (type === "openIdConnect") {
189
+ out.push({
190
+ key,
191
+ kind: "openIdConnect",
192
+ description: s.description,
193
+ openIdConnectUrl: s.openIdConnectUrl
194
+ });
195
+ continue;
196
+ }
197
+ out.push({ key, kind: "unknown", description: s.description });
198
+ }
199
+ out.sort((a, b) => kebabCase(a.key).localeCompare(kebabCase(b.key)));
200
+ return out;
201
+ }
202
+ var init_auth_schemes = () => {};
203
+
204
+ // src/cli/capabilities.ts
205
+ function uniqueSorted(items, compare) {
206
+ const out = [...items];
207
+ out.sort(compare);
208
+ return out.filter((v, i) => i === 0 || compare(out[i - 1], v) !== 0);
209
+ }
210
+ function hasSecurity(requirements) {
211
+ if (!requirements?.length)
212
+ return false;
213
+ return true;
214
+ }
215
+ function deriveCapabilities(input) {
216
+ const serverHasVars = input.servers.some((s) => s.variableNames.length > 0);
217
+ const authKinds = uniqueSorted(input.authSchemes.map((s) => s.kind), (a, b) => a.localeCompare(b));
218
+ const hasSecurityRequirements = hasSecurity(input.doc.security) || input.operations.some((op) => hasSecurity(op.security));
219
+ const opHasBodies = input.operations.some((op) => Boolean(op.requestBody));
220
+ const cmdResources = input.commands?.resources ?? [];
221
+ const cmdActions = cmdResources.flatMap((r) => r.actions);
222
+ const cmdHasBodies = cmdActions.some((a) => Boolean(a.requestBody));
223
+ return {
224
+ servers: {
225
+ count: input.servers.length,
226
+ hasVariables: serverHasVars
227
+ },
228
+ auth: {
229
+ count: input.authSchemes.length,
230
+ kinds: authKinds,
231
+ hasSecurityRequirements
232
+ },
233
+ operations: {
234
+ count: input.operations.length,
235
+ hasRequestBodies: opHasBodies
236
+ },
237
+ commands: {
238
+ countResources: cmdResources.length,
239
+ countActions: cmdActions.length,
240
+ hasRequestBodies: cmdHasBodies
241
+ }
242
+ };
243
+ }
244
+
245
+ // src/cli/command-index.ts
246
+ function buildCommandsIndex(commands) {
247
+ const byId = {};
248
+ for (const resource of commands?.resources ?? []) {
249
+ for (const action of resource.actions) {
250
+ byId[action.id] = action;
251
+ }
252
+ }
253
+ return { byId };
254
+ }
255
+
256
+ // src/cli/auth-requirements.ts
257
+ function isSecurityRequirement(value) {
258
+ if (!value || typeof value !== "object")
259
+ return false;
260
+ if (Array.isArray(value))
261
+ return false;
262
+ for (const [k, v] of Object.entries(value)) {
263
+ if (typeof k !== "string")
264
+ return false;
265
+ if (!Array.isArray(v))
266
+ return false;
267
+ if (!v.every((s) => typeof s === "string"))
268
+ return false;
269
+ }
270
+ return true;
271
+ }
272
+ function normalizeSecurity(value) {
273
+ if (value == null)
274
+ return { requirements: [], source: "none" };
275
+ if (!Array.isArray(value))
276
+ return { requirements: [], source: "none" };
277
+ const reqs = value.filter(isSecurityRequirement);
278
+ if (reqs.length === 0)
279
+ return { requirements: [], source: "empty" };
280
+ return { requirements: reqs, source: "non-empty" };
281
+ }
282
+ function summarizeAuth(operationSecurity, globalSecurity, knownSchemes) {
283
+ const op = normalizeSecurity(operationSecurity);
284
+ if (op.source === "non-empty") {
285
+ return { alternatives: toAlternatives(op.requirements, knownSchemes) };
286
+ }
287
+ if (op.source === "empty") {
288
+ return { alternatives: [] };
289
+ }
290
+ const global = normalizeSecurity(globalSecurity);
291
+ if (global.source === "non-empty") {
292
+ return { alternatives: toAlternatives(global.requirements, knownSchemes) };
293
+ }
294
+ return { alternatives: [] };
295
+ }
296
+ function toAlternatives(requirements, knownSchemes) {
297
+ const known = new Set(knownSchemes.map((s) => s.key));
298
+ return requirements.map((req) => {
299
+ const out = [];
300
+ for (const [key, scopes] of Object.entries(req)) {
301
+ out.push({
302
+ key,
303
+ scopes: Array.isArray(scopes) ? scopes : []
304
+ });
305
+ }
306
+ out.sort((a, b) => a.key.localeCompare(b.key));
307
+ out.sort((a, b) => {
308
+ const ak = known.has(a.key) ? 0 : 1;
309
+ const bk = known.has(b.key) ? 0 : 1;
310
+ if (ak !== bk)
311
+ return ak - bk;
312
+ return a.key.localeCompare(b.key);
313
+ });
314
+ return out;
315
+ });
316
+ }
317
+
318
+ // src/cli/command-id.ts
319
+ function buildCommandId(parts) {
320
+ const op = kebabCase(parts.operationKey.replace(/\s+/g, "-"));
321
+ return `${parts.specId}:${kebabCase(parts.resource)}:${kebabCase(parts.action)}:${op}`;
322
+ }
323
+ var init_command_id = () => {};
324
+
325
+ // src/cli/schema-shape.ts
326
+ function getSchemaType(schema) {
327
+ if (!schema || typeof schema !== "object")
328
+ return "unknown";
329
+ const t = schema.type;
330
+ if (t === "string")
331
+ return "string";
332
+ if (t === "number")
333
+ return "number";
334
+ if (t === "integer")
335
+ return "integer";
336
+ if (t === "boolean")
337
+ return "boolean";
338
+ if (t === "array")
339
+ return "array";
340
+ if (t === "object")
341
+ return "object";
342
+ return "unknown";
343
+ }
344
+ function getSchemaFormat(schema) {
345
+ if (!schema || typeof schema !== "object")
346
+ return;
347
+ const f = schema.format;
348
+ return typeof f === "string" ? f : undefined;
349
+ }
350
+ function getSchemaEnumStrings(schema) {
351
+ if (!schema || typeof schema !== "object")
352
+ return;
353
+ const e = schema.enum;
354
+ if (!Array.isArray(e))
355
+ return;
356
+ const values = e.filter((v) => typeof v === "string");
357
+ return values.length ? values : undefined;
358
+ }
359
+
360
+ // src/cli/params.ts
361
+ function deriveParamSpecs(op) {
362
+ const out = [];
363
+ for (const p of op.parameters) {
364
+ const flag = `--${kebabCase(p.name)}`;
365
+ const type = getSchemaType(p.schema);
366
+ const schemaObj = p.schema && typeof p.schema === "object" ? p.schema : undefined;
367
+ const itemsSchema = schemaObj && type === "array" && typeof schemaObj.items === "object" ? schemaObj.items : undefined;
368
+ out.push({
369
+ kind: p.in === "path" ? "positional" : "flag",
370
+ in: p.in,
371
+ name: p.name,
372
+ flag,
373
+ required: p.required,
374
+ description: p.description,
375
+ type,
376
+ format: getSchemaFormat(p.schema),
377
+ enum: getSchemaEnumStrings(p.schema),
378
+ itemType: type === "array" ? getSchemaType(itemsSchema) : undefined,
379
+ itemFormat: type === "array" ? getSchemaFormat(itemsSchema) : undefined,
380
+ itemEnum: type === "array" ? getSchemaEnumStrings(itemsSchema) : undefined,
381
+ schema: schemaObj
382
+ });
383
+ }
384
+ out.sort((a, b) => {
385
+ if (a.in !== b.in)
386
+ return a.in.localeCompare(b.in);
387
+ return a.name.localeCompare(b.name);
388
+ });
389
+ return out;
390
+ }
391
+ var init_params = () => {};
392
+
393
+ // src/cli/positional.ts
394
+ function derivePositionals(action) {
395
+ const byName = new Map;
396
+ for (const name of action.pathArgs) {
397
+ const p = action.params.find((x) => x.in === "path" && x.name === name);
398
+ byName.set(name, {
399
+ name,
400
+ required: true,
401
+ description: p?.description,
402
+ type: p?.type ?? "unknown",
403
+ format: p?.format,
404
+ enum: p?.enum
405
+ });
406
+ }
407
+ return [...byName.values()];
408
+ }
409
+ function deriveFlags(action) {
410
+ return {
411
+ flags: action.params.filter((p) => p.kind === "flag").map((p) => ({
412
+ in: p.in,
413
+ name: p.name,
414
+ flag: p.flag,
415
+ required: p.required,
416
+ description: p.description,
417
+ type: p.type,
418
+ format: p.format,
419
+ enum: p.enum,
420
+ itemType: p.itemType,
421
+ itemFormat: p.itemFormat,
422
+ itemEnum: p.itemEnum
423
+ }))
424
+ };
425
+ }
426
+
427
+ // src/cli/types.ts
428
+ function isJsonSchema(value) {
429
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
430
+ }
431
+
432
+ // src/cli/request-body.ts
433
+ function getRequestBody(op) {
434
+ return op.requestBody;
435
+ }
436
+ function deriveRequestBodyInfo(op) {
437
+ const rb = getRequestBody(op);
438
+ if (!rb)
439
+ return;
440
+ const content = [];
441
+ for (const contentType of rb.contentTypes) {
442
+ const schema = rb.schemasByContentType[contentType];
443
+ content.push({
444
+ contentType,
445
+ required: rb.required,
446
+ schemaType: getSchemaType(schema),
447
+ schemaFormat: getSchemaFormat(schema),
448
+ schemaEnum: getSchemaEnumStrings(schema)
449
+ });
450
+ }
451
+ content.sort((a, b) => a.contentType.localeCompare(b.contentType));
452
+ const hasJson = content.some((c) => c.contentType.includes("json"));
453
+ const hasFormUrlEncoded = content.some((c) => c.contentType === "application/x-www-form-urlencoded");
454
+ const hasMultipart = content.some((c) => c.contentType.startsWith("multipart/"));
455
+ const bodyFlags = ["--data", "--file"];
456
+ const preferredContentType = content.find((c) => c.contentType === "application/json")?.contentType ?? content.find((c) => c.contentType.includes("json"))?.contentType ?? content[0]?.contentType;
457
+ const preferredSchema = preferredContentType ? rb.schemasByContentType[preferredContentType] : undefined;
458
+ return {
459
+ required: rb.required,
460
+ content,
461
+ hasJson,
462
+ hasFormUrlEncoded,
463
+ hasMultipart,
464
+ bodyFlags,
465
+ preferredContentType,
466
+ preferredSchema: isJsonSchema(preferredSchema) ? preferredSchema : undefined
467
+ };
468
+ }
469
+ var init_request_body = () => {};
470
+
471
+ // src/cli/command-model.ts
472
+ function buildCommandModel(planned, options) {
473
+ const byResource = new Map;
474
+ for (const op of planned) {
475
+ const list = byResource.get(op.resource) ?? [];
476
+ const params = deriveParamSpecs(op);
477
+ const positionals = derivePositionals({ pathArgs: op.pathArgs, params });
478
+ const flags = deriveFlags({ pathArgs: op.pathArgs, params });
479
+ list.push({
480
+ id: buildCommandId({
481
+ specId: options.specId,
482
+ resource: op.resource,
483
+ action: op.action,
484
+ operationKey: op.key
485
+ }),
486
+ key: op.key,
487
+ action: op.action,
488
+ pathArgs: op.pathArgs,
489
+ method: op.method,
490
+ path: op.path,
491
+ operationId: op.operationId,
492
+ tags: op.tags,
493
+ summary: op.summary,
494
+ description: op.description,
495
+ deprecated: op.deprecated,
496
+ style: op.style,
497
+ params,
498
+ positionals,
499
+ flags: flags.flags,
500
+ auth: summarizeAuth(op.security, options.globalSecurity, options.authSchemes ?? []),
501
+ requestBody: deriveRequestBodyInfo(op),
502
+ requestBodySchema: deriveRequestBodyInfo(op)?.preferredSchema
503
+ });
504
+ byResource.set(op.resource, list);
505
+ }
506
+ const resources = [];
507
+ for (const [resource, actions] of byResource.entries()) {
508
+ actions.sort((a, b) => {
509
+ if (a.action !== b.action)
510
+ return a.action.localeCompare(b.action);
511
+ if (a.path !== b.path)
512
+ return a.path.localeCompare(b.path);
513
+ return a.method.localeCompare(b.method);
514
+ });
515
+ resources.push({ resource, actions });
516
+ }
517
+ resources.sort((a, b) => a.resource.localeCompare(b.resource));
518
+ return { resources };
519
+ }
520
+ var init_command_model = __esm(() => {
521
+ init_command_id();
522
+ init_params();
523
+ init_request_body();
524
+ });
525
+
526
+ // src/cli/pluralize.ts
527
+ function pluralize(word) {
528
+ const w = word.trim();
529
+ if (!w)
530
+ return w;
531
+ const lower = w.toLowerCase();
532
+ if (UNCOUNTABLE.has(lower))
533
+ return lower;
534
+ if (IRREGULAR[lower])
535
+ return IRREGULAR[lower];
536
+ if (lower.endsWith("s"))
537
+ return lower;
538
+ if (/[bcdfghjklmnpqrstvwxyz]y$/.test(lower)) {
539
+ return lower.replace(/y$/, "ies");
540
+ }
541
+ if (/(ch|sh|x|z)$/.test(lower)) {
542
+ return `${lower}es`;
543
+ }
544
+ return `${lower}s`;
545
+ }
546
+ var IRREGULAR, UNCOUNTABLE;
547
+ var init_pluralize = __esm(() => {
548
+ IRREGULAR = {
549
+ person: "people",
550
+ man: "men",
551
+ woman: "women",
552
+ child: "children",
553
+ tooth: "teeth",
554
+ foot: "feet",
555
+ mouse: "mice",
556
+ goose: "geese"
557
+ };
558
+ UNCOUNTABLE = new Set([
559
+ "metadata",
560
+ "information",
561
+ "equipment",
562
+ "money",
563
+ "series",
564
+ "species"
565
+ ]);
566
+ });
567
+
568
+ // src/cli/naming.ts
569
+ function getPathSegments(path) {
570
+ return path.split("/").map((s) => s.trim()).filter(Boolean);
571
+ }
572
+ function getPathArgs(path) {
573
+ const args = [];
574
+ const re = /\{([^}]+)\}/g;
575
+ while (true) {
576
+ const match = re.exec(path);
577
+ if (!match)
578
+ break;
579
+ args.push(match[1]);
580
+ }
581
+ return args;
582
+ }
583
+ function pickResourceFromTags(tags) {
584
+ if (!tags.length)
585
+ return;
586
+ const first = tags[0]?.trim();
587
+ if (!first)
588
+ return;
589
+ if (GENERIC_TAGS.has(first.toLowerCase()))
590
+ return;
591
+ return first;
592
+ }
593
+ function splitOperationId(operationId) {
594
+ const trimmed = operationId.trim();
595
+ if (!trimmed)
596
+ return {};
597
+ if (trimmed.includes(".")) {
598
+ const [prefix, ...rest] = trimmed.split(".");
599
+ return { prefix, suffix: rest.join(".") };
600
+ }
601
+ if (trimmed.includes("__")) {
602
+ const [prefix, ...rest] = trimmed.split("__");
603
+ return { prefix, suffix: rest.join("__") };
604
+ }
605
+ if (trimmed.includes("_")) {
606
+ const [prefix, ...rest] = trimmed.split("_");
607
+ return { prefix, suffix: rest.join("_") };
608
+ }
609
+ return { suffix: trimmed };
610
+ }
611
+ function inferStyle(op) {
612
+ if (op.path.includes("."))
613
+ return "rpc";
614
+ if (op.operationId?.includes(".") && op.method === "POST")
615
+ return "rpc";
616
+ return "rest";
617
+ }
618
+ function inferResource(op) {
619
+ const tag = pickResourceFromTags(op.tags);
620
+ if (tag)
621
+ return pluralize(kebabCase(tag));
622
+ if (op.operationId) {
623
+ const { prefix } = splitOperationId(op.operationId);
624
+ if (prefix) {
625
+ const fromId = kebabCase(prefix);
626
+ if (fromId === "ping")
627
+ return "ping";
628
+ return pluralize(fromId);
629
+ }
630
+ }
631
+ const segments = getPathSegments(op.path);
632
+ let first = segments[0] ?? "api";
633
+ first = first.includes(".") ? first.split(".")[0] : first;
634
+ if (first.toLowerCase() === "ping")
635
+ return "ping";
636
+ const cleaned = first.replace(/^\{.+\}$/, "");
637
+ return pluralize(kebabCase(cleaned || "api"));
638
+ }
639
+ function canonicalizeAction(action) {
640
+ const a = kebabCase(action);
641
+ if (a === "retrieve" || a === "read")
642
+ return "get";
643
+ if (a === "list" || a === "search")
644
+ return "list";
645
+ if (a === "create")
646
+ return "create";
647
+ if (a === "update" || a === "patch")
648
+ return "update";
649
+ if (a === "delete" || a === "remove")
650
+ return "delete";
651
+ return a;
652
+ }
653
+ function inferRestAction(op) {
654
+ if (op.operationId) {
655
+ const { suffix } = splitOperationId(op.operationId);
656
+ if (suffix) {
657
+ const fromId = canonicalizeAction(suffix);
658
+ if (fromId === "get" || fromId === "list" || fromId === "create" || fromId === "update" || fromId === "delete") {
659
+ return fromId;
660
+ }
661
+ }
662
+ }
663
+ const method = op.method.toUpperCase();
664
+ const args = getPathArgs(op.path);
665
+ const hasId = args.length > 0;
666
+ if (method === "GET" && !hasId)
667
+ return "list";
668
+ if (method === "POST" && !hasId)
669
+ return "create";
670
+ if (method === "GET" && hasId)
671
+ return "get";
672
+ if ((method === "PUT" || method === "PATCH") && hasId)
673
+ return "update";
674
+ if (method === "DELETE" && hasId)
675
+ return "delete";
676
+ return kebabCase(method);
677
+ }
678
+ function inferRpcAction(op) {
679
+ if (op.operationId) {
680
+ const { suffix } = splitOperationId(op.operationId);
681
+ if (suffix)
682
+ return canonicalizeAction(suffix);
683
+ }
684
+ const segments = getPathSegments(op.path);
685
+ const last = segments[segments.length - 1] ?? "";
686
+ if (last.includes(".")) {
687
+ const part = last.split(".").pop() ?? last;
688
+ return canonicalizeAction(part);
689
+ }
690
+ return kebabCase(op.method);
691
+ }
692
+ function planOperation(op) {
693
+ const style = inferStyle(op);
694
+ const resource = inferResource(op);
695
+ const action = style === "rpc" ? inferRpcAction(op) : inferRestAction(op);
696
+ return {
697
+ ...op,
698
+ key: op.key,
699
+ style,
700
+ resource,
701
+ action,
702
+ canonicalAction: action,
703
+ pathArgs: getPathArgs(op.path).map((a) => kebabCase(a))
704
+ };
705
+ }
706
+ function planOperations(ops) {
707
+ const planned = ops.map(planOperation);
708
+ const counts = new Map;
709
+ for (const op of planned) {
710
+ const key = `${op.resource}:${op.action}`;
711
+ counts.set(key, (counts.get(key) ?? 0) + 1);
712
+ }
713
+ const seen = new Map;
714
+ return planned.map((op) => {
715
+ const key = `${op.resource}:${op.action}`;
716
+ const total = counts.get(key) ?? 0;
717
+ if (total <= 1)
718
+ return op;
719
+ const idx = (seen.get(key) ?? 0) + 1;
720
+ seen.set(key, idx);
721
+ const suffix = op.operationId ? kebabCase(op.operationId) : kebabCase(`${op.method}-${op.path}`);
722
+ const disambiguatedAction = `${op.action}-${suffix}-${idx}`;
723
+ return {
724
+ ...op,
725
+ action: disambiguatedAction,
726
+ aliasOf: `${op.resource} ${op.canonicalAction}`
727
+ };
728
+ });
729
+ }
730
+ var GENERIC_TAGS;
731
+ var init_naming = __esm(() => {
732
+ init_pluralize();
733
+ GENERIC_TAGS = new Set(["default", "defaults", "api"]);
734
+ });
735
+
736
+ // src/cli/operations.ts
737
+ function operationKey(method, path) {
738
+ return `${method.toUpperCase()} ${path}`;
739
+ }
740
+ function normalizeParam(p) {
741
+ if (!p || typeof p !== "object")
742
+ return;
743
+ const loc = p.in;
744
+ const name = p.name;
745
+ if (loc !== "path" && loc !== "query" && loc !== "header" && loc !== "cookie") {
746
+ return;
747
+ }
748
+ if (!name)
749
+ return;
750
+ return {
751
+ in: loc,
752
+ name,
753
+ required: Boolean(p.required || loc === "path"),
754
+ description: p.description,
755
+ schema: p.schema
756
+ };
757
+ }
758
+ function mergeParameters(pathParams, opParams) {
759
+ const merged = new Map;
760
+ for (const p of pathParams ?? []) {
761
+ const normalized = normalizeParam(p);
762
+ if (!normalized)
763
+ continue;
764
+ merged.set(`${normalized.in}:${normalized.name}`, normalized);
765
+ }
766
+ for (const p of opParams ?? []) {
767
+ const normalized = normalizeParam(p);
768
+ if (!normalized)
769
+ continue;
770
+ merged.set(`${normalized.in}:${normalized.name}`, normalized);
771
+ }
772
+ return [...merged.values()];
773
+ }
774
+ function normalizeRequestBody(rb) {
775
+ if (!rb)
776
+ return;
777
+ const content = rb.content ?? {};
778
+ const contentTypes = Object.keys(content);
779
+ const schemasByContentType = {};
780
+ for (const contentType of contentTypes) {
781
+ schemasByContentType[contentType] = content[contentType]?.schema;
782
+ }
783
+ return {
784
+ required: Boolean(rb.required),
785
+ contentTypes,
786
+ schemasByContentType
787
+ };
788
+ }
789
+ function indexOperations(doc) {
790
+ const out = [];
791
+ const paths = doc.paths ?? {};
792
+ for (const [path, rawPathItem] of Object.entries(paths)) {
793
+ if (!rawPathItem || typeof rawPathItem !== "object")
794
+ continue;
795
+ const pathItem = rawPathItem;
796
+ for (const method of HTTP_METHODS) {
797
+ const op = pathItem[method];
798
+ if (!op)
799
+ continue;
800
+ const parameters = mergeParameters(pathItem.parameters, op.parameters);
801
+ const normalizedMethod = method.toUpperCase();
802
+ out.push({
803
+ key: operationKey(normalizedMethod, path),
804
+ method: normalizedMethod,
805
+ path,
806
+ operationId: op.operationId,
807
+ tags: op.tags ?? [],
808
+ summary: op.summary,
809
+ description: op.description,
810
+ deprecated: op.deprecated,
811
+ security: op.security ?? doc.security,
812
+ parameters,
813
+ requestBody: normalizeRequestBody(op.requestBody)
814
+ });
815
+ }
816
+ }
817
+ out.sort((a, b) => {
818
+ if (a.path !== b.path)
819
+ return a.path.localeCompare(b.path);
820
+ return a.method.localeCompare(b.method);
821
+ });
822
+ return out;
823
+ }
824
+ var HTTP_METHODS;
825
+ var init_operations = __esm(() => {
826
+ HTTP_METHODS = [
827
+ "get",
828
+ "post",
829
+ "put",
830
+ "patch",
831
+ "delete",
832
+ "options",
833
+ "head",
834
+ "trace"
835
+ ];
836
+ });
837
+
838
+ // src/cli/schema.ts
839
+ function buildSchemaOutput(loaded, operations, planned, servers, authSchemes, commands, commandsIndex, capabilities) {
840
+ return {
841
+ schemaVersion: 1,
842
+ openapi: {
843
+ version: loaded.doc.openapi,
844
+ title: loaded.doc.info?.title,
845
+ infoVersion: loaded.doc.info?.version
846
+ },
847
+ spec: {
848
+ id: loaded.id,
849
+ fingerprint: loaded.fingerprint,
850
+ source: loaded.source
851
+ },
852
+ capabilities,
853
+ servers,
854
+ authSchemes,
855
+ operations,
856
+ planned,
857
+ commands,
858
+ commandsIndex
859
+ };
860
+ }
861
+ function toMinimalSchemaOutput(output) {
862
+ return {
863
+ schemaVersion: output.schemaVersion,
864
+ openapi: output.openapi,
865
+ spec: output.spec,
866
+ capabilities: output.capabilities,
867
+ commands: output.commands
868
+ };
869
+ }
870
+
871
+ // src/cli/server.ts
872
+ function extractVariableNames(url) {
873
+ const names = [];
874
+ const re = /\{([^}]+)\}/g;
875
+ while (true) {
876
+ const match = re.exec(url);
877
+ if (!match)
878
+ break;
879
+ names.push(match[1] ?? "");
880
+ }
881
+ return names.map((n) => n.trim()).filter(Boolean);
882
+ }
883
+ function listServers(doc) {
884
+ const servers = doc.servers ?? [];
885
+ const out = [];
886
+ for (const raw of servers) {
887
+ const s = raw;
888
+ if (!s || typeof s !== "object")
889
+ continue;
890
+ if (typeof s.url !== "string")
891
+ continue;
892
+ const variableNames = extractVariableNames(s.url);
893
+ const variables = [];
894
+ const rawVars = s.variables && typeof s.variables === "object" && !Array.isArray(s.variables) ? s.variables : {};
895
+ for (const name of variableNames) {
896
+ const v = rawVars[name];
897
+ const def = v?.default;
898
+ const desc = v?.description;
899
+ variables.push({
900
+ name,
901
+ default: typeof def === "string" ? def : undefined,
902
+ enum: getSchemaEnumStrings(v),
903
+ description: typeof desc === "string" ? desc : undefined
904
+ });
905
+ }
906
+ out.push({
907
+ url: s.url,
908
+ description: typeof s.description === "string" ? s.description : undefined,
909
+ variables,
910
+ variableNames
911
+ });
912
+ }
913
+ return out;
914
+ }
915
+ var init_server = () => {};
916
+
917
+ // src/cli/crypto.ts
918
+ async function sha256Hex(text) {
919
+ const data = new TextEncoder().encode(text);
920
+ const hash = await crypto.subtle.digest("SHA-256", data);
921
+ const bytes = new Uint8Array(hash);
922
+ let out = "";
923
+ for (const b of bytes)
924
+ out += b.toString(16).padStart(2, "0");
925
+ return out;
926
+ }
927
+
928
+ // src/cli/spec-id.ts
929
+ function getSpecId(loaded) {
930
+ const title = loaded.doc.info?.title;
931
+ const fromTitle = title ? kebabCase(title) : "";
932
+ if (fromTitle)
933
+ return fromTitle;
934
+ return loaded.fingerprint.slice(0, 12);
935
+ }
936
+ var init_spec_id = () => {};
937
+
938
+ // src/cli/stable-json.ts
939
+ function stableStringify(value, options) {
940
+ const visiting = new WeakSet;
941
+ return JSON.stringify(sort(value, visiting), null, options?.space);
942
+ }
943
+ function sort(value, visiting) {
944
+ if (value === null)
945
+ return null;
946
+ if (Array.isArray(value)) {
947
+ if (visiting.has(value))
948
+ return { __specli_circular: true };
949
+ visiting.add(value);
950
+ const out = value.map((v) => sort(v, visiting));
951
+ visiting.delete(value);
952
+ return out;
953
+ }
954
+ if (typeof value === "object") {
955
+ if (visiting.has(value))
956
+ return { __specli_circular: true };
957
+ visiting.add(value);
958
+ const obj = value;
959
+ const out = {};
960
+ for (const key of Object.keys(obj).sort()) {
961
+ out[key] = sort(obj[key], visiting);
962
+ }
963
+ visiting.delete(value);
964
+ return out;
965
+ }
966
+ return value;
967
+ }
968
+
969
+ // src/cli/spec-loader.ts
970
+ import SwaggerParser from "@apidevtools/swagger-parser";
971
+ function isProbablyUrl(input) {
972
+ return /^https?:\/\//i.test(input);
973
+ }
974
+ function parseSpecText(text) {
975
+ const trimmed = text.trimStart();
976
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
977
+ return JSON.parse(text);
978
+ }
979
+ return parseYamlContent(text);
980
+ }
981
+ async function loadSpec(options) {
982
+ const { spec, embeddedSpecText } = options;
983
+ let source;
984
+ let inputForParser;
985
+ if (typeof embeddedSpecText === "string") {
986
+ source = "embedded";
987
+ inputForParser = parseSpecText(embeddedSpecText);
988
+ } else if (spec) {
989
+ source = isProbablyUrl(spec) ? "url" : "file";
990
+ inputForParser = spec;
991
+ } else {
992
+ throw new Error("Missing spec. Provide --spec <url|path> or build with an embedded spec.");
993
+ }
994
+ const doc = await SwaggerParser.dereference(inputForParser);
995
+ if (!doc || typeof doc !== "object" || typeof doc.openapi !== "string") {
996
+ throw new Error("Loaded spec is not a valid OpenAPI document");
997
+ }
998
+ const fingerprint = await sha256Hex(stableStringify(doc));
999
+ const id = getSpecId({ doc, fingerprint });
1000
+ return { source, id, fingerprint, doc };
1001
+ }
1002
+ var init_spec_loader = __esm(() => {
1003
+ init_compat();
1004
+ init_spec_id();
1005
+ });
1006
+
1007
+ // src/cli/runtime/context.ts
1008
+ async function buildRuntimeContext(options) {
1009
+ const loaded = await loadSpec({
1010
+ spec: options.spec,
1011
+ embeddedSpecText: options.embeddedSpecText
1012
+ });
1013
+ const operations = indexOperations(loaded.doc);
1014
+ const servers = listServers(loaded.doc);
1015
+ const authSchemes = listAuthSchemes(loaded.doc);
1016
+ const planned = planOperations(operations);
1017
+ const commands = buildCommandModel(planned, {
1018
+ specId: loaded.id,
1019
+ globalSecurity: loaded.doc.security,
1020
+ authSchemes
1021
+ });
1022
+ const commandsIndex = buildCommandsIndex(commands);
1023
+ const capabilities = deriveCapabilities({
1024
+ doc: loaded.doc,
1025
+ servers,
1026
+ authSchemes,
1027
+ operations,
1028
+ commands
1029
+ });
1030
+ const schema = buildSchemaOutput(loaded, operations, planned, servers, authSchemes, commands, commandsIndex, capabilities);
1031
+ return {
1032
+ loaded,
1033
+ operations,
1034
+ servers,
1035
+ authSchemes,
1036
+ planned,
1037
+ commands,
1038
+ commandsIndex,
1039
+ capabilities,
1040
+ schema
1041
+ };
1042
+ }
1043
+ var init_context = __esm(() => {
1044
+ init_auth_schemes();
1045
+ init_command_model();
1046
+ init_naming();
1047
+ init_operations();
1048
+ init_server();
1049
+ init_spec_loader();
1050
+ });
1051
+
1052
+ // src/cli/runtime/body-flags.ts
1053
+ var exports_body_flags = {};
1054
+ __export(exports_body_flags, {
1055
+ parseDotNotationFlags: () => parseDotNotationFlags,
1056
+ generateBodyFlags: () => generateBodyFlags,
1057
+ findMissingRequired: () => findMissingRequired
1058
+ });
1059
+ function generateBodyFlags(schema, reservedFlags) {
1060
+ if (!schema || schema.type !== "object" || !schema.properties) {
1061
+ return [];
1062
+ }
1063
+ const flags = [];
1064
+ const requiredSet = new Set(schema.required ?? []);
1065
+ collectFlags(schema.properties, [], requiredSet, flags, reservedFlags);
1066
+ return flags;
1067
+ }
1068
+ function collectFlags(properties, pathPrefix, requiredAtRoot, out, reservedFlags) {
1069
+ for (const [name, propSchema] of Object.entries(properties)) {
1070
+ if (!name || typeof name !== "string")
1071
+ continue;
1072
+ if (!propSchema || typeof propSchema !== "object")
1073
+ continue;
1074
+ const path = [...pathPrefix, name];
1075
+ const flagName = `--${path.join(".")}`;
1076
+ if (reservedFlags.has(flagName))
1077
+ continue;
1078
+ const t = propSchema.type;
1079
+ if (t === "object" && propSchema.properties) {
1080
+ const nestedRequired = new Set(propSchema.required ?? []);
1081
+ collectFlags(propSchema.properties, path, nestedRequired, out, reservedFlags);
1082
+ } else if (t === "string" || t === "number" || t === "integer" || t === "boolean") {
1083
+ const isRequired = pathPrefix.length === 0 ? requiredAtRoot.has(name) : false;
1084
+ out.push({
1085
+ flag: flagName,
1086
+ path,
1087
+ type: t,
1088
+ description: propSchema.description ?? `Body field '${path.join(".")}'`,
1089
+ required: isRequired
1090
+ });
1091
+ }
1092
+ }
1093
+ }
1094
+ function parseDotNotationFlags(flagValues, flagDefs) {
1095
+ const result = {};
1096
+ for (const def of flagDefs) {
1097
+ const dotKey = def.path.join(".");
1098
+ const value = flagValues[dotKey];
1099
+ if (value === undefined)
1100
+ continue;
1101
+ setNestedValue(result, def.path, value, def.type);
1102
+ }
1103
+ return result;
1104
+ }
1105
+ function setNestedValue(obj, path, value, type) {
1106
+ let current = obj;
1107
+ for (let i = 0;i < path.length - 1; i++) {
1108
+ const key = path[i];
1109
+ if (!(key in current) || typeof current[key] !== "object") {
1110
+ current[key] = {};
1111
+ }
1112
+ current = current[key];
1113
+ }
1114
+ const finalKey = path[path.length - 1];
1115
+ if (type === "boolean") {
1116
+ current[finalKey] = true;
1117
+ } else if (type === "integer") {
1118
+ current[finalKey] = Number.parseInt(String(value), 10);
1119
+ } else if (type === "number") {
1120
+ current[finalKey] = Number(String(value));
1121
+ } else {
1122
+ current[finalKey] = String(value);
1123
+ }
1124
+ }
1125
+ function findMissingRequired(flagValues, flagDefs) {
1126
+ const missing = [];
1127
+ for (const def of flagDefs) {
1128
+ if (!def.required)
1129
+ continue;
1130
+ const dotKey = def.path.join(".");
1131
+ if (flagValues[dotKey] === undefined) {
1132
+ missing.push(dotKey);
1133
+ }
1134
+ }
1135
+ return missing;
1136
+ }
1137
+
1138
+ // src/cli/runtime/auth/resolve.ts
1139
+ function resolveAuthScheme(authSchemes, required, inputs) {
1140
+ if (inputs.flagAuthScheme)
1141
+ return inputs.flagAuthScheme;
1142
+ if (inputs.profileAuthScheme && authSchemes.some((s) => s.key === inputs.profileAuthScheme)) {
1143
+ return inputs.profileAuthScheme;
1144
+ }
1145
+ if (inputs.embeddedAuthScheme && authSchemes.some((s) => s.key === inputs.embeddedAuthScheme)) {
1146
+ return inputs.embeddedAuthScheme;
1147
+ }
1148
+ const alts = required.alternatives;
1149
+ if (alts.length === 1 && alts[0]?.length === 1)
1150
+ return alts[0][0]?.key;
1151
+ if (authSchemes.length === 1)
1152
+ return authSchemes[0]?.key;
1153
+ if (inputs.hasStoredToken && alts.length > 0) {
1154
+ for (const alt of alts) {
1155
+ if (alt.length !== 1)
1156
+ continue;
1157
+ const key = alt[0]?.key;
1158
+ const scheme = authSchemes.find((s) => s.key === key);
1159
+ if (scheme && BEARER_COMPATIBLE_KINDS.has(scheme.kind)) {
1160
+ return key;
1161
+ }
1162
+ }
1163
+ }
1164
+ return;
1165
+ }
1166
+ var BEARER_COMPATIBLE_KINDS;
1167
+ var init_resolve = __esm(() => {
1168
+ BEARER_COMPATIBLE_KINDS = new Set([
1169
+ "http-bearer",
1170
+ "oauth2",
1171
+ "openIdConnect"
1172
+ ]);
1173
+ });
1174
+
1175
+ // src/cli/runtime/profile/secrets.ts
1176
+ function secretServiceForSpec(specId) {
1177
+ return `specli:${specId}`;
1178
+ }
1179
+ function tokenSecretKey(specId, profile) {
1180
+ return {
1181
+ service: secretServiceForSpec(specId),
1182
+ name: `profile:${profile}:token`
1183
+ };
1184
+ }
1185
+ async function setToken(specId, profile, token) {
1186
+ if (!isBun) {
1187
+ console.warn("Warning: Secure token storage requires Bun. Token will not be persisted.");
1188
+ console.warn("Use --bearer-token <token> flag instead when running with Node.js.");
1189
+ return;
1190
+ }
1191
+ const { secrets } = await import(bunLiteral);
1192
+ const key = tokenSecretKey(specId, profile);
1193
+ await secrets.set({ service: key.service, name: key.name, value: token });
1194
+ }
1195
+ async function getToken(specId, profile) {
1196
+ if (!isBun) {
1197
+ return null;
1198
+ }
1199
+ const { secrets } = await import(bunLiteral);
1200
+ const key = tokenSecretKey(specId, profile);
1201
+ return await secrets.get({ service: key.service, name: key.name });
1202
+ }
1203
+ async function deleteToken(specId, profile) {
1204
+ if (!isBun) {
1205
+ console.warn("Warning: Secure token storage requires Bun. No token to delete.");
1206
+ return false;
1207
+ }
1208
+ const { secrets } = await import(bunLiteral);
1209
+ const key = tokenSecretKey(specId, profile);
1210
+ return await secrets.delete({ service: key.service, name: key.name });
1211
+ }
1212
+ var bunLiteral = "bun";
1213
+ var init_secrets = __esm(() => {
1214
+ init_compat();
1215
+ });
1216
+
1217
+ // src/cli/runtime/profile/store.ts
1218
+ function configDir() {
1219
+ const home = process.env.HOME;
1220
+ if (!home)
1221
+ throw new Error("Missing HOME env var");
1222
+ return `${home}/.config/specli`;
1223
+ }
1224
+ function configPathJson() {
1225
+ return `${configDir()}/profiles.json`;
1226
+ }
1227
+ function configPathYaml() {
1228
+ return `${configDir()}/profiles.yaml`;
1229
+ }
1230
+ async function readProfiles() {
1231
+ const jsonPath = configPathJson();
1232
+ const yamlPath = configPathYaml();
1233
+ const jsonExists = await fileExists(jsonPath);
1234
+ const yamlExists = await fileExists(yamlPath);
1235
+ const filePath = jsonExists ? jsonPath : yamlExists ? yamlPath : null;
1236
+ if (!filePath)
1237
+ return { profiles: [] };
1238
+ const text = await readFileText(filePath);
1239
+ let parsed;
1240
+ try {
1241
+ parsed = parseYamlContent(text);
1242
+ } catch {
1243
+ parsed = JSON.parse(text);
1244
+ }
1245
+ const obj = parsed && typeof parsed === "object" ? parsed : {};
1246
+ const profiles = Array.isArray(obj.profiles) ? obj.profiles : [];
1247
+ return {
1248
+ profiles: profiles.filter(Boolean),
1249
+ defaultProfile: typeof obj.defaultProfile === "string" ? obj.defaultProfile : undefined
1250
+ };
1251
+ }
1252
+ async function writeProfiles(data) {
1253
+ const dir = configDir();
1254
+ await mkdirp(dir);
1255
+ await writeFileText(configPathJson(), JSON.stringify(data, null, 2));
1256
+ }
1257
+ function getProfile(data, name) {
1258
+ const wanted = name ?? data.defaultProfile;
1259
+ if (!wanted)
1260
+ return;
1261
+ return data.profiles.find((p) => p?.name === wanted);
1262
+ }
1263
+ function upsertProfile(data, profile) {
1264
+ const profiles = data.profiles.filter((p) => p.name !== profile.name);
1265
+ profiles.push(profile);
1266
+ profiles.sort((a, b) => a.name.localeCompare(b.name));
1267
+ return { ...data, profiles };
1268
+ }
1269
+ var init_store = __esm(() => {
1270
+ init_compat();
1271
+ });
1272
+
1273
+ // src/cli/runtime/template.ts
1274
+ function extractTemplateVars(template) {
1275
+ const out = [];
1276
+ const re = /\{([^}]+)\}/g;
1277
+ while (true) {
1278
+ const match = re.exec(template);
1279
+ if (!match)
1280
+ break;
1281
+ out.push((match[1] ?? "").trim());
1282
+ }
1283
+ return out.filter(Boolean);
1284
+ }
1285
+ function applyTemplate(template, vars, options) {
1286
+ const encode = options?.encode ?? false;
1287
+ return template.replace(/\{([^}]+)\}/g, (_, rawName) => {
1288
+ const name = String(rawName).trim();
1289
+ const value = vars[name];
1290
+ if (typeof value !== "string") {
1291
+ throw new Error(`Missing template variable: ${name}`);
1292
+ }
1293
+ return encode ? encodeURIComponent(value) : value;
1294
+ });
1295
+ }
1296
+
1297
+ // src/cli/runtime/server-url.ts
1298
+ function resolveServerUrl(input) {
1299
+ const base = input.serverOverride || input.servers[0]?.url;
1300
+ if (!base) {
1301
+ throw new Error("No server URL found. Provide --server <url> or define servers in the OpenAPI spec.");
1302
+ }
1303
+ const names = extractTemplateVars(base);
1304
+ if (!names.length)
1305
+ return base;
1306
+ const vars = {};
1307
+ for (const name of names) {
1308
+ const provided = input.serverVars[name];
1309
+ if (typeof provided === "string") {
1310
+ vars[name] = provided;
1311
+ continue;
1312
+ }
1313
+ const match = input.servers.find((s) => s.url === base);
1314
+ const v = match?.variables.find((x) => x.name === name);
1315
+ if (typeof v?.default === "string") {
1316
+ vars[name] = v.default;
1317
+ continue;
1318
+ }
1319
+ throw new Error(`Missing server variable '${name}'. Provide --server-var ${name}=...`);
1320
+ }
1321
+ return applyTemplate(base, vars);
1322
+ }
1323
+ var init_server_url = () => {};
1324
+
1325
+ // src/cli/runtime/validate/ajv.ts
1326
+ import Ajv from "ajv";
1327
+ import addFormats from "ajv-formats";
1328
+ function createAjv() {
1329
+ const ajv = new Ajv({
1330
+ allErrors: true,
1331
+ strict: false,
1332
+ coerceTypes: false
1333
+ });
1334
+ addFormats(ajv);
1335
+ return ajv;
1336
+ }
1337
+ var init_ajv = () => {};
1338
+
1339
+ // src/cli/runtime/validate/coerce.ts
1340
+ import { InvalidArgumentError } from "commander";
1341
+ function coerceValue(raw, type) {
1342
+ if (type === "string" || type === "unknown")
1343
+ return raw;
1344
+ if (type === "boolean") {
1345
+ if (raw === "true")
1346
+ return true;
1347
+ if (raw === "false")
1348
+ return false;
1349
+ throw new InvalidArgumentError(`Expected boolean, got '${raw}'`);
1350
+ }
1351
+ if (type === "integer") {
1352
+ const n = Number.parseInt(raw, 10);
1353
+ if (!Number.isFinite(n))
1354
+ throw new InvalidArgumentError(`Expected integer, got '${raw}'`);
1355
+ return n;
1356
+ }
1357
+ if (type === "number") {
1358
+ const n = Number(raw);
1359
+ if (!Number.isFinite(n))
1360
+ throw new InvalidArgumentError(`Expected number, got '${raw}'`);
1361
+ return n;
1362
+ }
1363
+ if (type === "object") {
1364
+ try {
1365
+ return JSON.parse(raw);
1366
+ } catch {
1367
+ throw new InvalidArgumentError(`Expected JSON object, got '${raw}'. Use --data/--file for complex bodies.`);
1368
+ }
1369
+ }
1370
+ if (type === "array") {
1371
+ return coerceArrayInput(raw, "string");
1372
+ }
1373
+ return raw;
1374
+ }
1375
+ function coerceArrayInput(raw, itemType) {
1376
+ const trimmed = raw.trim();
1377
+ if (!trimmed)
1378
+ return [];
1379
+ if (trimmed.startsWith("[")) {
1380
+ let parsed;
1381
+ try {
1382
+ parsed = JSON.parse(trimmed);
1383
+ } catch {
1384
+ throw new InvalidArgumentError(`Expected JSON array, got '${raw}'`);
1385
+ }
1386
+ if (!Array.isArray(parsed)) {
1387
+ throw new InvalidArgumentError(`Expected JSON array, got '${raw}'`);
1388
+ }
1389
+ return parsed.map((v) => coerceValue(String(v), itemType));
1390
+ }
1391
+ return trimmed.split(",").map((s) => s.trim()).filter(Boolean).map((s) => coerceValue(s, itemType));
1392
+ }
1393
+ var init_coerce = () => {};
1394
+
1395
+ // src/cli/runtime/validate/error.ts
1396
+ function formatAjvErrors(errors) {
1397
+ if (!errors?.length)
1398
+ return "Invalid input";
1399
+ return errors.map((e) => {
1400
+ const path = e.instancePath || e.schemaPath || "";
1401
+ if (e.keyword === "required" && e.params && typeof e.params === "object" && "missingProperty" in e.params) {
1402
+ const missing = String(e.params.missingProperty);
1403
+ const where = e.instancePath || "/";
1404
+ return `${where} missing required property '${missing}'`.trim();
1405
+ }
1406
+ const msg = e.message || "invalid";
1407
+ return `${path} ${msg}`.trim();
1408
+ }).join(`
1409
+ `);
1410
+ }
1411
+
1412
+ // src/cli/runtime/validate/schema.ts
1413
+ function deriveValidationSchemas(action) {
1414
+ const query = { type: "object", properties: {}, required: [] };
1415
+ const header = { type: "object", properties: {}, required: [] };
1416
+ const cookie = { type: "object", properties: {}, required: [] };
1417
+ for (const p of action.params) {
1418
+ if (p.kind !== "flag")
1419
+ continue;
1420
+ const target = p.in === "query" ? query : p.in === "header" ? header : p.in === "cookie" ? cookie : undefined;
1421
+ if (!target)
1422
+ continue;
1423
+ const schema = p.schema ?? (p.type === "unknown" ? {} : { type: p.type });
1424
+ target.properties[p.name] = schema;
1425
+ if (p.required) {
1426
+ if (!target.required)
1427
+ target.required = [];
1428
+ target.required.push(p.name);
1429
+ }
1430
+ }
1431
+ if (!query.required?.length)
1432
+ delete query.required;
1433
+ if (!header.required?.length)
1434
+ delete header.required;
1435
+ if (!cookie.required?.length)
1436
+ delete cookie.required;
1437
+ return {
1438
+ querySchema: Object.keys(query.properties).length ? query : undefined,
1439
+ headerSchema: Object.keys(header.properties).length ? header : undefined,
1440
+ cookieSchema: Object.keys(cookie.properties).length ? cookie : undefined
1441
+ };
1442
+ }
1443
+
1444
+ // src/cli/runtime/validate/index.ts
1445
+ var init_validate = __esm(() => {
1446
+ init_ajv();
1447
+ init_coerce();
1448
+ });
1449
+
1450
+ // src/cli/runtime/request.ts
1451
+ function parseKeyValuePairs(pairs) {
1452
+ const out = {};
1453
+ for (const pair of pairs ?? []) {
1454
+ const idx = pair.indexOf("=");
1455
+ if (idx === -1)
1456
+ throw new Error(`Invalid pair '${pair}', expected name=value`);
1457
+ const name = pair.slice(0, idx).trim();
1458
+ const value = pair.slice(idx + 1).trim();
1459
+ if (!name)
1460
+ throw new Error(`Invalid pair '${pair}', missing name`);
1461
+ out[name] = value;
1462
+ }
1463
+ return out;
1464
+ }
1465
+ function pickAuthSchemeKey(action, globals) {
1466
+ if (globals.auth)
1467
+ return globals.auth;
1468
+ const req = action.auth.alternatives;
1469
+ if (req.length === 1 && req[0]?.length === 1) {
1470
+ return req[0][0]?.key;
1471
+ }
1472
+ return;
1473
+ }
1474
+ function applyAuth(headers, url, action, globals, authSchemes) {
1475
+ const schemeKey = pickAuthSchemeKey(action, globals);
1476
+ if (!schemeKey)
1477
+ return { headers, url };
1478
+ const scheme = authSchemes.find((s) => s.key === schemeKey);
1479
+ if (!scheme) {
1480
+ throw new Error(`Unknown auth scheme '${schemeKey}'. Available: ${authSchemes.map((s) => s.key).join(", ")}`);
1481
+ }
1482
+ if (scheme.kind === "http-bearer" || scheme.kind === "oauth2" || scheme.kind === "openIdConnect") {
1483
+ const token = globals.bearerToken ?? globals.oauthToken;
1484
+ if (!token)
1485
+ throw new Error("Missing token. Provide --bearer-token <token>.");
1486
+ headers.set("Authorization", `Bearer ${token}`);
1487
+ return { headers, url };
1488
+ }
1489
+ if (scheme.kind === "http-basic") {
1490
+ if (!globals.username)
1491
+ throw new Error("Missing --username for basic auth");
1492
+ if (!globals.password)
1493
+ throw new Error("Missing --password for basic auth");
1494
+ const raw = `${globals.username}:${globals.password}`;
1495
+ const encoded = Buffer.from(raw, "utf8").toString("base64");
1496
+ headers.set("Authorization", `Basic ${encoded}`);
1497
+ return { headers, url };
1498
+ }
1499
+ if (scheme.kind === "api-key") {
1500
+ if (!scheme.name)
1501
+ throw new Error(`apiKey scheme '${scheme.key}' missing name`);
1502
+ if (!scheme.in)
1503
+ throw new Error(`apiKey scheme '${scheme.key}' missing location`);
1504
+ if (!globals.apiKey)
1505
+ throw new Error("Missing --api-key for apiKey auth");
1506
+ if (scheme.in === "header") {
1507
+ headers.set(scheme.name, globals.apiKey);
1508
+ }
1509
+ if (scheme.in === "query") {
1510
+ url.searchParams.set(scheme.name, globals.apiKey);
1511
+ }
1512
+ if (scheme.in === "cookie") {
1513
+ const existing = headers.get("Cookie");
1514
+ const part = `${scheme.name}=${globals.apiKey}`;
1515
+ headers.set("Cookie", existing ? `${existing}; ${part}` : part);
1516
+ }
1517
+ return { headers, url };
1518
+ }
1519
+ return { headers, url };
1520
+ }
1521
+ async function buildRequest(input) {
1522
+ const defaultProfileName = "default";
1523
+ const profilesFile = await readProfiles();
1524
+ const profile = getProfile(profilesFile, defaultProfileName);
1525
+ const embedded = input.embeddedDefaults;
1526
+ const embeddedServerVars = parseKeyValuePairs(embedded?.serverVars);
1527
+ const cliServerVars = parseKeyValuePairs(input.globals.serverVar);
1528
+ const serverVars = { ...embeddedServerVars, ...cliServerVars };
1529
+ const serverUrl = resolveServerUrl({
1530
+ serverOverride: input.globals.server ?? profile?.server ?? embedded?.server,
1531
+ servers: input.servers,
1532
+ serverVars
1533
+ });
1534
+ const pathVars = {};
1535
+ for (let i = 0;i < input.action.positionals.length; i++) {
1536
+ const pos = input.action.positionals[i];
1537
+ const raw = input.action.pathArgs[i];
1538
+ const value = input.positionalValues[i];
1539
+ if (typeof raw === "string" && typeof value === "string") {
1540
+ pathVars[raw] = value;
1541
+ }
1542
+ if (pos?.name && typeof value === "string") {
1543
+ pathVars[pos.name] = value;
1544
+ }
1545
+ }
1546
+ const path = applyTemplate(input.action.path, pathVars, { encode: true });
1547
+ const baseUrl = serverUrl.endsWith("/") ? serverUrl : `${serverUrl}/`;
1548
+ const relativePath = path.startsWith("/") ? path.slice(1) : path;
1549
+ const url = new URL(relativePath, baseUrl);
1550
+ const headers = new Headers;
1551
+ const queryValues = {};
1552
+ const headerValues = {};
1553
+ const cookieValues = {};
1554
+ for (const p of input.action.params) {
1555
+ if (p.kind !== "flag")
1556
+ continue;
1557
+ const optValue = input.flagValues[optionKeyFromFlag(p.flag)];
1558
+ if (typeof optValue === "undefined")
1559
+ continue;
1560
+ if (p.in === "query") {
1561
+ queryValues[p.name] = optValue;
1562
+ }
1563
+ if (p.in === "header") {
1564
+ headerValues[p.name] = optValue;
1565
+ }
1566
+ if (p.in === "cookie") {
1567
+ cookieValues[p.name] = optValue;
1568
+ }
1569
+ }
1570
+ const schemas = deriveValidationSchemas(input.action);
1571
+ const ajv2 = createAjv();
1572
+ if (schemas.querySchema) {
1573
+ const validate = ajv2.compile(schemas.querySchema);
1574
+ if (!validate(queryValues)) {
1575
+ throw new Error(formatAjvErrors(validate.errors));
1576
+ }
1577
+ }
1578
+ if (schemas.headerSchema) {
1579
+ const validate = ajv2.compile(schemas.headerSchema);
1580
+ if (!validate(headerValues)) {
1581
+ throw new Error(formatAjvErrors(validate.errors));
1582
+ }
1583
+ }
1584
+ if (schemas.cookieSchema) {
1585
+ const validate = ajv2.compile(schemas.cookieSchema);
1586
+ if (!validate(cookieValues)) {
1587
+ throw new Error(formatAjvErrors(validate.errors));
1588
+ }
1589
+ }
1590
+ for (const [name, value] of Object.entries(queryValues)) {
1591
+ if (Array.isArray(value)) {
1592
+ for (const item of value) {
1593
+ url.searchParams.append(name, String(item));
1594
+ }
1595
+ continue;
1596
+ }
1597
+ url.searchParams.set(name, String(value));
1598
+ }
1599
+ for (const [name, value] of Object.entries(headerValues)) {
1600
+ headers.set(name, String(value));
1601
+ }
1602
+ for (const [name, value] of Object.entries(cookieValues)) {
1603
+ const existing = headers.get("Cookie");
1604
+ const part = `${name}=${String(value)}`;
1605
+ headers.set("Cookie", existing ? `${existing}; ${part}` : part);
1606
+ }
1607
+ let body;
1608
+ if (input.action.requestBody) {
1609
+ const bodyFlagDefs = input.bodyFlagDefs ?? [];
1610
+ const hasBodyFlags = bodyFlagDefs.some((def) => {
1611
+ const dotKey = def.path.join(".");
1612
+ return input.flagValues[dotKey] !== undefined;
1613
+ });
1614
+ const contentType = input.action.requestBody.preferredContentType;
1615
+ if (contentType)
1616
+ headers.set("Content-Type", contentType);
1617
+ const schema2 = input.action.requestBodySchema;
1618
+ const requiredFields = bodyFlagDefs.filter((d) => d.required);
1619
+ if (!hasBodyFlags) {
1620
+ if (requiredFields.length > 0) {
1621
+ const flagList = requiredFields.map((d) => `--${d.path.join(".")}`);
1622
+ throw new Error(`Required: ${flagList.join(", ")}`);
1623
+ }
1624
+ if (input.action.requestBody.required) {
1625
+ body = "{}";
1626
+ }
1627
+ } else {
1628
+ if (!contentType?.includes("json")) {
1629
+ throw new Error("Body field flags are only supported for JSON request bodies.");
1630
+ }
1631
+ const { findMissingRequired: findMissingRequired2, parseDotNotationFlags: parseDotNotationFlags2 } = await Promise.resolve().then(() => exports_body_flags);
1632
+ const missing = findMissingRequired2(input.flagValues, bodyFlagDefs);
1633
+ if (missing.length > 0) {
1634
+ const missingFlags = missing.map((m) => `--${m}`).join(", ");
1635
+ throw new Error(`Missing required fields: ${missingFlags}`);
1636
+ }
1637
+ const built = parseDotNotationFlags2(input.flagValues, bodyFlagDefs);
1638
+ if (schema2) {
1639
+ const validate = ajv2.compile(schema2);
1640
+ if (!validate(built)) {
1641
+ throw new Error(formatAjvErrors(validate.errors));
1642
+ }
1643
+ }
1644
+ body = JSON.stringify(built);
1645
+ }
1646
+ }
1647
+ const storedToken = profile?.name ? await getToken(input.specId, profile.name) : null;
1648
+ const resolvedAuthScheme = resolveAuthScheme(input.authSchemes, input.action.auth, {
1649
+ flagAuthScheme: input.globals.auth,
1650
+ profileAuthScheme: profile?.authScheme,
1651
+ embeddedAuthScheme: embedded?.auth,
1652
+ hasStoredToken: Boolean(storedToken)
1653
+ });
1654
+ const tokenFromProfile = resolvedAuthScheme ? storedToken : null;
1655
+ const globalsWithProfileAuth = {
1656
+ ...input.globals,
1657
+ auth: resolvedAuthScheme,
1658
+ bearerToken: input.globals.bearerToken ?? input.globals.oauthToken ?? tokenFromProfile ?? undefined
1659
+ };
1660
+ const final = applyAuth(headers, url, input.action, globalsWithProfileAuth, input.authSchemes);
1661
+ const req = new Request(final.url.toString(), {
1662
+ method: input.action.method,
1663
+ headers: final.headers,
1664
+ body
1665
+ });
1666
+ const curl = buildCurl(req, body);
1667
+ return { request: req, curl };
1668
+ }
1669
+ function buildCurl(req, body) {
1670
+ const parts = ["curl", "-sS", "-X", req.method];
1671
+ for (const [k, v] of req.headers.entries()) {
1672
+ parts.push("-H", shellQuote(`${k}: ${v}`));
1673
+ }
1674
+ if (typeof body === "string") {
1675
+ parts.push("--data", shellQuote(body));
1676
+ }
1677
+ parts.push(shellQuote(req.url));
1678
+ return parts.join(" ");
1679
+ }
1680
+ function shellQuote(value) {
1681
+ return `'${value.replace(/'/g, `'\\''`)}'`;
1682
+ }
1683
+ function optionKeyFromFlag(flag) {
1684
+ const name = flag.replace(/^--/, "");
1685
+ return name.replace(/-([a-z])/g, (_, c) => String(c).toUpperCase());
1686
+ }
1687
+ var init_request = __esm(() => {
1688
+ init_resolve();
1689
+ init_secrets();
1690
+ init_store();
1691
+ init_server_url();
1692
+ init_validate();
1693
+ });
1694
+
1695
+ // src/cli/runtime/execute.ts
1696
+ function formatError(message, resourceName, actionName) {
1697
+ const helpCmd = resourceName ? `${resourceName} ${actionName} --help` : `${actionName} --help`;
1698
+ return `${message}
1699
+
1700
+ Run '${helpCmd}' to see available options.`;
1701
+ }
1702
+ async function execute(input) {
1703
+ const { request, curl } = await buildRequest({
1704
+ specId: input.specId,
1705
+ action: input.action,
1706
+ positionalValues: input.positionalValues,
1707
+ flagValues: input.flagValues,
1708
+ globals: input.globals,
1709
+ servers: input.servers,
1710
+ authSchemes: input.authSchemes,
1711
+ embeddedDefaults: input.embeddedDefaults,
1712
+ bodyFlagDefs: input.bodyFlagDefs
1713
+ });
1714
+ const res = await fetch(request);
1715
+ const contentType = res.headers.get("content-type") ?? "";
1716
+ const text = await res.text();
1717
+ let body = text;
1718
+ if (contentType.includes("json") && text) {
1719
+ try {
1720
+ body = JSON.parse(text);
1721
+ } catch {}
1722
+ }
1723
+ return {
1724
+ ok: res.ok,
1725
+ status: res.status,
1726
+ body,
1727
+ curl
1728
+ };
1729
+ }
1730
+ async function executeAction(input) {
1731
+ const actionName = input.action.action;
1732
+ const resourceName = input.resourceName;
1733
+ try {
1734
+ if (input.globals.curl) {
1735
+ const { curl } = await buildRequest({
1736
+ specId: input.specId,
1737
+ action: input.action,
1738
+ positionalValues: input.positionalValues,
1739
+ flagValues: input.flagValues,
1740
+ globals: input.globals,
1741
+ servers: input.servers,
1742
+ authSchemes: input.authSchemes,
1743
+ embeddedDefaults: input.embeddedDefaults,
1744
+ bodyFlagDefs: input.bodyFlagDefs
1745
+ });
1746
+ process.stdout.write(`${curl}
1747
+ `);
1748
+ return;
1749
+ }
1750
+ const result = await execute(input);
1751
+ if (!result.ok) {
1752
+ if (input.globals.json) {
1753
+ process.stdout.write(`${JSON.stringify({ status: result.status, body: result.body })}
1754
+ `);
1755
+ } else {
1756
+ process.stderr.write(`HTTP ${result.status}
1757
+ `);
1758
+ process.stderr.write(`${typeof result.body === "string" ? result.body : JSON.stringify(result.body, null, 2)}
1759
+ `);
1760
+ }
1761
+ process.exitCode = 1;
1762
+ return;
1763
+ }
1764
+ if (input.globals.json) {
1765
+ process.stdout.write(`${JSON.stringify(result.body)}
1766
+ `);
1767
+ return;
1768
+ }
1769
+ if (typeof result.body === "string") {
1770
+ process.stdout.write(result.body);
1771
+ if (!result.body.endsWith(`
1772
+ `))
1773
+ process.stdout.write(`
1774
+ `);
1775
+ } else {
1776
+ process.stdout.write(`${JSON.stringify(result.body, null, 2)}
1777
+ `);
1778
+ }
1779
+ } catch (err) {
1780
+ const rawMessage = err instanceof Error ? err.message : String(err);
1781
+ const message = formatError(rawMessage, resourceName, actionName);
1782
+ if (input.globals.json) {
1783
+ process.stdout.write(`${JSON.stringify({ error: rawMessage })}
1784
+ `);
1785
+ } else {
1786
+ process.stderr.write(`error: ${message}
1787
+ `);
1788
+ }
1789
+ process.exitCode = 1;
1790
+ }
1791
+ }
1792
+ var init_execute = __esm(() => {
1793
+ init_request();
1794
+ });
1795
+
1796
+ // src/cli/runtime/generated.ts
1797
+ import { Command } from "commander";
1798
+ function formatCustomHelp(cmd, action, operationFlags, bodyFlagDefs) {
1799
+ const lines = [];
1800
+ const cmdName = cmd.name();
1801
+ const parentName = cmd.parent?.name() ?? "";
1802
+ const fullCmd = parentName ? `${parentName} ${cmdName}` : cmdName;
1803
+ const positionals = action.positionals.map((p) => `<${p.name}>`).join(" ");
1804
+ const usageSuffix = positionals ? ` ${positionals}` : "";
1805
+ lines.push(`Usage: ${fullCmd}${usageSuffix} [options]`);
1806
+ lines.push("");
1807
+ const desc = action.summary ?? action.description ?? `${action.method} ${action.path}`;
1808
+ lines.push(desc);
1809
+ lines.push("");
1810
+ const requiredOpts = [];
1811
+ const optionalOpts = [];
1812
+ const formatOpt = (flag, type, desc2, required) => {
1813
+ const typeStr = type === "boolean" ? "" : ` <${type}>`;
1814
+ const reqMarker = required ? " (required)" : "";
1815
+ return ` ${flag}${typeStr}${reqMarker}
1816
+ ${desc2}`;
1817
+ };
1818
+ for (const f of operationFlags) {
1819
+ const type = f.type === "array" ? `${f.itemType ?? "string"}[]` : f.type;
1820
+ const line = formatOpt(f.flag, type, f.description ?? `${f.in} parameter`, f.required);
1821
+ if (f.required) {
1822
+ requiredOpts.push(line);
1823
+ } else {
1824
+ optionalOpts.push(line);
1825
+ }
1826
+ }
1827
+ for (const def of bodyFlagDefs) {
1828
+ const line = formatOpt(def.flag, def.type, def.description, def.required);
1829
+ if (def.required) {
1830
+ requiredOpts.push(line);
1831
+ } else {
1832
+ optionalOpts.push(line);
1833
+ }
1834
+ }
1835
+ if (requiredOpts.length > 0) {
1836
+ lines.push("Required:");
1837
+ lines.push(...requiredOpts);
1838
+ lines.push("");
1839
+ }
1840
+ if (optionalOpts.length > 0) {
1841
+ lines.push("Options:");
1842
+ lines.push(...optionalOpts);
1843
+ lines.push("");
1844
+ }
1845
+ lines.push("Global:");
1846
+ lines.push(` --curl
1847
+ Print curl command instead of executing`);
1848
+ lines.push(` --json
1849
+ Output response as JSON`);
1850
+ lines.push(` --server <url>
1851
+ Override the API server URL`);
1852
+ lines.push(` --bearer-token <token>
1853
+ Provide auth token (or use 'login' command)`);
1854
+ lines.push(` -h, --help
1855
+ Show this help message`);
1856
+ lines.push("");
1857
+ return lines.join(`
1858
+ `);
1859
+ }
1860
+ function addGeneratedCommands(program, context) {
1861
+ for (const resource of context.commands.resources) {
1862
+ const resourceCmd = program.command(resource.resource).description(`Operations for ${resource.resource}`);
1863
+ for (const action of resource.actions) {
1864
+ const cmd = resourceCmd.command(action.action);
1865
+ cmd.description(action.summary ?? action.description ?? `${action.method} ${action.path}`);
1866
+ for (const pos of action.positionals) {
1867
+ cmd.argument(`<${pos.name}>`, pos.description);
1868
+ }
1869
+ for (const flag of action.flags) {
1870
+ const opt = flag.flag;
1871
+ const desc = flag.description ?? `${flag.in} parameter`;
1872
+ if (flag.type === "boolean") {
1873
+ cmd.option(opt, desc);
1874
+ continue;
1875
+ }
1876
+ const isArray = flag.type === "array";
1877
+ const itemType = flag.itemType ?? "string";
1878
+ const flagType = isArray ? itemType : flag.type;
1879
+ const parser = (raw) => coerceValue(raw, flagType);
1880
+ if (isArray) {
1881
+ const key2 = `${opt} <value>`;
1882
+ cmd.option(key2, desc, (value, prev) => {
1883
+ const next = [...prev ?? []];
1884
+ const items = coerceArrayInput(value, itemType);
1885
+ for (const item of items) {
1886
+ next.push(item);
1887
+ }
1888
+ return next;
1889
+ });
1890
+ continue;
1891
+ }
1892
+ const key = `${opt} <value>`;
1893
+ if (flag.required)
1894
+ cmd.requiredOption(key, desc, parser);
1895
+ else
1896
+ cmd.option(key, desc, parser);
1897
+ }
1898
+ const operationFlagSet = new Set(action.flags.map((f) => f.flag));
1899
+ const reservedFlags = new Set([...operationFlagSet, "--curl"]);
1900
+ if (!operationFlagSet.has("--curl")) {
1901
+ cmd.option("--curl", "Print curl command without sending");
1902
+ }
1903
+ let bodyFlagDefs = [];
1904
+ if (action.requestBody) {
1905
+ bodyFlagDefs = generateBodyFlags(action.requestBodySchema, reservedFlags);
1906
+ for (const def of bodyFlagDefs) {
1907
+ if (def.type === "boolean") {
1908
+ cmd.option(def.flag, def.description);
1909
+ } else {
1910
+ cmd.option(`${def.flag} <value>`, def.description);
1911
+ }
1912
+ }
1913
+ }
1914
+ cmd.configureHelp({
1915
+ formatHelp: () => formatCustomHelp(cmd, action, action.flags, bodyFlagDefs)
1916
+ });
1917
+ cmd.action(async (...args) => {
1918
+ const command = args[args.length - 1];
1919
+ const positionalValues = args.slice(0, -1).map((v) => String(v));
1920
+ if (!(command instanceof Command)) {
1921
+ throw new Error("Unexpected commander action signature");
1922
+ }
1923
+ const globals = command.optsWithGlobals();
1924
+ const local = command.opts();
1925
+ await executeAction({
1926
+ action,
1927
+ positionalValues,
1928
+ flagValues: local,
1929
+ globals,
1930
+ servers: context.servers,
1931
+ authSchemes: context.authSchemes,
1932
+ specId: context.specId,
1933
+ embeddedDefaults: context.embeddedDefaults,
1934
+ bodyFlagDefs,
1935
+ resourceName: resource.resource
1936
+ });
1937
+ });
1938
+ }
1939
+ }
1940
+ }
1941
+ var init_generated = __esm(() => {
1942
+ init_execute();
1943
+ init_validate();
1944
+ });
1945
+
1946
+ // src/cli/main.ts
1947
+ import { Command as Command2 } from "commander";
1948
+ async function main(argv, options = {}) {
1949
+ const program = new Command2;
1950
+ program.name(options.cliName ?? "specli").description("Generate a CLI from an OpenAPI spec").option("--spec <urlOrPath>", "OpenAPI URL or file path").option("--server <url>", "Override server/base URL").option("--server-var <name=value>", "Server URL template variable (repeatable)", collectRepeatable).option("--auth <scheme>", "Select auth scheme by key").option("--bearer-token <token>", "Bearer token (Authorization: Bearer)").option("--oauth-token <token>", "OAuth token (alias of bearer)").option("--username <username>", "Basic auth username").option("--password <password>", "Basic auth password").option("--api-key <key>", "API key value").option("--json", "Machine-readable output").showHelpAfterError();
1951
+ const spec = getArgValue(argv, "--spec");
1952
+ const wantsHelp = hasAnyArg(argv, ["-h", "--help"]);
1953
+ if (!spec && !options.embeddedSpecText && wantsHelp) {
1954
+ program.addHelpText("after", `
1955
+ To see generated commands, run with --spec <url|path>.
1956
+ `);
1957
+ program.parse(argv);
1958
+ return;
1959
+ }
1960
+ const ctx = await buildRuntimeContext({
1961
+ spec,
1962
+ embeddedSpecText: options.embeddedSpecText
1963
+ });
1964
+ const defaultProfileName = "default";
1965
+ program.command("login [token]").description("Store a bearer token for authentication").action(async (tokenArg, _opts, command) => {
1966
+ const globals = command.optsWithGlobals();
1967
+ let token = tokenArg;
1968
+ if (!token) {
1969
+ const isTTY = process.stdin.isTTY;
1970
+ if (isTTY) {
1971
+ process.stdout.write("Enter token: ");
1972
+ const reader = process.stdin;
1973
+ const chunks = [];
1974
+ for await (const chunk of reader) {
1975
+ chunks.push(chunk);
1976
+ if (chunk.includes(10))
1977
+ break;
1978
+ }
1979
+ token = Buffer.concat(chunks).toString().trim();
1980
+ } else {
1981
+ const text = await readStdinText();
1982
+ token = text.trim();
1983
+ }
1984
+ }
1985
+ if (!token) {
1986
+ throw new Error("No token provided. Usage: login <token> or echo $TOKEN | login");
1987
+ }
1988
+ const file = await readProfiles();
1989
+ if (!file.profiles.find((p) => p.name === defaultProfileName)) {
1990
+ const updated = upsertProfile(file, { name: defaultProfileName });
1991
+ await writeProfiles({ ...updated, defaultProfile: defaultProfileName });
1992
+ } else if (!file.defaultProfile) {
1993
+ await writeProfiles({ ...file, defaultProfile: defaultProfileName });
1994
+ }
1995
+ await setToken(ctx.loaded.id, defaultProfileName, token);
1996
+ if (globals.json) {
1997
+ process.stdout.write(`${JSON.stringify({ ok: true })}
1998
+ `);
1999
+ return;
2000
+ }
2001
+ process.stdout.write(`ok: logged in
2002
+ `);
2003
+ });
2004
+ program.command("logout").description("Clear stored authentication token").action(async (_opts, command) => {
2005
+ const globals = command.optsWithGlobals();
2006
+ const deleted = await deleteToken(ctx.loaded.id, defaultProfileName);
2007
+ if (globals.json) {
2008
+ process.stdout.write(`${JSON.stringify({ ok: deleted })}
2009
+ `);
2010
+ return;
2011
+ }
2012
+ process.stdout.write(deleted ? `ok: logged out
2013
+ ` : `ok: not logged in
2014
+ `);
2015
+ });
2016
+ program.command("whoami").description("Show current authentication status").action(async (_opts, command) => {
2017
+ const globals = command.optsWithGlobals();
2018
+ const token = await getToken(ctx.loaded.id, defaultProfileName);
2019
+ const hasToken = Boolean(token);
2020
+ let maskedToken = null;
2021
+ if (token && token.length > 16) {
2022
+ maskedToken = `${token.slice(0, 8)}...${token.slice(-4)}`;
2023
+ } else if (token) {
2024
+ maskedToken = `${token.slice(0, 4)}...`;
2025
+ }
2026
+ if (globals.json) {
2027
+ process.stdout.write(`${JSON.stringify({ authenticated: hasToken, token: maskedToken })}
2028
+ `);
2029
+ return;
2030
+ }
2031
+ if (hasToken) {
2032
+ process.stdout.write(`authenticated: yes
2033
+ `);
2034
+ process.stdout.write(`token: ${maskedToken}
2035
+ `);
2036
+ } else {
2037
+ process.stdout.write(`authenticated: no
2038
+ `);
2039
+ process.stdout.write(`Run 'login <token>' to authenticate.
2040
+ `);
2041
+ }
2042
+ });
2043
+ program.command("__schema").description("Print indexed operations (machine-readable when --json)").option("--pretty", "Pretty-print JSON when used with --json").option("--min", "Minimal JSON output (commands + metadata only)").action(async (_opts, command) => {
2044
+ const flags = command.optsWithGlobals();
2045
+ if (flags.json) {
2046
+ const pretty = Boolean(flags.pretty);
2047
+ const payload = flags.min ? toMinimalSchemaOutput(ctx.schema) : ctx.schema;
2048
+ const text = stableStringify(payload, { space: pretty ? 2 : 0 });
2049
+ process.stdout.write(`${text}
2050
+ `);
2051
+ return;
2052
+ }
2053
+ process.stdout.write(`${ctx.schema.openapi.title ?? "(untitled)"}
2054
+ `);
2055
+ process.stdout.write(`OpenAPI: ${ctx.schema.openapi.version}
2056
+ `);
2057
+ process.stdout.write(`Spec: ${ctx.schema.spec.id} (${ctx.schema.spec.source})
2058
+ `);
2059
+ process.stdout.write(`Fingerprint: ${ctx.schema.spec.fingerprint}
2060
+ `);
2061
+ process.stdout.write(`Servers: ${ctx.schema.servers.length}
2062
+ `);
2063
+ process.stdout.write(`Auth Schemes: ${ctx.schema.authSchemes.length}
2064
+ `);
2065
+ process.stdout.write(`Operations: ${ctx.schema.operations.length}
2066
+ `);
2067
+ for (const op of ctx.schema.operations) {
2068
+ const id = op.operationId ? ` (${op.operationId})` : "";
2069
+ process.stdout.write(`- ${op.method} ${op.path}${id}
2070
+ `);
2071
+ }
2072
+ if (ctx.schema.planned?.length) {
2073
+ process.stdout.write(`
2074
+ Planned commands:
2075
+ `);
2076
+ for (const op of ctx.schema.planned) {
2077
+ const args = op.pathArgs.length ? ` ${op.pathArgs.map((a) => `<${a}>`).join(" ")}` : "";
2078
+ process.stdout.write(`- specli ${op.resource} ${op.action}${args}
2079
+ `);
2080
+ }
2081
+ }
2082
+ });
2083
+ addGeneratedCommands(program, {
2084
+ servers: ctx.servers,
2085
+ authSchemes: ctx.authSchemes,
2086
+ commands: ctx.commands,
2087
+ specId: ctx.loaded.id,
2088
+ embeddedDefaults: {
2089
+ server: options.server,
2090
+ serverVars: options.serverVars,
2091
+ auth: options.auth
2092
+ }
2093
+ });
2094
+ await program.parseAsync(argv);
2095
+ }
2096
+ var init_main = __esm(() => {
2097
+ init_compat();
2098
+ init_context();
2099
+ init_generated();
2100
+ init_secrets();
2101
+ init_store();
2102
+ });
2103
+
2104
+ // src/cli/exec.ts
2105
+ var exports_exec = {};
2106
+ __export(exports_exec, {
2107
+ execCommand: () => execCommand
2108
+ });
2109
+ async function execCommand(spec, options, commandArgs) {
2110
+ const remainingArgs = commandArgs.slice(1);
2111
+ const argv = [
2112
+ process.argv[0] ?? "bun",
2113
+ process.argv[1] ?? "specli",
2114
+ "--spec",
2115
+ spec
2116
+ ];
2117
+ if (options.server) {
2118
+ argv.push("--server", options.server);
2119
+ }
2120
+ if (options.serverVar) {
2121
+ for (const v of options.serverVar) {
2122
+ argv.push("--server-var", v);
2123
+ }
2124
+ }
2125
+ if (options.auth) {
2126
+ argv.push("--auth", options.auth);
2127
+ }
2128
+ if (options.bearerToken) {
2129
+ argv.push("--bearer-token", options.bearerToken);
2130
+ }
2131
+ if (options.oauthToken) {
2132
+ argv.push("--oauth-token", options.oauthToken);
2133
+ }
2134
+ if (options.username) {
2135
+ argv.push("--username", options.username);
2136
+ }
2137
+ if (options.password) {
2138
+ argv.push("--password", options.password);
2139
+ }
2140
+ if (options.apiKey) {
2141
+ argv.push("--api-key", options.apiKey);
2142
+ }
2143
+ if (options.profile) {
2144
+ argv.push("--profile", options.profile);
2145
+ }
2146
+ if (options.json) {
2147
+ argv.push("--json");
2148
+ }
2149
+ argv.push(...remainingArgs);
2150
+ await main(argv);
2151
+ }
2152
+ var init_exec = __esm(() => {
2153
+ init_main();
2154
+ });
2155
+
2156
+ // src/cli/derive-name.ts
2157
+ async function deriveBinaryName(spec) {
2158
+ try {
2159
+ const text = await loadSpecText(spec);
2160
+ const doc = parseSpec(text);
2161
+ const title = doc?.info?.title;
2162
+ if (title && typeof title === "string") {
2163
+ const name = sanitizeName(title);
2164
+ if (name)
2165
+ return name;
2166
+ }
2167
+ } catch {}
2168
+ if (/^https?:\/\//i.test(spec)) {
2169
+ try {
2170
+ const url = new URL(spec);
2171
+ const hostParts = url.hostname.split(".");
2172
+ const meaningful = hostParts.find((p) => p !== "www" && p !== "api" && p.length > 2);
2173
+ if (meaningful) {
2174
+ const name = sanitizeName(meaningful);
2175
+ if (name)
2176
+ return name;
2177
+ }
2178
+ } catch {}
2179
+ }
2180
+ return "specli";
2181
+ }
2182
+ async function loadSpecText(spec) {
2183
+ if (/^https?:\/\//i.test(spec)) {
2184
+ const res = await fetch(spec);
2185
+ if (!res.ok)
2186
+ throw new Error(`Failed to fetch: ${res.status}`);
2187
+ return res.text();
2188
+ }
2189
+ return Bun.file(spec).text();
2190
+ }
2191
+ function parseSpec(text) {
2192
+ try {
2193
+ const trimmed = text.trimStart();
2194
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
2195
+ return JSON.parse(text);
2196
+ }
2197
+ const { YAML } = globalThis.Bun ?? {};
2198
+ if (YAML?.parse) {
2199
+ return YAML.parse(text);
2200
+ }
2201
+ return null;
2202
+ } catch {
2203
+ return null;
2204
+ }
2205
+ }
2206
+ function sanitizeName(input) {
2207
+ let name = input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32);
2208
+ if (RESERVED_NAMES.includes(name)) {
2209
+ name = `${name}-cli`;
2210
+ }
2211
+ return name;
2212
+ }
2213
+ var RESERVED_NAMES;
2214
+ var init_derive_name = __esm(() => {
2215
+ RESERVED_NAMES = [
2216
+ "exec",
2217
+ "compile",
2218
+ "profile",
2219
+ "auth",
2220
+ "help",
2221
+ "version"
2222
+ ];
2223
+ });
2224
+
2225
+ // src/cli/compile.ts
2226
+ var exports_compile = {};
2227
+ __export(exports_compile, {
2228
+ compileCommand: () => compileCommand
2229
+ });
2230
+ function parseKeyValue(input) {
2231
+ const idx = input.indexOf("=");
2232
+ if (idx === -1)
2233
+ throw new Error(`Invalid --define '${input}', expected key=value`);
2234
+ const key = input.slice(0, idx).trim();
2235
+ const value = input.slice(idx + 1).trim();
2236
+ if (!key)
2237
+ throw new Error(`Invalid --define '${input}', missing key`);
2238
+ return { key, value };
2239
+ }
2240
+ async function compileCommand(spec, options) {
2241
+ const name = options.name ?? await deriveBinaryName(spec);
2242
+ const outfile = options.outfile ?? `./dist/${name}`;
2243
+ const target = options.target ? options.target : `bun-${process.platform}-${process.arch}`;
2244
+ const define = {};
2245
+ if (options.define) {
2246
+ for (const pair of options.define) {
2247
+ const { key, value } = parseKeyValue(pair);
2248
+ define[key] = JSON.stringify(value);
2249
+ }
2250
+ }
2251
+ const buildArgs = [
2252
+ "build",
2253
+ "--compile",
2254
+ `--outfile=${outfile}`,
2255
+ `--target=${target}`
2256
+ ];
2257
+ if (options.minify)
2258
+ buildArgs.push("--minify");
2259
+ if (options.bytecode)
2260
+ buildArgs.push("--bytecode");
2261
+ for (const [k, v] of Object.entries(define)) {
2262
+ buildArgs.push("--define", `${k}=${v}`);
2263
+ }
2264
+ if (options.dotenv === false)
2265
+ buildArgs.push("--no-compile-autoload-dotenv");
2266
+ if (options.bunfig === false)
2267
+ buildArgs.push("--no-compile-autoload-bunfig");
2268
+ buildArgs.push("./src/compiled.ts");
2269
+ const buildEnv = {
2270
+ ...process.env,
2271
+ SPECLI_SPEC: spec,
2272
+ SPECLI_NAME: name
2273
+ };
2274
+ if (options.server)
2275
+ buildEnv.SPECLI_SERVER = options.server;
2276
+ if (options.serverVar?.length)
2277
+ buildEnv.SPECLI_SERVER_VARS = options.serverVar.join(",");
2278
+ if (options.auth)
2279
+ buildEnv.SPECLI_AUTH = options.auth;
2280
+ const proc = Bun.spawn({
2281
+ cmd: ["bun", ...buildArgs],
2282
+ stdout: "pipe",
2283
+ stderr: "pipe",
2284
+ env: buildEnv
2285
+ });
2286
+ const output = await new Response(proc.stdout).text();
2287
+ const error2 = await new Response(proc.stderr).text();
2288
+ const code = await proc.exited;
2289
+ if (output)
2290
+ process.stdout.write(output);
2291
+ if (error2)
2292
+ process.stderr.write(error2);
2293
+ if (code !== 0) {
2294
+ process.exitCode = code;
2295
+ return;
2296
+ }
2297
+ process.stdout.write(`ok: built ${outfile}
2298
+ `);
2299
+ process.stdout.write(`target: ${target}
2300
+ `);
2301
+ process.stdout.write(`name: ${name}
2302
+ `);
2303
+ }
2304
+ var init_compile = __esm(() => {
2305
+ init_derive_name();
2306
+ });
2307
+
2308
+ // cli.ts
2309
+ import { Command as Command3 } from "commander";
2310
+ function collect(value, previous = []) {
2311
+ return previous.concat([value]);
2312
+ }
2313
+ var program = new Command3;
2314
+ program.name("specli").description("Generate CLIs from OpenAPI specs");
2315
+ program.command("exec <spec>").description("Execute commands from an OpenAPI spec").option("--server <url>", "Override server/base URL").option("--server-var <name=value>", "Server variable (repeatable)", collect, []).option("--auth <scheme>", "Select auth scheme").option("--bearer-token <token>", "Bearer token").option("--oauth-token <token>", "OAuth token").option("--username <username>", "Basic auth username").option("--password <password>", "Basic auth password").option("--api-key <key>", "API key value").option("--profile <name>", "Profile name").option("--json", "Machine-readable output").allowUnknownOption().allowExcessArguments().action(async (spec, options, command) => {
2316
+ const { execCommand: execCommand2 } = await Promise.resolve().then(() => (init_exec(), exports_exec));
2317
+ await execCommand2(spec, options, command.args);
2318
+ });
2319
+ program.command("compile <spec>").description("Compile an OpenAPI spec into a standalone CLI binary (requires Bun)").option("--name <name>", "Binary name (default: derived from spec)").option("--outfile <path>", "Output path (default: ./dist/<name>)").option("--target <target>", "Bun compile target (e.g. bun-linux-x64)").option("--minify", "Enable minification").option("--bytecode", "Enable bytecode compilation").option("--no-dotenv", "Disable .env autoload").option("--no-bunfig", "Disable bunfig.toml autoload").option("--define <k=v>", "Build-time constant (repeatable)", collect, []).option("--server <url>", "Default server URL (embedded)").option("--server-var <k=v>", "Default server variable (repeatable, embedded)", collect, []).option("--auth <scheme>", "Default auth scheme (embedded)").action(async (spec, options) => {
2320
+ if (typeof globalThis.Bun === "undefined") {
2321
+ console.error("Error: The 'compile' command requires Bun.");
2322
+ console.error("Install Bun: https://bun.sh");
2323
+ console.error("Then run: bunx specli compile <spec>");
2324
+ process.exit(1);
2325
+ }
2326
+ const { compileCommand: compileCommand2 } = await Promise.resolve().then(() => (init_compile(), exports_compile));
2327
+ await compileCommand2(spec, options);
2328
+ });
2329
+ await program.parseAsync(process.argv);
2330
+
2331
+ //# debugId=0B08E98087E7178B64756E2164756E21