@01.software/cli 0.2.0 → 0.3.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.
package/dist/index.js CHANGED
@@ -5,11 +5,24 @@ import { createRequire } from "module";
5
5
  import { Command } from "commander";
6
6
 
7
7
  // src/lib/client.ts
8
- import { CollectionClient, OrderApi, CartApi, ProductApi, parseApiKey } from "@01.software/sdk";
8
+ import {
9
+ CollectionClient,
10
+ OrderApi,
11
+ CartApi,
12
+ ProductApi,
13
+ parseApiKey
14
+ } from "@01.software/sdk";
9
15
  import pc from "picocolors";
10
16
 
11
17
  // src/lib/credentials.ts
12
- import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, appendFileSync } from "fs";
18
+ import {
19
+ existsSync,
20
+ mkdirSync,
21
+ readFileSync,
22
+ writeFileSync,
23
+ unlinkSync,
24
+ appendFileSync
25
+ } from "fs";
13
26
  import { join } from "path";
14
27
  import { homedir } from "os";
15
28
  var DIR_NAME = ".01software";
@@ -27,8 +40,14 @@ function saveCredentials(creds) {
27
40
  mkdirSync(dir, { recursive: true, mode: 448 });
28
41
  }
29
42
  const filePath = getCredentialsPath();
30
- const data = { ...creds, storedAt: (/* @__PURE__ */ new Date()).toISOString() };
31
- writeFileSync(filePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
43
+ const data = {
44
+ ...creds,
45
+ storedAt: (/* @__PURE__ */ new Date()).toISOString()
46
+ };
47
+ writeFileSync(filePath, JSON.stringify(data, null, 2), {
48
+ encoding: "utf-8",
49
+ mode: 384
50
+ });
32
51
  }
33
52
  function deleteCredentials() {
34
53
  const filePath = getCredentialsPath();
@@ -48,8 +67,14 @@ function saveLocalCredentials(creds) {
48
67
  mkdirSync(dir, { recursive: true, mode: 448 });
49
68
  }
50
69
  const filePath = getLocalCredentialsPath();
51
- const data = { ...creds, storedAt: (/* @__PURE__ */ new Date()).toISOString() };
52
- writeFileSync(filePath, JSON.stringify(data, null, 2), { encoding: "utf-8", mode: 384 });
70
+ const data = {
71
+ ...creds,
72
+ storedAt: (/* @__PURE__ */ new Date()).toISOString()
73
+ };
74
+ writeFileSync(filePath, JSON.stringify(data, null, 2), {
75
+ encoding: "utf-8",
76
+ mode: 384
77
+ });
53
78
  ensureGitignore();
54
79
  }
55
80
  function saveTenantList(tenants) {
@@ -58,7 +83,10 @@ function saveTenantList(tenants) {
58
83
  mkdirSync(dir, { recursive: true, mode: 448 });
59
84
  }
60
85
  const filePath = join(homedir(), DIR_NAME, TENANTS_FILE);
61
- writeFileSync(filePath, JSON.stringify(tenants, null, 2), { encoding: "utf-8", mode: 384 });
86
+ writeFileSync(filePath, JSON.stringify(tenants, null, 2), {
87
+ encoding: "utf-8",
88
+ mode: 384
89
+ });
62
90
  }
63
91
  function loadTenantList() {
64
92
  const filePath = join(homedir(), DIR_NAME, TENANTS_FILE);
@@ -111,8 +139,12 @@ function resolveClient(apiKeyFlag) {
111
139
  clientKey = parsed.clientKey;
112
140
  secretKey = parsed.secretKey;
113
141
  } catch {
114
- console.error(pc.red('Invalid --api-key value. Expected Base64-encoded "clientKey:secretKey".'));
115
- process.exit(1);
142
+ console.error(
143
+ pc.red(
144
+ 'Invalid --api-key value. Expected Base64-encoded "clientKey:secretKey".'
145
+ )
146
+ );
147
+ process.exit(2);
116
148
  }
117
149
  } else {
118
150
  clientKey = process.env.SOFTWARE_CLIENT_KEY;
@@ -139,14 +171,16 @@ function resolveClient(apiKeyFlag) {
139
171
  'Run "01 login" to authenticate via browser,\nor set SOFTWARE_CLIENT_KEY and SOFTWARE_SECRET_KEY environment variables,\nor use the --api-key <base64> flag.'
140
172
  )
141
173
  );
142
- process.exit(1);
174
+ process.exit(2);
143
175
  }
144
176
  const apiOpts = { clientKey, secretKey };
145
177
  return {
146
178
  collections: new CollectionClient(clientKey, secretKey),
147
179
  api: new OrderApi(apiOpts),
148
180
  cart: new CartApi(apiOpts),
149
- product: new ProductApi(apiOpts)
181
+ product: new ProductApi(apiOpts),
182
+ clientKey,
183
+ secretKey
150
184
  };
151
185
  }
152
186
 
@@ -163,13 +197,22 @@ function printTable(data) {
163
197
  }
164
198
  const keys = Object.keys(data[0]);
165
199
  const widths = keys.map(
166
- (k) => Math.max(k.length, ...data.map((row) => String(row[k] ?? "").length))
200
+ (k) => Math.max(
201
+ k.length,
202
+ ...data.map(
203
+ (row) => String(row[k] ?? "").length
204
+ )
205
+ )
167
206
  );
168
207
  console.log(keys.map((k, i) => k.padEnd(widths[i])).join(" "));
169
208
  console.log(keys.map((_, i) => "-".repeat(widths[i])).join(" "));
170
209
  for (const row of data) {
171
210
  console.log(
172
- keys.map((k, i) => String(row[k] ?? "").padEnd(widths[i])).join(" ")
211
+ keys.map(
212
+ (k, i) => String(row[k] ?? "").padEnd(
213
+ widths[i]
214
+ )
215
+ ).join(" ")
173
216
  );
174
217
  }
175
218
  } else if (data && typeof data === "object") {
@@ -183,13 +226,31 @@ function printTable(data) {
183
226
  console.log(String(data));
184
227
  }
185
228
  }
