@rooaak/cli 0.1.0-beta.1

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 (82) hide show
  1. package/README.md +121 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +4 -0
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +1 -0
  8. package/dist/src/commands/auth-login.d.ts +3 -0
  9. package/dist/src/commands/auth-login.d.ts.map +1 -0
  10. package/dist/src/commands/auth-login.js +97 -0
  11. package/dist/src/commands/config-profile-use.d.ts +3 -0
  12. package/dist/src/commands/config-profile-use.d.ts.map +1 -0
  13. package/dist/src/commands/config-profile-use.js +88 -0
  14. package/dist/src/commands/config-whoami.d.ts +3 -0
  15. package/dist/src/commands/config-whoami.d.ts.map +1 -0
  16. package/dist/src/commands/config-whoami.js +101 -0
  17. package/dist/src/commands/help.d.ts +3 -0
  18. package/dist/src/commands/help.d.ts.map +1 -0
  19. package/dist/src/commands/help.js +61 -0
  20. package/dist/src/commands/init/index.d.ts +3 -0
  21. package/dist/src/commands/init/index.d.ts.map +1 -0
  22. package/dist/src/commands/init/index.js +756 -0
  23. package/dist/src/commands/init/prompting.d.ts +16 -0
  24. package/dist/src/commands/init/prompting.d.ts.map +1 -0
  25. package/dist/src/commands/init/prompting.js +63 -0
  26. package/dist/src/commands/init/wait-for-message.d.ts +45 -0
  27. package/dist/src/commands/init/wait-for-message.d.ts.map +1 -0
  28. package/dist/src/commands/init/wait-for-message.js +27 -0
  29. package/dist/src/commands/version.d.ts +3 -0
  30. package/dist/src/commands/version.d.ts.map +1 -0
  31. package/dist/src/commands/version.js +14 -0
  32. package/dist/src/generated/handlers.d.ts +5 -0
  33. package/dist/src/generated/handlers.d.ts.map +1 -0
  34. package/dist/src/generated/handlers.js +17 -0
  35. package/dist/src/generated/manifest.d.ts +3 -0
  36. package/dist/src/generated/manifest.d.ts.map +1 -0
  37. package/dist/src/generated/manifest.js +56 -0
  38. package/dist/src/lib/argv.d.ts +16 -0
  39. package/dist/src/lib/argv.d.ts.map +1 -0
  40. package/dist/src/lib/argv.js +68 -0
  41. package/dist/src/lib/base-url.d.ts +7 -0
  42. package/dist/src/lib/base-url.d.ts.map +1 -0
  43. package/dist/src/lib/base-url.js +6 -0
  44. package/dist/src/lib/exit-codes.d.ts +11 -0
  45. package/dist/src/lib/exit-codes.d.ts.map +1 -0
  46. package/dist/src/lib/exit-codes.js +29 -0
  47. package/dist/src/lib/generated-command.d.ts +25 -0
  48. package/dist/src/lib/generated-command.d.ts.map +1 -0
  49. package/dist/src/lib/generated-command.js +357 -0
  50. package/dist/src/lib/normalize-error.d.ts +45 -0
  51. package/dist/src/lib/normalize-error.d.ts.map +1 -0
  52. package/dist/src/lib/normalize-error.js +128 -0
  53. package/dist/src/lib/options.d.ts +12 -0
  54. package/dist/src/lib/options.d.ts.map +1 -0
  55. package/dist/src/lib/options.js +49 -0
  56. package/dist/src/lib/package-version.d.ts +2 -0
  57. package/dist/src/lib/package-version.d.ts.map +1 -0
  58. package/dist/src/lib/package-version.js +22 -0
  59. package/dist/src/lib/paths.d.ts +2 -0
  60. package/dist/src/lib/paths.d.ts.map +1 -0
  61. package/dist/src/lib/paths.js +21 -0
  62. package/dist/src/lib/profile-name.d.ts +2 -0
  63. package/dist/src/lib/profile-name.d.ts.map +1 -0
  64. package/dist/src/lib/profile-name.js +4 -0
  65. package/dist/src/lib/profile-store.d.ts +31 -0
  66. package/dist/src/lib/profile-store.d.ts.map +1 -0
  67. package/dist/src/lib/profile-store.js +179 -0
  68. package/dist/src/lib/renderer.d.ts +10 -0
  69. package/dist/src/lib/renderer.d.ts.map +1 -0
  70. package/dist/src/lib/renderer.js +25 -0
  71. package/dist/src/lib/run.d.ts +12 -0
  72. package/dist/src/lib/run.d.ts.map +1 -0
  73. package/dist/src/lib/run.js +108 -0
  74. package/dist/src/lib/transport.d.ts +37 -0
  75. package/dist/src/lib/transport.d.ts.map +1 -0
  76. package/dist/src/lib/transport.js +65 -0
  77. package/dist/src/lib/types.d.ts +22 -0
  78. package/dist/src/lib/types.d.ts.map +1 -0
  79. package/dist/src/lib/types.js +1 -0
  80. package/package.json +46 -0
  81. package/rooaak.js +39 -0
  82. package/schemas/openapi.v1.json +6013 -0
