specli 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +76 -86
  2. package/cli.ts +4 -10
  3. package/package.json +8 -2
  4. package/src/cli/compile.ts +5 -28
  5. package/src/cli/derive-name.ts +2 -2
  6. package/src/cli/exec.ts +1 -1
  7. package/src/cli/main.ts +12 -27
  8. package/src/cli/runtime/auth/resolve.ts +10 -2
  9. package/src/cli/runtime/body-flags.ts +176 -0
  10. package/src/cli/runtime/execute.ts +41 -91
  11. package/src/cli/runtime/generated.ts +28 -93
  12. package/src/cli/runtime/profile/secrets.ts +1 -1
  13. package/src/cli/runtime/profile/store.ts +1 -1
  14. package/src/cli/runtime/request.ts +42 -152
  15. package/src/cli/stable-json.ts +2 -2
  16. package/src/compiled.ts +13 -15
  17. package/src/macros/env.ts +0 -4
  18. package/CLAUDE.md +0 -111
  19. package/PLAN.md +0 -274
  20. package/biome.jsonc +0 -1
  21. package/bun.lock +0 -98
  22. package/fixtures/openapi-array-items.json +0 -22
  23. package/fixtures/openapi-auth.json +0 -34
  24. package/fixtures/openapi-body.json +0 -41
  25. package/fixtures/openapi-collision.json +0 -21
  26. package/fixtures/openapi-oauth.json +0 -54
  27. package/fixtures/openapi-servers.json +0 -35
  28. package/fixtures/openapi.json +0 -87
  29. package/scripts/smoke-specs.ts +0 -64
  30. package/src/cli/auth-requirements.test.ts +0 -27
  31. package/src/cli/auth-schemes.test.ts +0 -66
  32. package/src/cli/capabilities.test.ts +0 -94
  33. package/src/cli/command-id.test.ts +0 -32
  34. package/src/cli/command-model.test.ts +0 -44
  35. package/src/cli/naming.test.ts +0 -86
  36. package/src/cli/operations.test.ts +0 -57
  37. package/src/cli/params.test.ts +0 -70
  38. package/src/cli/positional.test.ts +0 -65
  39. package/src/cli/request-body.test.ts +0 -35
  40. package/src/cli/runtime/request.test.ts +0 -153
  41. package/src/cli/server.test.ts +0 -35
  42. package/tsconfig.json +0 -29
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # opencli
1
+ # specli
2
2
 
3
- OpenCLI turns an OpenAPI spec into a non-interactive, “curl replacement” CLI.
3
+ specli turns an OpenAPI spec into a non-interactive, “curl replacement” CLI.
4
4
 
5
5
  It has two modes:
6
6
 
@@ -21,7 +21,7 @@ It works well for a large chunk of “typical” OpenAPI 3.x REST specs:
21
21
  - Path/query/header/cookie parameters.
22
22
  - Request bodies via `--data` / `--file`.
23
23
  - JSON request body parsing + schema validation.
24
- - Expanded JSON body flags for simple object bodies (`--body-*`).
24
+ - Body field flags matching OpenAPI schema properties (including nested objects with dot notation).
25
25
  - Auth injection for common schemes (bearer/basic/apiKey).
26
26
  - A deterministic `__schema` output for introspection.
27
27
 
@@ -38,25 +38,25 @@ bun install
38
38
  Inspect what commands will be generated:
39
39
 
40
40
  ```bash
41
- bunx opencli exec ./fixtures/openapi.json __schema
41
+ bunx specli exec ./fixtures/openapi.json __schema
42
42
  ```
43
43
 
44
44
  Machine-readable schema output:
45
45
 
46
46
  ```bash
47
- bunx opencli exec ./fixtures/openapi.json __schema --json
47
+ bunx specli exec ./fixtures/openapi.json __schema --json
48
48
  ```
49
49
 
50
50
  Minimal schema output (best for large specs):
51
51
 
52
52
  ```bash
53
- bunx opencli exec ./fixtures/openapi.json __schema --json --min
53
+ bunx specli exec ./fixtures/openapi.json __schema --json --min
54
54
  ```