229
+ function printNdjson(data) {
230
+ if (Array.isArray(data)) {
231
+ data.forEach((item) => console.log(JSON.stringify(item)));
232
+ } else if (data && typeof data === "object" && "docs" in data) {
233
+ const { docs, ...meta } = data;
234
+ docs.forEach((doc) => console.log(JSON.stringify(doc)));
235
+ if (Object.keys(meta).length > 0)
236
+ console.log(JSON.stringify({ _meta: meta }));
237
+ } else {
238
+ console.log(JSON.stringify(data));
239
+ }
240
+ }
186
241
  function printResult(data, format) {
187
- if (format === "table") {
242
+ if (format === "ndjson") {
243
+ printNdjson(data);
244
+ } else if (format === "table") {
188
245
  if (data && typeof data === "object" && "docs" in data) {
189
246
  const resp = data;
190
247
  printTable(resp.docs);
191
- console.log(pc2.dim(`
192
- ${resp.totalDocs} total | page ${resp.page}/${resp.totalPages}`));
248
+ console.log(
249
+ pc2.dim(
250
+ `
251
+ ${resp.totalDocs} total | page ${resp.page}/${resp.totalPages}`
252
+ )
253
+ );
193
254
  return;
194
255
  }
195
256
  printTable(data);
@@ -197,6 +258,26 @@ ${resp.totalDocs} total | page ${resp.page}/${resp.totalPages}`));
197
258
  printJson(data);
198
259
  }
199
260
  }
261
+ function getExitCode(error) {
262
+ if (!error || typeof error !== "object") return 1;
263
+ const err = error;
264
+ if (err.name === "ConfigError") return 2;
265
+ if (err.name === "ValidationError") return 3;
266
+ if (err.name === "NetworkError" || err.name === "TimeoutError") return 4;
267
+ if (err.name === "GoneError") return 5;
268
+ if (err.name === "UsageLimitError") return 6;
269
+ const s = err.status;
270
+ if (s === 401) return 2;
271
+ if (s === 400 || s === 422) return 3;
272
+ if (s === 408 || s === 503) return 4;
273
+ if (s === 404) return 5;
274
+ if (s === 429) return 6;
275
+ return 1;
276
+ }
277
+ function exitWithError(error) {
278
+ printError(error);
279
+ process.exit(getExitCode(error));
280
+ }
200
281
  function printError(error) {
201
282
  if (error && typeof error === "object" && "message" in error) {
202
283
  const err = error;
@@ -221,12 +302,12 @@ function parseJson(value, label) {
221
302
  const parsed = JSON.parse(value);
222
303
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
223
304
  console.error(pc3.red(`--${label} must be a JSON object.`));
224
- process.exit(1);
305
+ process.exit(3);
225
306
  }
226
307
  return parsed;
227
308
  } catch {
228
309
  console.error(pc3.red(`Invalid JSON for --${label}: ${value}`));
229
- process.exit(1);
310
+ process.exit(3);
230
311
  }
231
312
  }
232
313
  function parseJsonArray(value, label) {
@@ -234,12 +315,12 @@ function parseJsonArray(value, label) {
234
315
  const parsed = JSON.parse(value);
235
316
  if (!Array.isArray(parsed)) {
236
317
  console.error(pc3.red(`--${label} must be a JSON array.`));
237
- process.exit(1);
318
+ process.exit(3);
238
319
  }
239
320
  return parsed;
240
321
  } catch {
241
322
  console.error(pc3.red(`Invalid JSON for --${label}: ${value}`));
242
- process.exit(1);
323
+ process.exit(3);
243
324
  }
244
325
  }
245
326
 
@@ -248,15 +329,27 @@ function readFileAsBlob(filePath) {
248
329
  const buffer = readFileSync2(filePath);
249
330
  return { blob: new Blob([buffer]), filename: basename(filePath) };
250
331
  }
251
- var collectionList = COLLECTIONS.join(", ");
252
332
  function validateCollection(name) {
253
333
  if (!COLLECTIONS.includes(name)) {
254
- throw new Error(`Unknown collection "${name}". Available: ${collectionList}`);
334
+ const normalized = name.replace(/-/g, "").toLowerCase();
335
+ const suggestions = COLLECTIONS.filter((c) => {
336
+ const cn = c.replace(/-/g, "").toLowerCase();
337
+ return cn.startsWith(normalized) || normalized.startsWith(cn) || normalized.length >= 3 && cn.includes(normalized);
338
+ }).slice(0, 5);
339
+ const hint = suggestions.length > 0 ? `Did you mean: ${suggestions.join(", ")}?` : 'Run "01 --help" for available collections.';
340
+ throw new Error(`Unknown collection "${name}". ${hint}`);
255
341
  }
256
342
  return name;
257
343
  }
344
+ function parseSelect(input) {
345
+ return Object.fromEntries(input.split(",").map((f) => [f.trim(), true]));
346
+ }
258
347
  function registerCrudCommands(program2, getClient2, getFormat2) {
259
- program2.command("query <collection>").description("Query documents from a collection").option("--where <json>", "Filter conditions (JSON)").option("--limit <n>", "Max results", (v) => parseInt(v, 10)).option("--page <n>", "Page number", (v) => parseInt(v, 10)).option("--sort <field>", "Sort field (prefix with - for descending)").action(async (collection, opts) => {
348
+ program2.command("query <collection>").description("Query documents from a collection").option("--where <json>", "Filter conditions (JSON)").option("--limit <n>", "Max results", (v) => parseInt(v, 10)).option("--page <n>", "Page number", (v) => parseInt(v, 10)).option("--sort <field>", "Sort field (prefix with - for descending)").option(
349
+ "--depth <n>",
350
+ "Relationship depth (0 = no population)",
351
+ (v) => parseInt(v, 10)
352
+ ).option("--select <fields>", "Comma-separated fields to select").action(async (collection, opts) => {
260
353
  try {
261
354
  const col = validateCollection(collection);
262
355
  const client = getClient2();
@@ -265,29 +358,49 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
265
358
  if (opts.limit) options.limit = opts.limit;
266
359
  if (opts.page) options.page = opts.page;
267
360
  if (opts.sort) options.sort = opts.sort;
361
+ if (opts.depth != null) options.depth = opts.depth;
362
+ if (opts.select) options.select = parseSelect(opts.select);
268
363
  const result = await client.collections.from(col).find(options);
269
364
  printResult(result, getFormat2());
270
365
  } catch (e) {
271
- printError(e);
272
- process.exit(1);
366
+ exitWithError(e);
273
367
  }
274
368
  });
275
- program2.command("get <collection> <id>").description("Get a document by ID").action(async (collection, id) => {
369
+ program2.command("get <collection> <id>").description("Get a document by ID").option(
370
+ "--depth <n>",
371
+ "Relationship depth (0 = no population)",
372
+ (v) => parseInt(v, 10)
373
+ ).option("--select <fields>", "Comma-separated fields to select").action(async (collection, id, opts) => {
276
374
  try {
277
375
  const col = validateCollection(collection);
278
376
  const client = getClient2();
279
- const result = await client.collections.from(col).findById(id);
377
+ const options = {};
378
+ if (opts.depth != null) options.depth = opts.depth;
379
+ if (opts.select) options.select = parseSelect(opts.select);
380
+ const result = await client.collections.from(col).findById(id, options);
280
381
  printResult(result, getFormat2());
281
382
  } catch (e) {
282
- printError(e);
283
- process.exit(1);
383
+ exitWithError(e);
284
384
  }
285
385
  });
286
- program2.command("create <collection>").description("Create a new document").requiredOption("--data <json>", "Document data (JSON)").option("--file <path>", "File to upload (for upload collections)").action(async (collection, opts) => {
386
+ program2.command("create <collection>").description("Create a new document").requiredOption("--data <json>", "Document data (JSON)").option("--file <path>", "File to upload (for upload collections)").option("--dry-run", "Validate inputs without executing").action(async (collection, opts) => {
287
387
  try {
288
388
  const col = validateCollection(collection);
289
- const client = getClient2();
290
389
  const data = parseJson(opts.data, "data");
390
+ if (opts.dryRun) {
391
+ printResult(
392
+ {
393
+ dryRun: true,
394
+ valid: true,
395
+ action: "create",
396
+ collection: col,
397
+ data
398
+ },
399
+ getFormat2()
400
+ );
401
+ return;
402
+ }
403
+ const client = getClient2();
291
404
  let fileOpts;
292
405
  if (opts.file) {
293
406
  const { blob, filename } = readFileAsBlob(opts.file);
@@ -296,15 +409,28 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
296
409
  const result = await client.collections.from(col).create(data, fileOpts);
297
410
  printResult(result, getFormat2());
298
411
  } catch (e) {
299
- printError(e);
300
- process.exit(1);
412
+ exitWithError(e);
301
413
  }
302
414
  });
303
- program2.command("update <collection> <id>").description("Update a document by ID").requiredOption("--data <json>", "Document data (JSON)").option("--file <path>", "File to upload (for upload collections)").action(async (collection, id, opts) => {
415
+ program2.command("update <collection> <id>").description("Update a document by ID").requiredOption("--data <json>", "Document data (JSON)").option("--file <path>", "File to upload (for upload collections)").option("--dry-run", "Validate inputs without executing").action(async (collection, id, opts) => {
304
416
  try {
305
417
  const col = validateCollection(collection);
306
- const client = getClient2();
307
418
  const data = parseJson(opts.data, "data");
419
+ if (opts.dryRun) {
420
+ printResult(
421
+ {
422
+ dryRun: true,
423
+ valid: true,
424
+ action: "update",
425
+ collection: col,
426
+ id,
427
+ data
428
+ },
429
+ getFormat2()
430
+ );
431
+ return;
432
+ }
433
+ const client = getClient2();
308
434
  let fileOpts;
309
435
  if (opts.file) {
310
436
  const { blob, filename } = readFileAsBlob(opts.file);
@@ -313,44 +439,80 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
313
439
  const result = await client.collections.from(col).update(id, data, fileOpts);
314
440
  printResult(result, getFormat2());
315
441
  } catch (e) {
316
- printError(e);
317
- process.exit(1);
442
+ exitWithError(e);
318
443
  }
319
444
  });
320
- program2.command("delete <collection> <id>").description("Delete a document by ID").action(async (collection, id) => {
445
+ program2.command("delete <collection> <id>").description("Delete a document by ID").option("--dry-run", "Validate inputs without executing").action(async (collection, id, opts) => {
321
446
  try {
322
447
  const col = validateCollection(collection);
448
+ if (opts.dryRun) {
449
+ printResult(
450
+ {
451
+ dryRun: true,
452
+ valid: true,
453
+ action: "delete",
454
+ collection: col,
455
+ id
456
+ },
457
+ getFormat2()
458
+ );
459
+ return;
460
+ }
323
461
  const client = getClient2();
324
462
  const result = await client.collections.from(col).remove(id);
325
463
  printResult(result, getFormat2());
326
464
  } catch (e) {
327
- printError(e);
328
- process.exit(1);
465
+ exitWithError(e);
329
466
  }
330
467
  });
331
- program2.command("update-many <collection>").description("Update multiple documents matching a filter").requiredOption("--where <json>", "Filter conditions (JSON)").requiredOption("--data <json>", "Update data (JSON)").action(async (collection, opts) => {
468
+ program2.command("update-many <collection>").description("Update multiple documents matching a filter").requiredOption("--where <json>", "Filter conditions (JSON)").requiredOption("--data <json>", "Update data (JSON)").option("--dry-run", "Validate inputs without executing").action(async (collection, opts) => {
332
469
  try {
333
470
  const col = validateCollection(collection);
334
- const client = getClient2();
335
471
  const where = parseJson(opts.where, "where");
336
472
  const data = parseJson(opts.data, "data");
473
+ if (opts.dryRun) {
474
+ printResult(
475
+ {
476
+ dryRun: true,
477
+ valid: true,
478
+ action: "update-many",
479
+ collection: col,
480
+ where,
481
+ data
482
+ },
483
+ getFormat2()
484
+ );
485
+ return;
486
+ }
487
+ const client = getClient2();
337
488
  const result = await client.collections.from(col).updateMany(where, data);
338
489
  printResult(result, getFormat2());
339
490
  } catch (e) {
340
- printError(e);
341
- process.exit(1);
491
+ exitWithError(e);
342
492
  }
343
493
  });
344
- program2.command("delete-many <collection>").description("Delete multiple documents matching a filter").requiredOption("--where <json>", "Filter conditions (JSON)").action(async (collection, opts) => {
494
+ program2.command("delete-many <collection>").description("Delete multiple documents matching a filter").requiredOption("--where <json>", "Filter conditions (JSON)").option("--dry-run", "Validate inputs without executing").action(async (collection, opts) => {
345
495
  try {
346
496
  const col = validateCollection(collection);
347
- const client = getClient2();
348
497
  const where = parseJson(opts.where, "where");
498
+ if (opts.dryRun) {
499
+ printResult(
500
+ {
501
+ dryRun: true,
502
+ valid: true,
503
+ action: "delete-many",
504
+ collection: col,
505
+ where
506
+ },
507
+ getFormat2()
508
+ );
509
+ return;
510
+ }
511
+ const client = getClient2();
349
512
  const result = await client.collections.from(col).removeMany(where);
350
513
  printResult(result, getFormat2());
351
514
  } catch (e) {
352
- printError(e);
353
- process.exit(1);
515
+ exitWithError(e);
354
516
  }
355
517
  });
356
518
  }
@@ -358,21 +520,41 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
358
520
  // src/commands/order.ts
359
521
  function registerOrderCommands(program2, getClient2, getFormat2) {
360
522
  const order = program2.command("order").description("Order management");
361
- order.command("create").description("Create a new order").requiredOption("--payment-id <id>", "Payment ID").requiredOption("--order-number <num>", "Order number").requiredOption("--email <email>", "Customer email").requiredOption("--shipping-address <json>", "Shipping address (JSON)").requiredOption("--products <json>", "Order products array (JSON)").requiredOption("--total-amount <n>", "Total amount", parseFloat).action(async (opts) => {
523
+ order.command("create").description("Create a new order").option("--payment-id <id>", "Payment ID").requiredOption("--order-number <num>", "Order number").requiredOption("--email <email>", "Customer email").option("--customer <id>", "Customer ID").option("--name <name>", "Customer name").option("--phone <phone>", "Customer phone").requiredOption("--shipping-address <json>", "Shipping address (JSON)").requiredOption("--products <json>", "Order products array (JSON)").requiredOption("--total-amount <n>", "Total amount", parseFloat).option("--dry-run", "Validate inputs without executing").action(async (opts) => {
362
524
  try {
363
- const client = getClient2();
364
- const result = await client.api.createOrder({
525
+ const shippingAddress = parseJson(
526
+ opts.shippingAddress,
527
+ "shipping-address"
528
+ );
529
+ const orderProducts = parseJsonArray(opts.products, "products");
530
+ const data = {
365
531
  paymentId: opts.paymentId,
366
532
  orderNumber: opts.orderNumber,
367
- email: opts.email,
368
- shippingAddress: parseJson(opts.shippingAddress, "shipping-address"),
369
- orderProducts: parseJsonArray(opts.products, "products"),
533
+ customerSnapshot: {
534
+ email: opts.email,
535
+ name: opts.name,
536
+ phone: opts.phone
537
+ },
538
+ customer: opts.customer,
539
+ shippingAddress,
540
+ orderProducts,
370
541
  totalAmount: opts.totalAmount
542
+ };
543
+ if (opts.dryRun) {
544
+ printResult(
545
+ { dryRun: true, valid: true, action: "order create", data },
546
+ getFormat2()
547
+ );
548
+ return;
549
+ }
550
+ const client = getClient2();
551
+ const result = await client.api.createOrder({
552
+ ...data,
553
+ orderProducts
371
554
  });
372
555
  printResult(result, getFormat2());
373
556
  } catch (e) {
374
- printError(e);
375
- process.exit(1);
557
+ exitWithError(e);
376
558
  }
377
559
  });
378
560
  order.command("get <orderNumber>").description("Get an order by order number").action(async (orderNumber) => {
@@ -381,51 +563,76 @@ function registerOrderCommands(program2, getClient2, getFormat2) {
381
563
  const result = await client.api.getOrder({ orderNumber });
382
564
  printResult(result, getFormat2());
383
565
  } catch (e) {
384
- printError(e);
385
- process.exit(1);
566
+ exitWithError(e);
386
567
  }
387
568
  });
388
- order.command("update <orderNumber>").description("Update order status").requiredOption("--status <status>", "New status").action(async (orderNumber, opts) => {
569
+ order.command("update <orderNumber>").description("Update order status").requiredOption("--status <status>", "New status").option("--dry-run", "Validate inputs without executing").action(async (orderNumber, opts) => {
389
570
  try {
571
+ const data = { orderNumber, status: opts.status };
572
+ if (opts.dryRun) {
573
+ printResult(
574
+ { dryRun: true, valid: true, action: "order update", data },
575
+ getFormat2()
576
+ );
577
+ return;
578
+ }
390
579
  const client = getClient2();
391
- const result = await client.api.updateOrder({
392
- orderNumber,
393
- status: opts.status
394
- });
580
+ const result = await client.api.updateOrder(data);
395
581
  printResult(result, getFormat2());
396
582
  } catch (e) {
397
- printError(e);
398
- process.exit(1);
583
+ exitWithError(e);
399
584
  }
400
585
  });
401
- order.command("checkout").description("Convert a cart to an order").requiredOption("--cart-id <id>", "Cart ID").requiredOption("--payment-id <id>", "Payment ID").requiredOption("--order-number <num>", "Order number").requiredOption("--customer <json>", "Customer snapshot (JSON)").action(async (opts) => {
586
+ order.command("checkout").description("Convert a cart to an order").requiredOption("--cart-id <id>", "Cart ID").option("--payment-id <id>", "Payment ID (optional for free orders)").requiredOption("--order-number <num>", "Order number").requiredOption("--customer <json>", "Customer snapshot (JSON)").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
402
587
  try {
403
- const client = getClient2();
404
- const result = await client.api.checkout({
588
+ const customerSnapshot = parseJson(opts.customer, "customer");
589
+ const data = {
405
590
  cartId: opts.cartId,
406
591
  paymentId: opts.paymentId,
407
592
  orderNumber: opts.orderNumber,
408
- customerSnapshot: parseJson(opts.customer, "customer")
593
+ customerSnapshot
594
+ };
595
+ if (opts.dryRun) {
596
+ printResult(
597
+ { dryRun: true, valid: true, action: "order checkout", data },
598
+ getFormat2()
599
+ );
600
+ return;
601
+ }
602
+ const client = getClient2();
603
+ const result = await client.api.checkout({
604
+ ...data,
605
+ customerSnapshot
409
606
  });
410
607
  printResult(result, getFormat2());
411
608
  } catch (e) {
412
- printError(e);
413
- process.exit(1);
609
+ exitWithError(e);
414
610
  }
415
611
  });
416
- order.command("fulfill <orderNumber>").description("Create a fulfillment for an order").requiredOption("--items <json>", "Fulfillment items array (JSON)").option("--carrier <name>", "Shipping carrier").option("--tracking-number <num>", "Tracking number").action(async (orderNumber, opts) => {
612
+ order.command("fulfill <orderNumber>").description("Create a fulfillment for an order").requiredOption("--items <json>", "Fulfillment items array (JSON)").option("--carrier <name>", "Shipping carrier").option("--tracking-number <num>", "Tracking number").option("--dry-run", "Validate inputs without executing").action(async (orderNumber, opts) => {
417
613
  try {
418
- const client = getClient2();
419
- const result = await client.api.createFulfillment({
614
+ const items = parseJsonArray(opts.items, "items");
615
+ const data = {
420
616
  orderNumber,
421
- items: parseJsonArray(opts.items, "items"),
617
+ items,
422
618
  carrier: opts.carrier,
423
619
  trackingNumber: opts.trackingNumber
620
+ };
621
+ if (opts.dryRun) {
622
+ printResult(
623
+ { dryRun: true, valid: true, action: "order fulfill", data },
624
+ getFormat2()
625
+ );
626
+ return;
627
+ }
628
+ const client = getClient2();
629
+ const result = await client.api.createFulfillment({
630
+ ...data,
631
+ items
424
632
  });
425
633
  printResult(result, getFormat2());
426
634
  } catch (e) {
427
- printError(e);
428
- process.exit(1);
635
+ exitWithError(e);
429
636
  }
430
637
  });
431
638
  }
@@ -433,51 +640,83 @@ function registerOrderCommands(program2, getClient2, getFormat2) {
433
640
  // src/commands/return.ts
434
641
  function registerReturnCommands(program2, getClient2, getFormat2) {
435
642
  const ret = program2.command("return").description("Return management");
436
- ret.command("create <orderNumber>").description("Create a return request").requiredOption("--products <json>", "Return products array (JSON)").requiredOption("--refund-amount <n>", "Refund amount", parseFloat).option("--reason <reason>", "Return reason (change_of_mind, defective, wrong_delivery, damaged, other)").option("--reason-detail <text>", "Detailed reason").action(async (orderNumber, opts) => {
643
+ ret.command("create <orderNumber>").description("Create a return request").requiredOption("--products <json>", "Return products array (JSON)").requiredOption("--refund-amount <n>", "Refund amount", parseFloat).option(
644
+ "--reason <reason>",
645
+ "Return reason (change_of_mind, defective, wrong_delivery, damaged, other)"
646
+ ).option("--reason-detail <text>", "Detailed reason").option("--dry-run", "Validate inputs without executing").action(async (orderNumber, opts) => {
437
647
  try {
438
- const client = getClient2();
439
- const result = await client.api.createReturn({
648
+ const returnProducts = parseJsonArray(opts.products, "products");
649
+ const data = {
440
650
  orderNumber,
441
- returnProducts: parseJsonArray(opts.products, "products"),
651
+ returnProducts,
442
652
  refundAmount: opts.refundAmount,
443
653
  reason: opts.reason,
444
654
  reasonDetail: opts.reasonDetail
655
+ };
656
+ if (opts.dryRun) {
657
+ printResult(
658
+ { dryRun: true, valid: true, action: "return create", data },
659
+ getFormat2()
660
+ );
661
+ return;
662
+ }
663
+ const client = getClient2();
664
+ const result = await client.api.createReturn({
665
+ ...data,
666
+ returnProducts
445
667
  });
446
668
  printResult(result, getFormat2());
447
669
  } catch (e) {
448
- printError(e);
449
- process.exit(1);
670
+ exitWithError(e);
450
671
  }
451
672
  });
452
- ret.command("update <returnId>").description("Update return status").requiredOption("--status <status>", "New status (processing, approved, rejected, completed)").action(async (returnId, opts) => {
673
+ ret.command("update <returnId>").description("Update return status").requiredOption(
674
+ "--status <status>",
675
+ "New status (processing, approved, rejected, completed)"
676
+ ).option("--dry-run", "Validate inputs without executing").action(async (returnId, opts) => {
453
677
  try {
678
+ const data = { returnId, status: opts.status };
679
+ if (opts.dryRun) {
680
+ printResult(
681
+ { dryRun: true, valid: true, action: "return update", data },
682
+ getFormat2()
683
+ );
684
+ return;
685
+ }
454
686
  const client = getClient2();
455
- const result = await client.api.updateReturn({
456
- returnId,
457
- status: opts.status
458
- });
687
+ const result = await client.api.updateReturn(data);
459
688
  printResult(result, getFormat2());
460
689
  } catch (e) {
461
- printError(e);
462
- process.exit(1);
690
+ exitWithError(e);
463
691
  }
464
692
  });
465
- ret.command("refund <orderNumber>").description("Return with refund").requiredOption("--products <json>", "Return products array (JSON)").requiredOption("--refund-amount <n>", "Refund amount", parseFloat).requiredOption("--payment-id <id>", "Payment ID").option("--reason <reason>", "Return reason").option("--reason-detail <text>", "Detailed reason").option("--refund-receipt-url <url>", "Refund receipt URL").action(async (orderNumber, opts) => {
693
+ ret.command("refund <orderNumber>").description("Return with refund").requiredOption("--products <json>", "Return products array (JSON)").requiredOption("--refund-amount <n>", "Refund amount", parseFloat).requiredOption("--payment-id <id>", "Payment ID").option("--reason <reason>", "Return reason").option("--reason-detail <text>", "Detailed reason").option("--refund-receipt-url <url>", "Refund receipt URL").option("--dry-run", "Validate inputs without executing").action(async (orderNumber, opts) => {
466
694
  try {
467
- const client = getClient2();
468
- const result = await client.api.returnWithRefund({
695
+ const returnProducts = parseJsonArray(opts.products, "products");
696
+ const data = {
469
697
  orderNumber,
470
- returnProducts: parseJsonArray(opts.products, "products"),
698
+ returnProducts,
471
699
  refundAmount: opts.refundAmount,
472
700
  paymentId: opts.paymentId,
473
701
  reason: opts.reason,
474
702
  reasonDetail: opts.reasonDetail,
475
703
  refundReceiptUrl: opts.refundReceiptUrl
704
+ };
705
+ if (opts.dryRun) {
706
+ printResult(
707
+ { dryRun: true, valid: true, action: "return refund", data },
708
+ getFormat2()
709
+ );
710
+ return;
711
+ }
712
+ const client = getClient2();
713
+ const result = await client.api.returnWithRefund({
714
+ ...data,
715
+ returnProducts
476
716
  });
477
717
  printResult(result, getFormat2());
478
718
  } catch (e) {
479
- printError(e);
480
- process.exit(1);
719
+ exitWithError(e);
481
720
  }
482
721
  });
483
722
  }
@@ -485,43 +724,73 @@ function registerReturnCommands(program2, getClient2, getFormat2) {
485
724
  // src/commands/cart.ts
486
725
  function registerCartCommands(program2, getClient2, getFormat2) {
487
726
  const cart = program2.command("cart").description("Cart management");
488
- cart.command("add <cartId>").description("Add an item to cart").requiredOption("--product <id>", "Product ID").requiredOption("--variant <id>", "Variant ID").requiredOption("--option <id>", "Option ID").requiredOption("--quantity <n>", "Quantity", (v) => parseInt(v, 10)).action(async (cartId, opts) => {
727
+ cart.command("add <cartId>").description("Add an item to cart").requiredOption("--product <id>", "Product ID").requiredOption("--variant <id>", "Variant ID").requiredOption("--option <id>", "Option ID").requiredOption(
728
+ "--quantity <n>",
729
+ "Quantity",
730
+ (v) => parseInt(v, 10)
731
+ ).option("--dry-run", "Validate inputs without executing").action(async (cartId, opts) => {
489
732
  try {
490
- const client = getClient2();
491
- const result = await client.cart.addItem({
733
+ const data = {
492
734
  cartId,
493
735
  product: opts.product,
494
736
  variant: opts.variant,
495
737
  option: opts.option,
496
738
  quantity: opts.quantity
497
- });
739
+ };
740
+ if (opts.dryRun) {
741
+ printResult(
742
+ { dryRun: true, valid: true, action: "cart add", data },
743
+ getFormat2()
744
+ );
745
+ return;
746
+ }
747
+ const client = getClient2();
748
+ const result = await client.cart.addItem(data);
498
749
  printResult(result, getFormat2());
499
750
  } catch (e) {
500
- printError(e);
501
- process.exit(1);
751
+ exitWithError(e);
502
752
  }
503
753
  });
504
- cart.command("update <cartItemId>").description("Update cart item quantity").requiredOption("--quantity <n>", "New quantity", (v) => parseInt(v, 10)).action(async (cartItemId, opts) => {
754
+ cart.command("update <cartItemId>").description("Update cart item quantity").requiredOption(
755
+ "--quantity <n>",
756
+ "New quantity",
757
+ (v) => parseInt(v, 10)
758
+ ).option("--dry-run", "Validate inputs without executing").action(async (cartItemId, opts) => {
505
759
  try {
760
+ const data = { cartItemId, quantity: opts.quantity };
761
+ if (opts.dryRun) {
762
+ printResult(
763
+ { dryRun: true, valid: true, action: "cart update", data },
764
+ getFormat2()
765
+ );
766
+ return;
767
+ }
506
768
  const client = getClient2();
507
- const result = await client.cart.updateItem({
508
- cartItemId,
509
- quantity: opts.quantity
510
- });
769
+ const result = await client.cart.updateItem(data);
511
770
  printResult(result, getFormat2());
512
771
  } catch (e) {
513
- printError(e);
514
- process.exit(1);
772
+ exitWithError(e);
515
773
  }
516
774
  });
517
- cart.command("remove <cartItemId>").description("Remove an item from cart").action(async (cartItemId) => {
775
+ cart.command("remove <cartItemId>").description("Remove an item from cart").option("--dry-run", "Validate inputs without executing").action(async (cartItemId, opts) => {
518
776
  try {
777
+ if (opts.dryRun) {
778
+ printResult(
779
+ {
780
+ dryRun: true,
781
+ valid: true,
782
+ action: "cart remove",
783
+ data: { cartItemId }
784
+ },
785
+ getFormat2()
786
+ );
787
+ return;
788
+ }
519
789
  const client = getClient2();
520
790
  const result = await client.cart.removeItem({ cartItemId });
521
791
  printResult(result, getFormat2());
522
792
  } catch (e) {
523
- printError(e);
524
- process.exit(1);
793
+ exitWithError(e);
525
794
  }
526
795
  });
527
796
  }
@@ -529,15 +798,17 @@ function registerCartCommands(program2, getClient2, getFormat2) {
529
798
  // src/commands/stock.ts
530
799
  function registerStockCommands(program2, getClient2, getFormat2) {
531
800
  const stock = program2.command("stock").description("Stock management");
532
- stock.command("check").description("Check stock availability").requiredOption("--items <json>", "Items to check (JSON array of { optionId, quantity })").action(async (opts) => {
801
+ stock.command("check").description("Check stock availability").requiredOption(
802
+ "--items <json>",
803
+ "Items to check (JSON array of { optionId, quantity })"
804
+ ).action(async (opts) => {
533
805
  try {
534
806
  const client = getClient2();
535
807
  const items = parseJsonArray(opts.items, "items");
536
808
  const result = await client.product.stockCheck({ items });
537
809
  printResult(result, getFormat2());
538
810
  } catch (e) {
539
- printError(e);
540
- process.exit(1);
811
+ exitWithError(e);
541
812
  }
542
813
  });
543
814
  }
@@ -545,19 +816,29 @@ function registerStockCommands(program2, getClient2, getFormat2) {
545
816
  // src/commands/transaction.ts
546
817
  function registerTransactionCommands(program2, getClient2, getFormat2) {
547
818
  const tx = program2.command("transaction").description("Transaction management");
548
- tx.command("update").description("Update transaction status").requiredOption("--payment-id <id>", "Payment ID").requiredOption("--status <status>", "New status (pending, paid, failed, canceled)").requiredOption("--payment-method <method>", "Payment method").requiredOption("--receipt-url <url>", "Receipt URL").action(async (opts) => {
819
+ tx.command("update").description("Update transaction status").requiredOption("--payment-id <id>", "Payment ID").requiredOption(
820
+ "--status <status>",
821
+ "New status (pending, paid, failed, canceled)"
822
+ ).requiredOption("--payment-method <method>", "Payment method").requiredOption("--receipt-url <url>", "Receipt URL").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
549
823
  try {
550
- const client = getClient2();
551
- const result = await client.api.updateTransaction({
824
+ const data = {
552
825
  paymentId: opts.paymentId,
553
826
  status: opts.status,
554
827
  paymentMethod: opts.paymentMethod,
555
828
  receiptUrl: opts.receiptUrl
556
- });
829
+ };
830
+ if (opts.dryRun) {
831
+ printResult(
832
+ { dryRun: true, valid: true, action: "transaction update", data },
833
+ getFormat2()
834
+ );
835
+ return;
836
+ }
837
+ const client = getClient2();
838
+ const result = await client.api.updateTransaction(data);
557
839
  printResult(result, getFormat2());
558
840
  } catch (e) {
559
- printError(e);
560
- process.exit(1);
841
+ exitWithError(e);
561
842
  }
562
843
  });
563
844
  }
@@ -577,8 +858,12 @@ function escapeHtml(s) {
577
858
  function openBrowser(url) {
578
859
  const os = platform();
579
860
  const onError = () => {
580
- console.log(pc4.yellow(`Could not open browser automatically. Open this URL manually:
581
- ${url}`));
861
+ console.log(
862
+ pc4.yellow(
863
+ `Could not open browser automatically. Open this URL manually:
864
+ ${url}`
865
+ )
866
+ );
582
867
  };
583
868
  if (os === "win32") {
584
869
  exec(`start "" "${url}"`, (err) => {
@@ -610,7 +895,7 @@ var ERROR_HTML = (msg) => `<!DOCTYPE html>
610
895
  <style>${PAGE_STYLE}</style>
611
896
  </head><body><div class="card"><div class="icon err">!</div><h1>Authentication failed</h1><p>${escapeHtml(msg)}</p></div></body></html>`;
612
897
  function startAuthServer(options) {
613
- return new Promise((resolve, reject) => {
898
+ return new Promise((resolve2, reject) => {
614
899
  const server = createServer((req, res) => {
615
900
  if (!req.url) {
616
901
  res.writeHead(400).end();
@@ -631,19 +916,19 @@ function startAuthServer(options) {
631
916
  if (error) {
632
917
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }).end(ERROR_HTML(error));
633
918
  console.error(pc4.red(`Login failed: ${error}`));
634
- cleanup(1);
919
+ cleanup(2);
635
920
  return;
636
921
  }
637
922
  if (receivedState !== options.state) {
638
923
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }).end(ERROR_HTML("State mismatch \u2014 possible CSRF attack."));
639
924
  console.error(pc4.red("Login failed: state mismatch."));
640
- cleanup(1);
925
+ cleanup(2);
641
926
  return;
642
927
  }
643
928
  if (!clientKey || !secretKey || !tenant) {
644
929
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }).end(ERROR_HTML("Missing credentials in callback."));
645
930
  console.error(pc4.red("Login failed: missing credentials."));
646
- cleanup(1);
931
+ cleanup(2);
647
932
  return;
648
933
  }
649
934
  options.saveFn({
@@ -685,10 +970,12 @@ Logged in successfully!`));
685
970
  return;
686
971
  }
