@agenzo/merchant-cli 0.3.0 → 0.3.2

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.
package/dist/index.js CHANGED
@@ -2,31 +2,715 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import {
6
- ApiClient as ApiClient6,
7
- ConfigManager as ConfigManager8,
8
- Formatter as Formatter8,
9
- CliError as CliError9,
10
- UserCancelError,
11
- toErrorEnvelope,
12
- resolveFormat as resolveFormat8,
13
- exitCodeFor,
14
- getCurrentVersion
15
- } from "@agenzo/cli-core";
16
5
 
17
- // src/ride-elife/quote.ts
18
- import {
19
- ConfigManager,
20
- PromptEngine,
21
- Formatter,
22
- resolveFormat,
23
- notify,
24
- CliError as CliError2,
25
- renderWithContext
26
- } from "@agenzo/cli-core";
6
+ // ../../packages/cli-core/dist/index.js
7
+ import { readFileSync } from "fs";
8
+ import { dirname, join } from "path";
9
+ import { fileURLToPath } from "url";
10
+ import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, chmod as chmod3 } from "fs/promises";
11
+ import { join as join4 } from "path";
12
+ import { homedir as homedir3 } from "os";
13
+ import { input, password, select } from "@inquirer/prompts";
14
+ var CODE_NUM = {
15
+ AUTH_SESSION_EXPIRED: 1001,
16
+ AUTH_MAGIC_LINK_EXPIRED: 1002,
17
+ AUTH_INVITE_CODE_REQUIRED: 1003,
18
+ AUTH_INVITE_CODE_INVALID: 1004,
19
+ KEY_INVALID: 1101,
20
+ KEY_SCOPE_DENIED: 1102,
21
+ RESOURCE_NOT_FOUND: 2001,
22
+ RESOURCE_CONFLICT: 2002,
23
+ RESOURCE_STATE_INVALID: 2003,
24
+ PARAM_INVALID: 2101,
25
+ PARAM_IDEMPOTENCY_KEY_REQUIRED: 2102,
26
+ PARAM_IDEMPOTENCY_KEY_CONFLICT: 2103,
27
+ BILLING_MODE_MISMATCH: 3001,
28
+ ACCOUNT_NOT_FOUND: 3101,
29
+ ACCOUNT_SUSPENDED: 3102,
30
+ ACCOUNT_INSUFFICIENT_BALANCE: 3103,
31
+ PAYMENT_ORDER_NOT_FOUND: 3201,
32
+ PAYMENT_ORDER_NOT_PAID: 3202,
33
+ PAYMENT_ORDER_MISMATCH: 3203,
34
+ PAYMENT_ORDER_ALREADY_CONSUMED: 3204,
35
+ TOKEN_FEATURE_DISABLED: 4001,
36
+ SERVICE_NOT_FOUND: 4101,
37
+ VEHICLE_UNAVAILABLE: 4201,
38
+ QUOTE_EXPIRED: 4202,
39
+ BOOKING_FAILED: 4203,
40
+ CANCELLATION_NOT_ALLOWED: 4204,
41
+ RATE_LIMITED: 5001,
42
+ UPSTREAM_ERROR: 5101,
43
+ INTERNAL_ERROR: 5201,
44
+ NOT_IMPLEMENTED: 5300,
45
+ CLIENT_NOT_SIGNED_IN: 9001,
46
+ CLIENT_LOGIN_TIMEOUT: 9002,
47
+ CLIENT_ORG_NOT_LOCAL: 9003,
48
+ CLIENT_ORG_WRONG_ENV: 9004,
49
+ CLIENT_NO_PAYMENT_METHOD: 9005,
50
+ CLIENT_CARD_NOT_MATCHED: 9006,
51
+ CLIENT_ABORTED: 9007,
52
+ UPGRADE_REQUIRED: 9008
53
+ };
54
+ function codeNum(code) {
55
+ return CODE_NUM[code];
56
+ }
57
+ var CliError = class _CliError extends Error {
58
+ constructor(code, message, statusCode, requestId, upstream) {
59
+ super(message);
60
+ this.code = code;
61
+ this.statusCode = statusCode;
62
+ this.requestId = requestId;
63
+ this.upstream = upstream;
64
+ this.name = "CliError";
65
+ }
66
+ code;
67
+ statusCode;
68
+ requestId;
69
+ upstream;
70
+ /**
71
+ * Map a backend ApiError to a CLI-facing code (§8.5 transitional mapping).
72
+ * Backend numeric codes / HTTP status are translated to §8.4 string codes;
73
+ * the raw backend message is NOT passed through (§8.1 principle 4) — a
74
+ * stable, fixed message per code is used instead.
75
+ *
76
+ * The optional `opts.auth` selects the auth semantics for the 401 mapping:
77
+ * - `'bearer'` (default, admin-cli Bearer Token): 401 → `AUTH_SESSION_EXPIRED`.
78
+ * - `'api-key'` (token-cli `X-Api-Key`): 401 → `KEY_INVALID`.
79
+ * 403 maps to `KEY_SCOPE_DENIED` under both auth modes. Omitting `opts`
80
+ * preserves the original Bearer behavior exactly (§8.5 / requirement 6.4).
81
+ *
82
+ * Domain string-code routing (D3 / requirement 5.4): when the backend
83
+ * supplies a string `error.code` in the v3 envelope that is a known §8 code
84
+ * (present in {@link CODE_NUM}), it is used verbatim as the CLI-facing code
85
+ * so ride/merchant-specific codes (`QUOTE_EXPIRED`, `VEHICLE_UNAVAILABLE`,
86
+ * `BILLING_MODE_MISMATCH`, `PAYMENT_ORDER_*`, …) survive intact. Otherwise —
87
+ * including when no string code is provided, as is the case for admin/token
88
+ * today — mapping falls back to the HTTP-status table below, leaving the
89
+ * existing Bearer/api-key behavior unchanged.
90
+ */
91
+ static fromApi(error, opts) {
92
+ if (error.code && isKnownErrorCode(error.code)) {
93
+ return new _CliError(
94
+ error.code,
95
+ STABLE_MESSAGE[error.code] ?? "Request failed. Please check your input and retry.",
96
+ error.statusCode,
97
+ error.requestId,
98
+ error.upstream
99
+ );
100
+ }
101
+ const status = error.statusCode;
102
+ let code;
103
+ if (status === 401) code = opts?.auth === "api-key" ? "KEY_INVALID" : "AUTH_SESSION_EXPIRED";
104
+ else if (status === 403) code = "KEY_SCOPE_DENIED";
105
+ else if (status === 404) code = "RESOURCE_NOT_FOUND";
106
+ else if (status === 409) code = "RESOURCE_CONFLICT";
107
+ else if (status === 429) code = "RATE_LIMITED";
108
+ else if (status >= 500) code = "INTERNAL_ERROR";
109
+ else code = "PARAM_INVALID";
110
+ return new _CliError(
111
+ code,
112
+ STABLE_MESSAGE[code] ?? "Request failed. Please check your input and retry.",
113
+ status,
114
+ error.requestId,
115
+ error.upstream
116
+ );
117
+ }
118
+ };
119
+ var NetworkError = class extends CliError {
120
+ constructor(_url, timeout, _cause) {
121
+ super(
122
+ "UPSTREAM_ERROR",
123
+ timeout ? "The request timed out. The service may be temporarily unavailable \u2014 please retry." : "Connection failed. The service may be temporarily unavailable \u2014 please retry."
124
+ );
125
+ }
126
+ };
127
+ var ConfigError = class extends CliError {
128
+ constructor(message, filePath) {
129
+ super("INTERNAL_ERROR", message || "Unknown error");
130
+ this.filePath = filePath;
131
+ }
132
+ filePath;
133
+ };
134
+ var ValidationError = class extends CliError {
135
+ constructor(message) {
136
+ super("PARAM_INVALID", message || "Unknown error");
137
+ }
138
+ };
139
+ var IdempotencyKeyRequiredError = class extends CliError {
140
+ constructor(commandPath) {
141
+ super(
142
+ "PARAM_IDEMPOTENCY_KEY_REQUIRED",
143
+ `\`${commandPath}\` requires --idempotency-key <key>. Supply a unique key so the write can be safely retried.`
144
+ );
145
+ }
146
+ };
147
+ var UpgradeRequiredError = class extends CliError {
148
+ constructor(currentVersion, minVersion, upgradeCommand) {
149
+ super(
150
+ "UPGRADE_REQUIRED",
151
+ `agenzo-admin-cli ${currentVersion} is out of date \u2014 the server requires ${minVersion} or newer. To upgrade, run: ${upgradeCommand}`
152
+ );
153
+ }
154
+ };
155
+ var UserCancelError = class extends CliError {
156
+ constructor(message = "Operation cancelled by user") {
157
+ super("CLIENT_ABORTED", message || "Unknown error");
158
+ }
159
+ };
160
+ function isKnownErrorCode(value) {
161
+ return Object.prototype.hasOwnProperty.call(CODE_NUM, value);
162
+ }
163
+ var STABLE_MESSAGE = {
164
+ AUTH_SESSION_EXPIRED: "Your session has expired. Please run `agenzo-admin-cli auth login` again.",
165
+ AUTH_MAGIC_LINK_EXPIRED: "Verification link is invalid or has expired. Please request a new one.",
166
+ AUTH_INVITE_CODE_REQUIRED: "An invitation code is required to register.",
167
+ AUTH_INVITE_CODE_INVALID: "The invitation code is invalid.",
168
+ KEY_INVALID: "The API key is invalid or has been revoked. Please check your --api-key and retry.",
169
+ KEY_SCOPE_DENIED: "This API key does not have the required scope for this command.",
170
+ RESOURCE_NOT_FOUND: "The resource was not found or does not belong to the current organization.",
171
+ RESOURCE_CONFLICT: "A resource with the same unique value already exists.",
172
+ RESOURCE_STATE_INVALID: "The resource is in a state that does not permit this operation.",
173
+ RATE_LIMITED: "Too many requests. Please back off and retry.",
174
+ UPSTREAM_ERROR: "A third-party service is temporarily unavailable. Please try again later.",
175
+ INTERNAL_ERROR: "Something went wrong on the server. Please retry and note the request_id.",
176
+ PARAM_INVALID: "One or more parameters are invalid. Please check your input and retry.",
177
+ PARAM_IDEMPOTENCY_KEY_CONFLICT: "A request with this idempotency key was already processed with different parameters.",
178
+ TOKEN_FEATURE_DISABLED: "This token feature is currently unavailable.",
179
+ BILLING_MODE_MISMATCH: "The billing mode does not match this operation. Please verify your account billing configuration.",
180
+ ACCOUNT_NOT_FOUND: "The settlement account was not found.",
181
+ ACCOUNT_SUSPENDED: "The settlement account is suspended. Please contact support.",
182
+ ACCOUNT_INSUFFICIENT_BALANCE: "The settlement account has insufficient balance for this operation.",
183
+ PAYMENT_ORDER_NOT_FOUND: "The payment order was not found.",
184
+ PAYMENT_ORDER_NOT_PAID: "The payment order has not been paid. Please complete payment and retry.",
185
+ PAYMENT_ORDER_MISMATCH: "The payment order does not match this order. Please check the --payment-order-id.",
186
+ PAYMENT_ORDER_ALREADY_CONSUMED: "The payment order has already been consumed by another booking.",
187
+ SERVICE_NOT_FOUND: "The requested service was not found.",
188
+ VEHICLE_UNAVAILABLE: "No vehicle is available for the requested trip. Please try a different time or class.",
189
+ QUOTE_EXPIRED: "The quote has expired. Please request a new quote and retry.",
190
+ BOOKING_FAILED: "The booking could not be completed. Please retry.",
191
+ CANCELLATION_NOT_ALLOWED: "This order cannot be cancelled in its current state.",
192
+ NOT_IMPLEMENTED: "This operation is not implemented yet."
193
+ };
194
+ function toErrorEnvelope(error) {
195
+ if (error instanceof CliError) {
196
+ return {
197
+ error: {
198
+ code: error.code,
199
+ code_num: codeNum(error.code),
200
+ message: error.message || "Unknown error",
201
+ ...error.requestId ? { request_id: error.requestId } : {},
202
+ ...error.upstream ? { upstream: error.upstream } : {}
203
+ }
204
+ };
205
+ }
206
+ const message = error instanceof Error ? error.message : typeof error === "string" ? error : "Unexpected error";
207
+ return {
208
+ error: {
209
+ code: "INTERNAL_ERROR",
210
+ code_num: codeNum("INTERNAL_ERROR"),
211
+ message: message || "Unknown error"
212
+ }
213
+ };
214
+ }
215
+ var UPGRADE_COMMAND = "npm install -g agenzo-admin-cli@latest";
216
+ var FALLBACK_VERSION = "0.1.1";
217
+ var cachedVersion = null;
218
+ function getCurrentVersion() {
219
+ if (cachedVersion !== null) return cachedVersion;
220
+ const here = dirname(fileURLToPath(import.meta.url));
221
+ const candidates = [
222
+ join(here, "..", "package.json"),
223
+ // dist/ → project root
224
+ join(here, "..", "..", "package.json")
225
+ // src/utils/ → project root
226
+ ];
227
+ for (const p of candidates) {
228
+ try {
229
+ const pkg = JSON.parse(readFileSync(p, "utf-8"));
230
+ if (typeof pkg.version === "string") {
231
+ cachedVersion = pkg.version;
232
+ return cachedVersion;
233
+ }
234
+ } catch {
235
+ }
236
+ }
237
+ cachedVersion = FALLBACK_VERSION;
238
+ console.warn(
239
+ `[agenzo-admin-cli] package.json not found; using fallback version ${FALLBACK_VERSION}`
240
+ );
241
+ return cachedVersion;
242
+ }
243
+ function compareVersions(a, b) {
244
+ const parse = (v) => {
245
+ const clean = v.trim().replace(/^v/, "").split(/[-+]/)[0];
246
+ const parts = clean.split(".");
247
+ return [
248
+ parseInt(parts[0] ?? "0", 10) || 0,
249
+ parseInt(parts[1] ?? "0", 10) || 0,
250
+ parseInt(parts[2] ?? "0", 10) || 0
251
+ ];
252
+ };
253
+ const [a1, a2, a3] = parse(a);
254
+ const [b1, b2, b3] = parse(b);
255
+ if (a1 !== b1) return a1 - b1;
256
+ if (a2 !== b2) return a2 - b2;
257
+ return a3 - b3;
258
+ }
259
+ function isBelow(current, minimum) {
260
+ return compareVersions(current, minimum) < 0;
261
+ }
262
+ var ApiClient = class {
263
+ baseUrl;
264
+ timeout;
265
+ constructor(config) {
266
+ this.baseUrl = config.baseUrl.replace(/\/+$/, "");
267
+ this.timeout = config.timeout ?? 6e4;
268
+ }
269
+ buildHeaders(auth) {
270
+ const headers = {
271
+ "User-Agent": `agenzo-admin-cli/${getCurrentVersion()}`
272
+ };
273
+ if (auth.type === "bearer") {
274
+ headers["Authorization"] = `Bearer ${auth.token}`;
275
+ } else if (auth.type === "api-key") {
276
+ headers["X-Api-Key"] = auth.key;
277
+ }
278
+ return headers;
279
+ }
280
+ async get(path, auth, params) {
281
+ let url = `${this.baseUrl}${path}`;
282
+ if (params && Object.keys(params).length > 0) {
283
+ const searchParams = new URLSearchParams(params);
284
+ url += `?${searchParams.toString()}`;
285
+ }
286
+ return this.request(url, {
287
+ method: "GET",
288
+ headers: this.buildHeaders(auth)
289
+ });
290
+ }
291
+ async post(path, auth, body, extraHeaders) {
292
+ const url = `${this.baseUrl}${path}`;
293
+ const headers = this.buildHeaders(auth);
294
+ headers["Content-Type"] = "application/json";
295
+ if (extraHeaders) {
296
+ Object.assign(headers, extraHeaders);
297
+ }
298
+ return this.request(url, {
299
+ method: "POST",
300
+ headers,
301
+ body: body ? JSON.stringify(body) : void 0
302
+ });
303
+ }
304
+ async request(url, init) {
305
+ const controller = new AbortController();
306
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
307
+ try {
308
+ const response = await fetch(url, {
309
+ ...init,
310
+ signal: controller.signal
311
+ });
312
+ this.enforceMinVersion(response.headers.get("x-cli-min-version"));
313
+ const contentType = response.headers.get("content-type") ?? "";
314
+ let responseBody;
315
+ if (contentType.includes("application/json")) {
316
+ responseBody = await response.json();
317
+ } else {
318
+ const text = await response.text();
319
+ if (!response.ok) {
320
+ const statusMsg = this.friendlyStatusMessage(response.status);
321
+ return {
322
+ success: false,
323
+ errorCode: 0,
324
+ errorMessage: statusMsg,
325
+ statusCode: response.status
326
+ };
327
+ }
328
+ try {
329
+ responseBody = JSON.parse(text);
330
+ } catch {
331
+ return {
332
+ success: false,
333
+ errorCode: 0,
334
+ errorMessage: `Unexpected response from server (${response.status})`,
335
+ statusCode: response.status
336
+ };
337
+ }
338
+ }
339
+ const code = responseBody.code;
340
+ const message = responseBody.message;
341
+ const data = responseBody.data;
342
+ if (response.ok && (!code || code === "0000")) {
343
+ const payload = data ?? responseBody;
344
+ return { success: true, data: payload, message };
345
+ }
346
+ const errorCode = code ? parseInt(code, 10) : 0;
347
+ let errorMsg = message ?? response.statusText;
348
+ if (!errorMsg || errorMsg === response.statusText) {
349
+ const detail = responseBody.detail;
350
+ if (Array.isArray(detail)) {
351
+ errorMsg = detail.map((d) => {
352
+ const loc = d.loc?.slice(1).join(".") ?? "";
353
+ return loc ? `${loc}: ${d.msg}` : String(d.msg);
354
+ }).join("; ");
355
+ } else if (typeof detail === "string") {
356
+ errorMsg = detail;
357
+ }
358
+ }
359
+ const errorCodeStr = responseBody.error_code;
360
+ const rawData = responseBody.data;
361
+ const upstream = rawData?.upstream && typeof rawData.upstream === "object" ? rawData.upstream : void 0;
362
+ return {
363
+ success: false,
364
+ errorCode: isNaN(errorCode) ? 0 : errorCode,
365
+ errorMessage: errorMsg,
366
+ statusCode: response.status,
367
+ ...errorCodeStr ? { code: errorCodeStr } : typeof code === "string" && code ? { code } : {},
368
+ requestId: responseBody.request_id ?? responseBody.requestId,
369
+ ...upstream ? { upstream } : {}
370
+ };
371
+ } catch (error) {
372
+ if (error instanceof UpgradeRequiredError) {
373
+ throw error;
374
+ }
375
+ if (error instanceof DOMException && error.name === "AbortError") {
376
+ throw new NetworkError(url, this.timeout);
377
+ }
378
+ throw new NetworkError(url, void 0, error instanceof Error ? error : void 0);
379
+ } finally {
380
+ clearTimeout(timeoutId);
381
+ }
382
+ }
383
+ /**
384
+ * Validate that the running CLI meets the server-advertised minimum.
385
+ * Missing or empty header → skip (backward compat with servers that don't
386
+ * advertise yet, and clients hitting legacy proxies).
387
+ */
388
+ enforceMinVersion(headerValue) {
389
+ const minVersion = headerValue?.trim();
390
+ if (!minVersion) return;
391
+ const current = getCurrentVersion();
392
+ if (isBelow(current, minVersion)) {
393
+ throw new UpgradeRequiredError(current, minVersion, UPGRADE_COMMAND);
394
+ }
395
+ }
396
+ friendlyStatusMessage(status) {
397
+ const messages = {
398
+ 400: "Invalid request. Please check your input.",
399
+ 401: "Authentication failed. Please check your API key or login again.",
400
+ 403: "Access denied. You do not have permission for this operation.",
401
+ 404: "Resource not found. Please check the ID.",
402
+ 409: "Conflict. This resource may already exist.",
403
+ 422: "Invalid input. Please check the request parameters.",
404
+ 429: "Too many requests. Please wait and try again.",
405
+ 500: "Something went wrong on the server. Please try again later.",
406
+ 502: "Service is temporarily unavailable. Please try again in a moment.",
407
+ 503: "Service is temporarily unavailable. Please try again in a moment.",
408
+ 504: "The request took too long. Please try again."
409
+ };
410
+ return messages[status] ?? `Something went wrong (${status}). Please try again later.`;
411
+ }
412
+ };
413
+ var DEFAULT_API_PATH = "/api/admin/v1";
414
+ var DEFAULT_CONFIG = {
415
+ active_org: null,
416
+ active_developer_id: null,
417
+ api_host: "https://agent.everonet.com",
418
+ api_path: DEFAULT_API_PATH
419
+ };
420
+ var BUILTIN_PROFILES = {
421
+ production: "https://agent.everonet.com",
422
+ testing: "https://agent-test.everonet.com"
423
+ };
424
+ function resolveApiHost(host) {
425
+ if (BUILTIN_PROFILES[host]) {
426
+ return BUILTIN_PROFILES[host];
427
+ }
428
+ let url;
429
+ try {
430
+ url = new URL(host);
431
+ } catch {
432
+ throw new ValidationError(`Unknown profile or invalid URL: ${host}`);
433
+ }
434
+ if (url.protocol === "https:") {
435
+ return host;
436
+ }
437
+ if (url.protocol === "http:" && (url.hostname === "localhost" || url.hostname === "127.0.0.1")) {
438
+ return host;
439
+ }
440
+ throw new ValidationError(
441
+ `Insecure API host is not allowed: ${host}. Use HTTPS, except for localhost or 127.0.0.1.`
442
+ );
443
+ }
444
+ var ConfigManager = class {
445
+ basePath;
446
+ configPath;
447
+ /**
448
+ * Product-line API prefix this CLI targets (e.g. /api/admin/v1,
449
+ * /api/token/v1). Injected per binary so the four CLIs share one api_host
450
+ * but route to different product lines. Overrides any persisted api_path.
451
+ */
452
+ apiPath;
453
+ constructor(basePath, apiPath) {
454
+ this.basePath = basePath ?? join4(homedir3(), ".agenzo-admin-cli");
455
+ this.configPath = join4(this.basePath, "config.json");
456
+ this.apiPath = apiPath ?? DEFAULT_API_PATH;
457
+ }
458
+ /** The resolved product-line API prefix for this CLI (per-binary constant). */
459
+ getApiPath() {
460
+ return this.apiPath;
461
+ }
462
+ async ensureDirectories() {
463
+ await mkdir3(this.basePath, { recursive: true, mode: 448 });
464
+ await chmod3(this.basePath, 448);
465
+ const credDir = join4(this.basePath, "credentials");
466
+ await mkdir3(credDir, { recursive: true, mode: 448 });
467
+ await chmod3(credDir, 448);
468
+ }
469
+ async load() {
470
+ try {
471
+ const content = await readFile3(this.configPath, "utf-8");
472
+ try {
473
+ const raw = JSON.parse(content);
474
+ if (raw.api_base_url && !raw.api_host) {
475
+ const url = String(raw.api_base_url);
476
+ const pathIndex = url.indexOf("/api/");
477
+ raw.api_host = pathIndex > 0 ? url.slice(0, pathIndex) : url;
478
+ raw.api_path = pathIndex > 0 ? url.slice(pathIndex) : DEFAULT_CONFIG.api_path;
479
+ delete raw.api_base_url;
480
+ }
481
+ return {
482
+ active_org: raw.active_org ?? null,
483
+ active_developer_id: raw.active_developer_id ?? null,
484
+ api_host: raw.api_host ?? DEFAULT_CONFIG.api_host,
485
+ api_path: raw.api_path ?? DEFAULT_CONFIG.api_path
486
+ };
487
+ } catch {
488
+ throw new ConfigError(
489
+ `Invalid config file: ${this.configPath}`,
490
+ this.configPath
491
+ );
492
+ }
493
+ } catch (error) {
494
+ if (error instanceof ConfigError) throw error;
495
+ if (error.code === "ENOENT") {
496
+ return { ...DEFAULT_CONFIG };
497
+ }
498
+ throw error;
499
+ }
500
+ }
501
+ async save(config) {
502
+ await this.ensureDirectories();
503
+ await writeFile3(this.configPath, JSON.stringify(config, null, 2), {
504
+ encoding: "utf-8",
505
+ mode: 384
506
+ });
507
+ await chmod3(this.configPath, 384);
508
+ }
509
+ async getActiveOrg() {
510
+ const config = await this.load();
511
+ return config.active_org;
512
+ }
513
+ async setActiveOrg(orgId) {
514
+ const config = await this.load();
515
+ config.active_org = orgId;
516
+ await this.save(config);
517
+ }
518
+ async getApiBaseUrl() {
519
+ const config = await this.load();
520
+ const host = resolveApiHost(config.api_host).replace(/\/+$/, "");
521
+ const path = this.apiPath.startsWith("/") ? this.apiPath : `/${this.apiPath}`;
522
+ return `${host}${path}`;
523
+ }
524
+ async setApiHost(host) {
525
+ const config = await this.load();
526
+ config.api_host = resolveApiHost(host);
527
+ await this.save(config);
528
+ }
529
+ async getApiHost() {
530
+ const config = await this.load();
531
+ return resolveApiHost(config.api_host);
532
+ }
533
+ };
534
+ function exitCodeFor(error) {
535
+ if (!(error instanceof CliError)) {
536
+ return 1;
537
+ }
538
+ const code = error.code;
539
+ if (code === "UPGRADE_REQUIRED") {
540
+ return 2;
541
+ }
542
+ if (code === "CLIENT_ABORTED") {
543
+ return 5;
544
+ }
545
+ if (code.startsWith("AUTH_") || code.startsWith("KEY_")) {
546
+ return 3;
547
+ }
548
+ if (code === "UPSTREAM_ERROR" || code === "INTERNAL_ERROR" || code === "RATE_LIMITED") {
549
+ return 4;
550
+ }
551
+ return 1;
552
+ }
553
+ var STATUS_ICONS = {
554
+ success: "\u2713",
555
+ error: "\u2717",
556
+ info: "\u2139",
557
+ warning: "\u26A0",
558
+ loading: "\u280B"
559
+ };
560
+ var Formatter = class _Formatter {
561
+ /** Get display width of a string (CJK characters count as 2) */
562
+ static displayWidth(str) {
563
+ let width = 0;
564
+ for (const char of str) {
565
+ const code = char.codePointAt(0);
566
+ if (code >= 19968 && code <= 40959 || // CJK Unified
567
+ code >= 12288 && code <= 12351 || // CJK Punctuation
568
+ code >= 13312 && code <= 19903 || // CJK Extension A
569
+ code >= 65280 && code <= 65519 || // Fullwidth Forms
570
+ code >= 63744 && code <= 64255 || // CJK Compatibility
571
+ code >= 131072 && code <= 173791) {
572
+ width += 2;
573
+ } else {
574
+ width += 1;
575
+ }
576
+ }
577
+ return width;
578
+ }
579
+ /** Pad string to target display width (right-pad with spaces) */
580
+ static padEndDisplay(str, targetWidth) {
581
+ const currentWidth = _Formatter.displayWidth(str);
582
+ const padding = Math.max(0, targetWidth - currentWidth);
583
+ return str + " ".repeat(padding);
584
+ }
585
+ /** Pad string to target display width (left-pad with spaces) */
586
+ static padStartDisplay(str, targetWidth) {
587
+ const currentWidth = _Formatter.displayWidth(str);
588
+ const padding = Math.max(0, targetWidth - currentWidth);
589
+ return " ".repeat(padding) + str;
590
+ }
591
+ /** Table output for list commands — columns aligned by max width */
592
+ static table(headers, rows) {
593
+ const colWidths = headers.map((h, i) => {
594
+ const cellWidths = rows.map((r) => _Formatter.displayWidth(r[i] ?? ""));
595
+ return Math.max(_Formatter.displayWidth(h), ...cellWidths);
596
+ });
597
+ const sep = " ";
598
+ const headerLine = headers.map((h, i) => _Formatter.padEndDisplay(h, colWidths[i])).join(sep);
599
+ const divider = colWidths.map((w) => "-".repeat(w)).join(sep);
600
+ const dataLines = rows.map(
601
+ (row) => row.map((cell, i) => _Formatter.padEndDisplay(cell ?? "", colWidths[i])).join(sep)
602
+ );
603
+ return [headerLine, divider, ...dataLines].join("\n");
604
+ }
605
+ /** Key-value output for detail commands — keys left-aligned */
606
+ static keyValue(entries) {
607
+ const maxKeyWidth = Math.max(...entries.map(([k]) => _Formatter.displayWidth(k)));
608
+ return entries.map(([key, value]) => `${_Formatter.padEndDisplay(key, maxKeyWidth)} ${value}`).join("\n");
609
+ }
610
+ /** Status-prefixed message */
611
+ static status(type, message) {
612
+ return `${STATUS_ICONS[type]} ${message}`;
613
+ }
614
+ /** Mask sensitive info, keeping only the prefix */
615
+ static maskKey(key, prefixLength = 8) {
616
+ if (key.length <= prefixLength) {
617
+ return key;
618
+ }
619
+ return key.slice(0, prefixLength) + "*".repeat(key.length - prefixLength);
620
+ }
621
+ /**
622
+ * Format ISO 8601 timestamp to local timezone display.
623
+ * Automatically uses the user's system timezone.
624
+ * e.g. "2026-05-07T03:24:53+00:00" → "2026-05-07 11:24:53" (in CST)
625
+ * "2026-05-07T03:24:53+00:00" → "2026-05-06 20:24:53" (in PDT)
626
+ * Returns the original string if parsing fails or input is empty.
627
+ */
628
+ static formatTime(iso) {
629
+ if (!iso) return "";
630
+ const date = new Date(iso);
631
+ if (isNaN(date.getTime())) return iso;
632
+ const pad = (n) => String(n).padStart(2, "0");
633
+ const y = date.getFullYear();
634
+ const m = pad(date.getMonth() + 1);
635
+ const d = pad(date.getDate());
636
+ const h = pad(date.getHours());
637
+ const min = pad(date.getMinutes());
638
+ const s = pad(date.getSeconds());
639
+ const offsetMin = -date.getTimezoneOffset();
640
+ const sign = offsetMin >= 0 ? "+" : "-";
641
+ const absOffset = Math.abs(offsetMin);
642
+ const tzH = pad(Math.floor(absOffset / 60));
643
+ const tzM = pad(absOffset % 60);
644
+ return `${y}-${m}-${d} ${h}:${min}:${s} (UTC${sign}${tzH}:${tzM})`;
645
+ }
646
+ };
647
+ var DEFAULT_FORMAT = "table";
648
+ function isOutputFormat(value) {
649
+ return value === "json" || value === "table";
650
+ }
651
+ function resolveFormat(flag, env = process.env.AGENZO_FORMAT) {
652
+ if (flag !== void 0) {
653
+ return isOutputFormat(flag) ? flag : DEFAULT_FORMAT;
654
+ }
655
+ if (env !== void 0 && isOutputFormat(env)) {
656
+ return env;
657
+ }
658
+ return DEFAULT_FORMAT;
659
+ }
660
+ function render(result, opts) {
661
+ if (opts.format === "json") {
662
+ process.stdout.write(`${JSON.stringify(result.data, null, 2)}
663
+ `);
664
+ return;
665
+ }
666
+ process.stdout.write(`${result.text()}
667
+ `);
668
+ }
669
+ function notify(format, type, message) {
670
+ if (format === "json") {
671
+ return;
672
+ }
673
+ console.error(Formatter.status(type, message));
674
+ }
675
+ async function renderWithContext(result, opts, configManager) {
676
+ if (opts.format !== "json") {
677
+ render(result, opts);
678
+ return;
679
+ }
680
+ const config = await configManager.load();
681
+ const host = config.api_host.replace(/\/+$/, "");
682
+ const profile = Object.entries(BUILTIN_PROFILES).find(([, v]) => v === host)?.[0] ?? "custom";
683
+ const dataObj = result.data && typeof result.data === "object" ? result.data : { value: result.data };
684
+ const payload = {
685
+ profile,
686
+ endpoint: host,
687
+ ...dataObj
688
+ };
689
+ render({ ...result, data: payload }, opts);
690
+ }
691
+ var PromptEngine = class {
692
+ /** Return flagValue directly if provided, otherwise prompt interactively */
693
+ static async resolveInput(flagValue, config) {
694
+ if (flagValue !== void 0) {
695
+ return flagValue;
696
+ }
697
+ if (config.type === "password") {
698
+ return password({ message: config.message, mask: "*" });
699
+ }
700
+ if (config.type === "select" && config.choices) {
701
+ return select({
702
+ message: config.message,
703
+ choices: config.choices
704
+ });
705
+ }
706
+ return input({
707
+ message: config.message,
708
+ validate: config.validate
709
+ });
710
+ }
711
+ };
27
712
 