55
55
 
56
56
  Run a generated operation:
57
57
 
58
58
  ```bash
59
- bunx opencli exec ./fixtures/openapi.json contacts list --oc-curl
59
+ bunx specli exec ./fixtures/openapi.json contacts list --curl
60
60
  ```
61
61
 
62
62
  ## Build a Standalone Executable
@@ -65,27 +65,27 @@ Use the `compile` command to create a standalone binary with the spec embedded:
65
65
 
66
66
  ```bash
67
67
  # compile with auto-derived name (from spec title)
68
- bunx opencli compile ./path/to/openapi.yaml
68
+ bunx specli compile ./path/to/openapi.yaml
69
69
  # → ./dist/my-api (derived from info.title)
70
70
 
71
71
  # compile with explicit name
72
- bunx opencli compile ./path/to/openapi.yaml --name myapi
72
+ bunx specli compile ./path/to/openapi.yaml --name myapi
73
73
  # → ./dist/myapi
74
74
 
75
75
  # cross-compile (example: linux x64)
76
- bunx opencli compile https://api.vercel.com/copper/_openapi.json --target bun-linux-x64 --outfile ./dist/copper-linux
76
+ bunx specli compile https://api.vercel.com/copper/_openapi.json --target bun-linux-x64 --outfile ./dist/copper-linux
77
77
 
78
78
  # disable runtime config loading for deterministic behavior
79
- bunx opencli compile ./path/to/openapi.yaml --no-dotenv --no-bunfig
79
+ bunx specli compile ./path/to/openapi.yaml --no-dotenv --no-bunfig
80
80
 
81
81
  # bake in defaults (these become default flags; runtime flags override)
82
- bunx opencli compile https://api.vercel.com/copper/_openapi.json \
82
+ bunx specli compile https://api.vercel.com/copper/_openapi.json \
83
83
  --name copper \
84
84
  --server https://api.vercel.com \
85
85
  --auth VercelOidc
86
86
  ```
87
87
 
88
- The compiled binary is a root CLI - no `opencli` prefix needed:
88
+ The compiled binary is a root CLI - no `specli` prefix needed:
89
89
 
90
90
  ```bash
91
91
  ./dist/copper contacts list
@@ -100,10 +100,10 @@ Notes:
100
100
 
101
101
  ## CLI Shape
102
102
 
103
- OpenCLI generates commands of the form:
103
+ specli generates commands of the form:
104
104
 
105
105
  ```
106
- opencli <resource> <action> [...positionals] [options]
106
+ specli <resource> <action> [...positionals] [options]
107
107
  ```
108
108
 
109
109
  - `resource` comes from `tags[0]`, `operationId` prefix, or the first path segment (heuristics).
@@ -119,7 +119,7 @@ Available on the root command:
119
119
  - `--spec <urlOrPath>`: OpenAPI URL or file path (only needed for compiled binaries to override embedded spec)
120
120
  - `--server <url>`: override server/base URL
121
121
  - `--server-var <name=value>`: server URL template variable (repeatable)
122
- - `--profile <name>`: profile name (config under `~/.config/opencli`)
122
+ - `--profile <name>`: profile name (config under `~/.config/specli`)
123
123
 
124
124
  Auth selection + credentials:
125
125
 
@@ -189,9 +189,9 @@ Array parameters are treated as repeatable flags and appended to the query strin
189
189
  All of these become `?tag=a&tag=b`:
190
190
 
191
191
  ```bash