687
972
  timeout = setTimeout(() => {
688
- console.error(pc4.red("\nLogin timed out (3 minutes). Please try again."));
689
- cleanup(1);
973
+ console.error(
974
+ pc4.red("\nLogin timed out (3 minutes). Please try again.")
975
+ );
976
+ cleanup(4);
690
977
  }, TIMEOUT_MS);
691
- resolve({ port: addr.port, cleanup });
978
+ resolve2({ port: addr.port, cleanup });
692
979
  });
693
980
  server.on("error", (err) => {
694
981
  reject(err);
@@ -713,8 +1000,12 @@ function registerAuthCommands(program2) {
713
1000
  ${loginUrl}`));
714
1001
  openBrowser(loginUrl);
715
1002
  } catch (err) {
716
- console.error(pc4.red(`Server error: ${err instanceof Error ? err.message : String(err)}`));
717
- process.exit(1);
1003
+ console.error(
1004
+ pc4.red(
1005
+ `Server error: ${err instanceof Error ? err.message : String(err)}`
1006
+ )
1007
+ );
1008
+ process.exit(4);
718
1009
  }
719
1010
  });
720
1011
  program2.command("logout").description("Remove stored credentials").action(() => {
@@ -739,7 +1030,9 @@ ${loginUrl}`));
739
1030
  console.log(`Tenant: ${pc4.bold(creds.tenantName)}${scope}`);
740
1031
  console.log(`Client Key: ${pc4.dim(masked)}`);
741
1032
  console.log(`Stored at: ${pc4.dim(creds.storedAt)}`);
742
- console.log(`File: ${pc4.dim(isLocal ? getLocalCredentialsPath() : getCredentialsPath())}`);
1033
+ console.log(
1034
+ `File: ${pc4.dim(isLocal ? getLocalCredentialsPath() : getCredentialsPath())}`
1035
+ );
743
1036
  });
