@epilot/cli 0.1.0

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 (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +354 -0
  3. package/definitions/access-token.json +663 -0
  4. package/definitions/address-suggestions.json +582 -0
  5. package/definitions/address.json +578 -0
  6. package/definitions/ai-agents.json +1711 -0
  7. package/definitions/app.json +4443 -0
  8. package/definitions/audit-logs.json +305 -0
  9. package/definitions/automation.json +4815 -0
  10. package/definitions/billing.json +837 -0
  11. package/definitions/blueprint-manifest.json +3376 -0
  12. package/definitions/consent.json +344 -0
  13. package/definitions/customer-portal.json +15000 -0
  14. package/definitions/dashboard.json +484 -0
  15. package/definitions/data-management.json +962 -0
  16. package/definitions/deduplication.json +183 -0
  17. package/definitions/design.json +1423 -0
  18. package/definitions/document.json +758 -0
  19. package/definitions/email-settings.json +2627 -0
  20. package/definitions/email-template.json +1419 -0
  21. package/definitions/entity-mapping.json +1642 -0
  22. package/definitions/entity.json +10074 -0
  23. package/definitions/environments.json +363 -0
  24. package/definitions/erp-integration.json +5845 -0
  25. package/definitions/event-catalog.json +1051 -0
  26. package/definitions/file.json +2842 -0
  27. package/definitions/iban.json +132 -0
  28. package/definitions/journey.json +2341 -0
  29. package/definitions/kanban.json +929 -0
  30. package/definitions/message.json +2660 -0
  31. package/definitions/metering.json +2321 -0
  32. package/definitions/notes.json +1531 -0
  33. package/definitions/notification.json +1425 -0
  34. package/definitions/organization.json +629 -0
  35. package/definitions/partner-directory.json +1718 -0
  36. package/definitions/permissions.json +1480 -0
  37. package/definitions/pricing-tier.json +105 -0
  38. package/definitions/pricing.json +9884 -0
  39. package/definitions/purpose.json +524 -0
  40. package/definitions/sandbox.json +453 -0
  41. package/definitions/submission.json +313 -0
  42. package/definitions/targeting.json +1474 -0
  43. package/definitions/template-variables.json +1408 -0
  44. package/definitions/user.json +2408 -0
  45. package/definitions/validation-rules.json +1491 -0
  46. package/definitions/webhooks.json +1525 -0
  47. package/definitions/workflow-definition.json +3417 -0
  48. package/definitions/workflow.json +4106 -0
  49. package/dist/access-token-OG5AR7UB.js +51 -0
  50. package/dist/address-QUSMK5GV.js +51 -0
  51. package/dist/address-suggestions-E5SQNUS5.js +51 -0
  52. package/dist/ai-agents-PM42SJY3.js +51 -0
  53. package/dist/app-YTM3XAJL.js +51 -0
  54. package/dist/audit-logs-NXP7GFKX.js +51 -0
  55. package/dist/auth-CCBTXH5U.js +113 -0
  56. package/dist/auth-login-2ZIXM47J.js +137 -0
  57. package/dist/auth-token-OS4BEEVZ.js +43 -0
  58. package/dist/automation-TDJASTEV.js +51 -0
  59. package/dist/billing-M4MRBLEK.js +51 -0
  60. package/dist/bin/epilot.js +104 -0
  61. package/dist/blueprint-manifest-NQL7NRMV.js +51 -0
  62. package/dist/chunk-57PPARIW.js +715 -0
  63. package/dist/chunk-5WUPDZ5D.js +76 -0
  64. package/dist/chunk-IST42ZNL.js +78 -0
  65. package/dist/chunk-RC3GCXCI.js +76 -0
  66. package/dist/chunk-TKZLQD2B.js +72 -0
  67. package/dist/chunk-UJ6TU34M.js +56 -0
  68. package/dist/completion-GRQM2FJQ.js +168 -0
  69. package/dist/consent-KQ7MJAS6.js +51 -0
  70. package/dist/customer-portal-VUVSKWAQ.js +51 -0
  71. package/dist/dashboard-GVR4XNGR.js +51 -0
  72. package/dist/data-management-2RD3DLOS.js +51 -0
  73. package/dist/deduplication-PY77EINR.js +51 -0
  74. package/dist/design-M4FP2K5R.js +51 -0
  75. package/dist/document-P4QA7LEZ.js +51 -0
  76. package/dist/email-settings-7HGGRCCM.js +51 -0
  77. package/dist/email-template-3HXQI4CH.js +51 -0
  78. package/dist/entity-XUESZBPJ.js +51 -0
  79. package/dist/entity-mapping-JBKWWBH2.js +51 -0
  80. package/dist/environments-KKOS7ONY.js +51 -0
  81. package/dist/erp-integration-YTOWHCAW.js +51 -0
  82. package/dist/event-catalog-UKLZUGC4.js +51 -0
  83. package/dist/file-IFZNZ547.js +51 -0
  84. package/dist/iban-X2IW2NWU.js +51 -0
  85. package/dist/interactive-46ICLQKL.js +16 -0
  86. package/dist/journey-JU6X2KMX.js +51 -0
  87. package/dist/kanban-VHUU44PM.js +51 -0
  88. package/dist/message-AOUWJ4YX.js +51 -0
  89. package/dist/metering-RDS3XBD5.js +51 -0
  90. package/dist/notes-WE2UC75B.js +51 -0
  91. package/dist/notification-FKFNBHYZ.js +51 -0
  92. package/dist/organization-LMNFF6BX.js +51 -0
  93. package/dist/partner-directory-IIZVQDXJ.js +51 -0
  94. package/dist/permissions-AYCMVM7Y.js +51 -0
  95. package/dist/pricing-PS26FWBS.js +51 -0
  96. package/dist/pricing-tier-FBXWQ6T3.js +51 -0
  97. package/dist/profile-5Q5YARG7.js +135 -0
  98. package/dist/purpose-HE4E4SVU.js +51 -0
  99. package/dist/sandbox-Z7BU4UAD.js +51 -0
  100. package/dist/submission-MWVDF2ZB.js +51 -0
  101. package/dist/targeting-7NM5GDJ6.js +51 -0
  102. package/dist/template-variables-AJAR7PAV.js +51 -0
  103. package/dist/user-A26XQXG3.js +51 -0
  104. package/dist/validation-rules-VZTISEG2.js +51 -0
  105. package/dist/webhooks-RXH67WZ3.js +51 -0
  106. package/dist/workflow-G4FUUGZQ.js +51 -0
  107. package/dist/workflow-definition-LJYLMMGD.js +51 -0
  108. package/package.json +62 -0
@@ -0,0 +1,715 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveToken
4
+ } from "./chunk-5WUPDZ5D.js";
5
+ import {
6
+ getResolvedProfile
7
+ } from "./chunk-IST42ZNL.js";
8
+ import {
9
+ isInteractive,
10
+ pickOperation,
11
+ printOperationsTable,
12
+ promptParam
13
+ } from "./chunk-RC3GCXCI.js";
14
+ import {
15
+ BOLD,
16
+ DIM,
17
+ GREEN,
18
+ RED,
19
+ RESET,
20
+ YELLOW,
21
+ isValidJson,
22
+ methodColor,
23
+ parseKeyValue,
24
+ parseParamValue
25
+ } from "./chunk-TKZLQD2B.js";
26
+
27
+ // src/lib/call.ts
28
+ import OpenAPIClientAxiosModule from "openapi-client-axios";
29
+
30
+ // src/lib/definition-loader.ts
31
+ import { existsSync, readFileSync } from "fs";
32
+ import { resolve, join, dirname } from "path";
33
+ import { fileURLToPath } from "url";
34
+ var __filename = fileURLToPath(import.meta.url);
35
+ var __dirname = dirname(__filename);
36
+ var loadDefinition = async (apiName, definitionOverride) => {
37
+ if (definitionOverride) {
38
+ if (definitionOverride.startsWith("http://") || definitionOverride.startsWith("https://")) {
39
+ const res = await fetch(definitionOverride);
40
+ if (!res.ok) {
41
+ throw new Error(`Failed to fetch definition from ${definitionOverride}: ${res.status} ${res.statusText}`);
42
+ }
43
+ return await res.json();
44
+ }
45
+ const absPath = resolve(definitionOverride);
46
+ if (!existsSync(absPath)) {
47
+ throw new Error(`Definition file not found: ${absPath}`);
48
+ }
49
+ return JSON.parse(readFileSync(absPath, "utf-8"));
50
+ }
51
+ const overridePath = join(process.cwd(), ".epilot", "overrides", `${apiName}.json`);
52
+ if (existsSync(overridePath)) {
53
+ return JSON.parse(readFileSync(overridePath, "utf-8"));
54
+ }
55
+ const searchPaths = [
56
+ // Built dist: dist/bin/epilot.js -> dist/definitions/
57
+ resolve(__dirname, "..", "definitions", `${apiName}.json`),
58
+ // Built dist (deeper): dist/lib/ -> dist/definitions/
59
+ resolve(__dirname, "..", "..", "definitions", `${apiName}.json`),
60
+ // Dev mode with tsx: src/lib/ -> definitions/
61
+ resolve(__dirname, "..", "..", "..", "definitions", `${apiName}.json`),
62
+ // Dev mode: packages/cli/definitions/
63
+ resolve(__dirname, "..", "..", "definitions", `${apiName}.json`)
64
+ ];
65
+ for (const path of searchPaths) {
66
+ if (existsSync(path)) {
67
+ return JSON.parse(readFileSync(path, "utf-8"));
68
+ }
69
+ }
70
+ throw new Error(
71
+ `No OpenAPI definition found for "${apiName}". Use --definition <file|url> to provide one, or place it at .epilot/overrides/${apiName}.json`
72
+ );
73
+ };
74
+
75
+ // src/lib/param-collector.ts
76
+ var getOperationParams = (spec, operationId) => {
77
+ for (const [_path, methods] of Object.entries(spec.paths ?? {})) {
78
+ if (!methods) continue;
79
+ const pathParams = methods.parameters || [];
80
+ for (const method of ["get", "post", "put", "patch", "delete", "head", "options"]) {
81
+ const op = methods[method];
82
+ if (!op || op.operationId !== operationId) continue;
83
+ const opParams = op.parameters || [];
84
+ const merged = [...pathParams.filter((p) => p.name)];
85
+ for (const p of opParams) {
86
+ if (!p.name) continue;
87
+ const idx = merged.findIndex((pp) => pp.name === p.name && pp.in === p.in);
88
+ if (idx >= 0) merged[idx] = p;
89
+ else merged.push(p);
90
+ }
91
+ return merged;
92
+ }
93
+ }
94
+ return [];
95
+ };
96
+ var collectParams = (params, paramFlags, positionalArgs) => {
97
+ const result = {};
98
+ const pathParams = params.filter((p) => p.in === "path");
99
+ for (let i = 0; i < positionalArgs.length && i < pathParams.length; i++) {
100
+ result[pathParams[i].name] = parseParamValue(positionalArgs[i]);
101
+ }
102
+ if (paramFlags) {
103
+ const flags = Array.isArray(paramFlags) ? paramFlags : [paramFlags];
104
+ for (const flag of flags) {
105
+ const [key, value] = parseKeyValue(flag);
106
+ result[key] = parseParamValue(value);
107
+ }
108
+ }
109
+ return result;
110
+ };
111
+ var getMissingRequired = (params, collected) => {
112
+ return params.filter((p) => p.required && !(p.name in collected)).map((p) => `${p.name} (${p.in})`);
113
+ };
114
+
115
+ // src/lib/body-handler.ts
116
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync, unlinkSync } from "fs";
117
+ import { homedir } from "os";
118
+ import { join as join2 } from "path";
119
+ var resolveBody = async (opts) => {
120
+ const { dataFlag, hasRequestBody, isRequired, interactive, defaultTemplate, cacheKey } = opts;
121
+ if (dataFlag) {
122
+ if (!isValidJson(dataFlag)) {
123
+ throw new Error("Invalid JSON in -d flag. Provide valid JSON data.");
124
+ }
125
+ return JSON.parse(dataFlag);
126
+ }
127
+ if (!process.stdin.isTTY) {
128
+ const input = await readStdin();
129
+ if (input.trim()) {
130
+ if (!isValidJson(input)) {
131
+ throw new Error("Invalid JSON from stdin. Provide valid JSON data.");
132
+ }
133
+ return JSON.parse(input);
134
+ }
135
+ }
136
+ if (hasRequestBody && interactive && process.stdin.isTTY) {
137
+ const cached = cacheKey ? loadPayloadCache(cacheKey) : void 0;
138
+ let editorDefault = cached ?? (defaultTemplate ? JSON.stringify(defaultTemplate, null, 2) : "{\n \n}");
139
+ const { editor } = await import("@inquirer/prompts");
140
+ const MAX_RETRIES = 3;
141
+ for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
142
+ const result = await editor({
143
+ message: attempt === 0 ? "Edit request body (JSON):" : "Fix JSON and save (or empty to cancel):",
144
+ default: editorDefault,
145
+ waitForUserInput: false
146
+ });
147
+ const trimmed = result.trim();
148
+ if (!trimmed) {
149
+ if (cacheKey) clearPayloadCache(cacheKey);
150
+ if (isRequired) {
151
+ throw new Error("Request body is required but editor returned empty content.");
152
+ }
153
+ return null;
154
+ }
155
+ if (isValidJson(trimmed)) {
156
+ if (cacheKey) savePayloadCache(cacheKey, trimmed);
157
+ return JSON.parse(trimmed);
158
+ }
159
+ const parseError = getJsonParseError(trimmed);
160
+ process.stderr.write(`\x1B[31mInvalid JSON: ${parseError}\x1B[0m
161
+ `);
162
+ editorDefault = trimmed;
163
+ }
164
+ throw new Error("Invalid JSON from editor after multiple attempts.");
165
+ }
166
+ if (hasRequestBody && isRequired) {
167
+ throw new Error(
168
+ `This operation requires a request body. Provide data with -d '{"key":"value"}' or pipe via stdin.`
169
+ );
170
+ }
171
+ return null;
172
+ };
173
+ var getRequestBodyInfo = (spec, operationId) => {
174
+ const paths = spec.paths ?? {};
175
+ for (const methods of Object.values(paths)) {
176
+ for (const method of ["get", "post", "put", "patch", "delete", "head", "options"]) {
177
+ const op = methods[method];
178
+ if (!op || op.operationId !== operationId) continue;
179
+ const reqBody = op.requestBody;
180
+ if (!reqBody) return { hasBody: false, isRequired: false };
181
+ return {
182
+ hasBody: true,
183
+ isRequired: !!reqBody.required
184
+ };
185
+ }
186
+ }
187
+ return { hasBody: false, isRequired: false };
188
+ };
189
+ var getPayloadCacheDir = () => {
190
+ const xdgConfig = process.env.XDG_CONFIG_HOME;
191
+ const base = xdgConfig || join2(homedir(), ".config");
192
+ return join2(base, "epilot", "cache");
193
+ };
194
+ var getPayloadCachePath = (cacheKey) => {
195
+ return join2(getPayloadCacheDir(), `${cacheKey.replace(/\//g, "_")}.json`);
196
+ };
197
+ var loadPayloadCache = (cacheKey) => {
198
+ const path = getPayloadCachePath(cacheKey);
199
+ if (!existsSync2(path)) return void 0;
200
+ try {
201
+ return readFileSync2(path, "utf-8");
202
+ } catch {
203
+ return void 0;
204
+ }
205
+ };
206
+ var savePayloadCache = (cacheKey, payload) => {
207
+ const dir = getPayloadCacheDir();
208
+ mkdirSync(dir, { recursive: true });
209
+ writeFileSync(getPayloadCachePath(cacheKey), payload, "utf-8");
210
+ };
211
+ var clearPayloadCache = (cacheKey) => {
212
+ const path = getPayloadCachePath(cacheKey);
213
+ if (existsSync2(path)) {
214
+ try {
215
+ unlinkSync(path);
216
+ } catch {
217
+ }
218
+ }
219
+ };
220
+ var getJsonParseError = (str) => {
221
+ try {
222
+ JSON.parse(str);
223
+ return "unknown error";
224
+ } catch (e) {
225
+ return e instanceof Error ? e.message : String(e);
226
+ }
227
+ };
228
+ var readStdin = () => {
229
+ return new Promise((resolve2) => {
230
+ let data = "";
231
+ process.stdin.setEncoding("utf-8");
232
+ const timeout = setTimeout(() => {
233
+ process.stdin.removeAllListeners("data");
234
+ process.stdin.removeAllListeners("end");
235
+ resolve2(data);
236
+ }, 100);
237
+ process.stdin.on("data", (chunk) => {
238
+ data += chunk;
239
+ });
240
+ process.stdin.on("end", () => {
241
+ clearTimeout(timeout);
242
+ resolve2(data);
243
+ });
244
+ if (process.stdin.readableEnded) {
245
+ clearTimeout(timeout);
246
+ resolve2(data);
247
+ }
248
+ });
249
+ };
250
+
251
+ // src/lib/response-formatter.ts
252
+ var formatResponse = async (response, options) => {
253
+ const { json, include, verbose, jsonata } = options;
254
+ if (verbose) {
255
+ const req = response.config;
256
+ process.stderr.write(`${DIM}${req.method?.toUpperCase()} ${req.url}${RESET}
257
+ `);
258
+ if (req.headers) {
259
+ for (const [key, value] of Object.entries(req.headers)) {
260
+ if (typeof value === "string" && key.toLowerCase() !== "authorization") {
261
+ process.stderr.write(`${DIM}> ${key}: ${value}${RESET}
262
+ `);
263
+ } else if (key.toLowerCase() === "authorization") {
264
+ process.stderr.write(`${DIM}> ${key}: Bearer ***${RESET}
265
+ `);
266
+ }
267
+ }
268
+ }
269
+ process.stderr.write("\n");
270
+ }
271
+ if (!json && process.stdout.isTTY && process.stderr.isTTY) {
272
+ const statusColor = response.status >= 200 && response.status < 300 ? GREEN : response.status >= 400 ? RED : YELLOW;
273
+ process.stderr.write(
274
+ `${statusColor}${BOLD}${response.status}${RESET} ${statusColor}${response.statusText}${RESET}
275
+ `
276
+ );
277
+ }
278
+ if (include) {
279
+ process.stderr.write(`${DIM}HTTP/${response.status} ${response.statusText}${RESET}
280
+ `);
281
+ for (const [key, value] of Object.entries(response.headers)) {
282
+ process.stderr.write(`${DIM}${key}: ${value}${RESET}
283
+ `);
284
+ }
285
+ process.stderr.write("\n");
286
+ }
287
+ let data = response.data;
288
+ if (jsonata && data) {
289
+ try {
290
+ const jsonataModule = await import("jsonata");
291
+ const expression = jsonataModule.default(jsonata);
292
+ data = await expression.evaluate(data);
293
+ } catch (err) {
294
+ process.stderr.write(`${RED}JSONata error: ${err instanceof Error ? err.message : String(err)}${RESET}
295
+ `);
296
+ process.exit(1);
297
+ }
298
+ }
299
+ if (data !== void 0 && data !== null) {
300
+ if (typeof data === "string") {
301
+ process.stdout.write(data + "\n");
302
+ } else {
303
+ const indent = json ? 0 : 2;
304
+ process.stdout.write(JSON.stringify(data, null, indent) + "\n");
305
+ }
306
+ }
307
+ };
308
+
309
+ // src/lib/call.ts
310
+ import { mock } from "mock-json-schema";
311
+ import dereferenceJsonSchema from "dereference-json-schema";
312
+ var OpenAPIClientAxios = OpenAPIClientAxiosModule.default ?? OpenAPIClientAxiosModule;
313
+ var extractOperations = (spec) => {
314
+ const operations = [];
315
+ for (const [path, methods] of Object.entries(spec.paths ?? {})) {
316
+ if (!methods) continue;
317
+ for (const method of ["get", "post", "put", "patch", "delete", "head", "options"]) {
318
+ const op = methods[method];
319
+ if (!op?.operationId) continue;
320
+ operations.push({
321
+ operationId: op.operationId,
322
+ method: method.toUpperCase(),
323
+ path,
324
+ summary: ((op.description || "").split("\n")[0] || "").substring(0, 120)
325
+ });
326
+ }
327
+ }
328
+ return operations;
329
+ };
330
+ var sampleParamValue = (p) => {
331
+ const schema = p.schema;
332
+ if (p.example !== void 0) return String(p.example);
333
+ if (schema?.example !== void 0) return String(schema.example);
334
+ if (schema?.type === "boolean") return "true";
335
+ if (schema?.type === "integer" || schema?.type === "number") return "1";
336
+ if (p.name === "id" || p.name.endsWith("_id") || p.name.endsWith("Id"))
337
+ return "123e4567-e89b-12d3-a456-426614174000";
338
+ if (p.name === "slug") return "contact";
339
+ if (p.name === "email") return "user@example.com";
340
+ return "example";
341
+ };
342
+ var MAX_BODY_LINES = 30;
343
+ var truncateJson = (obj, depth = 0, maxDepth = 3) => {
344
+ if (obj === null || obj === void 0) return obj;
345
+ if (typeof obj !== "object") return obj;
346
+ if (depth >= maxDepth) return Array.isArray(obj) ? [] : {};
347
+ if (Array.isArray(obj)) {
348
+ return obj.slice(0, 2).map((item) => truncateJson(item, depth + 1, maxDepth));
349
+ }
350
+ const result = {};
351
+ for (const [key, value] of Object.entries(obj)) {
352
+ result[key] = truncateJson(value, depth + 1, maxDepth);
353
+ }
354
+ return result;
355
+ };
356
+ var mockFromSchema = (schema) => {
357
+ return mock(schema);
358
+ };
359
+ var { dereferenceSync } = dereferenceJsonSchema;
360
+ var w = (text) => process.stdout.write(text);
361
+ var getBodySchema = (spec, operationId) => {
362
+ const paths = spec.paths ?? {};
363
+ for (const methods of Object.values(paths)) {
364
+ if (!methods) continue;
365
+ for (const method of ["get", "post", "put", "patch", "delete", "head", "options"]) {
366
+ const op = methods[method];
367
+ if (!op || op.operationId !== operationId) continue;
368
+ const reqBody = op.requestBody;
369
+ if (!reqBody) return void 0;
370
+ const content = reqBody.content?.["application/json"];
371
+ return content?.schema;
372
+ }
373
+ }
374
+ return void 0;
375
+ };
376
+ var printOperationHelp = (apiName, operationId, spec) => {
377
+ for (const [path, methods] of Object.entries(spec.paths ?? {})) {
378
+ if (!methods) continue;
379
+ for (const method of ["get", "post", "put", "patch", "delete", "head", "options"]) {
380
+ const op = methods[method];
381
+ if (!op || op.operationId !== operationId) continue;
382
+ const color = methodColor(method);
383
+ const descFirstLine = (op.description || "").split("\n")[0].trim();
384
+ w(`
385
+ ${BOLD}epilot ${apiName} ${operationId}${RESET}`);
386
+ if (descFirstLine) w(` \u2014 ${descFirstLine}`);
387
+ w(`
388
+
389
+ `);
390
+ w(` ${color}${method.toUpperCase()}${RESET} ${path}
391
+ `);
392
+ w(`
393
+ `);
394
+ if (op.description) {
395
+ const restOfDesc = op.description.split("\n").slice(1).join("\n").trim();
396
+ if (restOfDesc) w(` ${DIM}${restOfDesc}${RESET}
397
+
398
+ `);
399
+ }
400
+ const params = getOperationParams(spec, operationId);
401
+ if (params.length > 0) {
402
+ w(`${BOLD}PARAMETERS${RESET}
403
+
404
+ `);
405
+ const nameWidth = Math.max(...params.map((p) => p.name.length), 4) + 2;
406
+ for (const p of params) {
407
+ const schema = p.schema;
408
+ const type = schema?.type || "";
409
+ const format = schema?.format ? ` (${schema.format})` : "";
410
+ const req = p.required ? `${YELLOW}required${RESET}` : `${DIM}optional${RESET}`;
411
+ const desc = p.description ? ` ${DIM}${p.description}${RESET}` : "";
412
+ w(` ${BOLD}${p.name.padEnd(nameWidth)}${RESET} ${p.in.padEnd(6)} ${type}${format} ${req}${desc}
413
+ `);
414
+ }
415
+ w(`
416
+ `);
417
+ }
418
+ const reqBody = op.requestBody;
419
+ if (reqBody) {
420
+ w(`${BOLD}REQUEST BODY${RESET}${reqBody.required ? ` ${YELLOW}(required)${RESET}` : ""}
421
+ `);
422
+ if (reqBody.description) w(` ${DIM}${reqBody.description}${RESET}
423
+ `);
424
+ const content = reqBody.content?.["application/json"];
425
+ const bodySchema = content?.schema;
426
+ if (bodySchema) {
427
+ try {
428
+ const mockBody = truncateJson(mockFromSchema(bodySchema));
429
+ const bodyStr = JSON.stringify(mockBody, null, 2);
430
+ const lines = bodyStr.split("\n");
431
+ w(`
432
+ `);
433
+ if (lines.length <= MAX_BODY_LINES) {
434
+ for (const line of lines) w(` ${DIM}${line}${RESET}
435
+ `);
436
+ } else {
437
+ for (const line of lines.slice(0, MAX_BODY_LINES)) w(` ${DIM}${line}${RESET}
438
+ `);
439
+ w(` ${DIM} ...${RESET}
440
+ `);
441
+ }
442
+ } catch {
443
+ }
444
+ }
445
+ w(`
446
+ `);
447
+ }
448
+ w(`${BOLD}EXAMPLES${RESET}
449
+
450
+ `);
451
+ const reqParams = params.filter((p) => p.required || p.in === "path");
452
+ const pathParams = params.filter((p) => p.in === "path");
453
+ const pFlags = reqParams.map((p) => `-p ${p.name}=${sampleParamValue(p)}`);
454
+ {
455
+ const parts = [` ${GREEN}$${RESET} epilot ${apiName} ${operationId}`];
456
+ for (const pf of pFlags) parts.push(pf);
457
+ w(parts.join(" \\\n ") + "\n");
458
+ }
459
+ w(`
460
+ `);
461
+ if (pathParams.length > 0) {
462
+ const positionalVals = pathParams.map((p) => sampleParamValue(p));
463
+ w(` ${DIM}# positional args for path parameters${RESET}
464
+ `);
465
+ w(` ${GREEN}$${RESET} epilot ${apiName} ${operationId} ${positionalVals.join(" ")}
466
+ `);
467
+ w(`
468
+ `);
469
+ }
470
+ if (reqBody) {
471
+ const content = reqBody.content?.["application/json"];
472
+ const bodySchema = content?.schema;
473
+ if (bodySchema) {
474
+ try {
475
+ const mockBody = truncateJson(mockFromSchema(bodySchema));
476
+ const compact = JSON.stringify(mockBody);
477
+ if (compact.length <= 80) {
478
+ w(` ${DIM}# with request body${RESET}
479
+ `);
480
+ w(` ${GREEN}$${RESET} epilot ${apiName} ${operationId}`);
481
+ if (pFlags.length > 0) w(` ${pFlags.join(" ")}`);
482
+ w(` -d '${compact}'
483
+ `);
484
+ } else {
485
+ const pretty = JSON.stringify(mockBody, null, 2);
486
+ w(` ${DIM}# with request body${RESET}
487
+ `);
488
+ const parts = [` ${GREEN}$${RESET} epilot ${apiName} ${operationId}`];
489
+ if (pFlags.length > 0) for (const pf of pFlags) parts.push(pf);
490
+ parts.push(`-d '${pretty}'`);
491
+ w(parts.join(" \\\n ") + "\n");
492
+ }
493
+ w(`
494
+ `);
495
+ } catch {
496
+ }
497
+ }
498
+ const pFlagsStr = pFlags.length > 0 ? " " + pFlags.join(" ") : "";
499
+ w(` ${DIM}# pipe from file${RESET}
500
+ `);
501
+ w(` ${GREEN}$${RESET} cat body.json | epilot ${apiName} ${operationId}${pFlagsStr}
502
+ `);
503
+ w(`
504
+ `);
505
+ }
506
+ {
507
+ const pFlagsStr = pFlags.length > 0 ? " " + pFlags.join(" ") : "";
508
+ const jsonataExpr = guessJsonataExpr(op);
509
+ w(` ${DIM}# filter response with JSONata${RESET}
510
+ `);
511
+ w(` ${GREEN}$${RESET} epilot ${apiName} ${operationId}${pFlagsStr} --jsonata '${jsonataExpr}'
512
+ `);
513
+ w(`
514
+ `);
515
+ }
516
+ {
517
+ const pFlagsStr = pFlags.length > 0 ? " " + pFlags.join(" ") : "";
518
+ w(` ${DIM}# raw JSON for scripting${RESET}
519
+ `);
520
+ w(` ${GREEN}$${RESET} epilot ${apiName} ${operationId}${pFlagsStr} --json
521
+ `);
522
+ w(`
523
+ `);
524
+ }
525
+ const successResp = op.responses?.["200"] || op.responses?.["201"];
526
+ if (successResp) {
527
+ const respContent = successResp.content?.["application/json"];
528
+ const respSchema = respContent?.schema;
529
+ if (respSchema) {
530
+ try {
531
+ const mockResp = truncateJson(mockFromSchema(respSchema));
532
+ const respStr = JSON.stringify(mockResp, null, 2);
533
+ const lines = respStr.split("\n");
534
+ w(`${BOLD}SAMPLE RESPONSE${RESET}
535
+
536
+ `);
537
+ const limit = 40;
538
+ const shown = lines.length <= limit ? lines : lines.slice(0, limit);
539
+ for (const line of shown) w(` ${DIM}${line}${RESET}
540
+ `);
541
+ if (lines.length > limit) w(` ${DIM} ... (${lines.length - limit} more lines)${RESET}
542
+ `);
543
+ w(`
544
+ `);
545
+ } catch {
546
+ }
547
+ }
548
+ }
549
+ return;
550
+ }
551
+ }
552
+ process.stderr.write(`${RED}Operation "${operationId}" not found.${RESET}
553
+ `);
554
+ process.exit(1);
555
+ };
556
+ var guessJsonataExpr = (op) => {
557
+ const successResp = op.responses?.["200"] || op.responses?.["201"];
558
+ if (!successResp) return "$";
559
+ const respContent = successResp.content?.["application/json"];
560
+ const schema = respContent?.schema;
561
+ if (!schema?.properties) return "$";
562
+ const props = schema.properties;
563
+ if (props.results) return "results[0]";
564
+ if (props.data) return "data";
565
+ if (props.items) return "items[0]";
566
+ if (props.hits) return "hits";
567
+ if (props.entity) return "entity._title";
568
+ if (props.id) return "id";
569
+ if (props.email) return "email";
570
+ const keys = Object.keys(props);
571
+ return keys.length > 0 ? keys[0] : "$";
572
+ };
573
+ var callApi = async (apiName, args) => {
574
+ const rawSpec = await loadDefinition(apiName, args.definition);
575
+ const spec = dereferenceSync(rawSpec);
576
+ const operations = extractOperations(spec);
577
+ if (!args.operation) {
578
+ process.stdout.write(`
579
+ ${BOLD}epilot ${apiName}${RESET} - ${spec.info?.title || apiName}
580
+
581
+ `);
582
+ process.stdout.write(`${BOLD}Available operations:${RESET}
583
+
584
+ `);
585
+ if (isInteractive({ interactive: args.interactive })) {
586
+ const operationId2 = await pickOperation(operations);
587
+ return callApi(apiName, { ...args, operation: operationId2 });
588
+ }
589
+ printOperationsTable(apiName, operations);
590
+ return;
591
+ }
592
+ const operationId = args.operation;
593
+ if (args.help) {
594
+ printOperationHelp(apiName, operationId, spec);
595
+ return;
596
+ }
597
+ const opExists = operations.some((op) => op.operationId === operationId);
598
+ if (!opExists) {
599
+ process.stderr.write(`${RED}Unknown operation "${operationId}" for ${apiName}.${RESET}
600
+ `);
601
+ process.stderr.write(`
602
+ Available operations:
603
+ `);
604
+ for (const op of operations) {
605
+ process.stderr.write(` ${op.operationId}
606
+ `);
607
+ }
608
+ process.exit(1);
609
+ }
610
+ let token = resolveToken(args.token, args.profile);
611
+ if (!token) {
612
+ if (isInteractive({ interactive: args.interactive })) {
613
+ const { promptToken } = await import("./interactive-46ICLQKL.js");
614
+ token = await promptToken();
615
+ }
616
+ if (!token) {
617
+ process.stderr.write(`${RED}No authentication token found.${RESET}
618
+ `);
619
+ process.stderr.write(`Run 'epilot auth login' or pass --token <token>
620
+ `);
621
+ process.exit(1);
622
+ }
623
+ }
624
+ const opParams = getOperationParams(spec, operationId);
625
+ const positionalArgs = args._args ?? [];
626
+ let collected = collectParams(opParams, args.param, positionalArgs);
627
+ const missing = getMissingRequired(opParams, collected);
628
+ if (missing.length > 0 && isInteractive({ interactive: args.interactive })) {
629
+ for (const param of opParams) {
630
+ if (param.required && !(param.name in collected)) {
631
+ const value = await promptParam(param.name, param);
632
+ if (value) collected[param.name] = value;
633
+ }
634
+ }
635
+ }
636
+ const stillMissing = getMissingRequired(opParams, collected);
637
+ if (stillMissing.length > 0) {
638
+ process.stderr.write(`${RED}Missing required parameters: ${stillMissing.join(", ")}${RESET}
639
+ `);
640
+ process.exit(1);
641
+ }
642
+ const { hasBody, isRequired } = getRequestBodyInfo(spec, operationId);
643
+ let bodyTemplate;
644
+ if (hasBody && isInteractive({ interactive: args.interactive })) {
645
+ const bodySchema = getBodySchema(spec, operationId);
646
+ if (bodySchema) {
647
+ try {
648
+ bodyTemplate = mockFromSchema(bodySchema);
649
+ } catch {
650
+ }
651
+ }
652
+ }
653
+ const body = await resolveBody({
654
+ dataFlag: args.data,
655
+ hasRequestBody: hasBody,
656
+ isRequired,
657
+ interactive: isInteractive({ interactive: args.interactive }),
658
+ defaultTemplate: bodyTemplate,
659
+ cacheKey: `${apiName}/${operationId}`
660
+ });
661
+ const customHeaders = {};
662
+ if (args.header) {
663
+ const headers = Array.isArray(args.header) ? args.header : [args.header];
664
+ for (const h of headers) {
665
+ const idx = h.indexOf(":");
666
+ if (idx > 0) {
667
+ customHeaders[h.substring(0, idx).trim()] = h.substring(idx + 1).trim();
668
+ }
669
+ }
670
+ }
671
+ const serverOverride = args.server || getResolvedProfile(args.profile)?.server;
672
+ if (serverOverride) {
673
+ const specDoc = spec;
674
+ specDoc.servers = [{ url: serverOverride }];
675
+ }
676
+ const api = new OpenAPIClientAxios({
677
+ definition: spec,
678
+ quick: true
679
+ });
680
+ const client = await api.init();
681
+ client.defaults.headers.common.authorization = `Bearer ${token}`;
682
+ for (const [key, value] of Object.entries(customHeaders)) {
683
+ client.defaults.headers.common[key] = value;
684
+ }
685
+ const operationFn = client[operationId];
686
+ if (typeof operationFn !== "function") {
687
+ process.stderr.write(`${RED}Operation "${operationId}" not found on client.${RESET}
688
+ `);
689
+ process.exit(1);
690
+ }
691
+ try {
692
+ const response = await operationFn(
693
+ Object.keys(collected).length > 0 ? collected : null,
694
+ body,
695
+ { validateStatus: () => true }
696
+ );
697
+ await formatResponse(response, {
698
+ json: args.json,
699
+ include: args.include,
700
+ verbose: args.verbose,
701
+ jsonata: args.jsonata
702
+ });
703
+ if (response.status >= 400) {
704
+ process.exit(1);
705
+ }
706
+ } catch (err) {
707
+ process.stderr.write(`${RED}Request failed: ${err instanceof Error ? err.message : String(err)}${RESET}
708
+ `);
709
+ process.exit(1);
710
+ }
711
+ };
712
+
713
+ export {
714
+ callApi
715
+ };