192
- opencli ... --tag a --tag b
193
- opencli ... --tag a,b
194
- opencli ... --tag '["a","b"]'
192
+ specli ... --tag a --tag b
193
+ specli ... --tag a,b
194
+ specli ... --tag '["a","b"]'
195
195
  ```
196
196
 
197
197
  Implementation notes:
@@ -201,79 +201,69 @@ Implementation notes:
201
201
 
202
202
  ## Request Bodies
203
203
 
204
- ### Selecting the Body Input
204
+ ### Body Field Flags
205
205
 
206
- If an operation has a `requestBody`, you may provide a body via:
206
+ When an operation has a `requestBody` and the preferred schema is a JSON object, specli generates convenience flags that match the property names:
207
207
 
208
- - `--data <string>`
209
- - `--file <path>`
210
- - Expanded `--body-*` flags (JSON-only; see below)
208
+ - For `string|number|integer`: `--<prop> <value>`
209
+ - For `boolean`: `--<prop>` (presence sets it to `true`)
210
+ - For nested objects: `--<parent>.<child> <value>` (dot notation)
211
211
 
212
- Rules:
213
-
214
- - `--data` and `--file` are mutually exclusive.
215
- - Expanded `--body-*` flags cannot be used with `--data` or `--file`.
216
- - If `requestBody.required` is true and you provide none of the above, the command fails with:
217
- - `Missing request body. Provide --data, --file, or --body-* flags.`
218
-
219
- ### Content-Type
220
-
221
- `Content-Type` is chosen as:
222
-
223
- 1. `--content-type` (explicit override)
224
- 2. The preferred content type derived from the OpenAPI requestBody (prefers `application/json` when present)
225
-
226
- ### JSON Parsing + Normalization
227
-
228
- If the selected `Content-Type` includes `json`:
229
-
230
- - `--data`/`--file` content is parsed as either JSON or YAML
231
- - the request is sent as normalized JSON (`JSON.stringify(parsed)`)
232
-
233
- If `Content-Type` does not include `json`:
234
-
235
- - the body is treated as a raw string
236
-
237
- ### Schema Validation (Ajv)
238
-
239
- OpenCLI uses Ajv (best-effort, `strict: false`) to validate:
212
+ Example (from `fixtures/openapi-body.json`):
240
213
 
241
- - query/header/cookie params
242
- - JSON request bodies when a requestBody schema is available
214
+ ```bash
215
+ bunx specli exec ./fixtures/openapi-body.json contacts create --name "Ada" --curl
216
+ ```
243
217
 
244
- Validation errors are formatted into a readable multiline message. For `required` errors, the message is normalized to:
218
+ Produces a JSON body:
245
219
 
246
- - `/<path> missing required property '<name>'`
220
+ ```json
221
+ {"name":"Ada"}
222
+ ```
247
223
 
248
- ### Expanded JSON Body Flags (`--body-*`)
224
+ #### Nested Objects
249
225
 
250
- When an operation has a `requestBody` and the preferred schema is a JSON object with scalar properties, OpenCLI generates convenience flags:
226
+ Nested object properties use dot notation. For a schema like:
251
227
 
252
- - For `string|number|integer`: `--body-<prop> <value>`
253
- - For `boolean`: `--body-<prop>` (presence sets it to `true`)
228
+ ```json
229
+ {
230
+ "type": "object",
231
+ "properties": {
232
+ "name": { "type": "string" },
233
+ "address": {
234
+ "type": "object",
235
+ "properties": {
236
+ "street": { "type": "string" },
237
+ "city": { "type": "string" }
238
+ }
239
+ }
240
+ }
241
+ }
242
+ ```
254
243
 
255
- Example (from `fixtures/openapi-body.json`):
244
+ You can use:
256
245
 
257
246
  ```bash
258
- bunx opencli exec ./fixtures/openapi-body.json contacts create --body-name "Ada" --oc-curl
247
+ mycli contacts create --name "Ada" --address.street "123 Main St" --address.city "NYC"
259
248
  ```
260
249
 
261
- Produces a JSON body:
250
+ Which produces:
262
251
 
263
252
  ```json
