specli 0.0.5 → 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 (208) 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 +3 -2
  201. package/src/cli/runtime/body.ts +3 -3
  202. package/src/cli/runtime/compat.ts +89 -0
  203. package/src/cli/runtime/execute.ts +98 -39
  204. package/src/cli/runtime/generated.ts +111 -4
  205. package/src/cli/runtime/profile/secrets.ts +42 -1
  206. package/src/cli/runtime/profile/store.ts +15 -13
  207. package/src/cli/runtime/request.ts +12 -4
  208. package/src/cli/spec-loader.ts +2 -2
@@ -1,7 +1,7 @@
1
1
  import { Command } from "commander";
2
2
 
3
3
  import type { AuthScheme } from "../auth-schemes.ts";
4
- import type { CommandModel } from "../command-model.ts";
4
+ import type { CommandAction, CommandModel } from "../command-model.ts";
5
5
  import type { ServerInfo } from "../server.ts";
6
6
 
7
7
  import { type BodyFlagDef, generateBodyFlags } from "./body-flags.ts";
@@ -9,6 +9,106 @@ import { executeAction } from "./execute.ts";
9
9
  import type { EmbeddedDefaults } from "./request.ts";
10
10
  import { coerceArrayInput, coerceValue } from "./validate/index.ts";
11
11
 
12
+ // Flag type from CommandAction
13
+ type CommandFlag = CommandAction["flags"][number];
14
+
15
+ /**
16
+ * Format help output that is clear for both humans and AI agents.
17
+ * Groups options into Required, Optional, and Global sections.
18
+ */
19
+ function formatCustomHelp(
20
+ cmd: Command,
21
+ action: CommandAction,
22
+ operationFlags: CommandFlag[],
23
+ bodyFlagDefs: BodyFlagDef[],
24
+ ): string {
25
+ const lines: string[] = [];
26
+ const cmdName = cmd.name();
27
+ const parentName = cmd.parent?.name() ?? "";
28
+ const fullCmd = parentName ? `${parentName} ${cmdName}` : cmdName;
29
+
30
+ // Usage line
31
+ const positionals = action.positionals.map((p) => `<${p.name}>`).join(" ");
32
+ const usageSuffix = positionals ? ` ${positionals}` : "";
33
+ lines.push(`Usage: ${fullCmd}${usageSuffix} [options]`);
34
+ lines.push("");
35
+
36
+ // Description
37
+ const desc =
38
+ action.summary ?? action.description ?? `${action.method} ${action.path}`;
39
+ lines.push(desc);
40
+ lines.push("");
41
+
42
+ // Collect all options into categories
43
+ const requiredOpts: string[] = [];
44
+ const optionalOpts: string[] = [];
45
+
46
+ // Format a single option line
47
+ const formatOpt = (
48
+ flag: string,
49
+ type: string,
50
+ desc: string,
51
+ required: boolean,
52
+ ): string => {
53
+ const typeStr = type === "boolean" ? "" : ` <${type}>`;
54
+ const reqMarker = required ? " (required)" : "";
55
+ return ` ${flag}${typeStr}${reqMarker}\n ${desc}`;
56
+ };
57
+
58
+ // Operation flags (query/header/path params)
59
+ for (const f of operationFlags) {
60
+ const type = f.type === "array" ? `${f.itemType ?? "string"}[]` : f.type;
61
+ const line = formatOpt(
62
+ f.flag,
63
+ type,
64
+ f.description ?? `${f.in} parameter`,
65
+ f.required,
66
+ );
67
+ if (f.required) {
68
+ requiredOpts.push(line);
69
+ } else {
70
+ optionalOpts.push(line);
71
+ }
72
+ }
73
+
74
+ // Body flags
75
+ for (const def of bodyFlagDefs) {
76
+ const line = formatOpt(def.flag, def.type, def.description, def.required);
77
+ if (def.required) {
78
+ requiredOpts.push(line);
79
+ } else {
80
+ optionalOpts.push(line);
81
+ }
82
+ }
83
+
84
+ // Required options section
85
+ if (requiredOpts.length > 0) {
86
+ lines.push("Required:");
87
+ lines.push(...requiredOpts);
88
+ lines.push("");
89
+ }
90
+
91
+ // Optional options section
92
+ if (optionalOpts.length > 0) {
93
+ lines.push("Options:");
94
+ lines.push(...optionalOpts);
95
+ lines.push("");
96
+ }
97
+
98
+ // Global options (always available)
99
+ lines.push("Global:");
100
+ lines.push(" --curl\n Print curl command instead of executing");
101
+ lines.push(" --json\n Output response as JSON");
102
+ lines.push(" --server <url>\n Override the API server URL");
103
+ lines.push(
104
+ " --bearer-token <token>\n Provide auth token (or use 'login' command)",
105
+ );
106
+ lines.push(" -h, --help\n Show this help message");
107
+ lines.push("");
108
+
109
+ return lines.join("\n");
110
+ }
111
+
12
112
  export type GeneratedCliContext = {
13
113
  servers: ServerInfo[];
14
114
  authSchemes: AuthScheme[];
@@ -78,11 +178,11 @@ export function addGeneratedCommands(
78
178
  }
79
179
 
80
180
  // Collect reserved flags: operation params + --curl
81
- const operationFlags = new Set(action.flags.map((f) => f.flag));
82
- const reservedFlags = new Set([...operationFlags, "--curl"]);
181
+ const operationFlagSet = new Set(action.flags.map((f) => f.flag));
182
+ const reservedFlags = new Set([...operationFlagSet, "--curl"]);
83
183
 
84
184
  // Only --curl is a built-in flag (for debugging)
85
- if (!operationFlags.has("--curl")) {
185
+ if (!operationFlagSet.has("--curl")) {
86
186
  cmd.option("--curl", "Print curl command without sending");
87
187
  }
88
188
 
@@ -106,6 +206,12 @@ export function addGeneratedCommands(
106
206
  }
107
207
  }
108
208
 
209
+ // Custom help output for better agent/human readability
210
+ cmd.configureHelp({
211
+ formatHelp: () =>
212
+ formatCustomHelp(cmd, action, action.flags, bodyFlagDefs),
213
+ });
214
+
109
215
  // Commander passes positional args and then the Command instance as last arg.
110
216
  cmd.action(async (...args) => {
111
217
  const command = args[args.length - 1];
@@ -128,6 +234,7 @@ export function addGeneratedCommands(
128
234
  specId: context.specId,
129
235
  embeddedDefaults: context.embeddedDefaults,
130
236
  bodyFlagDefs,
237
+ resourceName: resource.resource,
131
238
  });
132
239
  });