@@ -0,0 +1,357 @@
1
+ import { resolveBaseUrl } from "./base-url.js";
2
+ import { ExitCode } from "./exit-codes.js";
3
+ import { normalizeLocalUsageError, exitCodeForError, toJsonErrorEnvelope, toJsonOkEnvelope } from "./normalize-error.js";
4
+ import { parseOptions } from "./options.js";
5
+ import { createProfileStore } from "./profile-store.js";
6
+ import { createRenderer } from "./renderer.js";
7
+ import { createTransport } from "./transport.js";
8
+ function jsonTypeFromFlag(flag) {
9
+ if (flag.valueType === "boolean")
10
+ return "boolean";
11
+ if (flag.valueType === "number")
12
+ return "number";
13
+ if (flag.valueType === "json")
14
+ return "json";
15
+ return "string";
16
+ }
17
+ function coerceFlagValue(flag, raw) {
18
+ if (flag.valueType === "boolean") {
19
+ if (typeof raw === "boolean")
20
+ return raw;
21
+ const v = raw.toLowerCase();
22
+ if (v === "true")
23
+ return true;
24
+ if (v === "false")
25
+ return false;
26
+ throw new Error(`Expected boolean for ${flag.name} (true|false)`);
27
+ }
28
+ if (flag.valueType === "number") {
29
+ if (typeof raw !== "string")
30
+ throw new Error(`Expected number for ${flag.name}`);
31
+ const n = Number(raw);
32
+ if (!Number.isFinite(n))
33
+ throw new Error(`Expected number for ${flag.name}`);
34
+ return n;
35
+ }
36
+ if (flag.valueType === "json") {
37
+ if (typeof raw !== "string")
38
+ throw new Error(`Expected JSON for ${flag.name}`);
39
+ try {
40
+ return JSON.parse(raw);
41
+ }
42
+ catch {
43
+ throw new Error(`Expected valid JSON for ${flag.name}`);
44
+ }
45
+ }
46
+ if (typeof raw !== "string")
47
+ throw new Error(`Expected string for ${flag.name}`);
48
+ return raw;
49
+ }
50
+ function getProfileOrUsageError(ctx) {
51
+ const r = createRenderer(ctx);
52
+ const store = createProfileStore({ configPath: ctx.profileConfigPath });
53
+ const cfgRes = store.readConfig();
54
+ if (cfgRes.kind === "missing") {
55
+ const err = {
56
+ code: "auth.not_logged_in",
57
+ message: "Not logged in. Run `rooaak auth login --api-key ...`.",
58
+ details: {},
59
+ meta: {},
60
+ };
61
+ if (ctx.flags.json)
62
+ r.json(toJsonErrorEnvelope(err));
63
+ else
64
+ r.error(err.message);
65
+ return { ok: false, exit: exitCodeForError(err) };
66
+ }
67
+ if (cfgRes.kind === "corrupt") {
68
+ const err = {
69
+ code: "config.corrupt",
70
+ message: cfgRes.message,
71
+ details: { path: cfgRes.path },
72
+ meta: {},
73
+ };
74
+ if (ctx.flags.json)
75
+ r.json(toJsonErrorEnvelope(err));
76
+ else
77
+ r.error(err.message);
78
+ return { ok: false, exit: exitCodeForError(err) };
79
+ }
80
+ const config = cfgRes.config;
81
+ const profileName = config.currentProfile;
82
+ const profile = config.profiles[profileName];
83
+ if (!profile?.apiKey) {
84
+ const err = {
85
+ code: "auth.not_logged_in",
86
+ message: "Not logged in. Run `rooaak auth login --api-key ...`.",
87
+ details: {},
88
+ meta: {},
89
+ };
90
+ if (ctx.flags.json)
91
+ r.json(toJsonErrorEnvelope(err));
92
+ else
93
+ r.error(err.message);
94
+ return { ok: false, exit: exitCodeForError(err) };
95
+ }
96
+ const baseUrl = resolveBaseUrl({
97
+ cliFlag: ctx.flags.baseUrl,
98
+ env: ctx.env.ROOAAK_BASE_URL,
99
+ profile: profile.baseUrl,
100
+ });
101
+ return { ok: true, apiKey: profile.apiKey, baseUrl, profileName };
102
+ }
103
+ export function renderGeneratedCommandHelp(ctx, spec) {
104
+ const r = createRenderer(ctx);
105
+ const usage = `rooaak ${spec.group} ${spec.action} [flags]`;
106
+ const flags = [...spec.flags].sort((a, b) => {
107
+ // Required first, then by source, then by name.
108
+ const req = Number(b.required) - Number(a.required);
109
+ if (req !== 0)
110
+ return req;
111
+ const order = { path: 0, query: 1, header: 2, body: 3 };
112
+ const src = order[a.source] - order[b.source];
113
+ if (src !== 0)
114
+ return src;
115
+ return a.name.localeCompare(b.name);
116
+ });
117
+ if (ctx.flags.json) {
118
+ r.json(toJsonOkEnvelope({
119
+ type: "help",
120
+ usage,
121
+ operationId: spec.operationId,
122
+ summary: spec.summary,
123
+ description: spec.description,
124
+ method: spec.method,
125
+ path: spec.pathTemplate,
126
+ flags: flags.map((f) => ({
127
+ name: f.name,
128
+ required: f.required,
129
+ type: jsonTypeFromFlag(f),
130
+ source: f.source,
131
+ description: f.description,
132
+ })),
133
+ }));
134
+ return ExitCode.Success;
135
+ }
136
+ const lines = [];
137
+ lines.push("Usage:");
138
+ lines.push(` ${usage}`);
139
+ lines.push("");
140
+ lines.push("Endpoint:");
141
+ lines.push(` ${spec.method} ${spec.pathTemplate}`);
142
+ if (spec.summary)
143
+ lines.push(` ${spec.summary}`);
144
+ lines.push("");
145
+ lines.push("Flags:");
146
+ if (flags.length === 0) {
147
+ lines.push(" (none)");
148
+ }
149
+ else {
150
+ for (const f of flags) {
151
+ const req = f.required ? "required" : "optional";
152
+ const type = jsonTypeFromFlag(f);
153
+ const desc = f.description ? ` - ${f.description}` : "";
154
+ lines.push(` ${f.name} <${type}> (${req}, ${f.source})${desc}`);
155
+ }
156
+ }
157
+ lines.push("");
158
+ ctx.stdout.write(lines.join("\n") + "\n");
159
+ return ExitCode.Success;
160
+ }
161
+ export async function runGeneratedCommand(ctx, spec, argv) {
162
+ const r = createRenderer(ctx);
163
+ const optionSpecs = spec.flags.map((f) => ({ name: f.name, takesValue: f.takesValue }));
164
+ const parsed = parseOptions(argv, optionSpecs);
165
+ if (parsed.unknownOption) {
166
+ const err = normalizeLocalUsageError(`Unknown option: ${parsed.unknownOption}`);
167
+ if (ctx.flags.json)
168
+ r.json(toJsonErrorEnvelope(err));
169
+ else
170
+ r.error(err.message);
171
+ return ExitCode.Usage;
172
+ }
173
+ if (parsed.missingValueOption) {
174
+ const err = normalizeLocalUsageError(`Missing value for: ${parsed.missingValueOption}`);
175
+ if (ctx.flags.json)
176
+ r.json(toJsonErrorEnvelope(err));
177
+ else
178
+ r.error(err.message);
179
+ return ExitCode.Usage;
180
+ }
181
+ if (parsed.positionals.length > 0) {
182
+ const err = normalizeLocalUsageError("Unexpected extra arguments", { argc: parsed.positionals.length });
183
+ if (ctx.flags.json)
184
+ r.json(toJsonErrorEnvelope(err));
185
+ else
186
+ r.error(err.message);
187
+ return ExitCode.Usage;
188
+ }
189
+ // Parse `--body` early so we can treat it as an escape hatch for required body fields.
190
+ let bodyOverridePresent = false;
191
+ let bodyOverride = undefined;
192
+ const bodyExplicit = parsed.values["--body"];
193
+ if (typeof bodyExplicit === "string") {
194
+ bodyOverridePresent = true;
195
+ try {
196
+ bodyOverride = JSON.parse(bodyExplicit);
197
+ }
198
+ catch {
199
+ const err = normalizeLocalUsageError("Invalid JSON for --body");
200
+ if (ctx.flags.json)
201
+ r.json(toJsonErrorEnvelope(err));
202
+ else
203
+ r.error(err.message);
204
+ return ExitCode.Usage;
205
+ }
206
+ }
207
+ for (const f of spec.flags) {
208
+ if (!f.required)
209
+ continue;
210
+ if (bodyOverridePresent && f.source === "body" && f.name !== "--body")
211
+ continue;
212
+ const v = parsed.values[f.name];
213
+ if (v === undefined || v === false || v === "") {
214
+ const err = normalizeLocalUsageError(`Missing required flag: ${f.name}`);
215
+ if (ctx.flags.json)
216
+ r.json(toJsonErrorEnvelope(err));
217
+ else
218
+ r.error(err.message);
219
+ return ExitCode.Usage;
220
+ }
221
+ }
222
+ const auth = getProfileOrUsageError(ctx);
223
+ if (!auth.ok)
224
+ return auth.exit;
225
+ const transport = createTransport({
226
+ baseUrl: auth.baseUrl,
227
+ apiKey: auth.apiKey,
228
+ fetchFn: ctx.fetchFn,
229
+ });
230
+ let path = spec.pathTemplate;
231
+ const query = new URLSearchParams();
232
+ const headers = {};
233
+ let body = undefined;
234
+ const bodyObj = {};
235
+ let sawBodyField = false;
236
+ // Always bind path/query/header flags regardless of whether `--body` is present.
237
+ // Only the body-building portion is conditional: `--body` overrides individual body flags.
238
+ for (const f of spec.flags) {
239
+ const raw = parsed.values[f.name];
240
+ if (raw === undefined)
241
+ continue;
242
+ if (f.source === "path") {
243
+ if (typeof raw !== "string") {
244
+ const err = normalizeLocalUsageError(`Invalid value for ${f.name}`);
245
+ if (ctx.flags.json)
246
+ r.json(toJsonErrorEnvelope(err));
247
+ else
248
+ r.error(err.message);
249
+ return ExitCode.Usage;
250
+ }
251
+ const token = `{${f.wireName}}`;
252
+ if (!path.includes(token)) {
253
+ const err = normalizeLocalUsageError(`Unable to bind path param for ${f.name}`);
254
+ if (ctx.flags.json)
255
+ r.json(toJsonErrorEnvelope(err));
256
+ else
257
+ r.error(err.message);
258
+ return ExitCode.Usage;
259
+ }
260
+ path = path.replaceAll(token, encodeURIComponent(raw));
261
+ continue;
262
+ }
263
+ if (f.source === "query") {
264
+ if (typeof raw !== "string" && typeof raw !== "boolean") {
265
+ const err = normalizeLocalUsageError(`Invalid value for ${f.name}`);
266
+ if (ctx.flags.json)
267
+ r.json(toJsonErrorEnvelope(err));
268
+ else
269
+ r.error(err.message);
270
+ return ExitCode.Usage;
271
+ }
272
+ try {
273
+ const v = coerceFlagValue(f, raw);
274
+ query.set(f.wireName, typeof v === "string" ? v : JSON.stringify(v));
275
+ }
276
+ catch (e) {
277
+ const err = normalizeLocalUsageError(e instanceof Error ? e.message : `Invalid value for ${f.name}`);
278
+ if (ctx.flags.json)
279
+ r.json(toJsonErrorEnvelope(err));
280
+ else
281
+ r.error(err.message);
282
+ return ExitCode.Usage;
283
+ }
284
+ continue;
285
+ }
286
+ if (f.source === "header") {
287
+ if (typeof raw !== "string" && typeof raw !== "boolean") {
288
+ const err = normalizeLocalUsageError(`Invalid value for ${f.name}`);
289
+ if (ctx.flags.json)
290
+ r.json(toJsonErrorEnvelope(err));
291
+ else
292
+ r.error(err.message);
293
+ return ExitCode.Usage;
294
+ }
295
+ try {
296
+ const v = coerceFlagValue(f, raw);
297
+ headers[f.wireName] = typeof v === "string" ? v : JSON.stringify(v);
298
+ }
299
+ catch (e) {
300
+ const err = normalizeLocalUsageError(e instanceof Error ? e.message : `Invalid value for ${f.name}`);
301
+ if (ctx.flags.json)
302
+ r.json(toJsonErrorEnvelope(err));
303
+ else
304
+ r.error(err.message);
305
+ return ExitCode.Usage;
306
+ }
307
+ continue;
308
+ }
309
+ if (f.source === "body") {
310
+ if (f.name === "--body")
311
+ continue;
312
+ if (bodyOverridePresent)
313
+ continue;
314
+ sawBodyField = true;
315
+ try {
316
+ bodyObj[f.wireName] = coerceFlagValue(f, raw);
317
+ }
318
+ catch (e) {
319
+ const err = normalizeLocalUsageError(e instanceof Error ? e.message : `Invalid value for ${f.name}`);
320
+ if (ctx.flags.json)
321
+ r.json(toJsonErrorEnvelope(err));
322
+ else
323
+ r.error(err.message);
324
+ return ExitCode.Usage;
325
+ }
326
+ }
327
+ }
328
+ if (bodyOverridePresent)
329
+ body = bodyOverride;
330
+ else if (sawBodyField)
331
+ body = bodyObj;
332
+ const qs = query.toString();
333
+ const fullPath = qs.length > 0 ? `${path}?${qs}` : path;
334
+ r.debug(`${spec.method} ${auth.baseUrl}${fullPath}`);
335
+ const httpRes = await transport.requestJson({
336
+ method: spec.method,
337
+ path: fullPath,
338
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
339
+ body,
340
+ });
341
+ if (!httpRes.ok) {
342
+ const err = httpRes.error;
343
+ if (ctx.flags.json)
344
+ r.json(toJsonErrorEnvelope(err));
345
+ else
346
+ r.error(err.message);
347
+ return exitCodeForError(err);
348
+ }
349
+ const meta = { status: httpRes.status, requestId: httpRes.requestId };
350
+ if (ctx.flags.json) {
351
+ r.json(toJsonOkEnvelope(httpRes.data, meta));
352
+ }
353
+ else {
354
+ ctx.stdout.write(JSON.stringify(httpRes.data, null, 2) + "\n");
355
+ }
356
+ return ExitCode.Success;
357
+ }
@@ -0,0 +1,45 @@
1
+ import { ExitCode } from "./exit-codes.js";
2
+ export type JsonErrorEnvelope = {
3
+ ok: false;
4
+ error: {
5
+ code: string;
6
+ message: string;
7
+ details: Record<string, unknown>;
8
+ };
9
+ meta: {
10
+ status?: number;
11
+ requestId?: string;
12
+ };
13
+ };
14
+ export type JsonOkEnvelope<T> = {
15
+ ok: true;
16
+ data: T;
17
+ meta: {
18
+ status?: number;
19
+ requestId?: string;
20
+ };
21
+ };
22
+ export type JsonEnvelope<T> = JsonOkEnvelope<T> | JsonErrorEnvelope;
23
+ export type NormalizedError = {
24
+ code: string;
25
+ message: string;
26
+ details: Record<string, unknown>;
27
+ meta: {
28
+ status?: number;
29
+ requestId?: string;
30
+ };
31
+ };
32
+ export declare function getRequestIdFromHeaders(headers: Headers): string | undefined;
33
+ export declare function normalizeHttpError(input: {
34
+ status: number;
35
+ requestId?: string;
36
+ body: unknown;
37
+ }): NormalizedError;
38
+ export declare function normalizeLocalUsageError(message: string, details?: Record<string, unknown>): NormalizedError;
39
+ export declare function exitCodeForError(err: NormalizedError): ExitCode;
40
+ export declare function toJsonErrorEnvelope(err: NormalizedError): JsonErrorEnvelope;
41
+ export declare function toJsonOkEnvelope<T>(data: T, meta?: {
42
+ status?: number;
43
+ requestId?: string;
44
+ }): JsonOkEnvelope<T>;
45
+ //# sourceMappingURL=normalize-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-error.d.ts","sourceRoot":"","sources":["../../../src/lib/normalize-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAElE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAClC,CAAC;IACF,IAAI,EAAE;QACJ,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,EAAE,EAAE,IAAI,CAAC;IACT,IAAI,EAAE,CAAC,CAAC;IACR,IAAI,EAAE;QACJ,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC;AAEpE,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE;QACJ,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH,CAAC;AAMF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAO5E;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,eAAe,CAqElB;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,eAAe,CAOjB;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,eAAe,GAAG,QAAQ,CAY/D;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,eAAe,GAAG,iBAAiB,CAa3E;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAAC,CAAC,CAAC,CAS9G"}
@@ -0,0 +1,128 @@
1
+ import { exitCodeForHttpStatus, ExitCode } from "./exit-codes.js";
2
+ function isPlainObject(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
5
+ export function getRequestIdFromHeaders(headers) {
6
+ return (headers.get("x-request-id") ||
7
+ headers.get("x-correlation-id") ||
8
+ headers.get("x-correlation-id".toLowerCase()) ||
9
+ undefined);
10
+ }
11
+ export function normalizeHttpError(input) {
12
+ const status = input.status;
13
+ const serverCode = isPlainObject(input.body) &&
14
+ isPlainObject(input.body.error) &&
15
+ typeof input.body.error.code === "string"
16
+ ? input.body.error.code
17
+ : undefined;
18
+ const serverMessage = isPlainObject(input.body) &&
19
+ isPlainObject(input.body.error) &&
20
+ typeof input.body.error.message === "string"
21
+ ? input.body.error.message
22
+ : undefined;
23
+ const serverDetails = isPlainObject(input.body) &&
24
+ isPlainObject(input.body.error) &&
25
+ isPlainObject(input.body.error.details)
26
+ ? input.body.error.details
27
+ : {};
28
+ let code = "server.error";
29
+ let message = serverMessage || `Request failed (${status})`;
30
+ if (status === 401) {
31
+ if (serverMessage?.toLowerCase().includes("invalid api key")) {
32
+ code = "auth.invalid_api_key";
33
+ message = "Invalid API key";
34
+ }
35
+ else if (serverMessage?.toLowerCase().includes("missing api key")) {
36
+ code = "auth.missing_api_key";
37
+ message = "Missing API key";
38
+ }
39
+ else {
40
+ code = "auth.unauthorized";
41
+ message = "Unauthorized";
42
+ }
43
+ }
44
+ else if (status === 403) {
45
+ code = "permission.forbidden";
46
+ message = serverMessage || "Forbidden";
47
+ }
48
+ else if (status === 404) {
49
+ code = "not_found";
50
+ message = serverMessage || "Not found";
51
+ }
52
+ else if (status === 409) {
53
+ code = "conflict";
54
+ message = serverMessage || "Conflict";
55
+ }
56
+ else if (status === 400) {
57
+ code = "request.bad_request";
58
+ message = serverMessage || "Bad request";
59
+ }
60
+ else if (status === 422) {
61
+ code = "request.validation_error";
62
+ message = serverMessage || "Validation error";
63
+ }
64
+ else if (status >= 500) {
65
+ code = "server.error";
66
+ message = "Server error";
67
+ }
68
+ const details = {
69
+ ...(serverCode ? { serverCode } : {}),
70
+ ...(Object.keys(serverDetails).length > 0 ? { serverDetails } : {}),
71
+ };
72
+ return {
73
+ code,
74
+ message,
75
+ details,
76
+ meta: { status, requestId: input.requestId },
77
+ };
78
+ }
79
+ export function normalizeLocalUsageError(message, details = {}) {
80
+ return {
81
+ code: "usage.validation_error",
82
+ message,
83
+ details,
84
+ meta: {},
85
+ };
86
+ }
87
+ export function exitCodeForError(err) {
88
+ const status = err.meta.status;
89
+ if (typeof status === "number")
90
+ return exitCodeForHttpStatus(status);
91
+ if (err.code.startsWith("usage."))
92
+ return ExitCode.Usage;
93
+ if (err.code.startsWith("auth."))
94
+ return ExitCode.Auth;
95
+ if (err.code.startsWith("permission."))
96
+ return ExitCode.Permission;
97
+ if (err.code.startsWith("not_found"))
98
+ return ExitCode.NotFound;
99
+ if (err.code.startsWith("conflict"))
100
+ return ExitCode.Conflict;
101
+ if (err.code.startsWith("config."))
102
+ return ExitCode.Usage;
103
+ return ExitCode.Transient;
104
+ }
105
+ export function toJsonErrorEnvelope(err) {
106
+ return {
107
+ ok: false,
108
+ error: {
109
+ code: err.code,
110
+ message: err.message,
111
+ details: err.details,
112
+ },
113
+ meta: {
114
+ status: err.meta.status,
115
+ requestId: err.meta.requestId,
116
+ },
117
+ };
118
+ }
119
+ export function toJsonOkEnvelope(data, meta) {
120
+ return {
121
+ ok: true,
122
+ data,
123
+ meta: {
124
+ status: meta?.status,
125
+ requestId: meta?.requestId,
126
+ },
127
+ };
128
+ }
@@ -0,0 +1,12 @@
1
+ export type OptionSpec = {
2
+ name: string;
3
+ takesValue: boolean;
4
+ };
5
+ export type ParsedOptions = {
6
+ positionals: string[];
7
+ values: Record<string, string | boolean>;
8
+ unknownOption?: string;
9
+ missingValueOption?: string;
10
+ };
11
+ export declare function parseOptions(argv: string[], specs: OptionSpec[]): ParsedOptions;
12
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../../src/lib/options.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,aAAa,CAwD/E"}
@@ -0,0 +1,49 @@
1
+ export function parseOptions(argv, specs) {
2
+ const specMap = new Map();
3
+ for (const spec of specs)
4
+ specMap.set(spec.name, spec);
5
+ const values = {};
6
+ const positionals = [];
7
+ for (let i = 0; i < argv.length; i++) {
8
+ const arg = argv[i];
9
+ if (arg === "--") {
10
+ positionals.push(...argv.slice(i + 1));
11
+ break;
12
+ }
13
+ if (!arg.startsWith("-")) {
14
+ positionals.push(...argv.slice(i));
15
+ break;
16
+ }
17
+ if (arg.startsWith("--")) {
18
+ const [name, inline] = arg.split("=", 2);
19
+ const spec = specMap.get(name);
20
+ if (!spec)
21
+ return { positionals: [], values, unknownOption: name };
22
+ if (!spec.takesValue) {
23
+ values[name] = true;
24
+ continue;
25
+ }
26
+ if (inline !== undefined) {
27
+ if (inline.length === 0)
28
+ return { positionals: [], values, missingValueOption: name };
29
+ values[name] = inline;
30
+ continue;
31
+ }
32
+ const value = argv[i + 1];
33
+ if (!value || value === "--") {
34
+ return { positionals: [], values, missingValueOption: name };
35
+ }
36
+ // Only treat the next token as "missing" when it is a known option. This allows legitimate values
37
+ // that start with `-` (e.g. negative numbers, free-form strings like "-hello", or "--not-an-option").
38
+ const [nextName] = value.split("=", 2);
39
+ if (nextName.startsWith("--") && specMap.has(nextName)) {
40
+ return { positionals: [], values, missingValueOption: name };
41
+ }
42
+ values[name] = value;
43
+ i++;
44
+ continue;
45
+ }
46
+ return { positionals: [], values, unknownOption: arg };
47
+ }
48
+ return { positionals, values };
49
+ }
@@ -0,0 +1,2 @@
1
+ export declare function getPackageVersion(): string;
2
+ //# sourceMappingURL=package-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-version.d.ts","sourceRoot":"","sources":["../../../src/lib/package-version.ts"],"names":[],"mappings":"AAMA,wBAAgB,iBAAiB,IAAI,MAAM,CAiB1C"}
@@ -0,0 +1,22 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ let cached = null;
5
+ export function getPackageVersion() {
6
+ if (cached)
7
+ return cached;
8
+ try {
9
+ // Compiled output lives at `dist/**`; package.json is one directory up from `dist`.
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+ const pkgJsonPath = path.resolve(__dirname, "..", "..", "..", "package.json");
13
+ const raw = fs.readFileSync(pkgJsonPath, "utf8");
14
+ const parsed = JSON.parse(raw);
15
+ cached = typeof parsed.version === "string" ? parsed.version : "0.0.0";
16
+ return cached;
17
+ }
18
+ catch {
19
+ cached = "0.0.0";
20
+ return cached;
21
+ }
22
+ }
@@ -0,0 +1,2 @@
1
+ export declare function getDefaultConfigDir(appName: string): string;
2
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/lib/paths.ts"],"names":[],"mappings":"AAOA,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmB3D"}
@@ -0,0 +1,21 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ function assertNever(x) {
4
+ throw new Error(`Unexpected platform: ${String(x)}`);
5
+ }
6
+ export function getDefaultConfigDir(appName) {
7
+ const platform = process.platform;
8
+ const home = os.homedir();
9
+ if (platform === "darwin") {
10
+ return path.join(home, "Library", "Application Support", appName);
11
+ }
12
+ if (platform === "win32") {
13
+ const appData = process.env.APPDATA || path.join(home, "AppData", "Roaming");
14
+ return path.join(appData, appName);
15
+ }
16
+ if (platform === "linux") {
17
+ const xdgConfigHome = process.env.XDG_CONFIG_HOME || path.join(home, ".config");
18
+ return path.join(xdgConfigHome, appName);
19
+ }
20
+ assertNever(platform);
21
+ }
@@ -0,0 +1,2 @@
1
+ export declare function isValidProfileName(name: string): boolean;
2
+ //# sourceMappingURL=profile-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile-name.d.ts","sourceRoot":"","sources":["../../../src/lib/profile-name.ts"],"names":[],"mappings":"AAAA,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGxD"}
@@ -0,0 +1,4 @@
1
+ export function isValidProfileName(name) {
2
+ // Keep it simple and file-name safe.
3
+ return /^[a-zA-Z0-9._-]+$/.test(name);
4
+ }