264
- {"name":"Ada"}
253
+ {"name":"Ada","address":{"street":"123 Main St","city":"NYC"}}
265
254
  ```
266
255
 
267
256
  Notes / edge cases:
268
257
 
269
- - Expanded flags are only supported for JSON bodies. If you try to use them without a JSON content type, OpenCLI errors.
270
- - Required fields in the schema are checked in a “friendly way for expanded flags:
271
- - `Missing required body field 'name'. Provide --body-name or use --data/--file.`
272
- - Numeric coercion uses `Number(...)` / `parseInt(...)`. Today it does not explicitly reject `NaN` (this is an area to harden).
258
+ - Body field flags are only supported for JSON bodies.
259
+ - Required fields in the schema are checked with friendly error messages:
260
+ - `Missing required body field 'name'. Provide --name.`
261
+ - If a body field flag would conflict with an operation parameter flag or `--curl`, the operation parameter takes precedence.
262
+ - Numeric coercion uses `Number(...)` / `parseInt(...)`.
273
263
 
274
264
  ## Servers
275
265
 
276
- OpenCLI resolves the request base URL in this order:
266
+ specli resolves the request base URL in this order:
277
267
 
278
268
  1. `--server <url>`
279
269
  2. profile `server` (if `--profile` is set and the profile has a server)
@@ -288,7 +278,7 @@ If the chosen server URL has template variables (e.g. `https://{region}.api.exam
288
278
 
289
279
  ### Supported Scheme Kinds
290
280
 
291
- From `components.securitySchemes`, OpenCLI recognizes:
281
+ From `components.securitySchemes`, specli recognizes:
292
282
 
293
283
  - HTTP bearer (`type: http`, `scheme: bearer`)
294
284
  - HTTP basic (`type: http`, `scheme: basic`)
@@ -312,7 +302,7 @@ This “only if present in current spec” behavior prevents accidental auth lea
312
302
  Bearer-like schemes (`http-bearer`, `oauth2`, `openIdConnect`):
313
303
 
314
304
  - `--bearer-token <token>` or `--oauth-token <token>`
315
- - or a profile token stored via `opencli auth token ...`
305
+ - or a profile token stored via `specli auth token ...`
316
306
 
317
307
  Basic auth:
318
308
 
@@ -328,8 +318,8 @@ Profiles are for automation.
328
318
 
329
319
  Config file:
330
320
 
331
- - Read preference: `~/.config/opencli/profiles.json`, else `~/.config/opencli/profiles.yaml` if present
332
- - Writes always go to: `~/.config/opencli/profiles.json`
321
+ - Read preference: `~/.config/specli/profiles.json`, else `~/.config/specli/profiles.yaml` if present
322
+ - Writes always go to: `~/.config/specli/profiles.json`
333
323
 
334
324
  Secrets:
335
325
 
@@ -338,14 +328,14 @@ Secrets:
338
328
  Commands:
339
329
 
340
330
  ```bash
341
- opencli profile list
342
- opencli profile set --name dev --server https://api.example.com --auth bearerAuth --default
343
- opencli profile use --name dev
344
- opencli profile rm --name dev
345
-
346
- opencli auth token --name dev --set "..."
347
- opencli auth token --name dev --get
348
- opencli auth token --name dev --delete
331
+ specli profile list
332
+ specli profile set --name dev --server https://api.example.com --auth bearerAuth --default
333
+ specli profile use --name dev
334
+ specli profile rm --name dev
335
+
336
+ specli auth token --name dev --set "..."
337
+ specli auth token --name dev --get
338
+ specli auth token --name dev --delete
349
339
  ```
350
340
 
351
341
  ## Output Behavior
@@ -395,7 +385,7 @@ Prints the method, URL, headers, and body that would be sent without sending the
395
385
 
396
386
  ## `__schema`
397
387
 
398
- `opencli __schema` reports:
388
+ `specli __schema` reports:
399
389
 
400
390
  - OpenAPI title/version
401
391
  - spec source + computed spec id + fingerprint
@@ -440,15 +430,15 @@ bun run smoke:specs
440
430
  Or run ad-hoc smoke tests:
441
431
 
442
432
  ```bash
443
- bunx opencli exec <URL> __schema --json --min > /dev/null
444
- bunx opencli exec <URL> <some-resource> <some-action> --oc-curl
433
+ bunx specli exec <URL> __schema --json --min > /dev/null
434
+ bunx specli exec <URL> <some-resource> <some-action> --curl
445
435
  ```
446
436
 