133
240
  }
@@ -1,4 +1,6 @@
1
- import { secrets } from "bun";
1
+ import { isBun } from "../compat.ts";
2
+
3
+ const bunLiteral = "bun" as const;
2
4
 
3
5
  export type SecretKey = {
4
6
  service: string;
@@ -16,27 +18,66 @@ export function tokenSecretKey(specId: string, profile: string): SecretKey {
16
18
  };
17
19
  }
18
20
 
21
+ /**
22
+ * Store a token securely.
23
+ * In Bun: uses the native secrets store (system keychain)
24
+ * In Node.js: secrets are not supported, warns user
25
+ */
19
26
  export async function setToken(
20
27
  specId: string,
21
28
  profile: string,
22
29
  token: string,
23
30
  ): Promise<void> {
31
+ if (!isBun) {
32
+ console.warn(
33
+ "Warning: Secure token storage requires Bun. Token will not be persisted.",
34
+ );
35
+ console.warn(
36
+ "Use --bearer-token <token> flag instead when running with Node.js.",
37
+ );
38
+ return;
39
+ }
40
+
41
+ const { secrets } = await import(bunLiteral);
24
42
  const key = tokenSecretKey(specId, profile);
25
43
  await secrets.set({ service: key.service, name: key.name, value: token });
26
44
  }
27
45
 
46
+ /**
47
+ * Retrieve a stored token.
48
+ * In Bun: retrieves from the native secrets store
49
+ * In Node.js: returns null (secrets not supported)
50
+ */
28
51
  export async function getToken(
29
52
  specId: string,
30
53
  profile: string,
31
54
  ): Promise<string | null> {
55
+ if (!isBun) {
56
+ return null;
57
+ }
58
+
59
+ const { secrets } = await import(bunLiteral);
32
60
  const key = tokenSecretKey(specId, profile);
33
61
  return await secrets.get({ service: key.service, name: key.name });
34
62
  }
35
63
 
64
+ /**
65
+ * Delete a stored token.
66
+ * In Bun: removes from the native secrets store
67
+ * In Node.js: returns false (secrets not supported)
68
+ */
36
69
  export async function deleteToken(
37
70
  specId: string,
38
71
  profile: string,
39
72
  ): Promise<boolean> {
73
+ if (!isBun) {
74
+ console.warn(
75
+ "Warning: Secure token storage requires Bun. No token to delete.",
76
+ );
77
+ return false;
78
+ }
79
+
80
+ const { secrets } = await import(bunLiteral);
40
81
  const key = tokenSecretKey(specId, profile);
41
82
  return await secrets.delete({ service: key.service, name: key.name });
42
83
  }
