@eide/foir-cli 0.13.0 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +303 -235
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -3540,17 +3540,39 @@ async function provisionApiKey(client) {
3540
3540
 
3541
3541
  // src/lib/output.ts
3542
3542
  import chalk2 from "chalk";
3543
+ import {
3544
+ toJson
3545
+ } from "@bufbuild/protobuf";
3546
+ function bigintReplacer(_key, value) {
3547
+ return typeof value === "bigint" ? value.toString() : value;
3548
+ }
3549
+ function safeStringify(value, indent) {
3550
+ return JSON.stringify(value, bigintReplacer, indent);
3551
+ }
3543
3552
  function formatOutput(data, options) {
3544
3553
  if (options?.quiet) return;
3545
3554
  if (options?.json) {
3546
- console.log(JSON.stringify(data, null, 2));
3555
+ console.log(safeStringify(data, 2));
3547
3556
  return;
3548
3557
  }
3549
3558
  if (options?.jsonl) {
3550
- console.log(JSON.stringify(data));
3559
+ console.log(safeStringify(data));
3551
3560
  return;
3552
3561
  }
3553
- console.log(JSON.stringify(data, null, 2));
3562
+ console.log(safeStringify(data, 2));
3563
+ }
3564
+ function formatOutputProto(schema, message, options) {
3565
+ if (message == null) {
3566
+ formatOutput(null, options);
3567
+ return;
3568
+ }
3569
+ formatOutput(toJson(schema, message), options);
3570
+ }
3571
+ function formatListProto(schema, items, options, config2) {
3572
+ const converted = items.map(
3573
+ (item) => toJson(schema, item)
3574
+ );
3575
+ formatList(converted, options, config2);
3554
3576
  }
3555
3577
  function formatList(items, options, config2) {
3556
3578
  if (options?.quiet) {
@@ -3560,12 +3582,12 @@ function formatList(items, options, config2) {
3560
3582
  return;
3561
3583
  }
3562
3584
  if (options?.json) {
3563
- console.log(JSON.stringify(items, null, 2));
3585
+ console.log(safeStringify(items, 2));
3564
3586
  return;
3565
3587
  }
3566
3588
  if (options?.jsonl) {
3567
3589
  for (const item of items) {
3568
- console.log(JSON.stringify(item));
3590
+ console.log(safeStringify(item));
3569
3591
  }
3570
3592
  return;
3571
3593
  }
@@ -3703,7 +3725,11 @@ import { basename } from "path";
3703
3725
  import chalk3 from "chalk";
3704
3726
  import { createClient } from "@connectrpc/connect";
3705
3727
  import { createConnectTransport as createConnectTransport2 } from "@connectrpc/connect-node";
3706
- import { StorageService as StorageService3 } from "@eide/foir-proto-ts/storage/v1/storage_pb";
3728
+ import {
3729
+ StorageService as StorageService3,
3730
+ FileSchema,
3731
+ StorageUsageSchema
3732
+ } from "@eide/foir-proto-ts/storage/v1/storage_pb";
3707
3733
 
3708
3734
  // src/lib/input.ts
3709
3735
  import inquirer2 from "inquirer";
@@ -3876,7 +3902,7 @@ function registerMediaCommands(program2, globalOpts) {
3876
3902
  }
3877
3903
  const file = await storage.confirmFileUpload(upload.uploadId);
3878
3904
  if (opts.json || opts.jsonl) {
3879
- formatOutput(file, opts);
3905
+ formatOutputProto(FileSchema, file, opts);
3880
3906
  } else {
3881
3907
  success(`Uploaded ${filename}`);
3882
3908
  if (file?.url) {
@@ -3904,7 +3930,7 @@ function registerMediaCommands(program2, globalOpts) {
3904
3930
  limit: Number(flags.limit) || 50,
3905
3931
  offset: Number(flags.offset) || 0
3906
3932
  });
3907
- formatList(result.items, opts, {
3933
+ formatListProto(FileSchema, result.items, opts, {
3908
3934
  columns: [
3909
3935
  { key: "id", header: "ID", width: 28 },
3910
3936
  { key: "filename", header: "Filename", width: 24 },
@@ -3939,7 +3965,7 @@ function registerMediaCommands(program2, globalOpts) {
3939
3965
  const { getToken } = await getStorageAuth(opts);
3940
3966
  const storage = createStorageRpcClient(getToken);
3941
3967
  const file = await storage.getFile(id);
3942
- formatOutput(file, opts);
3968
+ formatOutputProto(FileSchema, file, opts);
3943
3969
  })
3944
3970
  );
3945
3971
  media.command("usage").description("Get storage usage").action(
@@ -3949,7 +3975,7 @@ function registerMediaCommands(program2, globalOpts) {
3949
3975
  const storage = createStorageRpcClient(getToken);
3950
3976
  const usage = await storage.getStorageUsage();
3951
3977
  if (opts.json || opts.jsonl) {
3952
- formatOutput(usage, opts);
3978
+ formatOutputProto(StorageUsageSchema, usage, opts);
3953
3979
  } else {
3954
3980
  const mb = (Number(usage?.totalBytes ?? 0) / (1024 * 1024)).toFixed(
3955
3981
  1
@@ -3973,7 +3999,7 @@ function registerMediaCommands(program2, globalOpts) {
3973
3999
  tags: flags.tags?.split(",").map((t) => t.trim())
3974
4000
  });
3975
4001
  if (opts.json || opts.jsonl) {
3976
- formatOutput(file, opts);
4002
+ formatOutputProto(FileSchema, file, opts);
3977
4003
  } else {
3978
4004
  success("Updated file");
3979
4005
  }
@@ -3994,7 +4020,7 @@ function registerMediaCommands(program2, globalOpts) {
3994
4020
  description: flags.description
3995
4021
  });
3996
4022
  if (opts.json || opts.jsonl) {
3997
- formatOutput(file, opts);
4023
+ formatOutputProto(FileSchema, file, opts);
3998
4024
  } else {
3999
4025
  success("Updated file metadata");
4000
4026
  }
@@ -4032,7 +4058,7 @@ function registerMediaCommands(program2, globalOpts) {
4032
4058
  const storage = createStorageRpcClient(getToken);
4033
4059
  const file = await storage.restoreFile(id);
4034
4060
  if (opts.json || opts.jsonl) {
4035
- formatOutput(file, opts);
4061
+ formatOutputProto(FileSchema, file, opts);
4036
4062
  } else {
4037
4063
  success("Restored file");
4038
4064
  }
@@ -4592,6 +4618,8 @@ function registerCreateConfigCommand(program2, globalOpts) {
4592
4618
  }
4593
4619
 
4594
4620
  // src/commands/search.ts
4621
+ import { toJson as toJson2 } from "@bufbuild/protobuf";
4622
+ import { SearchResultItemSchema } from "@eide/foir-proto-ts/records/v1/records_pb";
4595
4623
  function registerSearchCommands(program2, globalOpts) {
4596
4624
  program2.command("search <query>").description("Search across all records").option(
4597
4625
  "--models <keys>",
@@ -4609,7 +4637,15 @@ function registerSearchCommands(program2, globalOpts) {
4609
4637
  modelKeys
4610
4638
  });
4611
4639
  if (opts.json || opts.jsonl) {
4612
- formatOutput(result, opts);
4640
+ formatOutput(
4641
+ {
4642
+ items: result.items.map(
4643
+ (item) => toJson2(SearchResultItemSchema, item)
4644
+ ),
4645
+ total: result.total
4646
+ },
4647
+ opts
4648
+ );
4613
4649
  return;
4614
4650
  }
4615
4651
  if (result.items.length > 0) {
@@ -6267,6 +6303,7 @@ function registerProfilesCommand(program2, globalOpts) {
6267
6303
  }
6268
6304
 
6269
6305
  // src/commands/context.ts
6306
+ import { TenantSchema } from "@eide/foir-proto-ts/identity/v1/identity_pb";
6270
6307
  function registerContextCommands(program2, globalOpts) {
6271
6308
  const context = program2.command("context").description("Manage project and tenant context");
6272
6309
  context.command("projects").description("List available projects").action(
@@ -6331,7 +6368,8 @@ function registerContextCommands(program2, globalOpts) {
6331
6368
  const sessionContext = await client.identity.getSessionContext();
6332
6369
  if (!sessionContext)
6333
6370
  throw new Error("Could not retrieve session context.");
6334
- formatList(
6371
+ formatListProto(
6372
+ TenantSchema,
6335
6373
  sessionContext.availableTenants ?? [],
6336
6374
  opts,
6337
6375
  {
@@ -6346,6 +6384,10 @@ function registerContextCommands(program2, globalOpts) {
6346
6384
  }
6347
6385
 
6348
6386
  // src/commands/models.ts
6387
+ import {
6388
+ ModelSchema,
6389
+ ModelVersionSchema
6390
+ } from "@eide/foir-proto-ts/models/v1/models_pb";
6349
6391
  function registerModelsCommands(program2, globalOpts) {
6350
6392
  const models = program2.command("models").description("Manage models");
6351
6393
  models.command("list").description("List all models").option("--category <cat>", "Filter by category").option("--search <term>", "Search by name").option("--limit <n>", "Max results", "50").option("--offset <n>", "Skip results", "0").action(
@@ -6358,24 +6400,20 @@ function registerModelsCommands(program2, globalOpts) {
6358
6400
  limit: parseInt(cmdOpts.limit ?? "50", 10),
6359
6401
  offset: parseInt(cmdOpts.offset ?? "0", 10)
6360
6402
  });
6361
- formatList(
6362
- result.items,
6363
- opts,
6364
- {
6365
- columns: [
6366
- { key: "key", header: "Key", width: 24 },
6367
- { key: "name", header: "Name", width: 24 },
6368
- { key: "category", header: "Category", width: 14 },
6369
- {
6370
- key: "updatedAt",
6371
- header: "Updated",
6372
- width: 12,
6373
- format: (v) => timeAgo(v)
6374
- }
6375
- ],
6376
- total: result.total
6377
- }
6378
- );
6403
+ formatListProto(ModelSchema, result.items, opts, {
6404
+ columns: [
6405
+ { key: "key", header: "Key", width: 24 },
6406
+ { key: "name", header: "Name", width: 24 },
6407
+ { key: "category", header: "Category", width: 14 },
6408
+ {
6409
+ key: "updatedAt",
6410
+ header: "Updated",
6411
+ width: 12,
6412
+ format: (v) => timeAgo(v)
6413
+ }
6414
+ ],
6415
+ total: result.total
6416
+ });
6379
6417
  })
6380
6418
  );
6381
6419
  models.command("get <key>").description("Get a model by key").action(
@@ -6386,7 +6424,7 @@ function registerModelsCommands(program2, globalOpts) {
6386
6424
  if (!model) {
6387
6425
  throw new Error(`Model "${key}" not found.`);
6388
6426
  }
6389
- formatOutput(model, opts);
6427
+ formatOutputProto(ModelSchema, model, opts);
6390
6428
  })
6391
6429
  );
6392
6430
  models.command("create").description("Create a new model").option("-d, --data <json>", "Model data as JSON").option("-f, --file <path>", "Read data from file").action(
@@ -6395,7 +6433,7 @@ function registerModelsCommands(program2, globalOpts) {
6395
6433
  const client = await createPlatformClient(opts);
6396
6434
  const inputData = await parseInputData(cmdOpts);
6397
6435
  const model = await client.models.createModel(inputData);
6398
- formatOutput(model, opts);
6436
+ formatOutputProto(ModelSchema, model, opts);
6399
6437
  if (!(opts.json || opts.jsonl || opts.quiet)) {
6400
6438
  success(`Created model ${model?.key}`);
6401
6439
  }
@@ -6416,7 +6454,7 @@ function registerModelsCommands(program2, globalOpts) {
6416
6454
  id: existing.id,
6417
6455
  ...inputData
6418
6456
  });
6419
- formatOutput(model, opts);
6457
+ formatOutputProto(ModelSchema, model, opts);
6420
6458
  if (!(opts.json || opts.jsonl || opts.quiet)) {
6421
6459
  success(`Updated model ${key}`);
6422
6460
  }
@@ -6462,30 +6500,28 @@ function registerModelsCommands(program2, globalOpts) {
6462
6500
  const result = await client.models.listModelVersions(existing.id, {
6463
6501
  limit: parseInt(cmdOpts.limit ?? "20", 10)
6464
6502
  });
6465
- formatList(
6466
- result.items,
6467
- opts,
6468
- {
6469
- columns: [
6470
- { key: "id", header: "Version ID", width: 28 },
6471
- { key: "versionNumber", header: "#", width: 5 },
6472
- { key: "changeDescription", header: "Description", width: 32 },
6473
- {
6474
- key: "createdAt",
6475
- header: "Created",
6476
- width: 12,
6477
- format: (v) => timeAgo(v)
6478
- },
6479
- { key: "createdBy", header: "By", width: 18 }
6480
- ]
6481
- }
6482
- );
6503
+ formatListProto(ModelVersionSchema, result.items, opts, {
6504
+ columns: [
6505
+ { key: "id", header: "Version ID", width: 28 },
6506
+ { key: "versionNumber", header: "#", width: 5 },
6507
+ { key: "changeDescription", header: "Description", width: 32 },
6508
+ {
6509
+ key: "createdAt",
6510
+ header: "Created",
6511
+ width: 12,
6512
+ format: (v) => timeAgo(v)
6513
+ },
6514
+ { key: "createdBy", header: "By", width: 18 }
6515
+ ]
6516
+ });
6483
6517
  }
6484
6518
  )
6485
6519
  );
6486
6520
  }
6487
6521
 
6488
6522
  // src/commands/records.ts
6523
+ import { toJson as toJson3 } from "@bufbuild/protobuf";
6524
+ import { RecordSchema } from "@eide/foir-proto-ts/records/v1/records_pb";
6489
6525
  function registerRecordsCommands(program2, globalOpts) {
6490
6526
  const records = program2.command("records").description("Manage records");
6491
6527
  records.command("list <modelKey>").description("List records for a model").option("--filter <expr>", "Filter expression (e.g. status=active)").option("--limit <n>", "Max results", "20").option("--offset <n>", "Skip results", "0").action(
@@ -6501,24 +6537,20 @@ function registerRecordsCommands(program2, globalOpts) {
6501
6537
  };
6502
6538
  if (cmdOpts.filter) params.filters = parseFilters(cmdOpts.filter);
6503
6539
  const result = await client.records.listRecords(params);
6504
- formatList(
6505
- result.items,
6506
- opts,
6507
- {
6508
- columns: [
6509
- { key: "id", header: "ID", width: 28 },
6510
- { key: "naturalKey", header: "Key", width: 24 },
6511
- { key: "versionNumber", header: "Version", width: 8 },
6512
- {
6513
- key: "updatedAt",
6514
- header: "Updated",
6515
- width: 12,
6516
- format: (v) => timeAgo(v)
6517
- }
6518
- ],
6519
- total: result.total
6520
- }
6521
- );
6540
+ formatListProto(RecordSchema, result.items, opts, {
6541
+ columns: [
6542
+ { key: "id", header: "ID", width: 28 },
6543
+ { key: "naturalKey", header: "Key", width: 24 },
6544
+ { key: "versionNumber", header: "Version", width: 8 },
6545
+ {
6546
+ key: "updatedAt",
6547
+ header: "Updated",
6548
+ width: 12,
6549
+ format: (v) => timeAgo(v)
6550
+ }
6551
+ ],
6552
+ total: result.total
6553
+ });
6522
6554
  }
6523
6555
  )
6524
6556
  );
@@ -6528,23 +6560,13 @@ function registerRecordsCommands(program2, globalOpts) {
6528
6560
  async (modelKey, idOrKey, _cmdOpts) => {
6529
6561
  const opts = globalOpts();
6530
6562
  const client = await createPlatformClient(opts);
6531
- let result;
6532
- if (isUUID(idOrKey)) {
6533
- const record = await client.records.getRecord(idOrKey);
6534
- result = record;
6535
- } else {
6536
- const record = await client.records.getRecordByKey(
6537
- modelKey,
6538
- idOrKey
6539
- );
6540
- result = record;
6541
- }
6542
- if (!result) {
6563
+ const record = isUUID(idOrKey) ? await client.records.getRecord(idOrKey) : await client.records.getRecordByKey(modelKey, idOrKey);
6564
+ if (!record) {
6543
6565
  throw new Error(
6544
6566
  `Record "${idOrKey}" not found in model "${modelKey}".`
6545
6567
  );
6546
6568
  }
6547
- formatOutput(result, opts);
6569
+ formatOutputProto(RecordSchema, record, opts);
6548
6570
  }
6549
6571
  )
6550
6572
  );
@@ -6557,7 +6579,14 @@ function registerRecordsCommands(program2, globalOpts) {
6557
6579
  const inputData = await parseInputData(cmdOpts);
6558
6580
  const input = { modelKey, ...inputData };
6559
6581
  const result = await client.records.createRecord(input);
6560
- formatOutput(result, opts);
6582
+ formatOutput(
6583
+ {
6584
+ record: result.record ? toJson3(RecordSchema, result.record) : null,
6585
+ variant: result.variant ? toJson3(RecordSchema, result.variant) : null,
6586
+ version: result.version ? toJson3(RecordSchema, result.version) : null
6587
+ },
6588
+ opts
6589
+ );
6561
6590
  if (!(opts.json || opts.jsonl || opts.quiet)) {
6562
6591
  success(`Created record ${result.record?.id}`);
6563
6592
  }
@@ -6573,7 +6602,7 @@ function registerRecordsCommands(program2, globalOpts) {
6573
6602
  const inputData = await parseInputData(cmdOpts);
6574
6603
  const input = { id, ...inputData };
6575
6604
  const record = await client.records.updateRecord(input);
6576
- formatOutput(record, opts);
6605
+ formatOutputProto(RecordSchema, record, opts);
6577
6606
  if (!(opts.json || opts.jsonl || opts.quiet)) {
6578
6607
  success(`Updated record ${id}`);
6579
6608
  }
@@ -6634,7 +6663,7 @@ function registerRecordsCommands(program2, globalOpts) {
6634
6663
  const client = await createPlatformClient(opts);
6635
6664
  const naturalKey = cmdOpts.naturalKey ?? `${id}-copy`;
6636
6665
  const record = await client.records.duplicateRecord(id, naturalKey);
6637
- formatOutput(record, opts);
6666
+ formatOutputProto(RecordSchema, record, opts);
6638
6667
  if (!(opts.json || opts.jsonl || opts.quiet)) {
6639
6668
  success(`Duplicated \u2192 ${record?.id}`);
6640
6669
  }
@@ -6650,39 +6679,11 @@ function registerRecordsCommands(program2, globalOpts) {
6650
6679
  const result = await client.records.listRecordVersions(parentId, {
6651
6680
  limit: parseInt(cmdOpts.limit ?? "20", 10)
6652
6681
  });
6653
- formatList(
6654
- result.items,
6655
- opts,
6656
- {
6657
- columns: [
6658
- { key: "id", header: "Version ID", width: 28 },
6659
- { key: "versionNumber", header: "#", width: 5 },
6660
- { key: "changeDescription", header: "Description", width: 30 },
6661
- {
6662
- key: "createdAt",
6663
- header: "Created",
6664
- width: 12,
6665
- format: (v) => timeAgo(v)
6666
- }
6667
- ]
6668
- }
6669
- );
6670
- }
6671
- )
6672
- );
6673
- records.command("variants <recordId>").description("List variants for a record").action(
6674
- withErrorHandler(globalOpts, async (recordId) => {
6675
- const opts = globalOpts();
6676
- const client = await createPlatformClient(opts);
6677
- const result = await client.records.listRecordVariants(recordId);
6678
- formatList(
6679
- result.items,
6680
- opts,
6681
- {
6682
+ formatListProto(RecordSchema, result.items, opts, {
6682
6683
  columns: [
6683
- { key: "id", header: "Variant ID", width: 28 },
6684
- { key: "variantKey", header: "Key", width: 20 },
6685
- { key: "isDefault", header: "Default", width: 8 },
6684
+ { key: "id", header: "Version ID", width: 28 },
6685
+ { key: "versionNumber", header: "#", width: 5 },
6686
+ { key: "changeDescription", header: "Description", width: 30 },
6686
6687
  {
6687
6688
  key: "createdAt",
6688
6689
  header: "Created",
@@ -6690,8 +6691,28 @@ function registerRecordsCommands(program2, globalOpts) {
6690
6691
  format: (v) => timeAgo(v)
6691
6692
  }
6692
6693
  ]
6693
- }
6694
- );
6694
+ });
6695
+ }
6696
+ )
6697
+ );
6698
+ records.command("variants <recordId>").description("List variants for a record").action(
6699
+ withErrorHandler(globalOpts, async (recordId) => {
6700
+ const opts = globalOpts();
6701
+ const client = await createPlatformClient(opts);
6702
+ const result = await client.records.listRecordVariants(recordId);
6703
+ formatListProto(RecordSchema, result.items, opts, {
6704
+ columns: [
6705
+ { key: "id", header: "Variant ID", width: 28 },
6706
+ { key: "variantKey", header: "Key", width: 20 },
6707
+ { key: "isDefault", header: "Default", width: 8 },
6708
+ {
6709
+ key: "createdAt",
6710
+ header: "Created",
6711
+ width: 12,
6712
+ format: (v) => timeAgo(v)
6713
+ }
6714
+ ]
6715
+ });
6695
6716
  })
6696
6717
  );
6697
6718
  records.command("create-version <parentId>").description(
@@ -6708,7 +6729,7 @@ function registerRecordsCommands(program2, globalOpts) {
6708
6729
  inputData,
6709
6730
  cmdOpts.message
6710
6731
  );
6711
- formatOutput(version2, opts);
6732
+ formatOutputProto(RecordSchema, version2, opts);
6712
6733
  if (!(opts.json || opts.jsonl || opts.quiet)) {
6713
6734
  success(`Created version ${version2?.id}`);
6714
6735
  }
@@ -6725,7 +6746,7 @@ function registerRecordsCommands(program2, globalOpts) {
6725
6746
  recordId,
6726
6747
  cmdOpts.key
6727
6748
  );
6728
- formatOutput(variant, opts);
6749
+ formatOutputProto(RecordSchema, variant, opts);
6729
6750
  if (!(opts.json || opts.jsonl || opts.quiet)) {
6730
6751
  success(`Created variant ${variant?.id}`);
6731
6752
  }
@@ -6735,6 +6756,7 @@ function registerRecordsCommands(program2, globalOpts) {
6735
6756
  }
6736
6757
 
6737
6758
  // src/commands/customers.ts
6759
+ import { CustomerSchema } from "@eide/foir-proto-ts/identity/v1/identity_pb";
6738
6760
  var statusMap = {
6739
6761
  ACTIVE: CustomerStatus.ACTIVE,
6740
6762
  PENDING: CustomerStatus.PENDING,
@@ -6755,52 +6777,47 @@ function registerCustomersCommands(program2, globalOpts) {
6755
6777
  limit: parseInt(cmdOpts.limit ?? "20", 10),
6756
6778
  offset: parseInt(cmdOpts.offset ?? "0", 10)
6757
6779
  });
6758
- formatList(
6759
- result.items,
6760
- opts,
6761
- {
6762
- columns: [
6763
- { key: "id", header: "ID", width: 28 },
6764
- { key: "email", header: "Email", width: 30 },
6765
- { key: "status", header: "Status", width: 12 },
6766
- {
6767
- key: "lastLoginAt",
6768
- header: "Last Login",
6769
- width: 12,
6770
- format: (v) => timeAgo(v)
6771
- },
6772
- {
6773
- key: "createdAt",
6774
- header: "Created",
6775
- width: 12,
6776
- format: (v) => timeAgo(v)
6777
- }
6778
- ],
6779
- total: result.total
6780
- }
6781
- );
6780
+ formatListProto(CustomerSchema, result.items, opts, {
6781
+ columns: [
6782
+ { key: "id", header: "ID", width: 28 },
6783
+ { key: "email", header: "Email", width: 30 },
6784
+ { key: "status", header: "Status", width: 12 },
6785
+ {
6786
+ key: "lastLoginAt",
6787
+ header: "Last Login",
6788
+ width: 12,
6789
+ format: (v) => timeAgo(v)
6790
+ },
6791
+ {
6792
+ key: "createdAt",
6793
+ header: "Created",
6794
+ width: 12,
6795
+ format: (v) => timeAgo(v)
6796
+ }
6797
+ ],
6798
+ total: result.total
6799
+ });
6782
6800
  })
6783
6801
  );
6784
6802
  customers.command("get <idOrEmail>").description("Get a customer by ID or email").action(
6785
6803
  withErrorHandler(globalOpts, async (idOrEmail) => {
6786
6804
  const opts = globalOpts();
6787
6805
  const client = await createPlatformClient(opts);
6788
- let result = null;
6806
+ let customer;
6789
6807
  if (idOrEmail.includes("@")) {
6790
6808
  const list = await client.identity.listCustomers({
6791
6809
  search: idOrEmail,
6792
6810
  limit: 1
6793
6811
  });
6794
- const match = list.items[0];
6795
- result = match ? match : null;
6812
+ customer = list.items[0] ?? null;
6796
6813
  } else {
6797
6814
  const resp = await client.identity.getCustomer(idOrEmail);
6798
- result = resp.customer;
6815
+ customer = resp.customer ?? null;
6799
6816
  }
6800
- if (!result) {
6817
+ if (!customer) {
6801
6818
  throw new Error(`Customer "${idOrEmail}" not found.`);
6802
6819
  }
6803
- formatOutput(result, opts);
6820
+ formatOutputProto(CustomerSchema, customer, opts);
6804
6821
  })
6805
6822
  );
6806
6823
  customers.command("create").description("Create a new customer").option("--email <email>", "Customer email (required)").option("-d, --data <json>", "Additional data as JSON").action(
@@ -6824,11 +6841,8 @@ function registerCustomersCommands(program2, globalOpts) {
6824
6841
  throw new Error("--email is required.");
6825
6842
  }
6826
6843
  const resp = await client.identity.createCustomer(input);
6827
- const customer = resp.customer;
6828
- formatOutput(
6829
- customer,
6830
- opts
6831
- );
6844
+ const customer = resp.customer ?? null;
6845
+ formatOutputProto(CustomerSchema, customer, opts);
6832
6846
  if (!(opts.json || opts.jsonl || opts.quiet)) {
6833
6847
  success(`Created customer ${customer?.email}`);
6834
6848
  }
@@ -6860,6 +6874,7 @@ function registerCustomersCommands(program2, globalOpts) {
6860
6874
  }
6861
6875
 
6862
6876
  // src/commands/customer-profiles.ts
6877
+ import { CustomerProfileSchemaSchema } from "@eide/foir-proto-ts/settings/v1/settings_pb";
6863
6878
  function registerCustomerProfilesCommands(program2, globalOpts) {
6864
6879
  const cp = program2.command("customer-profiles").alias("cp").description("Manage customer profile schema and profiles");
6865
6880
  const schema = cp.command("schema").description("Manage the customer profile schema");
@@ -6878,7 +6893,7 @@ function registerCustomerProfilesCommands(program2, globalOpts) {
6878
6893
  }
6879
6894
  return;
6880
6895
  }
6881
- formatOutput(result, opts);
6896
+ formatOutputProto(CustomerProfileSchemaSchema, result, opts);
6882
6897
  })
6883
6898
  );
6884
6899
  schema.command("update").description(
@@ -6897,7 +6912,7 @@ function registerCustomerProfilesCommands(program2, globalOpts) {
6897
6912
  fields: inputData.fields,
6898
6913
  publicFields: inputData.publicFields ?? []
6899
6914
  });
6900
- formatOutput(result, opts);
6915
+ formatOutputProto(CustomerProfileSchemaSchema, result, opts);
6901
6916
  if (!(opts.json || opts.jsonl || opts.quiet)) {
6902
6917
  const version2 = result?.version;
6903
6918
  success(`Updated customer profile schema (version ${version2})`);
@@ -6938,6 +6953,11 @@ function registerCustomerProfilesCommands(program2, globalOpts) {
6938
6953
  }
6939
6954
 
6940
6955
  // src/commands/operations.ts
6956
+ import {
6957
+ OperationSchema,
6958
+ OperationExecutionSchema,
6959
+ DeadLetterEntrySchema
6960
+ } from "@eide/foir-proto-ts/operations/v1/operations_pb";
6941
6961
  function registerOperationsCommands(program2, globalOpts) {
6942
6962
  const operations = program2.command("operations").description("Manage operations");
6943
6963
  operations.command("list").description("List operations").option("--category <cat>", "Filter by category").option("--active", "Only active operations").option("--limit <n>", "Max results", "50").action(
@@ -6949,7 +6969,7 @@ function registerOperationsCommands(program2, globalOpts) {
6949
6969
  isActive: cmdOpts.active ? true : void 0,
6950
6970
  limit: parseInt(String(cmdOpts.limit ?? "50"), 10)
6951
6971
  });
6952
- formatList(data.operations, opts, {
6972
+ formatListProto(OperationSchema, data.operations, opts, {
6953
6973
  columns: [
6954
6974
  { key: "key", header: "Key", width: 24 },
6955
6975
  { key: "name", header: "Name", width: 24 },
@@ -6976,7 +6996,7 @@ function registerOperationsCommands(program2, globalOpts) {
6976
6996
  const client = await createPlatformClient(opts);
6977
6997
  const result = await client.operations.getOperation({ key });
6978
6998
  if (!result) throw new Error(`Operation "${key}" not found.`);
6979
- formatOutput(result, opts);
6999
+ formatOutputProto(OperationSchema, result, opts);
6980
7000
  })
6981
7001
  );
6982
7002
  operations.command("execute <key>").description("Execute an operation").option("-d, --data <json>", "Input data as JSON").option("-f, --file <path>", "Read input from file").option("--async", "Execute asynchronously").action(
@@ -6993,7 +7013,17 @@ function registerOperationsCommands(program2, globalOpts) {
6993
7013
  operationKey: key,
6994
7014
  input: inputData
6995
7015
  });
6996
- formatOutput(result.execution ?? result, opts);
7016
+ if (result.execution) {
7017
+ formatOutputProto(OperationExecutionSchema, result.execution, opts);
7018
+ } else {
7019
+ formatOutput(
7020
+ {
7021
+ completed: result.completed,
7022
+ errorMessage: result.errorMessage ?? null
7023
+ },
7024
+ opts
7025
+ );
7026
+ }
6997
7027
  if (!(opts.json || opts.jsonl || opts.quiet)) {
6998
7028
  if (result.completed) {
6999
7029
  success(`Operation completed in ${result.execution?.durationMs ?? 0}ms`);
@@ -7012,7 +7042,7 @@ function registerOperationsCommands(program2, globalOpts) {
7012
7042
  operationKey: cmdOpts.operation,
7013
7043
  limit: parseInt(cmdOpts.limit ?? "20", 10)
7014
7044
  });
7015
- formatList(data.entries, opts, {
7045
+ formatListProto(DeadLetterEntrySchema, data.entries, opts, {
7016
7046
  columns: [
7017
7047
  { key: "id", header: "ID", width: 28 },
7018
7048
  { key: "operationKey", header: "Operation", width: 20 },
@@ -7059,6 +7089,11 @@ function registerOperationsCommands(program2, globalOpts) {
7059
7089
  }
7060
7090
 
7061
7091
  // src/commands/segments.ts
7092
+ import {
7093
+ SegmentSchema,
7094
+ SegmentPreviewSchema,
7095
+ SegmentEvaluationResultSchema
7096
+ } from "@eide/foir-proto-ts/segments/v1/segments_pb";
7062
7097
  function registerSegmentsCommands(program2, globalOpts) {
7063
7098
  const segments = program2.command("segments").description("Manage segments");
7064
7099
  segments.command("list").description("List segments").option("--active", "Only active segments").option("--limit <n>", "Max results", "50").option("--offset <n>", "Skip results", "0").action(
@@ -7070,7 +7105,7 @@ function registerSegmentsCommands(program2, globalOpts) {
7070
7105
  limit: parseInt(String(cmdOpts.limit ?? "50"), 10),
7071
7106
  offset: parseInt(String(cmdOpts.offset ?? "0"), 10)
7072
7107
  });
7073
- formatList(data.segments, opts, {
7108
+ formatListProto(SegmentSchema, data.segments, opts, {
7074
7109
  columns: [
7075
7110
  { key: "id", header: "ID", width: 28 },
7076
7111
  { key: "key", header: "Key", width: 20 },
@@ -7103,7 +7138,7 @@ function registerSegmentsCommands(program2, globalOpts) {
7103
7138
  result = await client.segments.getSegmentByKey(idOrKey);
7104
7139
  }
7105
7140
  if (!result) throw new Error(`Segment "${idOrKey}" not found.`);
7106
- formatOutput(result, opts);
7141
+ formatOutputProto(SegmentSchema, result, opts);
7107
7142
  })
7108
7143
  );
7109
7144
  segments.command("create").description("Create a new segment").option("-d, --data <json>", "Segment data as JSON").option("-f, --file <path>", "Read data from file").action(
@@ -7114,7 +7149,7 @@ function registerSegmentsCommands(program2, globalOpts) {
7114
7149
  const result = await client.segments.createSegment(
7115
7150
  input
7116
7151
  );
7117
- formatOutput(result, opts);
7152
+ formatOutputProto(SegmentSchema, result, opts);
7118
7153
  if (!(opts.json || opts.jsonl || opts.quiet))
7119
7154
  success(`Created segment ${result?.key}`);
7120
7155
  })
@@ -7130,7 +7165,7 @@ function registerSegmentsCommands(program2, globalOpts) {
7130
7165
  id,
7131
7166
  ...input
7132
7167
  });
7133
- formatOutput(result, opts);
7168
+ formatOutputProto(SegmentSchema, result, opts);
7134
7169
  if (!(opts.json || opts.jsonl || opts.quiet))
7135
7170
  success(`Updated segment ${id}`);
7136
7171
  }
@@ -7166,7 +7201,7 @@ function registerSegmentsCommands(program2, globalOpts) {
7166
7201
  rules,
7167
7202
  parseInt(cmdOpts.sampleSize ?? "100", 10)
7168
7203
  );
7169
- formatOutput(result, opts);
7204
+ formatOutputProto(SegmentPreviewSchema, result, opts);
7170
7205
  })
7171
7206
  );
7172
7207
  segments.command("test <segmentId> <customerId>").description("Test whether a customer matches a segment").action(
@@ -7179,13 +7214,17 @@ function registerSegmentsCommands(program2, globalOpts) {
7179
7214
  segmentId,
7180
7215
  customerId
7181
7216
  );
7182
- formatOutput(result, opts);
7217
+ formatOutputProto(SegmentEvaluationResultSchema, result, opts);
7183
7218
  }
7184
7219
  )
7185
7220
  );
7186
7221
  }
7187
7222
 
7188
7223
  // src/commands/experiments.ts
7224
+ import {
7225
+ ExperimentSchema,
7226
+ ExperimentStatsSchema
7227
+ } from "@eide/foir-proto-ts/experiments/v1/experiments_pb";
7189
7228
  function registerExperimentsCommands(program2, globalOpts) {
7190
7229
  const experiments = program2.command("experiments").description("Manage experiments");
7191
7230
  experiments.command("list").description("List experiments").option("--status <status>", "Filter by status").option("--active", "Only active experiments").option("--limit <n>", "Max results", "50").option("--offset <n>", "Skip results", "0").action(
@@ -7198,7 +7237,7 @@ function registerExperimentsCommands(program2, globalOpts) {
7198
7237
  limit: parseInt(String(cmdOpts.limit ?? "50"), 10),
7199
7238
  offset: parseInt(String(cmdOpts.offset ?? "0"), 10)
7200
7239
  });
7201
- formatList(data.experiments, opts, {
7240
+ formatListProto(ExperimentSchema, data.experiments, opts, {
7202
7241
  columns: [
7203
7242
  { key: "id", header: "ID", width: 28 },
7204
7243
  { key: "key", header: "Key", width: 20 },
@@ -7231,7 +7270,7 @@ function registerExperimentsCommands(program2, globalOpts) {
7231
7270
  result = await client.experiments.getExperimentByKey(idOrKey);
7232
7271
  }
7233
7272
  if (!result) throw new Error(`Experiment "${idOrKey}" not found.`);
7234
- formatOutput(result, opts);
7273
+ formatOutputProto(ExperimentSchema, result, opts);
7235
7274
  })
7236
7275
  );
7237
7276
  experiments.command("create").description("Create a new experiment").option("-d, --data <json>", "Experiment data as JSON").option("-f, --file <path>", "Read data from file").action(
@@ -7242,7 +7281,7 @@ function registerExperimentsCommands(program2, globalOpts) {
7242
7281
  const result = await client.experiments.createExperiment(
7243
7282
  input
7244
7283
  );
7245
- formatOutput(result, opts);
7284
+ formatOutputProto(ExperimentSchema, result, opts);
7246
7285
  if (!(opts.json || opts.jsonl || opts.quiet))
7247
7286
  success(`Created experiment ${result?.key}`);
7248
7287
  })
@@ -7258,7 +7297,7 @@ function registerExperimentsCommands(program2, globalOpts) {
7258
7297
  id,
7259
7298
  ...input
7260
7299
  });
7261
- formatOutput(result, opts);
7300
+ formatOutputProto(ExperimentSchema, result, opts);
7262
7301
  if (!(opts.json || opts.jsonl || opts.quiet))
7263
7302
  success(`Updated experiment ${id}`);
7264
7303
  }
@@ -7289,7 +7328,7 @@ function registerExperimentsCommands(program2, globalOpts) {
7289
7328
  const opts = globalOpts();
7290
7329
  const client = await createPlatformClient(opts);
7291
7330
  const result = await client.experiments.startExperiment(id);
7292
- formatOutput(result, opts);
7331
+ formatOutputProto(ExperimentSchema, result, opts);
7293
7332
  if (!(opts.json || opts.jsonl || opts.quiet))
7294
7333
  success("Experiment started");
7295
7334
  })
@@ -7299,7 +7338,7 @@ function registerExperimentsCommands(program2, globalOpts) {
7299
7338
  const opts = globalOpts();
7300
7339
  const client = await createPlatformClient(opts);
7301
7340
  const result = await client.experiments.pauseExperiment(id);
7302
- formatOutput(result, opts);
7341
+ formatOutputProto(ExperimentSchema, result, opts);
7303
7342
  if (!(opts.json || opts.jsonl || opts.quiet))
7304
7343
  success("Experiment paused");
7305
7344
  })
@@ -7309,7 +7348,7 @@ function registerExperimentsCommands(program2, globalOpts) {
7309
7348
  const opts = globalOpts();
7310
7349
  const client = await createPlatformClient(opts);
7311
7350
  const result = await client.experiments.resumeExperiment(id);
7312
- formatOutput(result, opts);
7351
+ formatOutputProto(ExperimentSchema, result, opts);
7313
7352
  if (!(opts.json || opts.jsonl || opts.quiet))
7314
7353
  success("Experiment resumed");
7315
7354
  })
@@ -7319,7 +7358,7 @@ function registerExperimentsCommands(program2, globalOpts) {
7319
7358
  const opts = globalOpts();
7320
7359
  const client = await createPlatformClient(opts);
7321
7360
  const result = await client.experiments.endExperiment(id);
7322
- formatOutput(result, opts);
7361
+ formatOutputProto(ExperimentSchema, result, opts);
7323
7362
  if (!(opts.json || opts.jsonl || opts.quiet))
7324
7363
  success("Experiment ended");
7325
7364
  })
@@ -7329,12 +7368,13 @@ function registerExperimentsCommands(program2, globalOpts) {
7329
7368
  const opts = globalOpts();
7330
7369
  const client = await createPlatformClient(opts);
7331
7370
  const result = await client.experiments.getExperimentStats(id);
7332
- formatOutput(result, opts);
7371
+ formatOutputProto(ExperimentStatsSchema, result, opts);
7333
7372
  })
7334
7373
  );
7335
7374
  }
7336
7375
 
7337
7376
  // src/commands/schedules.ts
7377
+ import { CronScheduleSchema } from "@eide/foir-proto-ts/schedules/v1/schedules_pb";
7338
7378
  function registerSchedulesCommands(program2, globalOpts) {
7339
7379
  const schedules = program2.command("schedules").description("Manage schedules");
7340
7380
  schedules.command("list").description("List schedules").option("--active", "Only active schedules").option("--limit <n>", "Max results", "50").action(
@@ -7345,7 +7385,7 @@ function registerSchedulesCommands(program2, globalOpts) {
7345
7385
  isActive: cmdOpts.active ? true : void 0,
7346
7386
  limit: parseInt(String(cmdOpts.limit ?? "50"), 10)
7347
7387
  });
7348
- formatList(data.schedules, opts, {
7388
+ formatListProto(CronScheduleSchema, data.schedules, opts, {
7349
7389
  columns: [
7350
7390
  { key: "key", header: "Key", width: 20 },
7351
7391
  { key: "name", header: "Name", width: 24 },
@@ -7374,7 +7414,7 @@ function registerSchedulesCommands(program2, globalOpts) {
7374
7414
  const client = await createPlatformClient(opts);
7375
7415
  const result = await client.cronSchedules.getCronScheduleByKey(key);
7376
7416
  if (!result) throw new Error(`Schedule "${key}" not found.`);
7377
- formatOutput(result, opts);
7417
+ formatOutputProto(CronScheduleSchema, result, opts);
7378
7418
  })
7379
7419
  );
7380
7420
  schedules.command("create").description("Create a new schedule").option("-d, --data <json>", "Schedule data as JSON").option("-f, --file <path>", "Read data from file").action(
@@ -7385,7 +7425,7 @@ function registerSchedulesCommands(program2, globalOpts) {
7385
7425
  const result = await client.cronSchedules.createCronSchedule(
7386
7426
  input
7387
7427
  );
7388
- formatOutput(result, opts);
7428
+ formatOutputProto(CronScheduleSchema, result, opts);
7389
7429
  if (!(opts.json || opts.jsonl || opts.quiet))
7390
7430
  success(`Created schedule ${result?.key}`);
7391
7431
  })
@@ -7403,7 +7443,7 @@ function registerSchedulesCommands(program2, globalOpts) {
7403
7443
  id: existing.id,
7404
7444
  ...input
7405
7445
  });
7406
- formatOutput(result, opts);
7446
+ formatOutputProto(CronScheduleSchema, result, opts);
7407
7447
  if (!(opts.json || opts.jsonl || opts.quiet))
7408
7448
  success(`Updated schedule "${key}"`);
7409
7449
  }
@@ -7419,7 +7459,11 @@ function registerSchedulesCommands(program2, globalOpts) {
7419
7459
  id: existing.id
7420
7460
  });
7421
7461
  if (opts.json || opts.jsonl) {
7422
- formatOutput(result ?? { triggered: true }, opts);
7462
+ if (result) {
7463
+ formatOutputProto(CronScheduleSchema, result, opts);
7464
+ } else {
7465
+ formatOutput({ triggered: true }, opts);
7466
+ }
7423
7467
  } else {
7424
7468
  success(`Triggered schedule "${key}"`);
7425
7469
  }
@@ -7434,7 +7478,7 @@ function registerSchedulesCommands(program2, globalOpts) {
7434
7478
  const result = await client.cronSchedules.pauseCronSchedule({
7435
7479
  id: existing.id
7436
7480
  });
7437
- formatOutput(result, opts);
7481
+ formatOutputProto(CronScheduleSchema, result, opts);
7438
7482
  if (!(opts.json || opts.jsonl || opts.quiet))
7439
7483
  success(`Paused schedule "${key}"`);
7440
7484
  })
@@ -7448,7 +7492,7 @@ function registerSchedulesCommands(program2, globalOpts) {
7448
7492
  const result = await client.cronSchedules.resumeCronSchedule({
7449
7493
  id: existing.id
7450
7494
  });
7451
- formatOutput(result, opts);
7495
+ formatOutputProto(CronScheduleSchema, result, opts);
7452
7496
  if (!(opts.json || opts.jsonl || opts.quiet))
7453
7497
  success(`Resumed schedule "${key}"`);
7454
7498
  })
@@ -7481,6 +7525,8 @@ function registerSchedulesCommands(program2, globalOpts) {
7481
7525
 
7482
7526
  // src/commands/api-keys.ts
7483
7527
  import chalk10 from "chalk";
7528
+ import { toJson as toJson4 } from "@bufbuild/protobuf";
7529
+ import { ApiKeySchema } from "@eide/foir-proto-ts/identity/v1/identity_pb";
7484
7530
  function registerApiKeysCommands(program2, globalOpts) {
7485
7531
  const apiKeys = program2.command("api-keys").description("Manage API keys");
7486
7532
  apiKeys.command("list").description("List API keys").option("--include-inactive", "Include revoked/inactive keys").option("--search <term>", "Search by name").option("--limit <n>", "Max results", "50").action(
@@ -7490,7 +7536,7 @@ function registerApiKeysCommands(program2, globalOpts) {
7490
7536
  const result = await client.identity.listApiKeys({
7491
7537
  limit: parseInt(String(cmdOpts.limit ?? "50"), 10)
7492
7538
  });
7493
- formatList(result.items, opts, {
7539
+ formatListProto(ApiKeySchema, result.items, opts, {
7494
7540
  columns: [
7495
7541
  { key: "id", header: "ID", width: 28 },
7496
7542
  { key: "name", header: "Name", width: 24 },
@@ -7529,7 +7575,12 @@ function registerApiKeysCommands(program2, globalOpts) {
7529
7575
  name: cmdOpts.name
7530
7576
  });
7531
7577
  if (opts.json || opts.jsonl) {
7532
- formatOutput(result, opts);
7578
+ formatOutput(
7579
+ {
7580
+ apiKey: result.apiKey ? toJson4(ApiKeySchema, result.apiKey) : null
7581
+ },
7582
+ opts
7583
+ );
7533
7584
  } else {
7534
7585
  success(`Created API key: ${result.apiKey?.name}`);
7535
7586
  console.log("");
@@ -7556,7 +7607,12 @@ function registerApiKeysCommands(program2, globalOpts) {
7556
7607
  const client = await createPlatformClient(opts);
7557
7608
  const result = await client.identity.rotateApiKey(id);
7558
7609
  if (opts.json || opts.jsonl) {
7559
- formatOutput(result, opts);
7610
+ formatOutput(
7611
+ {
7612
+ apiKey: result.apiKey ? toJson4(ApiKeySchema, result.apiKey) : null
7613
+ },
7614
+ opts
7615
+ );
7560
7616
  } else {
7561
7617
  success(`Rotated API key: ${result.apiKey?.name}`);
7562
7618
  console.log("");
@@ -7597,6 +7653,7 @@ function registerApiKeysCommands(program2, globalOpts) {
7597
7653
 
7598
7654
  // src/commands/auth-providers.ts
7599
7655
  import chalk11 from "chalk";
7656
+ import { AuthProviderSchema } from "@eide/foir-proto-ts/identity/v1/identity_pb";
7600
7657
  var VALID_TYPES = [
7601
7658
  "OAUTH2",
7602
7659
  "TOKEN_SSO",
@@ -7614,7 +7671,7 @@ function registerAuthProvidersCommands(program2, globalOpts) {
7614
7671
  const result = await client.identity.listAuthProviders({
7615
7672
  enabled: cmdOpts.enabledOnly ? true : void 0
7616
7673
  });
7617
- formatList(result.items, opts, {
7674
+ formatListProto(AuthProviderSchema, result.items, opts, {
7618
7675
  columns: [
7619
7676
  { key: "id", header: "ID", width: 28 },
7620
7677
  { key: "key", header: "Key", width: 20 },
@@ -7646,7 +7703,7 @@ function registerAuthProvidersCommands(program2, globalOpts) {
7646
7703
  throw new Error(`Auth provider not found: ${id}`);
7647
7704
  }
7648
7705
  if (opts.json || opts.jsonl) {
7649
- formatOutput(provider, opts);
7706
+ formatOutputProto(AuthProviderSchema, provider, opts);
7650
7707
  } else {
7651
7708
  const p = provider;
7652
7709
  console.log(chalk11.bold(`${p.name}`) + chalk11.gray(` (${p.key})`));
@@ -7707,7 +7764,7 @@ function registerAuthProvidersCommands(program2, globalOpts) {
7707
7764
  input
7708
7765
  );
7709
7766
  if (opts.json || opts.jsonl) {
7710
- formatOutput(provider, opts);
7767
+ formatOutputProto(AuthProviderSchema, provider, opts);
7711
7768
  } else {
7712
7769
  success(
7713
7770
  `Created auth provider: ${provider?.name} (${provider?.key})`
@@ -7745,7 +7802,7 @@ function registerAuthProvidersCommands(program2, globalOpts) {
7745
7802
  input
7746
7803
  );
7747
7804
  if (opts.json || opts.jsonl) {
7748
- formatOutput(provider, opts);
7805
+ formatOutputProto(AuthProviderSchema, provider, opts);
7749
7806
  } else {
7750
7807
  success(
7751
7808
  `Updated auth provider: ${provider?.name} (${provider?.key})`
@@ -7780,6 +7837,7 @@ function registerAuthProvidersCommands(program2, globalOpts) {
7780
7837
  }
7781
7838
 
7782
7839
  // src/commands/locales.ts
7840
+ import { LocaleSchema } from "@eide/foir-proto-ts/settings/v1/settings_pb";
7783
7841
  function registerLocalesCommands(program2, globalOpts) {
7784
7842
  const locales = program2.command("locales").description("Manage locales");
7785
7843
  locales.command("list").description("List locales").option("--include-inactive", "Include inactive locales").option("--limit <n>", "Max results", "50").action(
@@ -7790,7 +7848,7 @@ function registerLocalesCommands(program2, globalOpts) {
7790
7848
  includeInactive: !!cmdOpts.includeInactive,
7791
7849
  limit: parseInt(String(cmdOpts.limit ?? "50"), 10)
7792
7850
  });
7793
- formatList(result.locales, opts, {
7851
+ formatListProto(LocaleSchema, result.locales, opts, {
7794
7852
  columns: [
7795
7853
  { key: "code", header: "Code", width: 8 },
7796
7854
  { key: "name", header: "Name", width: 20 },
@@ -7823,7 +7881,7 @@ function registerLocalesCommands(program2, globalOpts) {
7823
7881
  result = await client.settings.getLocaleByCode(idOrCode);
7824
7882
  }
7825
7883
  if (!result) throw new Error(`Locale "${idOrCode}" not found.`);
7826
- formatOutput(result, opts);
7884
+ formatOutputProto(LocaleSchema, result, opts);
7827
7885
  })
7828
7886
  );
7829
7887
  locales.command("default").description("Get the default locale").action(
@@ -7832,7 +7890,7 @@ function registerLocalesCommands(program2, globalOpts) {
7832
7890
  const client = await createPlatformClient(opts);
7833
7891
  const result = await client.settings.getDefaultLocale();
7834
7892
  if (!result) throw new Error("No default locale configured.");
7835
- formatOutput(result, opts);
7893
+ formatOutputProto(LocaleSchema, result, opts);
7836
7894
  })
7837
7895
  );
7838
7896
  locales.command("create").description("Create a new locale").option("-d, --data <json>", "Locale data as JSON").option("-f, --file <path>", "Read data from file").action(
@@ -7843,9 +7901,9 @@ function registerLocalesCommands(program2, globalOpts) {
7843
7901
  const result = await client.settings.createLocale(
7844
7902
  input
7845
7903
  );
7846
- formatOutput(result, opts);
7904
+ formatOutputProto(LocaleSchema, result, opts);
7847
7905
  if (!(opts.json || opts.jsonl || opts.quiet))
7848
- success(`Created locale ${result?.locale ?? result?.code}`);
7906
+ success(`Created locale ${result?.locale}`);
7849
7907
  })
7850
7908
  );
7851
7909
  locales.command("update <id>").description("Update a locale").option("-d, --data <json>", "Locale data as JSON").option("-f, --file <path>", "Read data from file").action(
@@ -7859,9 +7917,9 @@ function registerLocalesCommands(program2, globalOpts) {
7859
7917
  id,
7860
7918
  ...input
7861
7919
  });
7862
- formatOutput(result, opts);
7920
+ formatOutputProto(LocaleSchema, result, opts);
7863
7921
  if (!(opts.json || opts.jsonl || opts.quiet))
7864
- success(`Updated locale ${result?.locale ?? result?.code}`);
7922
+ success(`Updated locale ${result?.locale}`);
7865
7923
  }
7866
7924
  )
7867
7925
  );
@@ -7888,6 +7946,7 @@ function registerLocalesCommands(program2, globalOpts) {
7888
7946
  }
7889
7947
 
7890
7948
  // src/commands/settings.ts
7949
+ import { SettingSchema } from "@eide/foir-proto-ts/settings/v1/settings_pb";
7891
7950
  function inferDataType(value) {
7892
7951
  if (value === "true" || value === "false")
7893
7952
  return { dataType: "BOOLEAN", parsed: value === "true" };
@@ -7909,7 +7968,7 @@ function registerSettingsCommands(program2, globalOpts) {
7909
7968
  const items = await client.settings.getSettings({
7910
7969
  category: cmdOpts.category
7911
7970
  });
7912
- formatList(items, opts, {
7971
+ formatListProto(SettingSchema, items, opts, {
7913
7972
  columns: [
7914
7973
  { key: "key", header: "Key", width: 28 },
7915
7974
  {
@@ -7937,7 +7996,7 @@ function registerSettingsCommands(program2, globalOpts) {
7937
7996
  const items = await client.settings.getSettings({ key });
7938
7997
  const setting = items[0] ?? null;
7939
7998
  if (!setting) throw new Error(`Setting "${key}" not found.`);
7940
- formatOutput(setting, opts);
7999
+ formatOutputProto(SettingSchema, setting, opts);
7941
8000
  })
7942
8001
  );
7943
8002
  settings.command("set <key> <value>").description("Set a setting value").option("--category <cat>", "Category (required for new settings)").option("--data-type <type>", "Data type (STRING, NUMBER, BOOLEAN, JSON)").action(
@@ -7961,7 +8020,7 @@ function registerSettingsCommands(program2, globalOpts) {
7961
8020
  dataType
7962
8021
  }
7963
8022
  });
7964
- formatOutput(result, opts);
8023
+ formatOutputProto(SettingSchema, result, opts);
7965
8024
  if (!(opts.json || opts.jsonl || opts.quiet))
7966
8025
  success(`Set ${key} = ${value}`);
7967
8026
  }
@@ -7979,6 +8038,7 @@ function registerSettingsCommands(program2, globalOpts) {
7979
8038
  }
7980
8039
 
7981
8040
  // src/commands/variant-catalog.ts
8041
+ import { VariantCatalogEntrySchema } from "@eide/foir-proto-ts/settings/v1/settings_pb";
7982
8042
  function registerVariantCatalogCommands(program2, globalOpts) {
7983
8043
  const catalog = program2.command("variant-catalog").description("Manage variant catalog entries (markets, devices, locales)");
7984
8044
  catalog.command("list").description("List variant catalog entries").option("--active", "Only active entries").option("--limit <n>", "Max results", "50").action(
@@ -7989,7 +8049,7 @@ function registerVariantCatalogCommands(program2, globalOpts) {
7989
8049
  isActive: cmdOpts.active ? true : void 0,
7990
8050
  limit: parseInt(String(cmdOpts.limit ?? "50"), 10)
7991
8051
  });
7992
- formatList(result.entries, opts, {
8052
+ formatListProto(VariantCatalogEntrySchema, result.entries, opts, {
7993
8053
  columns: [
7994
8054
  { key: "key", header: "Key", width: 20 },
7995
8055
  { key: "name", header: "Name", width: 24 },
@@ -8024,7 +8084,7 @@ function registerVariantCatalogCommands(program2, globalOpts) {
8024
8084
  }
8025
8085
  if (!result)
8026
8086
  throw new Error(`Variant catalog entry "${idOrKey}" not found.`);
8027
- formatOutput(result, opts);
8087
+ formatOutputProto(VariantCatalogEntrySchema, result, opts);
8028
8088
  })
8029
8089
  );
8030
8090
  catalog.command("create").description("Create a variant catalog entry").option("-d, --data <json>", "Entry data as JSON").option("-f, --file <path>", "Read data from file").action(
@@ -8035,11 +8095,9 @@ function registerVariantCatalogCommands(program2, globalOpts) {
8035
8095
  const result = await client.settings.createVariantCatalogEntry(
8036
8096
  input
8037
8097
  );
8038
- formatOutput(result, opts);
8098
+ formatOutputProto(VariantCatalogEntrySchema, result, opts);
8039
8099
  if (!(opts.json || opts.jsonl || opts.quiet))
8040
- success(
8041
- `Created variant catalog entry ${result?.key}`
8042
- );
8100
+ success(`Created variant catalog entry ${result?.key}`);
8043
8101
  })
8044
8102
  );
8045
8103
  catalog.command("update <id>").description("Update a variant catalog entry").option("-d, --data <json>", "Entry data as JSON").option("-f, --file <path>", "Read data from file").action(
@@ -8053,11 +8111,9 @@ function registerVariantCatalogCommands(program2, globalOpts) {
8053
8111
  id,
8054
8112
  ...input
8055
8113
  });
8056
- formatOutput(result, opts);
8114
+ formatOutputProto(VariantCatalogEntrySchema, result, opts);
8057
8115
  if (!(opts.json || opts.jsonl || opts.quiet))
8058
- success(
8059
- `Updated variant catalog entry ${result?.key}`
8060
- );
8116
+ success(`Updated variant catalog entry ${result?.key}`);
8061
8117
  }
8062
8118
  )
8063
8119
  );
@@ -8085,6 +8141,10 @@ function registerVariantCatalogCommands(program2, globalOpts) {
8085
8141
  }
8086
8142
 
8087
8143
  // src/commands/files.ts
8144
+ import {
8145
+ FileSchema as FileSchema2,
8146
+ StorageUsageSchema as StorageUsageSchema2
8147
+ } from "@eide/foir-proto-ts/storage/v1/storage_pb";
8088
8148
  function registerFilesCommands(program2, globalOpts) {
8089
8149
  const files = program2.command("files").description("Manage files (for upload, use `foir media upload`)");
8090
8150
  files.command("list").description("List files").option("--folder <folder>", "Filter by folder").option("--mime-type <type>", "Filter by MIME type").option("--search <term>", "Search by filename").option("--limit <n>", "Max results", "50").option("--offset <n>", "Skip results", "0").action(
@@ -8098,7 +8158,7 @@ function registerFilesCommands(program2, globalOpts) {
8098
8158
  limit: parseInt(cmdOpts.limit ?? "50", 10),
8099
8159
  offset: parseInt(cmdOpts.offset ?? "0", 10)
8100
8160
  });
8101
- formatList(data.items, opts, {
8161
+ formatListProto(FileSchema2, data.items, opts, {
8102
8162
  columns: [
8103
8163
  { key: "id", header: "ID", width: 28 },
8104
8164
  { key: "filename", header: "Filename", width: 30 },
@@ -8127,7 +8187,7 @@ function registerFilesCommands(program2, globalOpts) {
8127
8187
  const client = await createPlatformClient(opts);
8128
8188
  const file = await client.storage.getFile(id);
8129
8189
  if (!file) throw new Error(`File "${id}" not found.`);
8130
- formatOutput(file, opts);
8190
+ formatOutputProto(FileSchema2, file, opts);
8131
8191
  })
8132
8192
  );
8133
8193
  files.command("usage").description("Get storage usage statistics").action(
@@ -8135,7 +8195,7 @@ function registerFilesCommands(program2, globalOpts) {
8135
8195
  const opts = globalOpts();
8136
8196
  const client = await createPlatformClient(opts);
8137
8197
  const usage = await client.storage.getStorageUsage();
8138
- formatOutput(usage, opts);
8198
+ formatOutputProto(StorageUsageSchema2, usage, opts);
8139
8199
  })
8140
8200
  );
8141
8201
  files.command("update <id>").description("Update file properties").option("--filename <name>", "New filename").option("--folder <folder>", "Move to folder").option("--tags <tags>", "Comma-separated tags").action(
@@ -8150,7 +8210,7 @@ function registerFilesCommands(program2, globalOpts) {
8150
8210
  if (cmdOpts.tags)
8151
8211
  params.tags = cmdOpts.tags.split(",").map((t) => t.trim());
8152
8212
  const file = await client.storage.updateFile(params);
8153
- formatOutput(file, opts);
8213
+ formatOutputProto(FileSchema2, file, opts);
8154
8214
  if (!(opts.json || opts.jsonl || opts.quiet))
8155
8215
  success(`Updated file ${id}`);
8156
8216
  }
@@ -8168,7 +8228,7 @@ function registerFilesCommands(program2, globalOpts) {
8168
8228
  caption: cmdOpts.caption,
8169
8229
  description: cmdOpts.description
8170
8230
  });
8171
- formatOutput(file, opts);
8231
+ formatOutputProto(FileSchema2, file, opts);
8172
8232
  if (!(opts.json || opts.jsonl || opts.quiet))
8173
8233
  success(`Updated metadata for file ${id}`);
8174
8234
  }
@@ -8206,6 +8266,7 @@ function formatBytes(bytes) {
8206
8266
  }
8207
8267
 
8208
8268
  // src/commands/notes.ts
8269
+ import { NoteSchema } from "@eide/foir-proto-ts/settings/v1/settings_pb";
8209
8270
  function registerNotesCommands(program2, globalOpts) {
8210
8271
  const notes = program2.command("notes").description("Manage notes and comments");
8211
8272
  notes.command("list").description("List notes for an entity").requiredOption("--entity-type <type>", "Entity type (e.g. record, model)").requiredOption("--entity-id <id>", "Entity ID").option("--include-resolved", "Include resolved notes").option("--limit <n>", "Max results", "20").action(
@@ -8217,7 +8278,7 @@ function registerNotesCommands(program2, globalOpts) {
8217
8278
  entityId: cmdOpts.entityId,
8218
8279
  limit: parseInt(String(cmdOpts.limit ?? "20"), 10)
8219
8280
  });
8220
- formatList(data.notes, opts, {
8281
+ formatListProto(NoteSchema, data.notes, opts, {
8221
8282
  columns: [
8222
8283
  { key: "id", header: "ID", width: 28 },
8223
8284
  { key: "content", header: "Content", width: 40 },
@@ -8245,7 +8306,7 @@ function registerNotesCommands(program2, globalOpts) {
8245
8306
  const client = await createPlatformClient(opts);
8246
8307
  const note = await client.settings.getNote(id);
8247
8308
  if (!note) throw new Error(`Note "${id}" not found.`);
8248
- formatOutput(note, opts);
8309
+ formatOutputProto(NoteSchema, note, opts);
8249
8310
  })
8250
8311
  );
8251
8312
  notes.command("create").description("Create a note").requiredOption("--entity-type <type>", "Entity type").requiredOption("--entity-id <id>", "Entity ID").requiredOption("--body <text>", "Note body text").option("--parent-note-id <id>", "Reply to a note").action(
@@ -8261,7 +8322,7 @@ function registerNotesCommands(program2, globalOpts) {
8261
8322
  };
8262
8323
  if (cmdOpts.parentNoteId) params.parentNoteId = cmdOpts.parentNoteId;
8263
8324
  const note = await client.settings.createNote(params);
8264
- formatOutput(note, opts);
8325
+ formatOutputProto(NoteSchema, note, opts);
8265
8326
  if (!(opts.json || opts.jsonl || opts.quiet)) success("Note created");
8266
8327
  })
8267
8328
  );
@@ -8275,7 +8336,7 @@ function registerNotesCommands(program2, globalOpts) {
8275
8336
  id,
8276
8337
  isResolved: true
8277
8338
  });
8278
- formatOutput(note, opts);
8339
+ formatOutputProto(NoteSchema, note, opts);
8279
8340
  if (!(opts.json || opts.jsonl || opts.quiet))
8280
8341
  success(`Resolved note ${id}`);
8281
8342
  }
@@ -8304,6 +8365,7 @@ function registerNotesCommands(program2, globalOpts) {
8304
8365
  }
8305
8366
 
8306
8367
  // src/commands/notifications.ts
8368
+ import { NotificationSchema } from "@eide/foir-proto-ts/notifications/v1/notifications_pb";
8307
8369
  function registerNotificationsCommands(program2, globalOpts) {
8308
8370
  const notifications = program2.command("notifications").description("Manage notifications");
8309
8371
  notifications.command("list").description("List notifications").option("--unread", "Only unread notifications").option("--limit <n>", "Max results", "20").action(
@@ -8318,7 +8380,7 @@ function registerNotificationsCommands(program2, globalOpts) {
8318
8380
  console.log(`Unread: ${data.unreadCount}
8319
8381
  `);
8320
8382
  }
8321
- formatList(data.notifications, opts, {
8383
+ formatListProto(NotificationSchema, data.notifications, opts, {
8322
8384
  columns: [
8323
8385
  { key: "id", header: "ID", width: 28 },
8324
8386
  { key: "type", header: "Type", width: 16 },
@@ -8367,6 +8429,7 @@ function registerNotificationsCommands(program2, globalOpts) {
8367
8429
  }
8368
8430
 
8369
8431
  // src/commands/configs.ts
8432
+ import { ConfigSchema } from "@eide/foir-proto-ts/configs/v1/configs_pb";
8370
8433
  function registerConfigsCommands(program2, globalOpts) {
8371
8434
  const configs = program2.command("configs").description("Manage configs (apps, webhooks)");
8372
8435
  configs.command("list").description("List configs").option("--type <type>", "Filter by config type").option("--enabled", "Only enabled configs").option("--limit <n>", "Max results", "50").action(
@@ -8378,7 +8441,7 @@ function registerConfigsCommands(program2, globalOpts) {
8378
8441
  enabled: cmdOpts.enabled ? true : void 0,
8379
8442
  limit: parseInt(String(cmdOpts.limit ?? "50"), 10)
8380
8443
  });
8381
- formatList(data.configs, opts, {
8444
+ formatListProto(ConfigSchema, data.configs, opts, {
8382
8445
  columns: [
8383
8446
  { key: "id", header: "ID", width: 28 },
8384
8447
  { key: "key", header: "Key", width: 20 },
@@ -8406,7 +8469,7 @@ function registerConfigsCommands(program2, globalOpts) {
8406
8469
  result = await client.configs.getConfigByKey(idOrKey);
8407
8470
  }
8408
8471
  if (!result) throw new Error(`Config "${idOrKey}" not found.`);
8409
- formatOutput(result, opts);
8472
+ formatOutputProto(ConfigSchema, result, opts);
8410
8473
  })
8411
8474
  );
8412
8475
  configs.command("create").description("Create a new config").option("-d, --data <json>", "Config data as JSON").option("-f, --file <path>", "Read data from file").action(
@@ -8415,7 +8478,7 @@ function registerConfigsCommands(program2, globalOpts) {
8415
8478
  const client = await createPlatformClient(opts);
8416
8479
  const input = await parseInputData(cmdOpts);
8417
8480
  const config2 = await client.configs.createConfig(input);
8418
- formatOutput(config2, opts);
8481
+ formatOutputProto(ConfigSchema, config2, opts);
8419
8482
  if (!(opts.json || opts.jsonl || opts.quiet))
8420
8483
  success(`Created config ${config2?.key}`);
8421
8484
  })
@@ -8437,6 +8500,10 @@ function registerConfigsCommands(program2, globalOpts) {
8437
8500
  }
8438
8501
 
8439
8502
  // src/commands/apps.ts
8503
+ import {
8504
+ AppSchema,
8505
+ ValidateManifestResponseSchema
8506
+ } from "@eide/foir-proto-ts/apps/v1/apps_service_pb";
8440
8507
  function registerAppsCommands(program2, globalOpts) {
8441
8508
  const apps = program2.command("apps").description("Install and manage apps");
8442
8509
  apps.command("list").description("List installed apps").action(
@@ -8448,7 +8515,7 @@ function registerAppsCommands(program2, globalOpts) {
8448
8515
  resolved.project.tenantId,
8449
8516
  resolved.project.id
8450
8517
  );
8451
- formatList(apps2, opts, {
8518
+ formatListProto(AppSchema, apps2, opts, {
8452
8519
  columns: [
8453
8520
  { key: "name", header: "Name", width: 24 },
8454
8521
  {
@@ -8463,9 +8530,10 @@ function registerAppsCommands(program2, globalOpts) {
8463
8530
  header: "Installed",
8464
8531
  width: 12,
8465
8532
  format: (v) => {
8466
- const ts = v;
8467
- if (!ts?.seconds) return "";
8468
- return new Date(Number(ts.seconds) * 1e3).toLocaleDateString();
8533
+ if (!v) return "";
8534
+ const date = new Date(v);
8535
+ if (Number.isNaN(date.getTime())) return "";
8536
+ return date.toLocaleDateString();
8469
8537
  }
8470
8538
  }
8471
8539
  ]
@@ -8483,7 +8551,7 @@ function registerAppsCommands(program2, globalOpts) {
8483
8551
  name
8484
8552
  );
8485
8553
  if (!app) throw new Error(`App "${name}" not installed.`);
8486
- formatOutput(app, opts);
8554
+ formatOutputProto(AppSchema, app, opts);
8487
8555
  })
8488
8556
  );
8489
8557
  apps.command("install <manifestUrl>").description("Install an app from a manifest URL").option(
@@ -8544,7 +8612,7 @@ function registerAppsCommands(program2, globalOpts) {
8544
8612
  placementFieldChoices
8545
8613
  });
8546
8614
  if (opts.json) {
8547
- formatOutput(app, opts);
8615
+ formatOutputProto(AppSchema, app, opts);
8548
8616
  } else {
8549
8617
  success(`Installed ${app?.name ?? ""}`);
8550
8618
  }
@@ -8587,7 +8655,7 @@ function registerAppsCommands(program2, globalOpts) {
8587
8655
  updateResp.newManifestHash
8588
8656
  );
8589
8657
  if (opts.json) {
8590
- formatOutput(app, opts);
8658
+ formatOutputProto(AppSchema, app, opts);
8591
8659
  } else {
8592
8660
  success(`Updated ${name}`);
8593
8661
  }
@@ -8645,7 +8713,7 @@ function registerAppsCommands(program2, globalOpts) {
8645
8713
  const client = await createPlatformClient(opts);
8646
8714
  const resp = await client.apps.validateManifestUrl(manifestUrl);
8647
8715
  if (opts.json) {
8648
- formatOutput(resp, opts);
8716
+ formatOutputProto(ValidateManifestResponseSchema, resp, opts);
8649
8717
  return;
8650
8718
  }
8651
8719
  if (resp.ok) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eide/foir-cli",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "Universal platform CLI for Foir platform",
5
5
  "type": "module",
6
6
  "publishConfig": {