744
1037
  const tenant = program2.command("tenant").description("Manage tenant switching");
745
1038
  tenant.command("list").description("Show cached tenant list").action(() => {
@@ -768,13 +1061,17 @@ ${loginUrl}`));
768
1061
  const tenants = loadTenantList();
769
1062
  if (!tenants || tenants.length === 0) {
770
1063
  console.error(pc4.red('No cached tenants. Run "01 login" first.'));
771
- process.exit(1);
1064
+ process.exit(2);
772
1065
  }
773
- const match = tenants.find((t) => t.name.toLowerCase() === name.toLowerCase());
1066
+ const match = tenants.find(
1067
+ (t) => t.name.toLowerCase() === name.toLowerCase()
1068
+ );
774
1069
  if (!match) {
775
1070
  console.error(pc4.red(`Tenant "${name}" not found in cache.`));
776
- console.error(pc4.dim(`Available: ${tenants.map((t) => t.name).join(", ")}`));
777
- process.exit(1);
1071
+ console.error(
1072
+ pc4.dim(`Available: ${tenants.map((t) => t.name).join(", ")}`)
1073
+ );
1074
+ process.exit(3);
778
1075
  }
779
1076
  const state = randomBytes(32).toString("hex");
780
1077
  const isLocal = !!opts.local;
@@ -784,10 +1081,14 @@ ${loginUrl}`));
784
1081
  saveFn: (creds) => {
785
1082
  if (isLocal) {
786
1083
  saveLocalCredentials(creds);
787
- console.log(pc4.dim(`Credentials saved to ${getLocalCredentialsPath()}`));
1084
+ console.log(
1085
+ pc4.dim(`Credentials saved to ${getLocalCredentialsPath()}`)
1086
+ );
788
1087
  } else {
789
1088
  saveCredentials(creds);
790
- console.log(pc4.dim(`Credentials saved to ${getCredentialsPath()}`));
1089
+ console.log(
1090
+ pc4.dim(`Credentials saved to ${getCredentialsPath()}`)
1091
+ );
791
1092
  }
792
1093
  }