@@ -1,4 +1,10 @@
1
- import { YAML } from "bun";
1
+ import {
2
+ fileExists,
3
+ mkdirp,
4
+ parseYamlContent,
5
+ readFileText,
6
+ writeFileText,
7
+ } from "../compat.ts";
2
8
 
3
9
  export type Profile = {
4
10
  name: string;
@@ -32,21 +38,17 @@ export async function readProfiles(): Promise<ProfilesFile> {
32
38
  const jsonPath = configPathJson();
33
39
  const yamlPath = configPathYaml();
34
40
 
35
- const jsonFile = Bun.file(jsonPath);
36
- const yamlFile = Bun.file(yamlPath);
41
+ const jsonExists = await fileExists(jsonPath);
42
+ const yamlExists = await fileExists(yamlPath);
37
43
 
38
- const file = (await jsonFile.exists())
39
- ? jsonFile
40
- : (await yamlFile.exists())
41
- ? yamlFile
42
- : null;
44
+ const filePath = jsonExists ? jsonPath : yamlExists ? yamlPath : null;
43
45
 
44
- if (!file) return { profiles: [] };
46
+ if (!filePath) return { profiles: [] };
45
47
 
46
- const text = await file.text();
48
+ const text = await readFileText(filePath);
47
49
  let parsed: unknown;
48
50
  try {
49
- parsed = YAML.parse(text) as unknown;
51
+ parsed = parseYamlContent(text) as unknown;
50
52
  } catch {
51
53
  parsed = JSON.parse(text) as unknown;
52
54
  }
@@ -70,8 +72,8 @@ export async function readProfiles(): Promise<ProfilesFile> {
70
72
 
71
73
  export async function writeProfiles(data: ProfilesFile): Promise<void> {
72
74
  const dir = configDir();
73
- await Bun.$`mkdir -p ${dir}`;
74
- await Bun.write(configPathJson(), JSON.stringify(data, null, 2));
75
+ await mkdirp(dir);
76
+ await writeFileText(configPathJson(), JSON.stringify(data, null, 2));
75
77
  }
76
78
 
77
79
  export function getProfile(
@@ -275,9 +275,18 @@ export async function buildRequest(
275
275
 
276
276
  const schema = input.action.requestBodySchema;
277
277
 
278
+ // Check if there are any required fields in the body
279
+ const requiredFields = bodyFlagDefs.filter((d) => d.required);
280
+
278
281
  if (!hasBodyFlags) {
282
+ if (requiredFields.length > 0) {
283
+ // Error: user must provide required fields
284
+ const flagList = requiredFields.map((d) => `--${d.path.join(".")}`);
285
+ throw new Error(`Required: ${flagList.join(", ")}`);
286
+ }
287
+ // No required fields - send empty body if body is required, otherwise skip
279
288
  if (input.action.requestBody.required) {
280
- throw new Error("Missing required request body fields.");
289
+ body = "{}";
281
290
  }
282
291
  } else {
283
292
  if (!contentType?.includes("json")) {
@@ -292,9 +301,8 @@ export async function buildRequest(
292
301
  );
293
302
  const missing = findMissingRequired(input.flagValues, bodyFlagDefs);
294
303
  if (missing.length > 0) {
295
- throw new Error(
296
- `Missing required body field '${missing[0]}'. Provide --${missing[0]}.`,
297
- );
304
+ const missingFlags = missing.map((m) => `--${m}`).join(", ");
305
+ throw new Error(`Missing required fields: ${missingFlags}`);
298
306
  }
299
307
 
300
308
  // Build nested object from dot-notation flags
@@ -1,7 +1,7 @@
1
1
  import SwaggerParser from "@apidevtools/swagger-parser";
2
- import { YAML } from "bun";
3
2
 
4
3
  import { sha256Hex } from "./crypto.ts";
4
+ import { parseYamlContent } from "./runtime/compat.ts";
5
5
  import { getSpecId } from "./spec-id.ts";
6
6
  import { stableStringify } from "./stable-json.ts";
7
7
  import type { LoadedSpec, OpenApiDoc, SpecSource } from "./types.ts";
@@ -21,7 +21,7 @@ function parseSpecText(text: string): unknown {
21
21
  return JSON.parse(text);
22
22
  }
23
23
 
24
- return YAML.parse(text);
24
+ return parseYamlContent(text);
25
25
  }
26
26
 
27
27
  export async function loadSpec(options: LoadSpecOptions): Promise<LoadedSpec> {