@eide/foir-cli 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +560 -344
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -472,6 +472,7 @@ import { HooksService as HooksService2 } from "@eide/foir-proto-ts/hooks/v1/hook
|
|
|
472
472
|
import { NotificationsService as NotificationsService2 } from "@eide/foir-proto-ts/notifications/v1/notifications_pb";
|
|
473
473
|
import { SchedulesService as SchedulesService2 } from "@eide/foir-proto-ts/schedules/v1/schedules_pb";
|
|
474
474
|
import { AppsService as AppsService2 } from "@eide/foir-proto-ts/apps/v1/apps_service_pb";
|
|
475
|
+
import { SecretsService as SecretsService2 } from "@eide/foir-proto-ts/secrets/v1/secrets_pb";
|
|
475
476
|
|
|
476
477
|
// src/lib/rpc/identity.ts
|
|
477
478
|
import { create } from "@bufbuild/protobuf";
|
|
@@ -1447,21 +1448,12 @@ import {
|
|
|
1447
1448
|
ListScheduledPublishesRequestSchema,
|
|
1448
1449
|
ListDraftVersionsRequestSchema,
|
|
1449
1450
|
BatchPublishVersionsRequestSchema,
|
|
1450
|
-
CreatePublishBatchRequestSchema,
|
|
1451
|
-
UpdatePublishBatchRequestSchema,
|
|
1452
|
-
CancelPublishBatchRequestSchema,
|
|
1453
|
-
RollbackPublishBatchRequestSchema,
|
|
1454
|
-
RetryFailedBatchItemsRequestSchema,
|
|
1455
|
-
AddItemsToPublishBatchRequestSchema,
|
|
1456
|
-
RemoveItemsFromPublishBatchRequestSchema,
|
|
1457
|
-
ListPublishBatchesRequestSchema,
|
|
1458
|
-
GetPublishBatchRequestSchema,
|
|
1459
1451
|
GlobalSearchRequestSchema,
|
|
1460
1452
|
GetEmbeddingStatsRequestSchema,
|
|
1461
1453
|
GetRecordEmbeddingsRequestSchema,
|
|
1462
1454
|
FindSimilarRecordsRequestSchema
|
|
1463
1455
|
} from "@eide/foir-proto-ts/records/v1/records_pb";
|
|
1464
|
-
import { RecordType
|
|
1456
|
+
import { RecordType } from "@eide/foir-proto-ts/records/v1/records_pb";
|
|
1465
1457
|
function sanitizeData(obj) {
|
|
1466
1458
|
const result = {};
|
|
1467
1459
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -1770,103 +1762,6 @@ function createRecordsMethods(client) {
|
|
|
1770
1762
|
publishedCount: resp.publishedCount
|
|
1771
1763
|
};
|
|
1772
1764
|
},
|
|
1773
|
-
// ── Publish Batches ───────────────────────────────────────
|
|
1774
|
-
async createPublishBatch(params) {
|
|
1775
|
-
const resp = await client.createPublishBatch(
|
|
1776
|
-
create4(CreatePublishBatchRequestSchema, {
|
|
1777
|
-
name: params.name,
|
|
1778
|
-
versionIds: params.versionIds,
|
|
1779
|
-
scheduledAt: params.scheduledAt ? {
|
|
1780
|
-
seconds: BigInt(
|
|
1781
|
-
Math.floor(params.scheduledAt.getTime() / 1e3)
|
|
1782
|
-
),
|
|
1783
|
-
nanos: 0
|
|
1784
|
-
} : void 0
|
|
1785
|
-
})
|
|
1786
|
-
);
|
|
1787
|
-
return resp.batch ?? null;
|
|
1788
|
-
},
|
|
1789
|
-
async updatePublishBatch(params) {
|
|
1790
|
-
const resp = await client.updatePublishBatch(
|
|
1791
|
-
create4(UpdatePublishBatchRequestSchema, {
|
|
1792
|
-
batchId: params.batchId,
|
|
1793
|
-
name: params.name,
|
|
1794
|
-
scheduledAt: params.scheduledAt ? {
|
|
1795
|
-
seconds: BigInt(
|
|
1796
|
-
Math.floor(params.scheduledAt.getTime() / 1e3)
|
|
1797
|
-
),
|
|
1798
|
-
nanos: 0
|
|
1799
|
-
} : void 0
|
|
1800
|
-
})
|
|
1801
|
-
);
|
|
1802
|
-
return resp.batch ?? null;
|
|
1803
|
-
},
|
|
1804
|
-
async cancelPublishBatch(batchId) {
|
|
1805
|
-
const resp = await client.cancelPublishBatch(
|
|
1806
|
-
create4(CancelPublishBatchRequestSchema, { batchId })
|
|
1807
|
-
);
|
|
1808
|
-
return resp.batch ?? null;
|
|
1809
|
-
},
|
|
1810
|
-
async rollbackPublishBatch(batchId) {
|
|
1811
|
-
const resp = await client.rollbackPublishBatch(
|
|
1812
|
-
create4(RollbackPublishBatchRequestSchema, { batchId })
|
|
1813
|
-
);
|
|
1814
|
-
return resp.batch ?? null;
|
|
1815
|
-
},
|
|
1816
|
-
async retryFailedBatchItems(batchId) {
|
|
1817
|
-
const resp = await client.retryFailedBatchItems(
|
|
1818
|
-
create4(RetryFailedBatchItemsRequestSchema, { batchId })
|
|
1819
|
-
);
|
|
1820
|
-
return {
|
|
1821
|
-
batch: resp.batch ?? null,
|
|
1822
|
-
retriedCount: resp.retriedCount
|
|
1823
|
-
};
|
|
1824
|
-
},
|
|
1825
|
-
async addItemsToPublishBatch(batchId, versionIds) {
|
|
1826
|
-
const resp = await client.addItemsToPublishBatch(
|
|
1827
|
-
create4(AddItemsToPublishBatchRequestSchema, { batchId, versionIds })
|
|
1828
|
-
);
|
|
1829
|
-
return resp.batch ?? null;
|
|
1830
|
-
},
|
|
1831
|
-
async removeItemsFromPublishBatch(batchId, versionIds) {
|
|
1832
|
-
const resp = await client.removeItemsFromPublishBatch(
|
|
1833
|
-
create4(RemoveItemsFromPublishBatchRequestSchema, {
|
|
1834
|
-
batchId,
|
|
1835
|
-
versionIds
|
|
1836
|
-
})
|
|
1837
|
-
);
|
|
1838
|
-
return resp.batch ?? null;
|
|
1839
|
-
},
|
|
1840
|
-
async listPublishBatches(params) {
|
|
1841
|
-
const resp = await client.listPublishBatches(
|
|
1842
|
-
create4(ListPublishBatchesRequestSchema, {
|
|
1843
|
-
status: params?.status,
|
|
1844
|
-
from: params?.from ? {
|
|
1845
|
-
seconds: BigInt(Math.floor(params.from.getTime() / 1e3)),
|
|
1846
|
-
nanos: 0
|
|
1847
|
-
} : void 0,
|
|
1848
|
-
to: params?.to ? {
|
|
1849
|
-
seconds: BigInt(Math.floor(params.to.getTime() / 1e3)),
|
|
1850
|
-
nanos: 0
|
|
1851
|
-
} : void 0,
|
|
1852
|
-
limit: params?.limit ?? 50,
|
|
1853
|
-
offset: params?.offset ?? 0
|
|
1854
|
-
})
|
|
1855
|
-
);
|
|
1856
|
-
return {
|
|
1857
|
-
items: resp.batches ?? [],
|
|
1858
|
-
total: resp.total
|
|
1859
|
-
};
|
|
1860
|
-
},
|
|
1861
|
-
async getPublishBatch(batchId) {
|
|
1862
|
-
const resp = await client.getPublishBatch(
|
|
1863
|
-
create4(GetPublishBatchRequestSchema, { batchId })
|
|
1864
|
-
);
|
|
1865
|
-
return {
|
|
1866
|
-
batch: resp.batch ?? null,
|
|
1867
|
-
versions: resp.versions ?? []
|
|
1868
|
-
};
|
|
1869
|
-
},
|
|
1870
1765
|
// ── Search & Embeddings ──────────────────────────────────
|
|
1871
1766
|
async globalSearch(params) {
|
|
1872
1767
|
const resp = await client.globalSearch(
|
|
@@ -3241,6 +3136,74 @@ function createCronSchedulesMethods(client) {
|
|
|
3241
3136
|
};
|
|
3242
3137
|
}
|
|
3243
3138
|
|
|
3139
|
+
// src/lib/rpc/secrets.ts
|
|
3140
|
+
import { create as create14 } from "@bufbuild/protobuf";
|
|
3141
|
+
import {
|
|
3142
|
+
PutSecretRequestSchema,
|
|
3143
|
+
GetSecretRequestSchema,
|
|
3144
|
+
ListSecretsRequestSchema,
|
|
3145
|
+
RotateSecretRequestSchema,
|
|
3146
|
+
DeleteSecretRequestSchema,
|
|
3147
|
+
RestoreSecretRequestSchema,
|
|
3148
|
+
PurgeSoftDeletedRequestSchema,
|
|
3149
|
+
OwnerKind
|
|
3150
|
+
} from "@eide/foir-proto-ts/secrets/v1/secrets_pb";
|
|
3151
|
+
function createSecretsMethods(client) {
|
|
3152
|
+
return {
|
|
3153
|
+
async put(args) {
|
|
3154
|
+
const resp = await client.putSecret(
|
|
3155
|
+
create14(PutSecretRequestSchema, {
|
|
3156
|
+
tenantId: args.tenantId,
|
|
3157
|
+
projectId: args.projectId,
|
|
3158
|
+
ownerKind: args.ownerKind,
|
|
3159
|
+
ownerId: args.ownerId ?? "",
|
|
3160
|
+
label: args.label ?? "",
|
|
3161
|
+
plaintext: args.plaintext
|
|
3162
|
+
})
|
|
3163
|
+
);
|
|
3164
|
+
return resp.ref;
|
|
3165
|
+
},
|
|
3166
|
+
async get(ref, purpose) {
|
|
3167
|
+
return client.getSecret(
|
|
3168
|
+
create14(GetSecretRequestSchema, { ref, purpose: purpose ?? "" })
|
|
3169
|
+
);
|
|
3170
|
+
},
|
|
3171
|
+
async list(args) {
|
|
3172
|
+
const resp = await client.listSecrets(
|
|
3173
|
+
create14(ListSecretsRequestSchema, {
|
|
3174
|
+
tenantId: args.tenantId,
|
|
3175
|
+
projectId: args.projectId,
|
|
3176
|
+
ownerKind: args.ownerKind ?? OwnerKind.UNSPECIFIED,
|
|
3177
|
+
ownerId: args.ownerId ?? "",
|
|
3178
|
+
includeSoftDeleted: args.includeSoftDeleted ?? false
|
|
3179
|
+
})
|
|
3180
|
+
);
|
|
3181
|
+
return resp.secrets;
|
|
3182
|
+
},
|
|
3183
|
+
async rotate(ref, plaintext) {
|
|
3184
|
+
const resp = await client.rotateSecret(
|
|
3185
|
+
create14(RotateSecretRequestSchema, { ref, plaintext })
|
|
3186
|
+
);
|
|
3187
|
+
return resp.newRef;
|
|
3188
|
+
},
|
|
3189
|
+
async delete(ref) {
|
|
3190
|
+
await client.deleteSecret(create14(DeleteSecretRequestSchema, { ref }));
|
|
3191
|
+
},
|
|
3192
|
+
async restore(ref) {
|
|
3193
|
+
await client.restoreSecret(create14(RestoreSecretRequestSchema, { ref }));
|
|
3194
|
+
},
|
|
3195
|
+
async purge(args = {}) {
|
|
3196
|
+
const resp = await client.purgeSoftDeleted(
|
|
3197
|
+
create14(PurgeSoftDeletedRequestSchema, {
|
|
3198
|
+
tenantId: args.tenantId ?? "",
|
|
3199
|
+
projectId: args.projectId ?? ""
|
|
3200
|
+
})
|
|
3201
|
+
);
|
|
3202
|
+
return resp.purgedCount;
|
|
3203
|
+
}
|
|
3204
|
+
};
|
|
3205
|
+
}
|
|
3206
|
+
|
|
3244
3207
|
// src/lib/client.ts
|
|
3245
3208
|
async function createPlatformClient(options) {
|
|
3246
3209
|
const apiUrl = getApiUrl(options);
|
|
@@ -3300,7 +3263,8 @@ async function createPlatformClient(options) {
|
|
|
3300
3263
|
cronSchedules: createCronSchedulesMethods(
|
|
3301
3264
|
createRpcClient(SchedulesService2, transport)
|
|
3302
3265
|
),
|
|
3303
|
-
apps: createAppsMethods(createRpcClient(AppsService2, transport))
|
|
3266
|
+
apps: createAppsMethods(createRpcClient(AppsService2, transport)),
|
|
3267
|
+
secrets: createSecretsMethods(createRpcClient(SecretsService2, transport))
|
|
3304
3268
|
};
|
|
3305
3269
|
}
|
|
3306
3270
|
function createPlatformClientWithHeaders(apiUrl, headers) {
|
|
@@ -3336,7 +3300,8 @@ function createPlatformClientWithHeaders(apiUrl, headers) {
|
|
|
3336
3300
|
cronSchedules: createCronSchedulesMethods(
|
|
3337
3301
|
createRpcClient(SchedulesService2, transport)
|
|
3338
3302
|
),
|
|
3339
|
-
apps: createAppsMethods(createRpcClient(AppsService2, transport))
|
|
3303
|
+
apps: createAppsMethods(createRpcClient(AppsService2, transport)),
|
|
3304
|
+
secrets: createSecretsMethods(createRpcClient(SecretsService2, transport))
|
|
3340
3305
|
};
|
|
3341
3306
|
}
|
|
3342
3307
|
async function getStorageAuth(options) {
|
|
@@ -3540,17 +3505,39 @@ async function provisionApiKey(client) {
|
|
|
3540
3505
|
|
|
3541
3506
|
// src/lib/output.ts
|
|
3542
3507
|
import chalk2 from "chalk";
|
|
3508
|
+
import {
|
|
3509
|
+
toJson
|
|
3510
|
+
} from "@bufbuild/protobuf";
|
|
3511
|
+
function bigintReplacer(_key, value) {
|
|
3512
|
+
return typeof value === "bigint" ? value.toString() : value;
|
|
3513
|
+
}
|
|
3514
|
+
function safeStringify(value, indent) {
|
|
3515
|
+
return JSON.stringify(value, bigintReplacer, indent);
|
|
3516
|
+
}
|
|
3543
3517
|
function formatOutput(data, options) {
|
|
3544
3518
|
if (options?.quiet) return;
|
|
3545
3519
|
if (options?.json) {
|
|
3546
|
-
console.log(
|
|
3520
|
+
console.log(safeStringify(data, 2));
|
|
3547
3521
|
return;
|
|
3548
3522
|
}
|
|
3549
3523
|
if (options?.jsonl) {
|
|
3550
|
-
console.log(
|
|
3524
|
+
console.log(safeStringify(data));
|
|
3525
|
+
return;
|
|
3526
|
+
}
|
|
3527
|
+
console.log(safeStringify(data, 2));
|
|
3528
|
+
}
|
|
3529
|
+
function formatOutputProto(schema, message, options) {
|
|
3530
|
+
if (message == null) {
|
|
3531
|
+
formatOutput(null, options);
|
|
3551
3532
|
return;
|
|
3552
3533
|
}
|
|
3553
|
-
|
|
3534
|
+
formatOutput(toJson(schema, message), options);
|
|
3535
|
+
}
|
|
3536
|
+
function formatListProto(schema, items, options, config2) {
|
|
3537
|
+
const converted = items.map(
|
|
3538
|
+
(item) => toJson(schema, item)
|
|
3539
|
+
);
|
|
3540
|
+
formatList(converted, options, config2);
|
|
3554
3541
|
}
|
|
3555
3542
|
function formatList(items, options, config2) {
|
|
3556
3543
|
if (options?.quiet) {
|
|
@@ -3560,12 +3547,12 @@ function formatList(items, options, config2) {
|
|
|
3560
3547
|
return;
|
|
3561
3548
|
}
|
|
3562
3549
|
if (options?.json) {
|
|
3563
|
-
console.log(
|
|
3550
|
+
console.log(safeStringify(items, 2));
|
|
3564
3551
|
return;
|
|
3565
3552
|
}
|
|
3566
3553
|
if (options?.jsonl) {
|
|
3567
3554
|
for (const item of items) {
|
|
3568
|
-
console.log(
|
|
3555
|
+
console.log(safeStringify(item));
|
|
3569
3556
|
}
|
|
3570
3557
|
return;
|
|
3571
3558
|
}
|
|
@@ -3703,7 +3690,11 @@ import { basename } from "path";
|
|
|
3703
3690
|
import chalk3 from "chalk";
|
|
3704
3691
|
import { createClient } from "@connectrpc/connect";
|
|
3705
3692
|
import { createConnectTransport as createConnectTransport2 } from "@connectrpc/connect-node";
|
|
3706
|
-
import {
|
|
3693
|
+
import {
|
|
3694
|
+
StorageService as StorageService3,
|
|
3695
|
+
FileSchema,
|
|
3696
|
+
StorageUsageSchema
|
|
3697
|
+
} from "@eide/foir-proto-ts/storage/v1/storage_pb";
|
|
3707
3698
|
|
|
3708
3699
|
// src/lib/input.ts
|
|
3709
3700
|
import inquirer2 from "inquirer";
|
|
@@ -3876,7 +3867,7 @@ function registerMediaCommands(program2, globalOpts) {
|
|
|
3876
3867
|
}
|
|
3877
3868
|
const file = await storage.confirmFileUpload(upload.uploadId);
|
|
3878
3869
|
if (opts.json || opts.jsonl) {
|
|
3879
|
-
|
|
3870
|
+
formatOutputProto(FileSchema, file, opts);
|
|
3880
3871
|
} else {
|
|
3881
3872
|
success(`Uploaded ${filename}`);
|
|
3882
3873
|
if (file?.url) {
|
|
@@ -3904,7 +3895,7 @@ function registerMediaCommands(program2, globalOpts) {
|
|
|
3904
3895
|
limit: Number(flags.limit) || 50,
|
|
3905
3896
|
offset: Number(flags.offset) || 0
|
|
3906
3897
|
});
|
|
3907
|
-
|
|
3898
|
+
formatListProto(FileSchema, result.items, opts, {
|
|
3908
3899
|
columns: [
|
|
3909
3900
|
{ key: "id", header: "ID", width: 28 },
|
|
3910
3901
|
{ key: "filename", header: "Filename", width: 24 },
|
|
@@ -3939,7 +3930,7 @@ function registerMediaCommands(program2, globalOpts) {
|
|
|
3939
3930
|
const { getToken } = await getStorageAuth(opts);
|
|
3940
3931
|
const storage = createStorageRpcClient(getToken);
|
|
3941
3932
|
const file = await storage.getFile(id);
|
|
3942
|
-
|
|
3933
|
+
formatOutputProto(FileSchema, file, opts);
|
|
3943
3934
|
})
|
|
3944
3935
|
);
|
|
3945
3936
|
media.command("usage").description("Get storage usage").action(
|
|
@@ -3949,7 +3940,7 @@ function registerMediaCommands(program2, globalOpts) {
|
|
|
3949
3940
|
const storage = createStorageRpcClient(getToken);
|
|
3950
3941
|
const usage = await storage.getStorageUsage();
|
|
3951
3942
|
if (opts.json || opts.jsonl) {
|
|
3952
|
-
|
|
3943
|
+
formatOutputProto(StorageUsageSchema, usage, opts);
|
|
3953
3944
|
} else {
|
|
3954
3945
|
const mb = (Number(usage?.totalBytes ?? 0) / (1024 * 1024)).toFixed(
|
|
3955
3946
|
1
|
|
@@ -3973,7 +3964,7 @@ function registerMediaCommands(program2, globalOpts) {
|
|
|
3973
3964
|
tags: flags.tags?.split(",").map((t) => t.trim())
|
|
3974
3965
|
});
|
|
3975
3966
|
if (opts.json || opts.jsonl) {
|
|
3976
|
-
|
|
3967
|
+
formatOutputProto(FileSchema, file, opts);
|
|
3977
3968
|
} else {
|
|
3978
3969
|
success("Updated file");
|
|
3979
3970
|
}
|
|
@@ -3994,7 +3985,7 @@ function registerMediaCommands(program2, globalOpts) {
|
|
|
3994
3985
|
description: flags.description
|
|
3995
3986
|
});
|
|
3996
3987
|
if (opts.json || opts.jsonl) {
|
|
3997
|
-
|
|
3988
|
+
formatOutputProto(FileSchema, file, opts);
|
|
3998
3989
|
} else {
|
|
3999
3990
|
success("Updated file metadata");
|
|
4000
3991
|
}
|
|
@@ -4032,7 +4023,7 @@ function registerMediaCommands(program2, globalOpts) {
|
|
|
4032
4023
|
const storage = createStorageRpcClient(getToken);
|
|
4033
4024
|
const file = await storage.restoreFile(id);
|
|
4034
4025
|
if (opts.json || opts.jsonl) {
|
|
4035
|
-
|
|
4026
|
+
formatOutputProto(FileSchema, file, opts);
|
|
4036
4027
|
} else {
|
|
4037
4028
|
success("Restored file");
|
|
4038
4029
|
}
|
|
@@ -4592,6 +4583,8 @@ function registerCreateConfigCommand(program2, globalOpts) {
|
|
|
4592
4583
|
}
|
|
4593
4584
|
|
|
4594
4585
|
// src/commands/search.ts
|
|
4586
|
+
import { toJson as toJson2 } from "@bufbuild/protobuf";
|
|
4587
|
+
import { SearchResultItemSchema } from "@eide/foir-proto-ts/records/v1/records_pb";
|
|
4595
4588
|
function registerSearchCommands(program2, globalOpts) {
|
|
4596
4589
|
program2.command("search <query>").description("Search across all records").option(
|
|
4597
4590
|
"--models <keys>",
|
|
@@ -4609,7 +4602,15 @@ function registerSearchCommands(program2, globalOpts) {
|
|
|
4609
4602
|
modelKeys
|
|
4610
4603
|
});
|
|
4611
4604
|
if (opts.json || opts.jsonl) {
|
|
4612
|
-
formatOutput(
|
|
4605
|
+
formatOutput(
|
|
4606
|
+
{
|
|
4607
|
+
items: result.items.map(
|
|
4608
|
+
(item) => toJson2(SearchResultItemSchema, item)
|
|
4609
|
+
),
|
|
4610
|
+
total: result.total
|
|
4611
|
+
},
|
|
4612
|
+
opts
|
|
4613
|
+
);
|
|
4613
4614
|
return;
|
|
4614
4615
|
}
|
|
4615
4616
|
if (result.items.length > 0) {
|
|
@@ -6267,6 +6268,7 @@ function registerProfilesCommand(program2, globalOpts) {
|
|
|
6267
6268
|
}
|
|
6268
6269
|
|
|
6269
6270
|
// src/commands/context.ts
|
|
6271
|
+
import { TenantSchema } from "@eide/foir-proto-ts/identity/v1/identity_pb";
|
|
6270
6272
|
function registerContextCommands(program2, globalOpts) {
|
|
6271
6273
|
const context = program2.command("context").description("Manage project and tenant context");
|
|
6272
6274
|
context.command("projects").description("List available projects").action(
|
|
@@ -6331,7 +6333,8 @@ function registerContextCommands(program2, globalOpts) {
|
|
|
6331
6333
|
const sessionContext = await client.identity.getSessionContext();
|
|
6332
6334
|
if (!sessionContext)
|
|
6333
6335
|
throw new Error("Could not retrieve session context.");
|
|
6334
|
-
|
|
6336
|
+
formatListProto(
|
|
6337
|
+
TenantSchema,
|
|
6335
6338
|
sessionContext.availableTenants ?? [],
|
|
6336
6339
|
opts,
|
|
6337
6340
|
{
|
|
@@ -6346,6 +6349,10 @@ function registerContextCommands(program2, globalOpts) {
|
|
|
6346
6349
|
}
|
|
6347
6350
|
|
|
6348
6351
|
// src/commands/models.ts
|
|
6352
|
+
import {
|
|
6353
|
+
ModelSchema,
|
|
6354
|
+
ModelVersionSchema
|
|
6355
|
+
} from "@eide/foir-proto-ts/models/v1/models_pb";
|
|
6349
6356
|
function registerModelsCommands(program2, globalOpts) {
|
|
6350
6357
|
const models = program2.command("models").description("Manage models");
|
|
6351
6358
|
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 +6365,20 @@ function registerModelsCommands(program2, globalOpts) {
|
|
|
6358
6365
|
limit: parseInt(cmdOpts.limit ?? "50", 10),
|
|
6359
6366
|
offset: parseInt(cmdOpts.offset ?? "0", 10)
|
|
6360
6367
|
});
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
],
|
|
6376
|
-
total: result.total
|
|
6377
|
-
}
|
|
6378
|
-
);
|
|
6368
|
+
formatListProto(ModelSchema, result.items, opts, {
|
|
6369
|
+
columns: [
|
|
6370
|
+
{ key: "key", header: "Key", width: 24 },
|
|
6371
|
+
{ key: "name", header: "Name", width: 24 },
|
|
6372
|
+
{ key: "category", header: "Category", width: 14 },
|
|
6373
|
+
{
|
|
6374
|
+
key: "updatedAt",
|
|
6375
|
+
header: "Updated",
|
|
6376
|
+
width: 12,
|
|
6377
|
+
format: (v) => timeAgo(v)
|
|
6378
|
+
}
|
|
6379
|
+
],
|
|
6380
|
+
total: result.total
|
|
6381
|
+
});
|
|
6379
6382
|
})
|
|
6380
6383
|
);
|
|
6381
6384
|
models.command("get <key>").description("Get a model by key").action(
|
|
@@ -6386,7 +6389,7 @@ function registerModelsCommands(program2, globalOpts) {
|
|
|
6386
6389
|
if (!model) {
|
|
6387
6390
|
throw new Error(`Model "${key}" not found.`);
|
|
6388
6391
|
}
|
|
6389
|
-
|
|
6392
|
+
formatOutputProto(ModelSchema, model, opts);
|
|
6390
6393
|
})
|
|
6391
6394
|
);
|
|
6392
6395
|
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 +6398,7 @@ function registerModelsCommands(program2, globalOpts) {
|
|
|
6395
6398
|
const client = await createPlatformClient(opts);
|
|
6396
6399
|
const inputData = await parseInputData(cmdOpts);
|
|
6397
6400
|
const model = await client.models.createModel(inputData);
|
|
6398
|
-
|
|
6401
|
+
formatOutputProto(ModelSchema, model, opts);
|
|
6399
6402
|
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
6400
6403
|
success(`Created model ${model?.key}`);
|
|
6401
6404
|
}
|
|
@@ -6416,7 +6419,7 @@ function registerModelsCommands(program2, globalOpts) {
|
|
|
6416
6419
|
id: existing.id,
|
|
6417
6420
|
...inputData
|
|
6418
6421
|
});
|
|
6419
|
-
|
|
6422
|
+
formatOutputProto(ModelSchema, model, opts);
|
|
6420
6423
|
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
6421
6424
|
success(`Updated model ${key}`);
|
|
6422
6425
|
}
|
|
@@ -6462,30 +6465,28 @@ function registerModelsCommands(program2, globalOpts) {
|
|
|
6462
6465
|
const result = await client.models.listModelVersions(existing.id, {
|
|
6463
6466
|
limit: parseInt(cmdOpts.limit ?? "20", 10)
|
|
6464
6467
|
});
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
{ key: "createdBy", header: "By", width: 18 }
|
|
6480
|
-
]
|
|
6481
|
-
}
|
|
6482
|
-
);
|
|
6468
|
+
formatListProto(ModelVersionSchema, result.items, opts, {
|
|
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
|
+
});
|
|
6483
6482
|
}
|
|
6484
6483
|
)
|
|
6485
6484
|
);
|
|
6486
6485
|
}
|
|
6487
6486
|
|
|
6488
6487
|
// src/commands/records.ts
|
|
6488
|
+
import { toJson as toJson3 } from "@bufbuild/protobuf";
|
|
6489
|
+
import { RecordSchema } from "@eide/foir-proto-ts/records/v1/records_pb";
|
|
6489
6490
|
function registerRecordsCommands(program2, globalOpts) {
|
|
6490
6491
|
const records = program2.command("records").description("Manage records");
|
|
6491
6492
|
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 +6502,20 @@ function registerRecordsCommands(program2, globalOpts) {
|
|
|
6501
6502
|
};
|
|
6502
6503
|
if (cmdOpts.filter) params.filters = parseFilters(cmdOpts.filter);
|
|
6503
6504
|
const result = await client.records.listRecords(params);
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
],
|
|
6519
|
-
total: result.total
|
|
6520
|
-
}
|
|
6521
|
-
);
|
|
6505
|
+
formatListProto(RecordSchema, result.items, opts, {
|
|
6506
|
+
columns: [
|
|
6507
|
+
{ key: "id", header: "ID", width: 28 },
|
|
6508
|
+
{ key: "naturalKey", header: "Key", width: 24 },
|
|
6509
|
+
{ key: "versionNumber", header: "Version", width: 8 },
|
|
6510
|
+
{
|
|
6511
|
+
key: "updatedAt",
|
|
6512
|
+
header: "Updated",
|
|
6513
|
+
width: 12,
|
|
6514
|
+
format: (v) => timeAgo(v)
|
|
6515
|
+
}
|
|
6516
|
+
],
|
|
6517
|
+
total: result.total
|
|
6518
|
+
});
|
|
6522
6519
|
}
|
|
6523
6520
|
)
|
|
6524
6521
|
);
|
|
@@ -6528,23 +6525,13 @@ function registerRecordsCommands(program2, globalOpts) {
|
|
|
6528
6525
|
async (modelKey, idOrKey, _cmdOpts) => {
|
|
6529
6526
|
const opts = globalOpts();
|
|
6530
6527
|
const client = await createPlatformClient(opts);
|
|
6531
|
-
|
|
6532
|
-
if (
|
|
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) {
|
|
6528
|
+
const record = isUUID(idOrKey) ? await client.records.getRecord(idOrKey) : await client.records.getRecordByKey(modelKey, idOrKey);
|
|
6529
|
+
if (!record) {
|
|
6543
6530
|
throw new Error(
|
|
6544
6531
|
`Record "${idOrKey}" not found in model "${modelKey}".`
|
|
6545
6532
|
);
|
|
6546
6533
|
}
|
|
6547
|
-
|
|
6534
|
+
formatOutputProto(RecordSchema, record, opts);
|
|
6548
6535
|
}
|
|
6549
6536
|
)
|
|
6550
6537
|
);
|
|
@@ -6557,7 +6544,14 @@ function registerRecordsCommands(program2, globalOpts) {
|
|
|
6557
6544
|
const inputData = await parseInputData(cmdOpts);
|
|
6558
6545
|
const input = { modelKey, ...inputData };
|
|
6559
6546
|
const result = await client.records.createRecord(input);
|
|
6560
|
-
formatOutput(
|
|
6547
|
+
formatOutput(
|
|
6548
|
+
{
|
|
6549
|
+
record: result.record ? toJson3(RecordSchema, result.record) : null,
|
|
6550
|
+
variant: result.variant ? toJson3(RecordSchema, result.variant) : null,
|
|
6551
|
+
version: result.version ? toJson3(RecordSchema, result.version) : null
|
|
6552
|
+
},
|
|
6553
|
+
opts
|
|
6554
|
+
);
|
|
6561
6555
|
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
6562
6556
|
success(`Created record ${result.record?.id}`);
|
|
6563
6557
|
}
|
|
@@ -6573,7 +6567,7 @@ function registerRecordsCommands(program2, globalOpts) {
|
|
|
6573
6567
|
const inputData = await parseInputData(cmdOpts);
|
|
6574
6568
|
const input = { id, ...inputData };
|
|
6575
6569
|
const record = await client.records.updateRecord(input);
|
|
6576
|
-
|
|
6570
|
+
formatOutputProto(RecordSchema, record, opts);
|
|
6577
6571
|
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
6578
6572
|
success(`Updated record ${id}`);
|
|
6579
6573
|
}
|
|
@@ -6634,7 +6628,7 @@ function registerRecordsCommands(program2, globalOpts) {
|
|
|
6634
6628
|
const client = await createPlatformClient(opts);
|
|
6635
6629
|
const naturalKey = cmdOpts.naturalKey ?? `${id}-copy`;
|
|
6636
6630
|
const record = await client.records.duplicateRecord(id, naturalKey);
|
|
6637
|
-
|
|
6631
|
+
formatOutputProto(RecordSchema, record, opts);
|
|
6638
6632
|
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
6639
6633
|
success(`Duplicated \u2192 ${record?.id}`);
|
|
6640
6634
|
}
|
|
@@ -6650,39 +6644,11 @@ function registerRecordsCommands(program2, globalOpts) {
|
|
|
6650
6644
|
const result = await client.records.listRecordVersions(parentId, {
|
|
6651
6645
|
limit: parseInt(cmdOpts.limit ?? "20", 10)
|
|
6652
6646
|
});
|
|
6653
|
-
|
|
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
|
-
{
|
|
6647
|
+
formatListProto(RecordSchema, result.items, opts, {
|
|
6682
6648
|
columns: [
|
|
6683
|
-
{ key: "id", header: "
|
|
6684
|
-
{ key: "
|
|
6685
|
-
{ key: "
|
|
6649
|
+
{ key: "id", header: "Version ID", width: 28 },
|
|
6650
|
+
{ key: "versionNumber", header: "#", width: 5 },
|
|
6651
|
+
{ key: "changeDescription", header: "Description", width: 30 },
|
|
6686
6652
|
{
|
|
6687
6653
|
key: "createdAt",
|
|
6688
6654
|
header: "Created",
|
|
@@ -6690,8 +6656,28 @@ function registerRecordsCommands(program2, globalOpts) {
|
|
|
6690
6656
|
format: (v) => timeAgo(v)
|
|
6691
6657
|
}
|
|
6692
6658
|
]
|
|
6693
|
-
}
|
|
6694
|
-
|
|
6659
|
+
});
|
|
6660
|
+
}
|
|
6661
|
+
)
|
|
6662
|
+
);
|
|
6663
|
+
records.command("variants <recordId>").description("List variants for a record").action(
|
|
6664
|
+
withErrorHandler(globalOpts, async (recordId) => {
|
|
6665
|
+
const opts = globalOpts();
|
|
6666
|
+
const client = await createPlatformClient(opts);
|
|
6667
|
+
const result = await client.records.listRecordVariants(recordId);
|
|
6668
|
+
formatListProto(RecordSchema, result.items, opts, {
|
|
6669
|
+
columns: [
|
|
6670
|
+
{ key: "id", header: "Variant ID", width: 28 },
|
|
6671
|
+
{ key: "variantKey", header: "Key", width: 20 },
|
|
6672
|
+
{ key: "isDefault", header: "Default", width: 8 },
|
|
6673
|
+
{
|
|
6674
|
+
key: "createdAt",
|
|
6675
|
+
header: "Created",
|
|
6676
|
+
width: 12,
|
|
6677
|
+
format: (v) => timeAgo(v)
|
|
6678
|
+
}
|
|
6679
|
+
]
|
|
6680
|
+
});
|
|
6695
6681
|
})
|
|
6696
6682
|
);
|
|
6697
6683
|
records.command("create-version <parentId>").description(
|
|
@@ -6708,7 +6694,7 @@ function registerRecordsCommands(program2, globalOpts) {
|
|
|
6708
6694
|
inputData,
|
|
6709
6695
|
cmdOpts.message
|
|
6710
6696
|
);
|
|
6711
|
-
|
|
6697
|
+
formatOutputProto(RecordSchema, version2, opts);
|
|
6712
6698
|
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
6713
6699
|
success(`Created version ${version2?.id}`);
|
|
6714
6700
|
}
|
|
@@ -6725,7 +6711,7 @@ function registerRecordsCommands(program2, globalOpts) {
|
|
|
6725
6711
|
recordId,
|
|
6726
6712
|
cmdOpts.key
|
|
6727
6713
|
);
|
|
6728
|
-
|
|
6714
|
+
formatOutputProto(RecordSchema, variant, opts);
|
|
6729
6715
|
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
6730
6716
|
success(`Created variant ${variant?.id}`);
|
|
6731
6717
|
}
|
|
@@ -6735,6 +6721,7 @@ function registerRecordsCommands(program2, globalOpts) {
|
|
|
6735
6721
|
}
|
|
6736
6722
|
|
|
6737
6723
|
// src/commands/customers.ts
|
|
6724
|
+
import { CustomerSchema } from "@eide/foir-proto-ts/identity/v1/identity_pb";
|
|
6738
6725
|
var statusMap = {
|
|
6739
6726
|
ACTIVE: CustomerStatus.ACTIVE,
|
|
6740
6727
|
PENDING: CustomerStatus.PENDING,
|
|
@@ -6755,52 +6742,47 @@ function registerCustomersCommands(program2, globalOpts) {
|
|
|
6755
6742
|
limit: parseInt(cmdOpts.limit ?? "20", 10),
|
|
6756
6743
|
offset: parseInt(cmdOpts.offset ?? "0", 10)
|
|
6757
6744
|
});
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
],
|
|
6779
|
-
total: result.total
|
|
6780
|
-
}
|
|
6781
|
-
);
|
|
6745
|
+
formatListProto(CustomerSchema, result.items, opts, {
|
|
6746
|
+
columns: [
|
|
6747
|
+
{ key: "id", header: "ID", width: 28 },
|
|
6748
|
+
{ key: "email", header: "Email", width: 30 },
|
|
6749
|
+
{ key: "status", header: "Status", width: 12 },
|
|
6750
|
+
{
|
|
6751
|
+
key: "lastLoginAt",
|
|
6752
|
+
header: "Last Login",
|
|
6753
|
+
width: 12,
|
|
6754
|
+
format: (v) => timeAgo(v)
|
|
6755
|
+
},
|
|
6756
|
+
{
|
|
6757
|
+
key: "createdAt",
|
|
6758
|
+
header: "Created",
|
|
6759
|
+
width: 12,
|
|
6760
|
+
format: (v) => timeAgo(v)
|
|
6761
|
+
}
|
|
6762
|
+
],
|
|
6763
|
+
total: result.total
|
|
6764
|
+
});
|
|
6782
6765
|
})
|
|
6783
6766
|
);
|
|
6784
6767
|
customers.command("get <idOrEmail>").description("Get a customer by ID or email").action(
|
|
6785
6768
|
withErrorHandler(globalOpts, async (idOrEmail) => {
|
|
6786
6769
|
const opts = globalOpts();
|
|
6787
6770
|
const client = await createPlatformClient(opts);
|
|
6788
|
-
let
|
|
6771
|
+
let customer;
|
|
6789
6772
|
if (idOrEmail.includes("@")) {
|
|
6790
6773
|
const list = await client.identity.listCustomers({
|
|
6791
6774
|
search: idOrEmail,
|
|
6792
6775
|
limit: 1
|
|
6793
6776
|
});
|
|
6794
|
-
|
|
6795
|
-
result = match ? match : null;
|
|
6777
|
+
customer = list.items[0] ?? null;
|
|
6796
6778
|
} else {
|
|
6797
6779
|
const resp = await client.identity.getCustomer(idOrEmail);
|
|
6798
|
-
|
|
6780
|
+
customer = resp.customer ?? null;
|
|
6799
6781
|
}
|
|
6800
|
-
if (!
|
|
6782
|
+
if (!customer) {
|
|
6801
6783
|
throw new Error(`Customer "${idOrEmail}" not found.`);
|
|
6802
6784
|
}
|
|
6803
|
-
|
|
6785
|
+
formatOutputProto(CustomerSchema, customer, opts);
|
|
6804
6786
|
})
|
|
6805
6787
|
);
|
|
6806
6788
|
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 +6806,8 @@ function registerCustomersCommands(program2, globalOpts) {
|
|
|
6824
6806
|
throw new Error("--email is required.");
|
|
6825
6807
|
}
|
|
6826
6808
|
const resp = await client.identity.createCustomer(input);
|
|
6827
|
-
const customer = resp.customer;
|
|
6828
|
-
|
|
6829
|
-
customer,
|
|
6830
|
-
opts
|
|
6831
|
-
);
|
|
6809
|
+
const customer = resp.customer ?? null;
|
|
6810
|
+
formatOutputProto(CustomerSchema, customer, opts);
|
|
6832
6811
|
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
6833
6812
|
success(`Created customer ${customer?.email}`);
|
|
6834
6813
|
}
|
|
@@ -6860,6 +6839,7 @@ function registerCustomersCommands(program2, globalOpts) {
|
|
|
6860
6839
|
}
|
|
6861
6840
|
|
|
6862
6841
|
// src/commands/customer-profiles.ts
|
|
6842
|
+
import { CustomerProfileSchemaSchema } from "@eide/foir-proto-ts/settings/v1/settings_pb";
|
|
6863
6843
|
function registerCustomerProfilesCommands(program2, globalOpts) {
|
|
6864
6844
|
const cp = program2.command("customer-profiles").alias("cp").description("Manage customer profile schema and profiles");
|
|
6865
6845
|
const schema = cp.command("schema").description("Manage the customer profile schema");
|
|
@@ -6878,7 +6858,7 @@ function registerCustomerProfilesCommands(program2, globalOpts) {
|
|
|
6878
6858
|
}
|
|
6879
6859
|
return;
|
|
6880
6860
|
}
|
|
6881
|
-
|
|
6861
|
+
formatOutputProto(CustomerProfileSchemaSchema, result, opts);
|
|
6882
6862
|
})
|
|
6883
6863
|
);
|
|
6884
6864
|
schema.command("update").description(
|
|
@@ -6897,7 +6877,7 @@ function registerCustomerProfilesCommands(program2, globalOpts) {
|
|
|
6897
6877
|
fields: inputData.fields,
|
|
6898
6878
|
publicFields: inputData.publicFields ?? []
|
|
6899
6879
|
});
|
|
6900
|
-
|
|
6880
|
+
formatOutputProto(CustomerProfileSchemaSchema, result, opts);
|
|
6901
6881
|
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
6902
6882
|
const version2 = result?.version;
|
|
6903
6883
|
success(`Updated customer profile schema (version ${version2})`);
|
|
@@ -6938,6 +6918,11 @@ function registerCustomerProfilesCommands(program2, globalOpts) {
|
|
|
6938
6918
|
}
|
|
6939
6919
|
|
|
6940
6920
|
// src/commands/operations.ts
|
|
6921
|
+
import {
|
|
6922
|
+
OperationSchema,
|
|
6923
|
+
OperationExecutionSchema,
|
|
6924
|
+
DeadLetterEntrySchema
|
|
6925
|
+
} from "@eide/foir-proto-ts/operations/v1/operations_pb";
|
|
6941
6926
|
function registerOperationsCommands(program2, globalOpts) {
|
|
6942
6927
|
const operations = program2.command("operations").description("Manage operations");
|
|
6943
6928
|
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 +6934,7 @@ function registerOperationsCommands(program2, globalOpts) {
|
|
|
6949
6934
|
isActive: cmdOpts.active ? true : void 0,
|
|
6950
6935
|
limit: parseInt(String(cmdOpts.limit ?? "50"), 10)
|
|
6951
6936
|
});
|
|
6952
|
-
|
|
6937
|
+
formatListProto(OperationSchema, data.operations, opts, {
|
|
6953
6938
|
columns: [
|
|
6954
6939
|
{ key: "key", header: "Key", width: 24 },
|
|
6955
6940
|
{ key: "name", header: "Name", width: 24 },
|
|
@@ -6976,7 +6961,7 @@ function registerOperationsCommands(program2, globalOpts) {
|
|
|
6976
6961
|
const client = await createPlatformClient(opts);
|
|
6977
6962
|
const result = await client.operations.getOperation({ key });
|
|
6978
6963
|
if (!result) throw new Error(`Operation "${key}" not found.`);
|
|
6979
|
-
|
|
6964
|
+
formatOutputProto(OperationSchema, result, opts);
|
|
6980
6965
|
})
|
|
6981
6966
|
);
|
|
6982
6967
|
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 +6978,17 @@ function registerOperationsCommands(program2, globalOpts) {
|
|
|
6993
6978
|
operationKey: key,
|
|
6994
6979
|
input: inputData
|
|
6995
6980
|
});
|
|
6996
|
-
|
|
6981
|
+
if (result.execution) {
|
|
6982
|
+
formatOutputProto(OperationExecutionSchema, result.execution, opts);
|
|
6983
|
+
} else {
|
|
6984
|
+
formatOutput(
|
|
6985
|
+
{
|
|
6986
|
+
completed: result.completed,
|
|
6987
|
+
errorMessage: result.errorMessage ?? null
|
|
6988
|
+
},
|
|
6989
|
+
opts
|
|
6990
|
+
);
|
|
6991
|
+
}
|
|
6997
6992
|
if (!(opts.json || opts.jsonl || opts.quiet)) {
|
|
6998
6993
|
if (result.completed) {
|
|
6999
6994
|
success(`Operation completed in ${result.execution?.durationMs ?? 0}ms`);
|
|
@@ -7012,7 +7007,7 @@ function registerOperationsCommands(program2, globalOpts) {
|
|
|
7012
7007
|
operationKey: cmdOpts.operation,
|
|
7013
7008
|
limit: parseInt(cmdOpts.limit ?? "20", 10)
|
|
7014
7009
|
});
|
|
7015
|
-
|
|
7010
|
+
formatListProto(DeadLetterEntrySchema, data.entries, opts, {
|
|
7016
7011
|
columns: [
|
|
7017
7012
|
{ key: "id", header: "ID", width: 28 },
|
|
7018
7013
|
{ key: "operationKey", header: "Operation", width: 20 },
|
|
@@ -7059,6 +7054,11 @@ function registerOperationsCommands(program2, globalOpts) {
|
|
|
7059
7054
|
}
|
|
7060
7055
|
|
|
7061
7056
|
// src/commands/segments.ts
|
|
7057
|
+
import {
|
|
7058
|
+
SegmentSchema,
|
|
7059
|
+
SegmentPreviewSchema,
|
|
7060
|
+
SegmentEvaluationResultSchema
|
|
7061
|
+
} from "@eide/foir-proto-ts/segments/v1/segments_pb";
|
|
7062
7062
|
function registerSegmentsCommands(program2, globalOpts) {
|
|
7063
7063
|
const segments = program2.command("segments").description("Manage segments");
|
|
7064
7064
|
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 +7070,7 @@ function registerSegmentsCommands(program2, globalOpts) {
|
|
|
7070
7070
|
limit: parseInt(String(cmdOpts.limit ?? "50"), 10),
|
|
7071
7071
|
offset: parseInt(String(cmdOpts.offset ?? "0"), 10)
|
|
7072
7072
|
});
|
|
7073
|
-
|
|
7073
|
+
formatListProto(SegmentSchema, data.segments, opts, {
|
|
7074
7074
|
columns: [
|
|
7075
7075
|
{ key: "id", header: "ID", width: 28 },
|
|
7076
7076
|
{ key: "key", header: "Key", width: 20 },
|
|
@@ -7103,7 +7103,7 @@ function registerSegmentsCommands(program2, globalOpts) {
|
|
|
7103
7103
|
result = await client.segments.getSegmentByKey(idOrKey);
|
|
7104
7104
|
}
|
|
7105
7105
|
if (!result) throw new Error(`Segment "${idOrKey}" not found.`);
|
|
7106
|
-
|
|
7106
|
+
formatOutputProto(SegmentSchema, result, opts);
|
|
7107
7107
|
})
|
|
7108
7108
|
);
|
|
7109
7109
|
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 +7114,7 @@ function registerSegmentsCommands(program2, globalOpts) {
|
|
|
7114
7114
|
const result = await client.segments.createSegment(
|
|
7115
7115
|
input
|
|
7116
7116
|
);
|
|
7117
|
-
|
|
7117
|
+
formatOutputProto(SegmentSchema, result, opts);
|
|
7118
7118
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7119
7119
|
success(`Created segment ${result?.key}`);
|
|
7120
7120
|
})
|
|
@@ -7130,7 +7130,7 @@ function registerSegmentsCommands(program2, globalOpts) {
|
|
|
7130
7130
|
id,
|
|
7131
7131
|
...input
|
|
7132
7132
|
});
|
|
7133
|
-
|
|
7133
|
+
formatOutputProto(SegmentSchema, result, opts);
|
|
7134
7134
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7135
7135
|
success(`Updated segment ${id}`);
|
|
7136
7136
|
}
|
|
@@ -7166,7 +7166,7 @@ function registerSegmentsCommands(program2, globalOpts) {
|
|
|
7166
7166
|
rules,
|
|
7167
7167
|
parseInt(cmdOpts.sampleSize ?? "100", 10)
|
|
7168
7168
|
);
|
|
7169
|
-
|
|
7169
|
+
formatOutputProto(SegmentPreviewSchema, result, opts);
|
|
7170
7170
|
})
|
|
7171
7171
|
);
|
|
7172
7172
|
segments.command("test <segmentId> <customerId>").description("Test whether a customer matches a segment").action(
|
|
@@ -7179,13 +7179,17 @@ function registerSegmentsCommands(program2, globalOpts) {
|
|
|
7179
7179
|
segmentId,
|
|
7180
7180
|
customerId
|
|
7181
7181
|
);
|
|
7182
|
-
|
|
7182
|
+
formatOutputProto(SegmentEvaluationResultSchema, result, opts);
|
|
7183
7183
|
}
|
|
7184
7184
|
)
|
|
7185
7185
|
);
|
|
7186
7186
|
}
|
|
7187
7187
|
|
|
7188
7188
|
// src/commands/experiments.ts
|
|
7189
|
+
import {
|
|
7190
|
+
ExperimentSchema,
|
|
7191
|
+
ExperimentStatsSchema
|
|
7192
|
+
} from "@eide/foir-proto-ts/experiments/v1/experiments_pb";
|
|
7189
7193
|
function registerExperimentsCommands(program2, globalOpts) {
|
|
7190
7194
|
const experiments = program2.command("experiments").description("Manage experiments");
|
|
7191
7195
|
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 +7202,7 @@ function registerExperimentsCommands(program2, globalOpts) {
|
|
|
7198
7202
|
limit: parseInt(String(cmdOpts.limit ?? "50"), 10),
|
|
7199
7203
|
offset: parseInt(String(cmdOpts.offset ?? "0"), 10)
|
|
7200
7204
|
});
|
|
7201
|
-
|
|
7205
|
+
formatListProto(ExperimentSchema, data.experiments, opts, {
|
|
7202
7206
|
columns: [
|
|
7203
7207
|
{ key: "id", header: "ID", width: 28 },
|
|
7204
7208
|
{ key: "key", header: "Key", width: 20 },
|
|
@@ -7231,7 +7235,7 @@ function registerExperimentsCommands(program2, globalOpts) {
|
|
|
7231
7235
|
result = await client.experiments.getExperimentByKey(idOrKey);
|
|
7232
7236
|
}
|
|
7233
7237
|
if (!result) throw new Error(`Experiment "${idOrKey}" not found.`);
|
|
7234
|
-
|
|
7238
|
+
formatOutputProto(ExperimentSchema, result, opts);
|
|
7235
7239
|
})
|
|
7236
7240
|
);
|
|
7237
7241
|
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 +7246,7 @@ function registerExperimentsCommands(program2, globalOpts) {
|
|
|
7242
7246
|
const result = await client.experiments.createExperiment(
|
|
7243
7247
|
input
|
|
7244
7248
|
);
|
|
7245
|
-
|
|
7249
|
+
formatOutputProto(ExperimentSchema, result, opts);
|
|
7246
7250
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7247
7251
|
success(`Created experiment ${result?.key}`);
|
|
7248
7252
|
})
|
|
@@ -7258,7 +7262,7 @@ function registerExperimentsCommands(program2, globalOpts) {
|
|
|
7258
7262
|
id,
|
|
7259
7263
|
...input
|
|
7260
7264
|
});
|
|
7261
|
-
|
|
7265
|
+
formatOutputProto(ExperimentSchema, result, opts);
|
|
7262
7266
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7263
7267
|
success(`Updated experiment ${id}`);
|
|
7264
7268
|
}
|
|
@@ -7289,7 +7293,7 @@ function registerExperimentsCommands(program2, globalOpts) {
|
|
|
7289
7293
|
const opts = globalOpts();
|
|
7290
7294
|
const client = await createPlatformClient(opts);
|
|
7291
7295
|
const result = await client.experiments.startExperiment(id);
|
|
7292
|
-
|
|
7296
|
+
formatOutputProto(ExperimentSchema, result, opts);
|
|
7293
7297
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7294
7298
|
success("Experiment started");
|
|
7295
7299
|
})
|
|
@@ -7299,7 +7303,7 @@ function registerExperimentsCommands(program2, globalOpts) {
|
|
|
7299
7303
|
const opts = globalOpts();
|
|
7300
7304
|
const client = await createPlatformClient(opts);
|
|
7301
7305
|
const result = await client.experiments.pauseExperiment(id);
|
|
7302
|
-
|
|
7306
|
+
formatOutputProto(ExperimentSchema, result, opts);
|
|
7303
7307
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7304
7308
|
success("Experiment paused");
|
|
7305
7309
|
})
|
|
@@ -7309,7 +7313,7 @@ function registerExperimentsCommands(program2, globalOpts) {
|
|
|
7309
7313
|
const opts = globalOpts();
|
|
7310
7314
|
const client = await createPlatformClient(opts);
|
|
7311
7315
|
const result = await client.experiments.resumeExperiment(id);
|
|
7312
|
-
|
|
7316
|
+
formatOutputProto(ExperimentSchema, result, opts);
|
|
7313
7317
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7314
7318
|
success("Experiment resumed");
|
|
7315
7319
|
})
|
|
@@ -7319,7 +7323,7 @@ function registerExperimentsCommands(program2, globalOpts) {
|
|
|
7319
7323
|
const opts = globalOpts();
|
|
7320
7324
|
const client = await createPlatformClient(opts);
|
|
7321
7325
|
const result = await client.experiments.endExperiment(id);
|
|
7322
|
-
|
|
7326
|
+
formatOutputProto(ExperimentSchema, result, opts);
|
|
7323
7327
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7324
7328
|
success("Experiment ended");
|
|
7325
7329
|
})
|
|
@@ -7329,12 +7333,13 @@ function registerExperimentsCommands(program2, globalOpts) {
|
|
|
7329
7333
|
const opts = globalOpts();
|
|
7330
7334
|
const client = await createPlatformClient(opts);
|
|
7331
7335
|
const result = await client.experiments.getExperimentStats(id);
|
|
7332
|
-
|
|
7336
|
+
formatOutputProto(ExperimentStatsSchema, result, opts);
|
|
7333
7337
|
})
|
|
7334
7338
|
);
|
|
7335
7339
|
}
|
|
7336
7340
|
|
|
7337
7341
|
// src/commands/schedules.ts
|
|
7342
|
+
import { CronScheduleSchema } from "@eide/foir-proto-ts/schedules/v1/schedules_pb";
|
|
7338
7343
|
function registerSchedulesCommands(program2, globalOpts) {
|
|
7339
7344
|
const schedules = program2.command("schedules").description("Manage schedules");
|
|
7340
7345
|
schedules.command("list").description("List schedules").option("--active", "Only active schedules").option("--limit <n>", "Max results", "50").action(
|
|
@@ -7345,7 +7350,7 @@ function registerSchedulesCommands(program2, globalOpts) {
|
|
|
7345
7350
|
isActive: cmdOpts.active ? true : void 0,
|
|
7346
7351
|
limit: parseInt(String(cmdOpts.limit ?? "50"), 10)
|
|
7347
7352
|
});
|
|
7348
|
-
|
|
7353
|
+
formatListProto(CronScheduleSchema, data.schedules, opts, {
|
|
7349
7354
|
columns: [
|
|
7350
7355
|
{ key: "key", header: "Key", width: 20 },
|
|
7351
7356
|
{ key: "name", header: "Name", width: 24 },
|
|
@@ -7374,7 +7379,7 @@ function registerSchedulesCommands(program2, globalOpts) {
|
|
|
7374
7379
|
const client = await createPlatformClient(opts);
|
|
7375
7380
|
const result = await client.cronSchedules.getCronScheduleByKey(key);
|
|
7376
7381
|
if (!result) throw new Error(`Schedule "${key}" not found.`);
|
|
7377
|
-
|
|
7382
|
+
formatOutputProto(CronScheduleSchema, result, opts);
|
|
7378
7383
|
})
|
|
7379
7384
|
);
|
|
7380
7385
|
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 +7390,7 @@ function registerSchedulesCommands(program2, globalOpts) {
|
|
|
7385
7390
|
const result = await client.cronSchedules.createCronSchedule(
|
|
7386
7391
|
input
|
|
7387
7392
|
);
|
|
7388
|
-
|
|
7393
|
+
formatOutputProto(CronScheduleSchema, result, opts);
|
|
7389
7394
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7390
7395
|
success(`Created schedule ${result?.key}`);
|
|
7391
7396
|
})
|
|
@@ -7403,7 +7408,7 @@ function registerSchedulesCommands(program2, globalOpts) {
|
|
|
7403
7408
|
id: existing.id,
|
|
7404
7409
|
...input
|
|
7405
7410
|
});
|
|
7406
|
-
|
|
7411
|
+
formatOutputProto(CronScheduleSchema, result, opts);
|
|
7407
7412
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7408
7413
|
success(`Updated schedule "${key}"`);
|
|
7409
7414
|
}
|
|
@@ -7419,7 +7424,11 @@ function registerSchedulesCommands(program2, globalOpts) {
|
|
|
7419
7424
|
id: existing.id
|
|
7420
7425
|
});
|
|
7421
7426
|
if (opts.json || opts.jsonl) {
|
|
7422
|
-
|
|
7427
|
+
if (result) {
|
|
7428
|
+
formatOutputProto(CronScheduleSchema, result, opts);
|
|
7429
|
+
} else {
|
|
7430
|
+
formatOutput({ triggered: true }, opts);
|
|
7431
|
+
}
|
|
7423
7432
|
} else {
|
|
7424
7433
|
success(`Triggered schedule "${key}"`);
|
|
7425
7434
|
}
|
|
@@ -7434,7 +7443,7 @@ function registerSchedulesCommands(program2, globalOpts) {
|
|
|
7434
7443
|
const result = await client.cronSchedules.pauseCronSchedule({
|
|
7435
7444
|
id: existing.id
|
|
7436
7445
|
});
|
|
7437
|
-
|
|
7446
|
+
formatOutputProto(CronScheduleSchema, result, opts);
|
|
7438
7447
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7439
7448
|
success(`Paused schedule "${key}"`);
|
|
7440
7449
|
})
|
|
@@ -7448,7 +7457,7 @@ function registerSchedulesCommands(program2, globalOpts) {
|
|
|
7448
7457
|
const result = await client.cronSchedules.resumeCronSchedule({
|
|
7449
7458
|
id: existing.id
|
|
7450
7459
|
});
|
|
7451
|
-
|
|
7460
|
+
formatOutputProto(CronScheduleSchema, result, opts);
|
|
7452
7461
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7453
7462
|
success(`Resumed schedule "${key}"`);
|
|
7454
7463
|
})
|
|
@@ -7481,6 +7490,8 @@ function registerSchedulesCommands(program2, globalOpts) {
|
|
|
7481
7490
|
|
|
7482
7491
|
// src/commands/api-keys.ts
|
|
7483
7492
|
import chalk10 from "chalk";
|
|
7493
|
+
import { toJson as toJson4 } from "@bufbuild/protobuf";
|
|
7494
|
+
import { ApiKeySchema } from "@eide/foir-proto-ts/identity/v1/identity_pb";
|
|
7484
7495
|
function registerApiKeysCommands(program2, globalOpts) {
|
|
7485
7496
|
const apiKeys = program2.command("api-keys").description("Manage API keys");
|
|
7486
7497
|
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 +7501,7 @@ function registerApiKeysCommands(program2, globalOpts) {
|
|
|
7490
7501
|
const result = await client.identity.listApiKeys({
|
|
7491
7502
|
limit: parseInt(String(cmdOpts.limit ?? "50"), 10)
|
|
7492
7503
|
});
|
|
7493
|
-
|
|
7504
|
+
formatListProto(ApiKeySchema, result.items, opts, {
|
|
7494
7505
|
columns: [
|
|
7495
7506
|
{ key: "id", header: "ID", width: 28 },
|
|
7496
7507
|
{ key: "name", header: "Name", width: 24 },
|
|
@@ -7529,7 +7540,12 @@ function registerApiKeysCommands(program2, globalOpts) {
|
|
|
7529
7540
|
name: cmdOpts.name
|
|
7530
7541
|
});
|
|
7531
7542
|
if (opts.json || opts.jsonl) {
|
|
7532
|
-
formatOutput(
|
|
7543
|
+
formatOutput(
|
|
7544
|
+
{
|
|
7545
|
+
apiKey: result.apiKey ? toJson4(ApiKeySchema, result.apiKey) : null
|
|
7546
|
+
},
|
|
7547
|
+
opts
|
|
7548
|
+
);
|
|
7533
7549
|
} else {
|
|
7534
7550
|
success(`Created API key: ${result.apiKey?.name}`);
|
|
7535
7551
|
console.log("");
|
|
@@ -7556,7 +7572,12 @@ function registerApiKeysCommands(program2, globalOpts) {
|
|
|
7556
7572
|
const client = await createPlatformClient(opts);
|
|
7557
7573
|
const result = await client.identity.rotateApiKey(id);
|
|
7558
7574
|
if (opts.json || opts.jsonl) {
|
|
7559
|
-
formatOutput(
|
|
7575
|
+
formatOutput(
|
|
7576
|
+
{
|
|
7577
|
+
apiKey: result.apiKey ? toJson4(ApiKeySchema, result.apiKey) : null
|
|
7578
|
+
},
|
|
7579
|
+
opts
|
|
7580
|
+
);
|
|
7560
7581
|
} else {
|
|
7561
7582
|
success(`Rotated API key: ${result.apiKey?.name}`);
|
|
7562
7583
|
console.log("");
|
|
@@ -7597,6 +7618,7 @@ function registerApiKeysCommands(program2, globalOpts) {
|
|
|
7597
7618
|
|
|
7598
7619
|
// src/commands/auth-providers.ts
|
|
7599
7620
|
import chalk11 from "chalk";
|
|
7621
|
+
import { AuthProviderSchema } from "@eide/foir-proto-ts/identity/v1/identity_pb";
|
|
7600
7622
|
var VALID_TYPES = [
|
|
7601
7623
|
"OAUTH2",
|
|
7602
7624
|
"TOKEN_SSO",
|
|
@@ -7614,7 +7636,7 @@ function registerAuthProvidersCommands(program2, globalOpts) {
|
|
|
7614
7636
|
const result = await client.identity.listAuthProviders({
|
|
7615
7637
|
enabled: cmdOpts.enabledOnly ? true : void 0
|
|
7616
7638
|
});
|
|
7617
|
-
|
|
7639
|
+
formatListProto(AuthProviderSchema, result.items, opts, {
|
|
7618
7640
|
columns: [
|
|
7619
7641
|
{ key: "id", header: "ID", width: 28 },
|
|
7620
7642
|
{ key: "key", header: "Key", width: 20 },
|
|
@@ -7646,7 +7668,7 @@ function registerAuthProvidersCommands(program2, globalOpts) {
|
|
|
7646
7668
|
throw new Error(`Auth provider not found: ${id}`);
|
|
7647
7669
|
}
|
|
7648
7670
|
if (opts.json || opts.jsonl) {
|
|
7649
|
-
|
|
7671
|
+
formatOutputProto(AuthProviderSchema, provider, opts);
|
|
7650
7672
|
} else {
|
|
7651
7673
|
const p = provider;
|
|
7652
7674
|
console.log(chalk11.bold(`${p.name}`) + chalk11.gray(` (${p.key})`));
|
|
@@ -7707,7 +7729,7 @@ function registerAuthProvidersCommands(program2, globalOpts) {
|
|
|
7707
7729
|
input
|
|
7708
7730
|
);
|
|
7709
7731
|
if (opts.json || opts.jsonl) {
|
|
7710
|
-
|
|
7732
|
+
formatOutputProto(AuthProviderSchema, provider, opts);
|
|
7711
7733
|
} else {
|
|
7712
7734
|
success(
|
|
7713
7735
|
`Created auth provider: ${provider?.name} (${provider?.key})`
|
|
@@ -7745,7 +7767,7 @@ function registerAuthProvidersCommands(program2, globalOpts) {
|
|
|
7745
7767
|
input
|
|
7746
7768
|
);
|
|
7747
7769
|
if (opts.json || opts.jsonl) {
|
|
7748
|
-
|
|
7770
|
+
formatOutputProto(AuthProviderSchema, provider, opts);
|
|
7749
7771
|
} else {
|
|
7750
7772
|
success(
|
|
7751
7773
|
`Updated auth provider: ${provider?.name} (${provider?.key})`
|
|
@@ -7780,6 +7802,7 @@ function registerAuthProvidersCommands(program2, globalOpts) {
|
|
|
7780
7802
|
}
|
|
7781
7803
|
|
|
7782
7804
|
// src/commands/locales.ts
|
|
7805
|
+
import { LocaleSchema } from "@eide/foir-proto-ts/settings/v1/settings_pb";
|
|
7783
7806
|
function registerLocalesCommands(program2, globalOpts) {
|
|
7784
7807
|
const locales = program2.command("locales").description("Manage locales");
|
|
7785
7808
|
locales.command("list").description("List locales").option("--include-inactive", "Include inactive locales").option("--limit <n>", "Max results", "50").action(
|
|
@@ -7790,7 +7813,7 @@ function registerLocalesCommands(program2, globalOpts) {
|
|
|
7790
7813
|
includeInactive: !!cmdOpts.includeInactive,
|
|
7791
7814
|
limit: parseInt(String(cmdOpts.limit ?? "50"), 10)
|
|
7792
7815
|
});
|
|
7793
|
-
|
|
7816
|
+
formatListProto(LocaleSchema, result.locales, opts, {
|
|
7794
7817
|
columns: [
|
|
7795
7818
|
{ key: "code", header: "Code", width: 8 },
|
|
7796
7819
|
{ key: "name", header: "Name", width: 20 },
|
|
@@ -7823,7 +7846,7 @@ function registerLocalesCommands(program2, globalOpts) {
|
|
|
7823
7846
|
result = await client.settings.getLocaleByCode(idOrCode);
|
|
7824
7847
|
}
|
|
7825
7848
|
if (!result) throw new Error(`Locale "${idOrCode}" not found.`);
|
|
7826
|
-
|
|
7849
|
+
formatOutputProto(LocaleSchema, result, opts);
|
|
7827
7850
|
})
|
|
7828
7851
|
);
|
|
7829
7852
|
locales.command("default").description("Get the default locale").action(
|
|
@@ -7832,7 +7855,7 @@ function registerLocalesCommands(program2, globalOpts) {
|
|
|
7832
7855
|
const client = await createPlatformClient(opts);
|
|
7833
7856
|
const result = await client.settings.getDefaultLocale();
|
|
7834
7857
|
if (!result) throw new Error("No default locale configured.");
|
|
7835
|
-
|
|
7858
|
+
formatOutputProto(LocaleSchema, result, opts);
|
|
7836
7859
|
})
|
|
7837
7860
|
);
|
|
7838
7861
|
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 +7866,9 @@ function registerLocalesCommands(program2, globalOpts) {
|
|
|
7843
7866
|
const result = await client.settings.createLocale(
|
|
7844
7867
|
input
|
|
7845
7868
|
);
|
|
7846
|
-
|
|
7869
|
+
formatOutputProto(LocaleSchema, result, opts);
|
|
7847
7870
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7848
|
-
success(`Created locale ${result?.locale
|
|
7871
|
+
success(`Created locale ${result?.locale}`);
|
|
7849
7872
|
})
|
|
7850
7873
|
);
|
|
7851
7874
|
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 +7882,9 @@ function registerLocalesCommands(program2, globalOpts) {
|
|
|
7859
7882
|
id,
|
|
7860
7883
|
...input
|
|
7861
7884
|
});
|
|
7862
|
-
|
|
7885
|
+
formatOutputProto(LocaleSchema, result, opts);
|
|
7863
7886
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7864
|
-
success(`Updated locale ${result?.locale
|
|
7887
|
+
success(`Updated locale ${result?.locale}`);
|
|
7865
7888
|
}
|
|
7866
7889
|
)
|
|
7867
7890
|
);
|
|
@@ -7888,6 +7911,7 @@ function registerLocalesCommands(program2, globalOpts) {
|
|
|
7888
7911
|
}
|
|
7889
7912
|
|
|
7890
7913
|
// src/commands/settings.ts
|
|
7914
|
+
import { SettingSchema } from "@eide/foir-proto-ts/settings/v1/settings_pb";
|
|
7891
7915
|
function inferDataType(value) {
|
|
7892
7916
|
if (value === "true" || value === "false")
|
|
7893
7917
|
return { dataType: "BOOLEAN", parsed: value === "true" };
|
|
@@ -7909,7 +7933,7 @@ function registerSettingsCommands(program2, globalOpts) {
|
|
|
7909
7933
|
const items = await client.settings.getSettings({
|
|
7910
7934
|
category: cmdOpts.category
|
|
7911
7935
|
});
|
|
7912
|
-
|
|
7936
|
+
formatListProto(SettingSchema, items, opts, {
|
|
7913
7937
|
columns: [
|
|
7914
7938
|
{ key: "key", header: "Key", width: 28 },
|
|
7915
7939
|
{
|
|
@@ -7937,7 +7961,7 @@ function registerSettingsCommands(program2, globalOpts) {
|
|
|
7937
7961
|
const items = await client.settings.getSettings({ key });
|
|
7938
7962
|
const setting = items[0] ?? null;
|
|
7939
7963
|
if (!setting) throw new Error(`Setting "${key}" not found.`);
|
|
7940
|
-
|
|
7964
|
+
formatOutputProto(SettingSchema, setting, opts);
|
|
7941
7965
|
})
|
|
7942
7966
|
);
|
|
7943
7967
|
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 +7985,7 @@ function registerSettingsCommands(program2, globalOpts) {
|
|
|
7961
7985
|
dataType
|
|
7962
7986
|
}
|
|
7963
7987
|
});
|
|
7964
|
-
|
|
7988
|
+
formatOutputProto(SettingSchema, result, opts);
|
|
7965
7989
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
7966
7990
|
success(`Set ${key} = ${value}`);
|
|
7967
7991
|
}
|
|
@@ -7979,6 +8003,7 @@ function registerSettingsCommands(program2, globalOpts) {
|
|
|
7979
8003
|
}
|
|
7980
8004
|
|
|
7981
8005
|
// src/commands/variant-catalog.ts
|
|
8006
|
+
import { VariantCatalogEntrySchema } from "@eide/foir-proto-ts/settings/v1/settings_pb";
|
|
7982
8007
|
function registerVariantCatalogCommands(program2, globalOpts) {
|
|
7983
8008
|
const catalog = program2.command("variant-catalog").description("Manage variant catalog entries (markets, devices, locales)");
|
|
7984
8009
|
catalog.command("list").description("List variant catalog entries").option("--active", "Only active entries").option("--limit <n>", "Max results", "50").action(
|
|
@@ -7989,7 +8014,7 @@ function registerVariantCatalogCommands(program2, globalOpts) {
|
|
|
7989
8014
|
isActive: cmdOpts.active ? true : void 0,
|
|
7990
8015
|
limit: parseInt(String(cmdOpts.limit ?? "50"), 10)
|
|
7991
8016
|
});
|
|
7992
|
-
|
|
8017
|
+
formatListProto(VariantCatalogEntrySchema, result.entries, opts, {
|
|
7993
8018
|
columns: [
|
|
7994
8019
|
{ key: "key", header: "Key", width: 20 },
|
|
7995
8020
|
{ key: "name", header: "Name", width: 24 },
|
|
@@ -8024,7 +8049,7 @@ function registerVariantCatalogCommands(program2, globalOpts) {
|
|
|
8024
8049
|
}
|
|
8025
8050
|
if (!result)
|
|
8026
8051
|
throw new Error(`Variant catalog entry "${idOrKey}" not found.`);
|
|
8027
|
-
|
|
8052
|
+
formatOutputProto(VariantCatalogEntrySchema, result, opts);
|
|
8028
8053
|
})
|
|
8029
8054
|
);
|
|
8030
8055
|
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 +8060,9 @@ function registerVariantCatalogCommands(program2, globalOpts) {
|
|
|
8035
8060
|
const result = await client.settings.createVariantCatalogEntry(
|
|
8036
8061
|
input
|
|
8037
8062
|
);
|
|
8038
|
-
|
|
8063
|
+
formatOutputProto(VariantCatalogEntrySchema, result, opts);
|
|
8039
8064
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
8040
|
-
success(
|
|
8041
|
-
`Created variant catalog entry ${result?.key}`
|
|
8042
|
-
);
|
|
8065
|
+
success(`Created variant catalog entry ${result?.key}`);
|
|
8043
8066
|
})
|
|
8044
8067
|
);
|
|
8045
8068
|
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 +8076,9 @@ function registerVariantCatalogCommands(program2, globalOpts) {
|
|
|
8053
8076
|
id,
|
|
8054
8077
|
...input
|
|
8055
8078
|
});
|
|
8056
|
-
|
|
8079
|
+
formatOutputProto(VariantCatalogEntrySchema, result, opts);
|
|
8057
8080
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
8058
|
-
success(
|
|
8059
|
-
`Updated variant catalog entry ${result?.key}`
|
|
8060
|
-
);
|
|
8081
|
+
success(`Updated variant catalog entry ${result?.key}`);
|
|
8061
8082
|
}
|
|
8062
8083
|
)
|
|
8063
8084
|
);
|
|
@@ -8085,6 +8106,10 @@ function registerVariantCatalogCommands(program2, globalOpts) {
|
|
|
8085
8106
|
}
|
|
8086
8107
|
|
|
8087
8108
|
// src/commands/files.ts
|
|
8109
|
+
import {
|
|
8110
|
+
FileSchema as FileSchema2,
|
|
8111
|
+
StorageUsageSchema as StorageUsageSchema2
|
|
8112
|
+
} from "@eide/foir-proto-ts/storage/v1/storage_pb";
|
|
8088
8113
|
function registerFilesCommands(program2, globalOpts) {
|
|
8089
8114
|
const files = program2.command("files").description("Manage files (for upload, use `foir media upload`)");
|
|
8090
8115
|
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 +8123,7 @@ function registerFilesCommands(program2, globalOpts) {
|
|
|
8098
8123
|
limit: parseInt(cmdOpts.limit ?? "50", 10),
|
|
8099
8124
|
offset: parseInt(cmdOpts.offset ?? "0", 10)
|
|
8100
8125
|
});
|
|
8101
|
-
|
|
8126
|
+
formatListProto(FileSchema2, data.items, opts, {
|
|
8102
8127
|
columns: [
|
|
8103
8128
|
{ key: "id", header: "ID", width: 28 },
|
|
8104
8129
|
{ key: "filename", header: "Filename", width: 30 },
|
|
@@ -8127,7 +8152,7 @@ function registerFilesCommands(program2, globalOpts) {
|
|
|
8127
8152
|
const client = await createPlatformClient(opts);
|
|
8128
8153
|
const file = await client.storage.getFile(id);
|
|
8129
8154
|
if (!file) throw new Error(`File "${id}" not found.`);
|
|
8130
|
-
|
|
8155
|
+
formatOutputProto(FileSchema2, file, opts);
|
|
8131
8156
|
})
|
|
8132
8157
|
);
|
|
8133
8158
|
files.command("usage").description("Get storage usage statistics").action(
|
|
@@ -8135,7 +8160,7 @@ function registerFilesCommands(program2, globalOpts) {
|
|
|
8135
8160
|
const opts = globalOpts();
|
|
8136
8161
|
const client = await createPlatformClient(opts);
|
|
8137
8162
|
const usage = await client.storage.getStorageUsage();
|
|
8138
|
-
|
|
8163
|
+
formatOutputProto(StorageUsageSchema2, usage, opts);
|
|
8139
8164
|
})
|
|
8140
8165
|
);
|
|
8141
8166
|
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 +8175,7 @@ function registerFilesCommands(program2, globalOpts) {
|
|
|
8150
8175
|
if (cmdOpts.tags)
|
|
8151
8176
|
params.tags = cmdOpts.tags.split(",").map((t) => t.trim());
|
|
8152
8177
|
const file = await client.storage.updateFile(params);
|
|
8153
|
-
|
|
8178
|
+
formatOutputProto(FileSchema2, file, opts);
|
|
8154
8179
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
8155
8180
|
success(`Updated file ${id}`);
|
|
8156
8181
|
}
|
|
@@ -8168,7 +8193,7 @@ function registerFilesCommands(program2, globalOpts) {
|
|
|
8168
8193
|
caption: cmdOpts.caption,
|
|
8169
8194
|
description: cmdOpts.description
|
|
8170
8195
|
});
|
|
8171
|
-
|
|
8196
|
+
formatOutputProto(FileSchema2, file, opts);
|
|
8172
8197
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
8173
8198
|
success(`Updated metadata for file ${id}`);
|
|
8174
8199
|
}
|
|
@@ -8206,6 +8231,7 @@ function formatBytes(bytes) {
|
|
|
8206
8231
|
}
|
|
8207
8232
|
|
|
8208
8233
|
// src/commands/notes.ts
|
|
8234
|
+
import { NoteSchema } from "@eide/foir-proto-ts/settings/v1/settings_pb";
|
|
8209
8235
|
function registerNotesCommands(program2, globalOpts) {
|
|
8210
8236
|
const notes = program2.command("notes").description("Manage notes and comments");
|
|
8211
8237
|
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 +8243,7 @@ function registerNotesCommands(program2, globalOpts) {
|
|
|
8217
8243
|
entityId: cmdOpts.entityId,
|
|
8218
8244
|
limit: parseInt(String(cmdOpts.limit ?? "20"), 10)
|
|
8219
8245
|
});
|
|
8220
|
-
|
|
8246
|
+
formatListProto(NoteSchema, data.notes, opts, {
|
|
8221
8247
|
columns: [
|
|
8222
8248
|
{ key: "id", header: "ID", width: 28 },
|
|
8223
8249
|
{ key: "content", header: "Content", width: 40 },
|
|
@@ -8245,7 +8271,7 @@ function registerNotesCommands(program2, globalOpts) {
|
|
|
8245
8271
|
const client = await createPlatformClient(opts);
|
|
8246
8272
|
const note = await client.settings.getNote(id);
|
|
8247
8273
|
if (!note) throw new Error(`Note "${id}" not found.`);
|
|
8248
|
-
|
|
8274
|
+
formatOutputProto(NoteSchema, note, opts);
|
|
8249
8275
|
})
|
|
8250
8276
|
);
|
|
8251
8277
|
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 +8287,7 @@ function registerNotesCommands(program2, globalOpts) {
|
|
|
8261
8287
|
};
|
|
8262
8288
|
if (cmdOpts.parentNoteId) params.parentNoteId = cmdOpts.parentNoteId;
|
|
8263
8289
|
const note = await client.settings.createNote(params);
|
|
8264
|
-
|
|
8290
|
+
formatOutputProto(NoteSchema, note, opts);
|
|
8265
8291
|
if (!(opts.json || opts.jsonl || opts.quiet)) success("Note created");
|
|
8266
8292
|
})
|
|
8267
8293
|
);
|
|
@@ -8275,7 +8301,7 @@ function registerNotesCommands(program2, globalOpts) {
|
|
|
8275
8301
|
id,
|
|
8276
8302
|
isResolved: true
|
|
8277
8303
|
});
|
|
8278
|
-
|
|
8304
|
+
formatOutputProto(NoteSchema, note, opts);
|
|
8279
8305
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
8280
8306
|
success(`Resolved note ${id}`);
|
|
8281
8307
|
}
|
|
@@ -8304,6 +8330,7 @@ function registerNotesCommands(program2, globalOpts) {
|
|
|
8304
8330
|
}
|
|
8305
8331
|
|
|
8306
8332
|
// src/commands/notifications.ts
|
|
8333
|
+
import { NotificationSchema } from "@eide/foir-proto-ts/notifications/v1/notifications_pb";
|
|
8307
8334
|
function registerNotificationsCommands(program2, globalOpts) {
|
|
8308
8335
|
const notifications = program2.command("notifications").description("Manage notifications");
|
|
8309
8336
|
notifications.command("list").description("List notifications").option("--unread", "Only unread notifications").option("--limit <n>", "Max results", "20").action(
|
|
@@ -8318,7 +8345,7 @@ function registerNotificationsCommands(program2, globalOpts) {
|
|
|
8318
8345
|
console.log(`Unread: ${data.unreadCount}
|
|
8319
8346
|
`);
|
|
8320
8347
|
}
|
|
8321
|
-
|
|
8348
|
+
formatListProto(NotificationSchema, data.notifications, opts, {
|
|
8322
8349
|
columns: [
|
|
8323
8350
|
{ key: "id", header: "ID", width: 28 },
|
|
8324
8351
|
{ key: "type", header: "Type", width: 16 },
|
|
@@ -8367,6 +8394,7 @@ function registerNotificationsCommands(program2, globalOpts) {
|
|
|
8367
8394
|
}
|
|
8368
8395
|
|
|
8369
8396
|
// src/commands/configs.ts
|
|
8397
|
+
import { ConfigSchema } from "@eide/foir-proto-ts/configs/v1/configs_pb";
|
|
8370
8398
|
function registerConfigsCommands(program2, globalOpts) {
|
|
8371
8399
|
const configs = program2.command("configs").description("Manage configs (apps, webhooks)");
|
|
8372
8400
|
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 +8406,7 @@ function registerConfigsCommands(program2, globalOpts) {
|
|
|
8378
8406
|
enabled: cmdOpts.enabled ? true : void 0,
|
|
8379
8407
|
limit: parseInt(String(cmdOpts.limit ?? "50"), 10)
|
|
8380
8408
|
});
|
|
8381
|
-
|
|
8409
|
+
formatListProto(ConfigSchema, data.configs, opts, {
|
|
8382
8410
|
columns: [
|
|
8383
8411
|
{ key: "id", header: "ID", width: 28 },
|
|
8384
8412
|
{ key: "key", header: "Key", width: 20 },
|
|
@@ -8406,7 +8434,7 @@ function registerConfigsCommands(program2, globalOpts) {
|
|
|
8406
8434
|
result = await client.configs.getConfigByKey(idOrKey);
|
|
8407
8435
|
}
|
|
8408
8436
|
if (!result) throw new Error(`Config "${idOrKey}" not found.`);
|
|
8409
|
-
|
|
8437
|
+
formatOutputProto(ConfigSchema, result, opts);
|
|
8410
8438
|
})
|
|
8411
8439
|
);
|
|
8412
8440
|
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 +8443,7 @@ function registerConfigsCommands(program2, globalOpts) {
|
|
|
8415
8443
|
const client = await createPlatformClient(opts);
|
|
8416
8444
|
const input = await parseInputData(cmdOpts);
|
|
8417
8445
|
const config2 = await client.configs.createConfig(input);
|
|
8418
|
-
|
|
8446
|
+
formatOutputProto(ConfigSchema, config2, opts);
|
|
8419
8447
|
if (!(opts.json || opts.jsonl || opts.quiet))
|
|
8420
8448
|
success(`Created config ${config2?.key}`);
|
|
8421
8449
|
})
|
|
@@ -8437,6 +8465,10 @@ function registerConfigsCommands(program2, globalOpts) {
|
|
|
8437
8465
|
}
|
|
8438
8466
|
|
|
8439
8467
|
// src/commands/apps.ts
|
|
8468
|
+
import {
|
|
8469
|
+
AppSchema,
|
|
8470
|
+
ValidateManifestResponseSchema
|
|
8471
|
+
} from "@eide/foir-proto-ts/apps/v1/apps_service_pb";
|
|
8440
8472
|
function registerAppsCommands(program2, globalOpts) {
|
|
8441
8473
|
const apps = program2.command("apps").description("Install and manage apps");
|
|
8442
8474
|
apps.command("list").description("List installed apps").action(
|
|
@@ -8448,7 +8480,7 @@ function registerAppsCommands(program2, globalOpts) {
|
|
|
8448
8480
|
resolved.project.tenantId,
|
|
8449
8481
|
resolved.project.id
|
|
8450
8482
|
);
|
|
8451
|
-
|
|
8483
|
+
formatListProto(AppSchema, apps2, opts, {
|
|
8452
8484
|
columns: [
|
|
8453
8485
|
{ key: "name", header: "Name", width: 24 },
|
|
8454
8486
|
{
|
|
@@ -8463,9 +8495,10 @@ function registerAppsCommands(program2, globalOpts) {
|
|
|
8463
8495
|
header: "Installed",
|
|
8464
8496
|
width: 12,
|
|
8465
8497
|
format: (v) => {
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8498
|
+
if (!v) return "";
|
|
8499
|
+
const date = new Date(v);
|
|
8500
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
8501
|
+
return date.toLocaleDateString();
|
|
8469
8502
|
}
|
|
8470
8503
|
}
|
|
8471
8504
|
]
|
|
@@ -8483,7 +8516,7 @@ function registerAppsCommands(program2, globalOpts) {
|
|
|
8483
8516
|
name
|
|
8484
8517
|
);
|
|
8485
8518
|
if (!app) throw new Error(`App "${name}" not installed.`);
|
|
8486
|
-
|
|
8519
|
+
formatOutputProto(AppSchema, app, opts);
|
|
8487
8520
|
})
|
|
8488
8521
|
);
|
|
8489
8522
|
apps.command("install <manifestUrl>").description("Install an app from a manifest URL").option(
|
|
@@ -8544,7 +8577,7 @@ function registerAppsCommands(program2, globalOpts) {
|
|
|
8544
8577
|
placementFieldChoices
|
|
8545
8578
|
});
|
|
8546
8579
|
if (opts.json) {
|
|
8547
|
-
|
|
8580
|
+
formatOutputProto(AppSchema, app, opts);
|
|
8548
8581
|
} else {
|
|
8549
8582
|
success(`Installed ${app?.name ?? ""}`);
|
|
8550
8583
|
}
|
|
@@ -8587,7 +8620,7 @@ function registerAppsCommands(program2, globalOpts) {
|
|
|
8587
8620
|
updateResp.newManifestHash
|
|
8588
8621
|
);
|
|
8589
8622
|
if (opts.json) {
|
|
8590
|
-
|
|
8623
|
+
formatOutputProto(AppSchema, app, opts);
|
|
8591
8624
|
} else {
|
|
8592
8625
|
success(`Updated ${name}`);
|
|
8593
8626
|
}
|
|
@@ -8645,7 +8678,7 @@ function registerAppsCommands(program2, globalOpts) {
|
|
|
8645
8678
|
const client = await createPlatformClient(opts);
|
|
8646
8679
|
const resp = await client.apps.validateManifestUrl(manifestUrl);
|
|
8647
8680
|
if (opts.json) {
|
|
8648
|
-
|
|
8681
|
+
formatOutputProto(ValidateManifestResponseSchema, resp, opts);
|
|
8649
8682
|
return;
|
|
8650
8683
|
}
|
|
8651
8684
|
if (resp.ok) {
|
|
@@ -8690,6 +8723,188 @@ function classToLabel(n) {
|
|
|
8690
8723
|
}
|
|
8691
8724
|
}
|
|
8692
8725
|
|
|
8726
|
+
// src/commands/secrets.ts
|
|
8727
|
+
import { promises as fs5 } from "fs";
|
|
8728
|
+
function registerSecretsCommands(program2, globalOpts) {
|
|
8729
|
+
const secrets = program2.command("secrets").description("Manage vault secrets");
|
|
8730
|
+
secrets.command("put").description("Store a new secret and print its ref").option("--label <label>", "Optional human-readable label").option("--app <name>", "Owner: app name (defaults to project-owned)").option("--file <path>", "Read plaintext from file (binary-safe)").option("--value <plaintext>", "Plaintext value (string only; prefer --file for binary)").action(
|
|
8731
|
+
withErrorHandler(globalOpts, async (cmdOpts) => {
|
|
8732
|
+
const opts = globalOpts();
|
|
8733
|
+
const resolved = await requireProject2(opts);
|
|
8734
|
+
const plaintext = await readPlaintext(cmdOpts);
|
|
8735
|
+
const client = await createPlatformClient(opts);
|
|
8736
|
+
const ownerKind = cmdOpts.app ? OwnerKind.APP : OwnerKind.PROJECT;
|
|
8737
|
+
const ref = await client.secrets.put({
|
|
8738
|
+
tenantId: resolved.project.tenantId,
|
|
8739
|
+
projectId: resolved.project.id,
|
|
8740
|
+
ownerKind,
|
|
8741
|
+
ownerId: cmdOpts.app,
|
|
8742
|
+
label: cmdOpts.label,
|
|
8743
|
+
plaintext
|
|
8744
|
+
});
|
|
8745
|
+
if (opts.json || opts.jsonl) {
|
|
8746
|
+
formatOutput({ ref }, opts);
|
|
8747
|
+
} else if (opts.quiet) {
|
|
8748
|
+
console.log(ref);
|
|
8749
|
+
} else {
|
|
8750
|
+
success(`Stored secret`);
|
|
8751
|
+
console.log(` ref: ${ref}`);
|
|
8752
|
+
if (cmdOpts.label) console.log(` label: ${cmdOpts.label}`);
|
|
8753
|
+
if (cmdOpts.app) console.log(` app: ${cmdOpts.app}`);
|
|
8754
|
+
}
|
|
8755
|
+
})
|
|
8756
|
+
);
|
|
8757
|
+
secrets.command("list").description("List secrets metadata (no plaintext)").option("--app <name>", "List app-owned secrets for this app").option("--include-soft-deleted", "Include soft-deleted entries").action(
|
|
8758
|
+
withErrorHandler(globalOpts, async (cmdOpts) => {
|
|
8759
|
+
const opts = globalOpts();
|
|
8760
|
+
const resolved = await requireProject2(opts);
|
|
8761
|
+
const client = await createPlatformClient(opts);
|
|
8762
|
+
const ownerKind = cmdOpts.app ? OwnerKind.APP : OwnerKind.PROJECT;
|
|
8763
|
+
const items = await client.secrets.list({
|
|
8764
|
+
tenantId: resolved.project.tenantId,
|
|
8765
|
+
projectId: resolved.project.id,
|
|
8766
|
+
ownerKind,
|
|
8767
|
+
ownerId: typeof cmdOpts.app === "string" ? cmdOpts.app : "",
|
|
8768
|
+
includeSoftDeleted: !!cmdOpts.includeSoftDeleted
|
|
8769
|
+
});
|
|
8770
|
+
if (opts.json || opts.jsonl) {
|
|
8771
|
+
formatOutput(
|
|
8772
|
+
items.map((s) => ({
|
|
8773
|
+
ref: s.ref,
|
|
8774
|
+
label: s.label,
|
|
8775
|
+
ownerKind: ownerKindToString(s.ownerKind),
|
|
8776
|
+
ownerId: s.ownerId,
|
|
8777
|
+
createdAt: tsToString(s.createdAt),
|
|
8778
|
+
lastReadAt: tsToString(s.lastReadAt),
|
|
8779
|
+
softDeletedAt: tsToString(s.softDeletedAt)
|
|
8780
|
+
})),
|
|
8781
|
+
opts
|
|
8782
|
+
);
|
|
8783
|
+
return;
|
|
8784
|
+
}
|
|
8785
|
+
if (items.length === 0) {
|
|
8786
|
+
warn("No secrets found.");
|
|
8787
|
+
return;
|
|
8788
|
+
}
|
|
8789
|
+
for (const s of items) {
|
|
8790
|
+
const owner = s.ownerKind === OwnerKind.APP ? `app:${s.ownerId}` : "project";
|
|
8791
|
+
const deleted = s.softDeletedAt ? " [soft-deleted]" : "";
|
|
8792
|
+
console.log(`${s.ref} ${owner.padEnd(24)} ${s.label ?? ""}${deleted}`);
|
|
8793
|
+
}
|
|
8794
|
+
})
|
|
8795
|
+
);
|
|
8796
|
+
secrets.command("rotate <ref>").description("Replace plaintext for an existing ref; returns new ref").option("--file <path>", "Read plaintext from file (binary-safe)").option("--value <plaintext>", "Plaintext value (string only; prefer --file for binary)").option("--confirm", "Skip confirmation prompt").action(
|
|
8797
|
+
withErrorHandler(globalOpts, async (ref, cmdOpts) => {
|
|
8798
|
+
const opts = globalOpts();
|
|
8799
|
+
const confirmed = await confirmAction(
|
|
8800
|
+
`Rotate secret ${ref}? Every record pointing at it will be updated to the new ref.`,
|
|
8801
|
+
{ confirm: !!cmdOpts.confirm }
|
|
8802
|
+
);
|
|
8803
|
+
if (!confirmed) {
|
|
8804
|
+
console.log("Aborted.");
|
|
8805
|
+
return;
|
|
8806
|
+
}
|
|
8807
|
+
const plaintext = await readPlaintext(cmdOpts);
|
|
8808
|
+
const client = await createPlatformClient(opts);
|
|
8809
|
+
const newRef = await client.secrets.rotate(ref, plaintext);
|
|
8810
|
+
if (opts.json || opts.jsonl) {
|
|
8811
|
+
formatOutput({ oldRef: ref, newRef }, opts);
|
|
8812
|
+
} else if (opts.quiet) {
|
|
8813
|
+
console.log(newRef);
|
|
8814
|
+
} else {
|
|
8815
|
+
success(`Rotated`);
|
|
8816
|
+
console.log(` old: ${ref}`);
|
|
8817
|
+
console.log(` new: ${newRef}`);
|
|
8818
|
+
}
|
|
8819
|
+
})
|
|
8820
|
+
);
|
|
8821
|
+
secrets.command("delete <ref>").description("Soft-delete a secret (recoverable until purged)").option("--confirm", "Skip confirmation prompt").action(
|
|
8822
|
+
withErrorHandler(globalOpts, async (ref, cmdOpts) => {
|
|
8823
|
+
const opts = globalOpts();
|
|
8824
|
+
const confirmed = await confirmAction(
|
|
8825
|
+
`Soft-delete secret ${ref}? Refuses if the secret is still referenced.`,
|
|
8826
|
+
{ confirm: !!cmdOpts.confirm }
|
|
8827
|
+
);
|
|
8828
|
+
if (!confirmed) {
|
|
8829
|
+
console.log("Aborted.");
|
|
8830
|
+
return;
|
|
8831
|
+
}
|
|
8832
|
+
const client = await createPlatformClient(opts);
|
|
8833
|
+
await client.secrets.delete(ref);
|
|
8834
|
+
success(`Deleted ${ref}`);
|
|
8835
|
+
})
|
|
8836
|
+
);
|
|
8837
|
+
secrets.command("restore <ref>").description("Undo a soft-delete (only valid before purge_after passes)").action(
|
|
8838
|
+
withErrorHandler(globalOpts, async (ref) => {
|
|
8839
|
+
const opts = globalOpts();
|
|
8840
|
+
const client = await createPlatformClient(opts);
|
|
8841
|
+
await client.secrets.restore(ref);
|
|
8842
|
+
success(`Restored ${ref}`);
|
|
8843
|
+
})
|
|
8844
|
+
);
|
|
8845
|
+
secrets.command("purge").description("Drop every soft-deleted secret past its TTL (admin-only)").option("--confirm", "Skip confirmation prompt").action(
|
|
8846
|
+
withErrorHandler(globalOpts, async (cmdOpts) => {
|
|
8847
|
+
const opts = globalOpts();
|
|
8848
|
+
const confirmed = await confirmAction(
|
|
8849
|
+
`Purge soft-deleted secrets? Cannot be undone.`,
|
|
8850
|
+
{ confirm: !!cmdOpts.confirm }
|
|
8851
|
+
);
|
|
8852
|
+
if (!confirmed) {
|
|
8853
|
+
console.log("Aborted.");
|
|
8854
|
+
return;
|
|
8855
|
+
}
|
|
8856
|
+
const resolved = await requireProject2(opts);
|
|
8857
|
+
const client = await createPlatformClient(opts);
|
|
8858
|
+
const count = await client.secrets.purge({
|
|
8859
|
+
tenantId: resolved.project.tenantId,
|
|
8860
|
+
projectId: resolved.project.id
|
|
8861
|
+
});
|
|
8862
|
+
success(`Purged ${count} secret(s)`);
|
|
8863
|
+
})
|
|
8864
|
+
);
|
|
8865
|
+
}
|
|
8866
|
+
async function requireProject2(opts) {
|
|
8867
|
+
const resolved = await resolveProjectContext(opts);
|
|
8868
|
+
if (!resolved) {
|
|
8869
|
+
throw new Error(
|
|
8870
|
+
"No project selected. Run `foir select-project` or set FOIR_PROJECT."
|
|
8871
|
+
);
|
|
8872
|
+
}
|
|
8873
|
+
return resolved;
|
|
8874
|
+
}
|
|
8875
|
+
async function readPlaintext(cmdOpts) {
|
|
8876
|
+
const file = typeof cmdOpts.file === "string" ? cmdOpts.file : "";
|
|
8877
|
+
const value = typeof cmdOpts.value === "string" ? cmdOpts.value : "";
|
|
8878
|
+
if (file && value) {
|
|
8879
|
+
throw new Error("Pass either --file or --value, not both.");
|
|
8880
|
+
}
|
|
8881
|
+
if (!file && !value) {
|
|
8882
|
+
throw new Error("One of --file or --value is required.");
|
|
8883
|
+
}
|
|
8884
|
+
if (file) {
|
|
8885
|
+
return fs5.readFile(file);
|
|
8886
|
+
}
|
|
8887
|
+
return new TextEncoder().encode(value);
|
|
8888
|
+
}
|
|
8889
|
+
function ownerKindToString(k) {
|
|
8890
|
+
switch (k) {
|
|
8891
|
+
case OwnerKind.PROJECT:
|
|
8892
|
+
return "project";
|
|
8893
|
+
case OwnerKind.APP:
|
|
8894
|
+
return "app";
|
|
8895
|
+
case OwnerKind.CUSTOMER:
|
|
8896
|
+
return "customer";
|
|
8897
|
+
default:
|
|
8898
|
+
return "";
|
|
8899
|
+
}
|
|
8900
|
+
}
|
|
8901
|
+
function tsToString(t) {
|
|
8902
|
+
if (!t || t.seconds === void 0 && t.nanos === void 0) return "";
|
|
8903
|
+
const seconds = Number(t.seconds ?? 0n);
|
|
8904
|
+
const nanos = t.nanos ?? 0;
|
|
8905
|
+
return new Date(seconds * 1e3 + Math.floor(nanos / 1e6)).toISOString();
|
|
8906
|
+
}
|
|
8907
|
+
|
|
8693
8908
|
// src/cli.ts
|
|
8694
8909
|
var __filename = fileURLToPath(import.meta.url);
|
|
8695
8910
|
var __dirname = dirname4(__filename);
|
|
@@ -8739,4 +8954,5 @@ registerNotesCommands(program, getGlobalOpts);
|
|
|
8739
8954
|
registerNotificationsCommands(program, getGlobalOpts);
|
|
8740
8955
|
registerConfigsCommands(program, getGlobalOpts);
|
|
8741
8956
|
registerAppsCommands(program, getGlobalOpts);
|
|
8957
|
+
registerSecretsCommands(program, getGlobalOpts);
|
|
8742
8958
|
program.parse();
|