793
1094
  });
@@ -802,22 +1103,117 @@ ${loginUrl}`));
802
1103
  ${loginUrl}`));
803
1104
  openBrowser(loginUrl);
804
1105
  } catch (err) {
805
- console.error(pc4.red(`Server error: ${err instanceof Error ? err.message : String(err)}`));
806
- process.exit(1);
1106
+ console.error(
1107
+ pc4.red(
1108
+ `Server error: ${err instanceof Error ? err.message : String(err)}`
1109
+ )
1110
+ );
1111
+ process.exit(4);
807
1112
  }
808
1113
  });
809
1114
  }
810
1115
 
1116
+ // src/commands/schema.ts
1117
+ import { COLLECTIONS as COLLECTIONS2 } from "@01.software/sdk";
1118
+ function getApiUrl() {
1119
+ return (process.env.SOFTWARE_API_URL || process.env.NEXT_PUBLIC_SOFTWARE_API_URL || "https://api.01.software").replace(/\/$/, "");
1120
+ }
1121
+ function registerSchemaCommands(program2, getClient2, getFormat2) {
1122
+ const schema = program2.command("schema").description("Collection schema introspection");
1123
+ schema.command("list").description("List available collections").action(() => {
1124
+ printResult(COLLECTIONS2, getFormat2());
1125
+ });
1126
+ schema.command("show <collection>").description("Show collection field schema").action(async (collection) => {
1127
+ try {
1128
+ if (!COLLECTIONS2.includes(collection)) {
1129
+ const normalized = collection.replace(/-/g, "").toLowerCase();
1130
+ const suggestions = COLLECTIONS2.filter((c) => {
1131
+ const cn = c.replace(/-/g, "").toLowerCase();
1132
+ return cn.startsWith(normalized) || normalized.startsWith(cn) || normalized.length >= 3 && cn.includes(normalized);
1133
+ }).slice(0, 5);
1134
+ const hint = suggestions.length > 0 ? `Did you mean: ${suggestions.join(", ")}?` : 'Run "01 schema list" for available collections.';
1135
+ throw new Error(`Unknown collection "${collection}". ${hint}`);
1136
+ }
1137
+ const client = getClient2();
1138
+ const { createServerToken } = await import("@01.software/sdk/auth");
1139
+ const token = await createServerToken(
1140
+ client.clientKey,
1141
+ client.secretKey
1142
+ );
1143
+ const baseUrl = getApiUrl();
1144
+ const url = `${baseUrl}/api/tenants/schema/${encodeURIComponent(collection)}`;
1145
+ const response = await fetch(url, {
1146
+ headers: {
1147
+ "X-Client-Key": client.clientKey,
1148
+ Authorization: `Bearer ${token}`
1149
+ }
1150
+ });
1151
+ if (!response.ok) {
1152
+ const body = await response.json().catch(() => ({ error: response.statusText }));
1153
+ const err = new Error(
1154
+ body.error || `HTTP ${response.status}`
1155
+ );
1156
+ Object.assign(err, { status: response.status });
1157
+ throw err;
1158
+ }
1159
+ const result = await response.json();
1160
+ printResult(result, getFormat2());
1161
+ } catch (e) {
1162
+ exitWithError(e);
1163
+ }
1164
+ });
1165
+ }
1166
+
1167
+ // src/commands/mcp.ts
1168
+ import { resolve, dirname } from "path";
1169
+ import { existsSync as existsSync2 } from "fs";
1170
+ import { spawn } from "child_process";
1171
+ import { fileURLToPath } from "url";
1172
+ var __dirname = dirname(fileURLToPath(import.meta.url));
1173
+ function findStdioEntry() {
1174
+ for (const depth of ["../../../..", "../../.."]) {
1175
+ const candidate = resolve(__dirname, depth, "apps/mcp/.xmcp/stdio.js");
1176
+ if (existsSync2(candidate)) return candidate;
1177
+ }
1178
+ return null;
1179
+ }
1180
+ function registerMcpCommands(program2) {
1181
+ program2.command("mcp").description("Start MCP server over stdio").action(() => {
1182
+ const client = resolveClient(program2.opts().apiKey);
1183
+ const stdioEntry = findStdioEntry();
1184
+ if (!stdioEntry) {
1185
+ exitWithError(
1186
+ new Error(
1187
+ "MCP server not found. Ensure apps/mcp is built (pnpm --filter mcp build)."
1188
+ )
1189
+ );
1190
+ }
1191
+ const child = spawn(process.execPath, [stdioEntry], {
1192
+ env: {
1193
+ ...process.env,
1194
+ SOFTWARE_CLIENT_KEY: client.clientKey,
1195
+ SOFTWARE_SECRET_KEY: client.secretKey
1196
+ },
1197
+ stdio: ["inherit", "inherit", "inherit"]
1198
+ });
1199
+ child.on("error", (err) => {
1200
+ exitWithError(new Error(`Failed to start MCP server: ${err.message}`));
1201
+ });
1202
+ child.on("exit", (code) => {
1203
+ process.exit(code ?? 0);
1204
+ });
1205
+ });
1206
+ }
1207
+
811
1208
  // src/index.ts