447
- Note: Kubernetes publishes a Swagger 2.0 document (`swagger.json`) which is not OpenAPI 3.x. OpenCLI currently expects `openapi: "3.x"` and will reject Swagger 2.0 specs.
437
+ Note: Kubernetes publishes a Swagger 2.0 document (`swagger.json`) which is not OpenAPI 3.x. specli currently expects `openapi: "3.x"` and will reject Swagger 2.0 specs.
448
438
 
449
439
  ## Limitations (Important)
450
440
 
451
- OpenCLI is intentionally v1-simple; common gaps for real-world specs:
441
+ specli is intentionally v1-simple; common gaps for real-world specs:
452
442
 
453
443
  - OpenAPI 3.x only (Swagger 2.0 not supported).
454
444
  - Parameter serialization is simplified:
package/cli.ts CHANGED
@@ -8,7 +8,7 @@ function collect(value: string, previous: string[] = []): string[] {
8
8
 
9
9
  const program = new Command();
10
10
 
11
- program.name("opencli").description("Generate CLIs from OpenAPI specs");
11
+ program.name("specli").description("Generate CLIs from OpenAPI specs");
12
12
 
13
13
  // ─────────────────────────────────────────────────────────────
14
14
  // exec command - runs spec dynamically
@@ -51,21 +51,15 @@ program
51
51
  .option("--bytecode", "Enable bytecode compilation")
52
52
  .option("--no-dotenv", "Disable .env autoload")
53
53
  .option("--no-bunfig", "Disable bunfig.toml autoload")
54
- .option(
55
- "--exec-argv <arg>",
56
- "Embedded process.execArgv (repeatable)",
57
- collect,
58
- [],
59
- )
60
54
  .option("--define <k=v>", "Build-time constant (repeatable)", collect, [])
61
- .option("--server <url>", "Default server URL (baked in)")
55
+ .option("--server <url>", "Default server URL (embedded)")
62
56
  .option(
63
57
  "--server-var <k=v>",
64
- "Default server variable (repeatable)",
58
+ "Default server variable (repeatable, embedded)",
65
59
  collect,
66
60
  [],
67
61
  )
68
- .option("--auth <scheme>", "Default auth scheme")
62
+ .option("--auth <scheme>", "Default auth scheme (embedded)")
69
63
  .action(async (spec, options) => {
70
64
  const { compileCommand } = await import("./src/cli/compile.ts");
71
65
  await compileCommand(spec, options);
package/package.json CHANGED
@@ -2,10 +2,16 @@
2
2
  "name": "specli",
3
3
  "module": "index.ts",
4
4
  "type": "module",
5
- "version": "0.0.1",
5
+ "version": "0.0.3",
6
6
  "bin": {
7
- "opencli": "./cli.ts"
7
+ "specli": "./cli.ts"
8
8
  },
9
+ "files": [
10
+ "cli.ts",
11
+ "index.ts",
12
+ "src",
13
+ "!**/*.test.ts"
14
+ ],
9
15
  "scripts": {
10
16
  "lint": "biome ci",
11
17
  "lint:check": "biome check --write --unsafe",
@@ -8,7 +8,6 @@ export type CompileOptions = {
8
8
  bytecode?: boolean;
9
9
  dotenv?: boolean; // --no-dotenv sets this to false
10
10
  bunfig?: boolean; // --no-bunfig sets this to false
11
- execArgv?: string[];
12
11
  define?: string[];
13
12
  server?: string;
14
13
  serverVar?: string[];
@@ -37,23 +36,6 @@ export async function compileCommand(
37
36
  ? (options.target as Bun.Build.Target)
38
37
  : (`bun-${process.platform}-${process.arch}` as Bun.Build.Target);
39
38
 
40
- // Build embedded execArgv for runtime defaults
41
- const embeddedExecArgv: string[] = [];
42
- if (options.server) {
43
- embeddedExecArgv.push(`--server=${options.server}`);
44
- }
45
- if (options.serverVar) {
46
- for (const pair of options.serverVar) {
47
- embeddedExecArgv.push(`--server-var=${pair}`);
48
- }
49
- }
50
- if (options.auth) {
51
- embeddedExecArgv.push(`--auth=${options.auth}`);
52
- }
53
-
54
- // User-provided exec-argv
55
- const compileExecArgv = options.execArgv ?? [];
56
-
57
39
  // Parse --define pairs
58
40
  const define: Record<string, string> = {};
59
41
  if (options.define) {
@@ -78,14 +60,6 @@ export async function compileCommand(
78
60
  buildArgs.push("--define", `${k}=${v}`);
79
61
  }
80
62
 
81
- const execArgv =
82
- embeddedExecArgv.length || compileExecArgv.length
83
- ? [...embeddedExecArgv, ...compileExecArgv]
84
- : [];
85
- for (const arg of execArgv) {
86
- buildArgs.push("--compile-exec-argv", arg);
87
- }
88
-
89
63
  if (options.dotenv === false) buildArgs.push("--no-compile-autoload-dotenv");
90
64
  if (options.bunfig === false) buildArgs.push("--no-compile-autoload-bunfig");
91
65
 
@@ -97,8 +71,11 @@ export async function compileCommand(
97
71
  stderr: "pipe",
98
72
  env: {
99
73
  ...process.env,
100
- OPENCLI_EMBED_SPEC: spec,
101
- OPENCLI_CLI_NAME: name,
74
+ SPECLI_SPEC: spec,
75
+ SPECLI_NAME: name,
76
+ SPECLI_SERVER: options.server ?? "",
77
+ SPECLI_SERVER_VARS: options.serverVar?.join(",") ?? "",
78
+ SPECLI_AUTH: options.auth ?? "",
102
79
  },
103
80
  });
104
81
 
@@ -12,7 +12,7 @@ const RESERVED_NAMES = [
12
12
  * Priority:
13
13
  * 1. info.title (kebab-cased, sanitized)
14
14
  * 2. Host from spec URL (if URL provided)
15
- * 3. Fallback to "opencli"
15
+ * 3. Fallback to "specli"
16
16
  */
17
17
  export async function deriveBinaryName(spec: string): Promise<string> {
18
18
  try {
@@ -48,7 +48,7 @@ export async function deriveBinaryName(spec: string): Promise<string> {
48
48
  }
49
49
 
50
50
  // Fallback
51
- return "opencli";
51
+ return "specli";
52
52
  }
53
53
 
54
54
  async function loadSpecText(spec: string): Promise<string> {
package/src/cli/exec.ts CHANGED
@@ -26,7 +26,7 @@ export async function execCommand(
26
26
  // [node, script, --spec, <spec>, ...options, ...remainingArgs]
27
27
  const argv = [
28
28
  process.argv[0] ?? "bun",
29
- process.argv[1] ?? "opencli",
29
+ process.argv[1] ?? "specli",
30
30
  "--spec",
31
31
  spec,
32
32
  ];
package/src/cli/main.ts CHANGED
@@ -18,13 +18,16 @@ import { stableStringify } from "./stable-json.ts";
18
18
  type MainOptions = {
19
19
  embeddedSpecText?: string;
20
20
  cliName?: string;
21
+ server?: string;
22
+ serverVars?: string[];
23
+ auth?: string;
21
24
  };
22
25
 
23
26
  export async function main(argv: string[], options: MainOptions = {}) {
24
27
  const program = new Command();
25
28
 
26
29
  program
27
- .name(options.cliName ?? "opencli")
30
+ .name(options.cliName ?? "specli")
28
31
  .description("Generate a CLI from an OpenAPI spec")
29
32
  .option("--spec <urlOrPath>", "OpenAPI URL or file path")
30
33
  .option("--server <url>", "Override server/base URL")
@@ -39,31 +42,10 @@ export async function main(argv: string[], options: MainOptions = {}) {
39
42
  .option("--username <username>", "Basic auth username")
40
43
  .option("--password <password>", "Basic auth password")
41
44
  .option("--api-key <key>", "API key value")
42
- .option("--profile <name>", "Profile name (stored under ~/.config/opencli)")
45
+ .option("--profile <name>", "Profile name (stored under ~/.config/specli)")
43
46
  .option("--json", "Machine-readable output")
44
47
  .showHelpAfterError();
45
48
 
46
- // Provide namespaced variants for flags which may collide with operation flags.
47
- // (Some real-world APIs define parameters named "accept", etc.)
48
- program
49
- .option(
50
- "--oc-header <header>",
51
- "Extra header (repeatable, namespaced)",
52
- collectRepeatable,
53
- )
54
- .option("--oc-accept <type>", "Override Accept header (namespaced)")
55
- .option("--oc-status", "Include status in --json output (namespaced)")
56
- .option("--oc-headers", "Include headers in --json output (namespaced)")
57
- .option("--oc-dry-run", "Print request without sending (namespaced)")
58
- .option("--oc-curl", "Print curl command without sending (namespaced)")
59
- .option("--oc-timeout <ms>", "Request timeout in milliseconds (namespaced)")
60
- .option("--oc-data <data>", "Inline request body (namespaced)")
61
- .option("--oc-file <path>", "Request body from file (namespaced)")
62
- .option(
63
- "--oc-content-type <type>",
64
- "Override Content-Type (defaults from OpenAPI) (namespaced)",
65
- );
66
-
67
49
  // If user asks for help and we have no embedded spec and no --spec, show minimal help.
68
50
  const spec = getArgValue(argv, "--spec");
69
51
  const wantsHelp = hasAnyArg(argv, ["-h", "--help"]);
@@ -83,7 +65,7 @@ export async function main(argv: string[], options: MainOptions = {}) {
83
65
 
84
66
  const profileCmd = program
85
67
  .command("profile")
86
- .description("Manage OpenCLI profiles");
68
+ .description("Manage specli profiles");
87
69
 
88
70
  profileCmd
89
71
  .command("list")
@@ -318,9 +300,7 @@ export async function main(argv: string[], options: MainOptions = {}) {
318
300
  const args = op.pathArgs.length
319
301
  ? ` ${op.pathArgs.map((a) => `<${a}>`).join(" ")}`
320
302
  : "";
321
- process.stdout.write(
322
- `- opencli ${op.resource} ${op.action}${args}\n`,
323
- );
303
+ process.stdout.write(`- specli ${op.resource} ${op.action}${args}\n`);
324
304
  }
325
305
  }
326
306
  });
@@ -330,6 +310,11 @@ export async function main(argv: string[], options: MainOptions = {}) {
330
310
  authSchemes: ctx.authSchemes,
331
311
  commands: ctx.commands,
332
312
  specId: ctx.loaded.id,
313
+ embeddedDefaults: {
314
+ server: options.server,
315
+ serverVars: options.serverVars,
316
+ auth: options.auth,
317
+ },
333
318
  });
334
319
 
335
320
  await program.parseAsync(argv);
@@ -1,8 +1,9 @@
1
1
  import type { AuthScheme } from "../../auth-schemes.ts";
2
2
 
3
3
  export type AuthInputs = {
4
- profileAuthScheme?: string;
5
4
  flagAuthScheme?: string;
5
+ profileAuthScheme?: string;
6
+ embeddedAuthScheme?: string;
6
7
  };
7
8
 
8
9
  export function resolveAuthScheme(
@@ -10,7 +11,7 @@ export function resolveAuthScheme(
10
11
  required: import("../../auth-requirements.ts").AuthSummary,
11
12
  inputs: AuthInputs,
12
13
  ): string | undefined {
13
- // Explicit flag wins (but may still be validated later when applying).
14
+ // Priority: CLI flag > profile > embedded default
14
15
  if (inputs.flagAuthScheme) return inputs.flagAuthScheme;
15
16
 
16
17
  if (
@@ -20,6 +21,13 @@ export function resolveAuthScheme(
20
21
  return inputs.profileAuthScheme;
21
22
  }
22
23
 
24
+ if (
25
+ inputs.embeddedAuthScheme &&
26
+ authSchemes.some((s) => s.key === inputs.embeddedAuthScheme)
27
+ ) {
28
+ return inputs.embeddedAuthScheme;
29
+ }
30
+
23
31
  // If operation requires exactly one scheme, choose it.
24
32
  const alts = required.alternatives;
25
33
  if (alts.length === 1 && alts[0]?.length === 1) return alts[0][0]?.key;