28
713
  // src/ride-elife/watch.ts
29
- import { CliError } from "@agenzo/cli-core";
30
714
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
31
715
  "At destination",
32
716
  "Cancelled",
@@ -371,14 +1055,14 @@ var listOrdersSchema = {
371
1055
  // src/ride-elife/quote.ts
372
1056
  function need(value, flag) {
373
1057
  if (value === void 0) {
374
- throw new CliError2("PARAM_INVALID", `Missing required --${flag}.`);
1058
+ throw new CliError("PARAM_INVALID", `Missing required --${flag}.`);
375
1059
  }
376
1060
  return value;
377
1061
  }
378
1062
  function num(value, flag) {
379
1063
  const n = Number(need(value, flag));
380
1064
  if (!Number.isFinite(n)) {
381
- throw new CliError2("PARAM_INVALID", `--${flag} must be a number.`);
1065
+ throw new CliError("PARAM_INVALID", `--${flag} must be a number.`);
382
1066
  }
383
1067
  return n;
384
1068
  }
@@ -454,7 +1138,7 @@ function registerQuoteCommand(parent, deps) {
454
1138
  body
455
1139
  );
456
1140
  if (!result.success) {
457
- throw CliError2.fromApi(result, { auth: "api-key" });
1141
+ throw CliError.fromApi(result, { auth: "api-key" });
458
1142
  }
459
1143
  const data = result.data;
460
1144
  const configManager = new ConfigManager();
@@ -468,28 +1152,14 @@ function registerQuoteCommand(parent, deps) {
468
1152
 
469
1153
  // src/ride-elife/book.ts
470
1154
  import { confirm } from "@inquirer/prompts";
471
- import {
472
- ConfigManager as ConfigManager2,
473
- PromptEngine as PromptEngine3,
474
- Formatter as Formatter2,
475
- resolveFormat as resolveFormat2,
476
- notify as notify2,
477
- CliError as CliError4,
478
- renderWithContext as renderWithContext2
479
- } from "@agenzo/cli-core";
480
1155
 
481
1156
  // src/idempotency.ts
482
- import {
483
- CliError as CliError3,
484
- IdempotencyKeyRequiredError,
485
- PromptEngine as PromptEngine2
486
- } from "@agenzo/cli-core";
487
1157
  var IDEMPOTENCY_KEY_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
488
1158
  var IDEMPOTENCY_KEY_RULE = "Use 1-128 characters from [A-Za-z0-9_-].";
489
1159
  function normalizeIdempotencyKey(key) {
490
1160
  const trimmed = key.trim();
491
1161
  if (!IDEMPOTENCY_KEY_PATTERN.test(trimmed)) {
492
- throw new CliError3(
1162
+ throw new CliError(
493
1163
  "PARAM_INVALID",
494
1164
  `Invalid idempotency key: "${key}". ${IDEMPOTENCY_KEY_RULE}`
495
1165
  );
@@ -503,7 +1173,7 @@ async function resolveIdempotencyKey(flagValue, opts) {
503
1173
  if (opts.yes) {
504
1174
  throw new IdempotencyKeyRequiredError(opts.commandPath);
505
1175
  }
506
- const entered = await PromptEngine2.resolveInput(void 0, {
1176
+ const entered = await PromptEngine.resolveInput(void 0, {
507
1177
  message: "Idempotency key (unique per write, for safe retry):",
508
1178
  validate: (v) => IDEMPOTENCY_KEY_PATTERN.test(v.trim()) || IDEMPOTENCY_KEY_RULE
509
1179
  });
@@ -513,21 +1183,21 @@ async function resolveIdempotencyKey(flagValue, opts) {
513
1183
  // src/ride-elife/book.ts
514
1184
  function need2(value, flag) {
515
1185
  if (value === void 0) {
516
- throw new CliError4("PARAM_INVALID", `Missing required --${flag}.`);
1186
+ throw new CliError("PARAM_INVALID", `Missing required --${flag}.`);
517
1187
  }
518
1188
  return value;
519
1189
  }
520
1190
  function num2(value, flag) {
521
1191
  const n = Number(need2(value, flag));
522
1192
  if (!Number.isFinite(n)) {
523
- throw new CliError4("PARAM_INVALID", `--${flag} must be a number.`);
1193
+ throw new CliError("PARAM_INVALID", `--${flag} must be a number.`);
524
1194
  }
525
1195
  return n;
526
1196
  }
527
1197
  function seatCount(value, flag) {
528
1198
  const n = num2(value, flag);
529
1199
  if (!Number.isInteger(n) || n < 0 || n > 5) {
530
- throw new CliError4("PARAM_INVALID", `--${flag} must be an integer between 0 and 5.`);
1200
+ throw new CliError("PARAM_INVALID", `--${flag} must be an integer between 0 and 5.`);
531
1201
  }
532
1202
  return n;
533
1203
  }
@@ -546,7 +1216,7 @@ function formatBook(data) {
546
1216
  lines.push(["Payment status", String(data.payment_status ?? "-")]);
547
1217
  if (data.billing_entry_id) lines.push(["Billing entry", String(data.billing_entry_id)]);
548
1218
  if (data.payment_order_id) lines.push(["Payment order", String(data.payment_order_id)]);
549
- return Formatter2.keyValue(lines);
1219
+ return Formatter.keyValue(lines);
550
1220
  }
551
1221
  function registerBookCommand(parent, deps) {
552
1222
  const cmd = parent.command("book").description("Book a ride using a quote_id returned by quote").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--quote-id <id>", "Quote id from `ride-elife quote`").option("--vehicle-class <class>", "Chosen vehicle class").option("--price-amount <amount>", "Fare in decimal currency units (not cents)").option("--price-currency <currency>", "Currency code (default USD)").option("--payment-order-id <id>", "Paid payment order id (pay_per_call mode only)").option("--passenger-name <name>", "Passenger full name").option("--passenger-phone <phone>", "Passenger phone").option("--passenger-email <email>", "Passenger email").option("--luggage-count <n>", "Luggage count").option("--special-requests <text>", "Free-text special requests").option("--pickup-lat <lat>", "Pickup latitude").option("--pickup-lng <lng>", "Pickup longitude").option("--pickup-name <name>", "Pickup location name").option("--dropoff-lat <lat>", "Dropoff latitude").option("--dropoff-lng <lng>", "Dropoff longitude").option("--dropoff-name <name>", "Dropoff location name").option("--pickup-time <time>", 'Pickup time: epoch seconds, or "now"').option("--meet-and-greet", "Enable meet & greet service").option("--meet-and-greet-price <amount>", "Meet & greet surcharge").option("--welcome-sign <text>", "Welcome sign text").option("--child-seat-count <n>", "Number of child seats needed (0-5)").option("--infant-seat-count <n>", "Number of infant seats needed (0-5)").option("--toddler-seat-count <n>", "Number of toddler seats needed (0-5)").option("--arrival-flight-no <no>", "Arrival flight number").option("--arrival-airline <airline>", "Arrival airline").option("--departure-flight-no <no>", "Departure flight number").option("--departure-airline <airline>", "Departure airline").option(
@@ -556,9 +1226,9 @@ function registerBookCommand(parent, deps) {
556
1226
  attachSchemaHelp(cmd, bookSchema);
557
1227
  cmd.action(async () => {
558
1228
  const opts = cmd.optsWithGlobals();
559
- const format = resolveFormat2(opts.format);
1229
+ const format = resolveFormat(opts.format);
560
1230
  const isYes = Boolean(opts.yes);
561
- const apiKey = await PromptEngine3.resolveInput(opts.apiKey, {
1231
+ const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
562
1232
  message: "API Key:",
563
1233
  type: "password"
564
1234
  });
@@ -626,14 +1296,14 @@ function registerBookCommand(parent, deps) {
626
1296
  default: true
627
1297
  });
628
1298
  if (!confirmed) {
629
- throw new CliError4("CLIENT_ABORTED", "Booking cancelled by user.");
1299
+ throw new CliError("CLIENT_ABORTED", "Booking cancelled by user.");
630
1300
  }
631
1301
  }
632
1302
  const idempotencyKey = await resolveIdempotencyKey(opts.idempotencyKey, {
633
1303
  yes: isYes,
634
1304
  commandPath: "ride-elife book"
635
1305
  });
636
- notify2(format, "loading", "Booking ride...");
1306
+ notify(format, "loading", "Booking ride...");
637
1307
  const result = await deps.apiClient.post(
638
1308
  "/ride/book",
639
1309
  { type: "api-key", key: apiKey },
@@ -641,31 +1311,22 @@ function registerBookCommand(parent, deps) {
641
1311
  { "Idempotency-Key": idempotencyKey }
642
1312
  );
643
1313
  if (!result.success) {
644
- throw CliError4.fromApi(result, { auth: "api-key" });
1314
+ throw CliError.fromApi(result, { auth: "api-key" });
645
1315
  }
646
1316
  const data = result.data;
647
- const configManager = new ConfigManager2();
1317
+ const configManager = new ConfigManager();
648
1318
  const commandResult = {
649
1319
  data,
650
1320
  text: () => formatBook(data)
651
1321
  };
652
- await renderWithContext2(commandResult, { format }, configManager);
1322
+ await renderWithContext(commandResult, { format }, configManager);
653
1323
  });
654
1324
  }
655
1325
 
656
1326
  // src/ride-elife/get.ts
657
- import {
658
- ConfigManager as ConfigManager3,
659
- PromptEngine as PromptEngine4,
660
- Formatter as Formatter3,
661
- resolveFormat as resolveFormat3,
662
- notify as notify3,
663
- CliError as CliError5,
664
- renderWithContext as renderWithContext3
665
- } from "@agenzo/cli-core";
666
1327
  function need3(value, flag) {
667
1328
  if (value === void 0) {
668
- throw new CliError5("PARAM_INVALID", `Missing required --${flag}.`);
1329
+ throw new CliError("PARAM_INVALID", `Missing required --${flag}.`);
669
1330
  }
670
1331
  return value;
671
1332
  }
@@ -705,7 +1366,7 @@ function formatGetOrder(data) {
705
1366
  lines.push(["Vehicle", `${desc}${plate}`]);
706
1367
  }
707
1368
  if (data.created_at) lines.push(["Created at", String(data.created_at)]);
708
- return Formatter3.keyValue(lines);
1369
+ return Formatter.keyValue(lines);
709
1370
  }
710
1371
  function registerRideGetCommand(parent, deps) {
711
1372
  const cmd = parent.command("get").description("Retrieve a ride order status by id (repeatable for polling)").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--order-id <id>", "Ride order id (the ride_id returned by `ride-elife book`)").option("--watch", "Poll until a terminal status, emitting one NDJSON line per update").option(
@@ -718,8 +1379,8 @@ function registerRideGetCommand(parent, deps) {
718
1379
  attachSchemaHelp(cmd, rideGetSchema);
719
1380
  cmd.action(async () => {
720
1381
  const opts = cmd.optsWithGlobals();
721
- const format = resolveFormat3(opts.format);
722
- const apiKey = await PromptEngine4.resolveInput(opts.apiKey, {
1382
+ const format = resolveFormat(opts.format);
1383
+ const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
723
1384
  message: "API Key:",
724
1385
  type: "password"
725
1386
  });
@@ -737,38 +1398,29 @@ function registerRideGetCommand(parent, deps) {
737
1398
  });
738
1399
  return;
739
1400
  }
740
- notify3(format, "loading", "Fetching ride status...");
1401
+ notify(format, "loading", "Fetching ride status...");
741
1402
  const result = await deps.apiClient.get(
742
1403
  `/ride/${encodeURIComponent(orderId)}/status`,
743
1404
  { type: "api-key", key: apiKey }
744
1405
  );
745
1406
  if (!result.success) {
746
- throw CliError5.fromApi(result, { auth: "api-key" });
1407
+ throw CliError.fromApi(result, { auth: "api-key" });
747
1408
  }
748
1409
  const data = result.data;
749
- const configManager = new ConfigManager3();
1410
+ const configManager = new ConfigManager();
750
1411
  const commandResult = {
751
1412
  data,
752
1413
  text: () => formatGetOrder(data)
753
1414
  };
754
- await renderWithContext3(commandResult, { format }, configManager);
1415
+ await renderWithContext(commandResult, { format }, configManager);
755
1416
  });
756
1417
  }
757
1418
 
758
1419
  // src/ride-elife/cancel.ts
759
1420
  import { confirm as confirm2 } from "@inquirer/prompts";
760
- import {
761
- ConfigManager as ConfigManager4,
762
- PromptEngine as PromptEngine5,
763
- Formatter as Formatter4,
764
- resolveFormat as resolveFormat4,
765
- notify as notify4,
766
- CliError as CliError6,
767
- renderWithContext as renderWithContext4
768
- } from "@agenzo/cli-core";
769
1421
  function need4(value, flag) {
770
1422
  if (value === void 0) {
771
- throw new CliError6("PARAM_INVALID", `Missing required --${flag}.`);
1423
+ throw new CliError("PARAM_INVALID", `Missing required --${flag}.`);
772
1424
  }
773
1425
  return value;
774
1426
  }
@@ -785,7 +1437,7 @@ function formatCancel(data) {
785
1437
  if (data.refund_amount !== void 0 && data.refund_amount !== null) {
786
1438
  lines.push(["Refund amount", String(data.refund_amount)]);
787
1439
  }
788
- return Formatter4.keyValue(lines);
1440
+ return Formatter.keyValue(lines);
789
1441
  }
790
1442
  function registerCancelCommand(parent, deps) {
791
1443
  const cmd = parent.command("cancel").description("Cancel a ride order by id (may incur a cancellation fee)").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--order-id <id>", "Ride order id to cancel (the ride_id returned by book)").option(
@@ -795,9 +1447,9 @@ function registerCancelCommand(parent, deps) {
795
1447
  attachSchemaHelp(cmd, cancelSchema);
796
1448
  cmd.action(async () => {
797
1449
  const opts = cmd.optsWithGlobals();
798
- const format = resolveFormat4(opts.format);
1450
+ const format = resolveFormat(opts.format);
799
1451
  const isYes = Boolean(opts.yes);
800
- const apiKey = await PromptEngine5.resolveInput(opts.apiKey, {
1452
+ const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
801
1453
  message: "API Key:",
802
1454
  type: "password"
803
1455
  });
@@ -808,14 +1460,14 @@ function registerCancelCommand(parent, deps) {
808
1460
  default: false
809
1461
  });
810
1462
  if (!confirmed) {
811
- throw new CliError6("CLIENT_ABORTED", "Cancellation aborted by user.");
1463
+ throw new CliError("CLIENT_ABORTED", "Cancellation aborted by user.");
812
1464
  }
813
1465
  }
814
1466
  const idempotencyKey = await resolveIdempotencyKey(opts.idempotencyKey, {
815
1467
  yes: isYes,
816
1468
  commandPath: "ride-elife cancel"
817
1469
  });
818
- notify4(format, "loading", "Cancelling ride...");
1470
+ notify(format, "loading", "Cancelling ride...");
819
1471
  const result = await deps.apiClient.post(
820
1472
  `/ride/${encodeURIComponent(orderId)}/cancel`,
821
1473
  { type: "api-key", key: apiKey },
@@ -823,41 +1475,32 @@ function registerCancelCommand(parent, deps) {
823
1475
  { "Idempotency-Key": idempotencyKey }
824
1476
  );
825
1477
  if (!result.success) {
826
- throw CliError6.fromApi(result, { auth: "api-key" });
1478
+ throw CliError.fromApi(result, { auth: "api-key" });
827
1479
  }
828
1480
  const data = result.data;
829
- const configManager = new ConfigManager4();
1481
+ const configManager = new ConfigManager();
830
1482
  const commandResult = {
831
1483
  data,
832
1484
  text: () => formatCancel(data)
833
1485
  };
834
- await renderWithContext4(commandResult, { format }, configManager);
1486
+ await renderWithContext(commandResult, { format }, configManager);
835
1487
  });
836
1488
  }
837
1489
 
838
1490
  // src/ride-elife/list-orders.ts
839
- import {
840
- ConfigManager as ConfigManager5,
841
- PromptEngine as PromptEngine6,
842
- Formatter as Formatter5,
843
- resolveFormat as resolveFormat5,
844
- notify as notify5,
845
- CliError as CliError7,
846
- renderWithContext as renderWithContext5
847
- } from "@agenzo/cli-core";
848
1491
  var DEFAULT_PAGE = "1";
849
1492
  var DEFAULT_PAGE_SIZE = "20";
850
1493
  function positiveInt(value, flag) {
851
1494
  const n = Number(value);
852
1495
  if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
853
- throw new CliError7("PARAM_INVALID", `--${flag} must be a positive integer.`);
1496
+ throw new CliError("PARAM_INVALID", `--${flag} must be a positive integer.`);
854
1497
  }
855
1498
  return String(n);
856
1499
  }
857
1500
  function formatOrders(data) {
858
1501
  const orders = data.orders ?? [];
859
1502
  if (orders.length === 0) {
860
- return Formatter5.status("info", "No ride orders found");
1503
+ return Formatter.status("info", "No ride orders found");
861
1504
  }
862
1505
  const headers = ["Order ID", "Ride ID", "Status", "Vehicle Class", "Price", "Currency", "Payment"];
863
1506
  const rows = orders.map((o) => [
@@ -874,16 +1517,16 @@ function formatOrders(data) {
874
1517
  ["Page", String(data.page ?? "-")],
875
1518
  ["Page size", String(data.page_size ?? "-")]
876
1519
  ];
877
- return `${Formatter5.table(headers, rows)}
878
- ${Formatter5.keyValue(summary)}`;
1520
+ return `${Formatter.table(headers, rows)}
1521
+ ${Formatter.keyValue(summary)}`;
879
1522
  }
880
1523
  function registerListOrdersCommand(parent, deps) {
881
1524
  const cmd = parent.command("list-orders").description("List previously placed ride orders").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--page <page>", "Page number", DEFAULT_PAGE).option("--page-size <size>", "Page size", DEFAULT_PAGE_SIZE).option("--status <status>", "Filter by order status").option("--order-type <type>", "Filter by order type");
882
1525
  attachSchemaHelp(cmd, listOrdersSchema);
883
1526
  cmd.action(async () => {
884
1527
  const opts = cmd.optsWithGlobals();
885
- const format = resolveFormat5(opts.format);
886
- const apiKey = await PromptEngine6.resolveInput(opts.apiKey, {
1528
+ const format = resolveFormat(opts.format);
1529
+ const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
887
1530
  message: "API Key:",
888
1531
  type: "password"
889
1532
  });
@@ -893,28 +1536,25 @@ function registerListOrdersCommand(parent, deps) {
893
1536
  };
894
1537
  if (opts.status !== void 0) params.status = opts.status;
895
1538
  if (opts.orderType !== void 0) params.order_type = opts.orderType;
896
- notify5(format, "loading", "Fetching orders...");
1539
+ notify(format, "loading", "Fetching orders...");
897
1540
  const result = await deps.apiClient.get(
898
1541
  "/ride/orders",
899
1542
  { type: "api-key", key: apiKey },
900
1543
  params
901
1544
  );
902
1545
  if (!result.success) {
903
- throw CliError7.fromApi(result, { auth: "api-key" });
1546
+ throw CliError.fromApi(result, { auth: "api-key" });
904
1547
  }
905
1548
  const data = result.data;
906
- const configManager = new ConfigManager5();
1549
+ const configManager = new ConfigManager();
907
1550
  const commandResult = {
908
1551
  data,
909
1552
  text: () => formatOrders(data)
910
1553
  };
911
- await renderWithContext5(commandResult, { format }, configManager);
1554
+ await renderWithContext(commandResult, { format }, configManager);
912
1555
  });
913
1556
  }
914
1557
 
915
- // src/services/list.ts
916
- import { ConfigManager as ConfigManager6, Formatter as Formatter6, resolveFormat as resolveFormat6, renderWithContext as renderWithContext6 } from "@agenzo/cli-core";
917
-
918
1558
  // src/services/registry.ts
919
1559
  var SERVICE_REGISTRY = [
920
1560
  {
@@ -960,14 +1600,14 @@ function registerServicesListCommand(parent) {
960
1600
  const cmd = parent.command("list").description("List available merchant services from the registry");
961
1601
  cmd.action(async () => {
962
1602
  const opts = cmd.optsWithGlobals();
963
- const format = resolveFormat6(opts.format);
1603
+ const format = resolveFormat(opts.format);
964
1604
  const services = SERVICE_REGISTRY.map(toListItem);
965
- const configManager = new ConfigManager6();
1605
+ const configManager = new ConfigManager();
966
1606
  const commandResult = {
967
1607
  data: { services },
968
1608
  text: () => {
969
1609
  if (services.length === 0) {
970
- return Formatter6.status("info", "No services found");
1610
+ return Formatter.status("info", "No services found");
971
1611
  }
972
1612
  const headers = ["Service ID", "Name", "Category", "Provider", "Version", "Verbs"];
973
1613
  const rows = services.map((s) => [
@@ -978,21 +1618,14 @@ function registerServicesListCommand(parent) {
978
1618
  s.version,
979
1619
  s.verbs.join(", ")
980
1620
  ]);
981
- return Formatter6.table(headers, rows);
1621
+ return Formatter.table(headers, rows);
982
1622
  }
983
1623
  };
984
- await renderWithContext6(commandResult, { format }, configManager);
1624
+ await renderWithContext(commandResult, { format }, configManager);
985
1625
  });
986
1626
  }
987
1627
 
988
1628
  // src/services/get.ts
989
- import {
990
- ConfigManager as ConfigManager7,
991
- Formatter as Formatter7,
992
- CliError as CliError8,
993
- resolveFormat as resolveFormat7,
994
- renderWithContext as renderWithContext7
995
- } from "@agenzo/cli-core";
996
1629
  function formatServiceGet(s) {
997
1630
  const lines = [
998
1631
  ["Service ID", s.service_id],
@@ -1008,7 +1641,7 @@ function formatServiceGet(s) {
1008
1641
  ["Help", s.discovery.help_command]
1009
1642
  ];
1010
1643
  const verbDetail = s.verbs.map((v) => ` ${v}: ${s.verb_descriptions[v] ?? ""}`).join("\n");
1011
- return `${Formatter7.keyValue(lines)}
1644
+ return `${Formatter.keyValue(lines)}
1012
1645
  Verb descriptions:
1013
1646
  ${verbDetail}`;
1014
1647
  }
@@ -1016,30 +1649,30 @@ function registerServiceGetCommand(parent) {
1016
1649
  const cmd = parent.command("get <service-id>").description("Retrieve a single merchant service by id");
1017
1650
  cmd.action(async (serviceId) => {
1018
1651
  const opts = cmd.optsWithGlobals();
1019
- const format = resolveFormat7(opts.format);
1652
+ const format = resolveFormat(opts.format);
1020
1653
  const service = findService(serviceId);
1021
1654
  if (!service) {
1022
- throw new CliError8(
1655
+ throw new CliError(
1023
1656
  "SERVICE_NOT_FOUND",
1024
1657
  `Service '${serviceId}' was not found in the registry. Run "services list" to see available services.`
1025
1658
  );
1026
1659
  }
1027
- const configManager = new ConfigManager7();
1660
+ const configManager = new ConfigManager();
1028
1661
  const commandResult = {
1029
1662
  data: service,
1030
1663
  text: () => formatServiceGet(service)
1031
1664
  };
1032
- await renderWithContext7(commandResult, { format }, configManager);
1665
+ await renderWithContext(commandResult, { format }, configManager);
1033
1666
  });
1034
1667
  }
1035
1668
 
1036
1669
  // src/index.ts
1037
1670
  var programRef;
1038
1671
  async function main() {
1039
- const configManager = new ConfigManager8();
1672
+ const configManager = new ConfigManager(void 0, "/api/merchant/v1");
1040
1673
  await configManager.ensureDirectories();
1041
1674
  const apiBaseUrl = await configManager.getApiBaseUrl();
1042
- const apiClient = new ApiClient6({ baseUrl: apiBaseUrl });
1675
+ const apiClient = new ApiClient({ baseUrl: apiBaseUrl });
1043
1676
  const deps = { apiClient };
1044
1677
  const program = new Command();
1045
1678
  programRef = program;
@@ -1052,7 +1685,7 @@ async function main() {
1052
1685
  ).option("--api-key <key>", "API Key for authentication (X-Api-Key)");
1053
1686
  program.hook("preAction", (thisCommand) => {
1054
1687
  const flag = thisCommand.opts().format;
1055
- process.env.AGENZO_FORMAT = resolveFormat8(flag);
1688
+ process.env.AGENZO_FORMAT = resolveFormat(flag);
1056
1689
  });
1057
1690
  const rideCmd = program.command("ride-elife").description("Ride ordering (eLife)");
1058
1691
  registerQuoteCommand(rideCmd, deps);
@@ -1067,7 +1700,7 @@ async function main() {
1067
1700
  }
1068
1701
  function resolveActiveFormat() {
1069
1702
  const flag = programRef?.opts().format;
1070
- return resolveFormat8(flag);
1703
+ return resolveFormat(flag);
1071
1704
  }
1072
1705
  function reportError(error) {
1073
1706
  const envelope = toErrorEnvelope(error);
@@ -1076,9 +1709,9 @@ function reportError(error) {
1076
1709
  console.error(JSON.stringify(envelope));
1077
1710
  } else {
1078
1711
  console.error(
1079
- Formatter8.status("error", `[${envelope.error.code_num}] ${envelope.error.message}`)
1712
+ Formatter.status("error", `[${envelope.error.code_num}] ${envelope.error.message}`)
1080
1713
  );
1081
- if (!(error instanceof CliError9) && process.argv.includes("--verbose")) {
1714
+ if (!(error instanceof CliError) && process.argv.includes("--verbose")) {
1082
1715
  console.error(error);
1083
1716
  }
1084
1717
  }