812
1209
  var require2 = createRequire(import.meta.url);
813
1210
  var { version } = require2("../package.json");
814
1211
  process.on("unhandledRejection", (err) => {
815
- printError(err);
816
- process.exit(1);
1212
+ exitWithError(err);
817
1213
  });
818
1214
  var program = new Command();
819
- program.name("01").description("CLI for the 01.software platform").version(version).option("--api-key <base64>", "Base64-encoded API key (clientKey:secretKey)").option("--format <format>", "Output format: json (default) or table", "json");
820
- var getFormat = () => program.opts().format;
1215
+ program.name("01").description("CLI for the 01.software platform").version(version).option("--api-key <base64>", "Base64-encoded API key (clientKey:secretKey)").option("--format <format>", "Output format: json, table, or ndjson");
1216
+ var getFormat = () => program.opts().format ?? process.env.OUTPUT_FORMAT ?? "json";
821
1217
  var getClient = () => resolveClient(program.opts().apiKey);
822
1218
  registerCrudCommands(program, getClient, getFormat);
823
1219
  registerOrderCommands(program, getClient, getFormat);
@@ -825,6 +1221,8 @@ registerReturnCommands(program, getClient, getFormat);
825
1221
  registerCartCommands(program, getClient, getFormat);
826
1222
  registerStockCommands(program, getClient, getFormat);
827
1223
  registerTransactionCommands(program, getClient, getFormat);
1224
+ registerSchemaCommands(program, getClient, getFormat);
1225
+ registerMcpCommands(program);
828
1226
  registerAuthCommands(program);
829
1227
  program.parse();
830
1228
  //# sourceMappingURL=index.js.map