@alvera-ai/platform-sdk 0.7.2 → 0.8.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/src/cli.ts CHANGED
@@ -1,145 +1,25 @@
1
1
  #!/usr/bin/env tsx
2
2
 
3
3
  import { readFileSync } from 'node:fs';
4
- import { createInterface } from 'node:readline';
5
4
  import { dirname, resolve } from 'node:path';
6
5
  import { fileURLToPath } from 'node:url';
7
6
  import { Command, Option } from 'commander';
8
- import { ValiError } from 'valibot';
9
- import { createPlatformApi, createSession, revokeSession } from './client.js';
7
+ import { ENVIRONMENTS } from './config.js';
8
+ import { die } from './cli/helpers.js';
9
+ import { register as registerAuth } from './cli/auth.js';
10
+ import { register as registerEnv } from './cli/env.js';
11
+ import { register as registerInit } from './cli/init.js';
12
+ import { register as registerRaw } from './cli/raw.js';
13
+ import { register as registerResources } from './cli/resources.js';
14
+ import { register as registerWorkflows } from './cli/workflows.js';
10
15
 
11
16
  const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');
12
17
  const { version: packageVersion } = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as {
13
18
  version: string;
14
19
  };
15
- import {
16
- CONFIG_PATHS,
17
- DEFAULT_ENVIRONMENT,
18
- ENVIRONMENTS,
19
- clearProfileCreds,
20
- getProfileName,
21
- readProfileConfig,
22
- resolveProfile,
23
- writeProfileConfig,
24
- writeProfileCreds,
25
- } from './config.js';
26
20
 
27
21
  const ENVIRONMENT_NAMES = Object.keys(ENVIRONMENTS);
28
22
 
29
- // ---------------------------------------------------------------------------
30
- // Helpers
31
- // ---------------------------------------------------------------------------
32
-
33
- function out(value: unknown): void {
34
- process.stdout.write(JSON.stringify(value, null, 2) + '\n');
35
- }
36
-
37
- function die(message: string, code = 1): never {
38
- process.stderr.write(`alvera: ${message}\n`);
39
- process.exit(code);
40
- }
41
-
42
- async function prompt(question: string, { hidden = false } = {}): Promise<string> {
43
- const rl = createInterface({ input: process.stdin, output: process.stderr, terminal: true });
44
- if (!hidden) {
45
- return new Promise((resolve) => rl.question(question, (ans) => {
46
- rl.close();
47
- resolve(ans);
48
- }));
49
- }
50
- // Hidden input — mute output by replacing _writeToOutput.
51
- const anyRl = rl as unknown as { _writeToOutput: (s: string) => void };
52
- const originalWrite = anyRl._writeToOutput.bind(rl);
53
- anyRl._writeToOutput = (s: string) => {
54
- if (s.includes(question)) originalWrite(s);
55
- else originalWrite('');
56
- };
57
- return new Promise((resolve) => rl.question(question, (ans) => {
58
- rl.close();
59
- process.stderr.write('\n');
60
- resolve(ans);
61
- }));
62
- }
63
-
64
- function readBody(body: string | undefined, bodyFile: string | undefined): Record<string, unknown> {
65
- if (body && bodyFile) die('use only one of --body or --body-file');
66
- let raw: string;
67
- if (body) raw = body;
68
- else if (bodyFile === '-') raw = readFileSync(0, 'utf8');
69
- else if (bodyFile) raw = readFileSync(bodyFile, 'utf8');
70
- else die('missing request body (pass --body <json> or --body-file <path>)');
71
- try {
72
- const parsed = JSON.parse(raw);
73
- if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
74
- die('body must be a JSON object');
75
- }
76
- return parsed;
77
- } catch (err) {
78
- die(`invalid JSON in body: ${(err as Error).message}`);
79
- }
80
- }
81
-
82
- function resolveTenant(explicit: string | undefined, profileTenant: string | null): string {
83
- const tenant = explicit ?? profileTenant;
84
- if (!tenant) die('tenant slug required (pass as argument or set `tenant_slug` in the profile)');
85
- return tenant;
86
- }
87
-
88
- interface GlobalOpts {
89
- profile?: string;
90
- env?: string;
91
- }
92
-
93
- function authedApi(opts: GlobalOpts) {
94
- const profile = getProfileName(opts.profile);
95
- const resolved = resolveProfile(profile);
96
- if (!resolved.sessionToken) {
97
- die(
98
- `no session token for profile "${profile}". ` +
99
- `Run \`alvera login --profile ${profile}\` or set ALVERA_SESSION_TOKEN.`,
100
- );
101
- }
102
- if (resolved.expiresAt && new Date(resolved.expiresAt) < new Date()) {
103
- die(
104
- `session for profile "${profile}" expired at ${resolved.expiresAt}. ` +
105
- `Run \`alvera login --profile ${profile}\` to refresh.`,
106
- );
107
- }
108
- return { api: createPlatformApi({ baseUrl: resolved.baseUrl, sessionToken: resolved.sessionToken }), resolved };
109
- }
110
-
111
- async function run(fn: () => Promise<unknown>): Promise<void> {
112
- try {
113
- const result = await fn();
114
- if (result !== undefined) out(result);
115
- } catch (err) {
116
- die(formatError(err));
117
- }
118
- }
119
-
120
- function formatError(err: unknown): string {
121
- if (err instanceof ValiError) {
122
- const lines = err.issues.map((issue) => {
123
- const path = (issue.path ?? [])
124
- .map((p: { key?: unknown }) => String(p.key ?? '?'))
125
- .join('.') || '(root)';
126
- return ` ${path}: ${issue.message}`;
127
- });
128
- return `validation failed:\n${lines.join('\n')}`;
129
- }
130
- if (err instanceof Error) return err.message;
131
- if (err && typeof err === 'object') {
132
- const detail = (err as { errors?: { detail?: unknown } }).errors?.detail;
133
- if (typeof detail === 'string') return detail;
134
- return JSON.stringify(err, null, 2);
135
- }
136
- return String(err);
137
- }
138
-
139
- // ---------------------------------------------------------------------------
140
- // Program
141
- // ---------------------------------------------------------------------------
142
-
143
23
  const program = new Command();
144
24
  program
145
25
  .name('alvera')
@@ -154,7 +34,7 @@ program
154
34
  )
155
35
  .showHelpAfterError()
156
36
  .hook('preAction', (thisCommand) => {
157
- const env = thisCommand.optsWithGlobals<GlobalOpts>().env;
37
+ const env = thisCommand.optsWithGlobals<{ env?: string }>().env;
158
38
  if (env !== undefined) process.env.ALVERA_ENV = env;
159
39
  const candidate = process.env.ALVERA_ENV;
160
40
  if (candidate !== undefined && !ENVIRONMENT_NAMES.includes(candidate)) {
@@ -164,1223 +44,11 @@ program
164
44
  }
165
45
  });
166
46
 
167
- // -- configure --------------------------------------------------------------
168
- program
169
- .command('configure')
170
- .description('Interactively set defaults (environment, tenant, email) for a profile')
171
- .action(async () => {
172
- const profile = getProfileName(program.opts<GlobalOpts>().profile);
173
- const current = resolveProfile(profile);
174
- const currentCfg = readProfileConfig(profile);
175
-
176
- const options = ENVIRONMENT_NAMES.map(
177
- (name) => `${name} (${ENVIRONMENTS[name as keyof typeof ENVIRONMENTS].base_url})`,
178
- ).join(', ');
179
- const defaultChoice = currentCfg.environment ?? current.environment;
180
- const envInput =
181
- (await prompt(`Environment [${defaultChoice}] — one of: ${options}, or a custom URL: `)) ||
182
- defaultChoice;
183
-
184
- const patch: { environment?: string; base_url?: string; tenant_slug?: string; email?: string } = {};
185
- const unset: Array<'environment' | 'base_url'> = [];
186
- if (ENVIRONMENT_NAMES.includes(envInput)) {
187
- patch.environment = envInput;
188
- unset.push('base_url');
189
- } else if (/^https?:\/\//.test(envInput)) {
190
- patch.base_url = envInput;
191
- unset.push('environment');
192
- } else {
193
- die(
194
- `"${envInput}" is not a known environment or a URL. ` +
195
- `Valid: ${ENVIRONMENT_NAMES.join(', ')} or http(s)://…`,
196
- );
197
- }
198
-
199
- patch.tenant_slug =
200
- (await prompt(`Default tenant slug [${current.tenantSlug ?? ''}]: `)) || current.tenantSlug || '';
201
- patch.email = (await prompt(`Email [${current.email ?? ''}]: `)) || current.email || '';
202
- writeProfileConfig(profile, patch, unset);
203
- process.stderr.write(`Saved profile "${profile}" → ${CONFIG_PATHS.config}\n`);
204
- });
205
-
206
- // -- login ------------------------------------------------------------------
207
- program
208
- .command('login')
209
- .description('Exchange credentials for a session token and store it')
210
- .option('--email <email>')
211
- .option('--password <password>')
212
- .option('--tenant <slug>')
213
- .option('--base-url <url>')
214
- .option('--expires-in <seconds>', 'session duration (default 86400, max 2592000)')
215
- .action(async (opts: Record<string, string>) => {
216
- const profile = getProfileName(program.opts<GlobalOpts>().profile);
217
- const current = resolveProfile(profile);
218
- const baseUrl = opts.baseUrl ?? current.baseUrl;
219
- const email = opts.email ?? current.email ?? (await prompt('Email: '));
220
- const password = opts.password ?? process.env.ALVERA_PASSWORD ?? (await prompt('Password: ', { hidden: true }));
221
- const tenant = opts.tenant ?? current.tenantSlug ?? (await prompt('Tenant slug: '));
222
- if (!email || !password || !tenant) die('email, password, and tenant are required');
223
-
224
- await run(async () => {
225
- const session = await createSession({
226
- baseUrl,
227
- email,
228
- password,
229
- tenantSlug: tenant,
230
- expiresIn: opts.expiresIn ? Number(opts.expiresIn) : undefined,
231
- });
232
- // Only pin base_url into the profile when the user explicitly overrode it.
233
- // Otherwise the environment selection (profile.environment) keeps driving baseUrl.
234
- writeProfileConfig(profile, {
235
- ...(opts.baseUrl ? { base_url: baseUrl } : {}),
236
- tenant_slug: tenant,
237
- email,
238
- });
239
- writeProfileCreds(profile, {
240
- session_token: session.sessionToken,
241
- expires_at: session.expiresAt ?? '',
242
- });
243
- const tenantLabel = session.tenant ? `tenant "${session.tenant.slug}"` : 'no tenant';
244
- process.stderr.write(
245
- `Logged in as ${email} → ${tenantLabel} (profile "${profile}").\n` +
246
- `Token stored in ${CONFIG_PATHS.credentials}\n` +
247
- (session.expiresAt ? `Expires at ${session.expiresAt}\n` : ''),
248
- );
249
- return undefined;
250
- });
251
- });
252
-
253
- // -- logout -----------------------------------------------------------------
254
- program
255
- .command('logout')
256
- .description('Revoke the current session and clear stored credentials')
257
- .action(async () => {
258
- const profile = getProfileName(program.opts<GlobalOpts>().profile);
259
- const resolved = resolveProfile(profile);
260
- if (resolved.sessionToken) {
261
- createPlatformApi({ baseUrl: resolved.baseUrl, sessionToken: resolved.sessionToken });
262
- try {
263
- await revokeSession();
264
- } catch {
265
- // Token may already be invalid/expired — clear local state anyway.
266
- }
267
- }
268
- clearProfileCreds(profile);
269
- process.stderr.write(`Cleared credentials for profile "${profile}".\n`);
270
- });
271
-
272
- // -- whoami -----------------------------------------------------------------
273
- program
274
- .command('whoami')
275
- .description('Print the current profile configuration')
276
- .action(() => {
277
- const profile = getProfileName(program.opts<GlobalOpts>().profile);
278
- const resolved = resolveProfile(profile);
279
- out({
280
- profile: resolved.profile,
281
- environment: resolved.environment,
282
- baseUrl: resolved.baseUrl,
283
- tenantSlug: resolved.tenantSlug,
284
- email: resolved.email,
285
- hasSessionToken: Boolean(resolved.sessionToken),
286
- expiresAt: resolved.expiresAt,
287
- });
288
- });
289
-
290
- // -- ping -------------------------------------------------------------------
291
- program
292
- .command('ping')
293
- .description('Health check')
294
- .action(async () => {
295
- await run(async () => {
296
- const { api } = authedApi(program.opts<GlobalOpts>());
297
- const { data } = await api.ping();
298
- return data;
299
- });
300
- });
301
-
302
- // -- env --------------------------------------------------------------------
303
- // Environments are baked from spec/openapi.yaml servers[] at build time.
304
- // Default (prod / or last-in-list) is chosen in scripts/gen-environments.mjs.
305
- const envCmd = program
306
- .command('env')
307
- .description('List and switch Alvera API environments');
308
-
309
- envCmd
310
- .command('list')
311
- .description('List available environments (from spec/openapi.yaml)')
312
- .action(() => {
313
- const profile = getProfileName(program.opts<GlobalOpts>().profile);
314
- const resolved = resolveProfile(profile);
315
- out(
316
- ENVIRONMENT_NAMES.map((name) => ({
317
- name,
318
- baseUrl: ENVIRONMENTS[name as keyof typeof ENVIRONMENTS].base_url,
319
- description: ENVIRONMENTS[name as keyof typeof ENVIRONMENTS].description,
320
- default: name === DEFAULT_ENVIRONMENT,
321
- active: name === resolved.environment,
322
- })),
323
- );
324
- });
325
-
326
- envCmd
327
- .command('use <name>')
328
- .description('Persist the selected environment to the profile (clears any custom base_url)')
329
- .action((name: string) => {
330
- if (!ENVIRONMENT_NAMES.includes(name)) {
331
- die(`unknown environment "${name}". Valid: ${ENVIRONMENT_NAMES.join(', ')}`);
332
- }
333
- const profile = getProfileName(program.opts<GlobalOpts>().profile);
334
- writeProfileConfig(profile, { environment: name }, ['base_url']);
335
- process.stderr.write(
336
- `Profile "${profile}" now uses environment "${name}" ` +
337
- `(${ENVIRONMENTS[name as keyof typeof ENVIRONMENTS].base_url}).\n`,
338
- );
339
- });
340
-
341
- // -- tenants ----------------------------------------------------------------
342
- const tenants = program.command('tenants').description('Manage tenants');
343
-
344
- tenants
345
- .command('list')
346
- .description('List tenants accessible to the current session')
347
- .action(async () => {
348
- await run(async () => {
349
- const { api } = authedApi(program.opts<GlobalOpts>());
350
- const { data } = await api.tenants.list();
351
- return data;
352
- });
353
- });
354
-
355
- // ---------------------------------------------------------------------------
356
- // Resource commands — thin wrappers over the SDK
357
- // ---------------------------------------------------------------------------
358
-
359
- const bodyOption = (cmd: Command): Command =>
360
- cmd
361
- .option('--body <json>', 'request body as a JSON string')
362
- .option('--body-file <path>', 'path to a JSON file (or "-" for stdin)');
363
-
364
- // -- datalakes --------------------------------------------------------------
365
- const datalakes = program.command('datalakes').description('Manage datalakes');
366
-
367
- datalakes
368
- .command('list [tenant]')
369
- .description('List datalakes for a tenant')
370
- .action(async (tenant: string | undefined) => {
371
- await run(async () => {
372
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
373
- const { data } = await api.datalakes.list(resolveTenant(tenant, resolved.tenantSlug));
374
- return data;
375
- });
376
- });
377
-
378
- datalakes
379
- .command('get <id> [tenant]')
380
- .description('Get a datalake by id')
381
- .action(async (id: string, tenant: string | undefined) => {
382
- await run(async () => {
383
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
384
- const { data } = await api.datalakes.get(resolveTenant(tenant, resolved.tenantSlug), id);
385
- return data;
386
- });
387
- });
388
-
389
- // -- data-sources -----------------------------------------------------------
390
- const dataSources = program.command('data-sources').description('Manage data sources');
391
-
392
- dataSources
393
- .command('list <datalake> [tenant]')
394
- .description('List data sources in a datalake')
395
- .action(async (datalake: string, tenant: string | undefined) => {
396
- await run(async () => {
397
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
398
- const { data } = await api.dataSources.list(resolveTenant(tenant, resolved.tenantSlug), datalake);
399
- return data;
400
- });
401
- });
402
-
403
- bodyOption(dataSources.command('create <datalake> [tenant]').description('Create a data source'))
404
- .action(async (datalake: string, tenant: string | undefined, opts: Record<string, string>) => {
405
- await run(async () => {
406
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
407
- const { data } = await api.dataSources.create(
408
- resolveTenant(tenant, resolved.tenantSlug),
409
- datalake,
410
- readBody(opts.body, opts.bodyFile),
411
- );
412
- return data;
413
- });
414
- });
415
-
416
- bodyOption(dataSources.command('update <datalake> <id> [tenant]').description('Update a data source'))
417
- .action(async (datalake: string, id: string, tenant: string | undefined, opts: Record<string, string>) => {
418
- await run(async () => {
419
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
420
- const { data } = await api.dataSources.update(
421
- resolveTenant(tenant, resolved.tenantSlug),
422
- datalake,
423
- id,
424
- readBody(opts.body, opts.bodyFile),
425
- );
426
- return data;
427
- });
428
- });
429
-
430
- // -- tools ------------------------------------------------------------------
431
- const tools = program.command('tools').description('Manage tools');
432
-
433
- tools
434
- .command('list [tenant]')
435
- .description('List tools for a tenant')
436
- .action(async (tenant: string | undefined) => {
437
- await run(async () => {
438
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
439
- const { data } = await api.tools.list(resolveTenant(tenant, resolved.tenantSlug));
440
- return data;
441
- });
442
- });
443
-
444
- tools
445
- .command('get <id> [tenant]')
446
- .description('Get a tool by id')
447
- .action(async (id: string, tenant: string | undefined) => {
448
- await run(async () => {
449
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
450
- const { data } = await api.tools.get(resolveTenant(tenant, resolved.tenantSlug), id);
451
- return data;
452
- });
453
- });
454
-
455
- bodyOption(tools.command('create [tenant]').description('Create a tool'))
456
- .action(async (tenant: string | undefined, opts: Record<string, string>) => {
457
- await run(async () => {
458
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
459
- const { data } = await api.tools.create(
460
- resolveTenant(tenant, resolved.tenantSlug),
461
- readBody(opts.body, opts.bodyFile),
462
- );
463
- return data;
464
- });
465
- });
466
-
467
- bodyOption(tools.command('update <id> [tenant]').description('Update a tool'))
468
- .action(async (id: string, tenant: string | undefined, opts: Record<string, string>) => {
469
- await run(async () => {
470
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
471
- const { data } = await api.tools.update(
472
- resolveTenant(tenant, resolved.tenantSlug),
473
- id,
474
- readBody(opts.body, opts.bodyFile),
475
- );
476
- return data;
477
- });
478
- });
479
-
480
- tools
481
- .command('delete <id> [tenant]')
482
- .description('Delete a tool')
483
- .action(async (id: string, tenant: string | undefined) => {
484
- await run(async () => {
485
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
486
- const { data } = await api.tools.delete(resolveTenant(tenant, resolved.tenantSlug), id);
487
- return data;
488
- });
489
- });
490
-
491
- // -- generic-tables ---------------------------------------------------------
492
- const genericTables = program.command('generic-tables').description('Manage generic tables');
493
-
494
- genericTables
495
- .command('list <datalake> [tenant]')
496
- .description('List generic tables in a datalake')
497
- .action(async (datalake: string, tenant: string | undefined) => {
498
- await run(async () => {
499
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
500
- const { data } = await api.genericTables.list(resolveTenant(tenant, resolved.tenantSlug), datalake);
501
- return data;
502
- });
503
- });
504
-
505
- bodyOption(genericTables.command('create <datalake> [tenant]').description('Create a generic table'))
506
- .action(async (datalake: string, tenant: string | undefined, opts: Record<string, string>) => {
507
- await run(async () => {
508
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
509
- const { data } = await api.genericTables.create(
510
- resolveTenant(tenant, resolved.tenantSlug),
511
- datalake,
512
- readBody(opts.body, opts.bodyFile) as never,
513
- );
514
- return data;
515
- });
516
- });
517
-
518
- // -- action-status-updaters -------------------------------------------------
519
- const updaters = program.command('action-status-updaters').description('Manage action status updaters');
520
-
521
- updaters
522
- .command('list [tenant]')
523
- .description('List action status updaters')
524
- .action(async (tenant: string | undefined) => {
525
- await run(async () => {
526
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
527
- const { data } = await api.actionStatusUpdaters.list(resolveTenant(tenant, resolved.tenantSlug));
528
- return data;
529
- });
530
- });
531
-
532
- bodyOption(updaters.command('create [tenant]').description('Create an action status updater'))
533
- .action(async (tenant: string | undefined, opts: Record<string, string>) => {
534
- await run(async () => {
535
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
536
- const { data } = await api.actionStatusUpdaters.create(
537
- resolveTenant(tenant, resolved.tenantSlug),
538
- readBody(opts.body, opts.bodyFile) as never,
539
- );
540
- return data;
541
- });
542
- });
543
-
544
- bodyOption(updaters.command('update <id> [tenant]').description('Update an action status updater'))
545
- .action(async (id: string, tenant: string | undefined, opts: Record<string, string>) => {
546
- await run(async () => {
547
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
548
- const { data } = await api.actionStatusUpdaters.update(
549
- resolveTenant(tenant, resolved.tenantSlug),
550
- id,
551
- readBody(opts.body, opts.bodyFile) as never,
552
- );
553
- return data;
554
- });
555
- });
556
-
557
- // -- ai-agents --------------------------------------------------------------
558
- const aiAgents = program.command('ai-agents').description('Manage AI agents');
559
-
560
- aiAgents
561
- .command('list <datalake> [tenant]')
562
- .description('List AI agents in a datalake')
563
- .action(async (datalake: string, tenant: string | undefined) => {
564
- await run(async () => {
565
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
566
- const { data } = await api.aiAgents.list(resolveTenant(tenant, resolved.tenantSlug), datalake);
567
- return data;
568
- });
569
- });
570
-
571
- aiAgents
572
- .command('get <datalake> <id> [tenant]')
573
- .description('Get an AI agent by id')
574
- .action(async (datalake: string, id: string, tenant: string | undefined) => {
575
- await run(async () => {
576
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
577
- const { data } = await api.aiAgents.get(resolveTenant(tenant, resolved.tenantSlug), datalake, id);
578
- return data;
579
- });
580
- });
581
-
582
- bodyOption(aiAgents.command('create <datalake> [tenant]').description('Create an AI agent'))
583
- .action(async (datalake: string, tenant: string | undefined, opts: Record<string, string>) => {
584
- await run(async () => {
585
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
586
- const { data } = await api.aiAgents.create(
587
- resolveTenant(tenant, resolved.tenantSlug),
588
- datalake,
589
- readBody(opts.body, opts.bodyFile) as never,
590
- );
591
- return data;
592
- });
593
- });
594
-
595
- bodyOption(aiAgents.command('update <datalake> <id> [tenant]').description('Update an AI agent'))
596
- .action(async (datalake: string, id: string, tenant: string | undefined, opts: Record<string, string>) => {
597
- await run(async () => {
598
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
599
- const { data } = await api.aiAgents.update(
600
- resolveTenant(tenant, resolved.tenantSlug),
601
- datalake,
602
- id,
603
- readBody(opts.body, opts.bodyFile) as never,
604
- );
605
- return data;
606
- });
607
- });
608
-
609
- aiAgents
610
- .command('delete <datalake> <id> [tenant]')
611
- .description('Delete an AI agent')
612
- .action(async (datalake: string, id: string, tenant: string | undefined) => {
613
- await run(async () => {
614
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
615
- const { data } = await api.aiAgents.delete(resolveTenant(tenant, resolved.tenantSlug), datalake, id);
616
- return data;
617
- });
618
- });
619
-
620
- // -- session verify (via API) ----------------------------------------------
621
- program
622
- .command('sessions-verify')
623
- .description('Verify the current session token via the API')
624
- .action(async () => {
625
- await run(async () => {
626
- const { api } = authedApi(program.opts<GlobalOpts>());
627
- const { data } = await api.sessions.verify();
628
- return data;
629
- });
630
- });
631
-
632
- // -- datasets ---------------------------------------------------------------
633
- const datasets = program.command('datasets').description('Search datasets');
634
-
635
- datasets
636
- .command('search <dataset>')
637
- .description('Search a dataset (e.g. patient, member)')
638
- .option('--datalake-id <id>', 'restrict to a specific datalake')
639
- .option('--page <n>', 'page number', (v) => Number(v))
640
- .option('--page-size <n>', 'results per page (max 100)', (v) => Number(v))
641
- .action(async (dataset: string, opts: Record<string, unknown>) => {
642
- await run(async () => {
643
- const { api } = authedApi(program.opts<GlobalOpts>());
644
- const { data } = await api.datasets.search(dataset, {
645
- datalakeId: opts.datalakeId as string | undefined,
646
- page: opts.page as number | undefined,
647
- pageSize: opts.pageSize as number | undefined,
648
- });
649
- return data;
650
- });
651
- });
652
-
653
- // -- datalakes create (extension) ------------------------------------------
654
- bodyOption(datalakes.command('create [tenant]').description('Create a datalake'))
655
- .action(async (tenant: string | undefined, opts: Record<string, string>) => {
656
- await run(async () => {
657
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
658
- const { data } = await api.datalakes.create(
659
- resolveTenant(tenant, resolved.tenantSlug),
660
- readBody(opts.body, opts.bodyFile),
661
- );
662
- return data;
663
- });
664
- });
665
-
666
- // -- connected-apps (datalake-scoped management + tenant-scoped actions) ---
667
- const connectedApps = program.command('connected-apps').description('Manage connected apps');
668
-
669
- connectedApps
670
- .command('list <datalake> [tenant]')
671
- .description('List connected apps in a datalake')
672
- .action(async (datalake: string, tenant: string | undefined) => {
673
- await run(async () => {
674
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
675
- const { data } = await api.connectedApps.list(resolveTenant(tenant, resolved.tenantSlug), datalake);
676
- return data;
677
- });
678
- });
679
-
680
- connectedApps
681
- .command('get <datalake> <id> [tenant]')
682
- .description('Get a connected app by id')
683
- .action(async (datalake: string, id: string, tenant: string | undefined) => {
684
- await run(async () => {
685
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
686
- const { data } = await api.connectedApps.get(resolveTenant(tenant, resolved.tenantSlug), datalake, id);
687
- return data;
688
- });
689
- });
690
-
691
- bodyOption(connectedApps.command('create <datalake> [tenant]').description('Create a connected app'))
692
- .action(async (datalake: string, tenant: string | undefined, opts: Record<string, string>) => {
693
- await run(async () => {
694
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
695
- const { data } = await api.connectedApps.create(
696
- resolveTenant(tenant, resolved.tenantSlug),
697
- datalake,
698
- readBody(opts.body, opts.bodyFile),
699
- );
700
- return data;
701
- });
702
- });
703
-
704
- bodyOption(connectedApps.command('update <datalake> <id> [tenant]').description('Update a connected app'))
705
- .action(async (datalake: string, id: string, tenant: string | undefined, opts: Record<string, string>) => {
706
- await run(async () => {
707
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
708
- const { data } = await api.connectedApps.update(
709
- resolveTenant(tenant, resolved.tenantSlug),
710
- datalake,
711
- id,
712
- readBody(opts.body, opts.bodyFile),
713
- );
714
- return data;
715
- });
716
- });
717
-
718
- connectedApps
719
- .command('sync-routes <datalake> <id> [tenant]')
720
- .description('Trigger a sync of routes for a connected app')
721
- .action(async (datalake: string, id: string, tenant: string | undefined) => {
722
- await run(async () => {
723
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
724
- const { data } = await api.connectedApps.syncRoutes(
725
- resolveTenant(tenant, resolved.tenantSlug),
726
- datalake,
727
- id,
728
- );
729
- return data;
730
- });
731
- });
732
-
733
- bodyOption(
734
- connectedApps
735
- .command('resolve-page <slug> [tenant]')
736
- .description('Resolve a connected app page (tenant-scoped, by slug)'),
737
- )
738
- .action(async (slug: string, tenant: string | undefined, opts: Record<string, string>) => {
739
- await run(async () => {
740
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
741
- const { data } = await api.connectedApps.resolvePage(
742
- resolveTenant(tenant, resolved.tenantSlug),
743
- slug,
744
- readBody(opts.body, opts.bodyFile),
745
- );
746
- return data;
747
- });
748
- });
749
-
750
- bodyOption(
751
- connectedApps
752
- .command('update-message-tracking <slug> [tenant]')
753
- .description('Update page message tracking for a connected app'),
754
- )
755
- .action(async (slug: string, tenant: string | undefined, opts: Record<string, string>) => {
756
- await run(async () => {
757
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
758
- const { data } = await api.connectedApps.updateMessageTracking(
759
- resolveTenant(tenant, resolved.tenantSlug),
760
- slug,
761
- readBody(opts.body, opts.bodyFile),
762
- );
763
- return data;
764
- });
765
- });
766
-
767
- // -- data-activation-clients -----------------------------------------------
768
- const dac = program.command('data-activation-clients').description('Manage data activation clients');
769
-
770
- dac
771
- .command('list <datalake> [tenant]')
772
- .description('List data activation clients in a datalake')
773
- .action(async (datalake: string, tenant: string | undefined) => {
774
- await run(async () => {
775
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
776
- const { data } = await api.dataActivationClients.list(
777
- resolveTenant(tenant, resolved.tenantSlug),
778
- datalake,
779
- );
780
- return data;
781
- });
782
- });
783
-
784
- dac
785
- .command('get <datalake> <slug> [tenant]')
786
- .description('Get a data activation client by slug')
787
- .action(async (datalake: string, slug: string, tenant: string | undefined) => {
788
- await run(async () => {
789
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
790
- const { data } = await api.dataActivationClients.get(
791
- resolveTenant(tenant, resolved.tenantSlug),
792
- datalake,
793
- slug,
794
- );
795
- return data;
796
- });
797
- });
798
-
799
- bodyOption(dac.command('create <datalake> [tenant]').description('Create a data activation client'))
800
- .action(async (datalake: string, tenant: string | undefined, opts: Record<string, string>) => {
801
- await run(async () => {
802
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
803
- const { data } = await api.dataActivationClients.create(
804
- resolveTenant(tenant, resolved.tenantSlug),
805
- datalake,
806
- readBody(opts.body, opts.bodyFile),
807
- );
808
- return data;
809
- });
810
- });
811
-
812
- bodyOption(dac.command('update <datalake> <slug> [tenant]').description('Update a data activation client'))
813
- .action(async (datalake: string, slug: string, tenant: string | undefined, opts: Record<string, string>) => {
814
- await run(async () => {
815
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
816
- const { data } = await api.dataActivationClients.update(
817
- resolveTenant(tenant, resolved.tenantSlug),
818
- datalake,
819
- slug,
820
- readBody(opts.body, opts.bodyFile),
821
- );
822
- return data;
823
- });
824
- });
825
-
826
- dac
827
- .command('delete <datalake> <slug> [tenant]')
828
- .description('Delete a data activation client')
829
- .action(async (datalake: string, slug: string, tenant: string | undefined) => {
830
- await run(async () => {
831
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
832
- const { data } = await api.dataActivationClients.delete(
833
- resolveTenant(tenant, resolved.tenantSlug),
834
- datalake,
835
- slug,
836
- );
837
- return data;
838
- });
839
- });
840
-
841
- dac
842
- .command('metadata <datalake> <slug> [tenant]')
843
- .description('Get markdown metadata for a data activation client')
844
- .action(async (datalake: string, slug: string, tenant: string | undefined) => {
845
- await run(async () => {
846
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
847
- const { data } = await api.dataActivationClients.metadata(
848
- resolveTenant(tenant, resolved.tenantSlug),
849
- datalake,
850
- slug,
851
- );
852
- return data;
853
- });
854
- });
855
-
856
- bodyOption(
857
- dac
858
- .command('run-manually <datalake> <slug> [tenant]')
859
- .description('Trigger a manual run (optional --body for tool_call override)'),
860
- )
861
- .action(async (datalake: string, slug: string, tenant: string | undefined, opts: Record<string, string>) => {
862
- await run(async () => {
863
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
864
- const body = opts.body || opts.bodyFile ? readBody(opts.body, opts.bodyFile) : undefined;
865
- const { data } = await api.dataActivationClients.runManually(
866
- resolveTenant(tenant, resolved.tenantSlug),
867
- datalake,
868
- slug,
869
- body,
870
- );
871
- return data;
872
- });
873
- });
874
-
875
- bodyOption(dac.command('ingest <datalake> <slug> [tenant]').description('Ingest a JSON payload'))
876
- .action(async (datalake: string, slug: string, tenant: string | undefined, opts: Record<string, string>) => {
877
- await run(async () => {
878
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
879
- const { data } = await api.dataActivationClients.ingest(
880
- resolveTenant(tenant, resolved.tenantSlug),
881
- datalake,
882
- slug,
883
- readBody(opts.body, opts.bodyFile),
884
- );
885
- return data;
886
- });
887
- });
888
-
889
- dac
890
- .command('ingest-file <datalake> <slug> <key> [tenant]')
891
- .description('Ingest a previously uploaded file (key from upload-link)')
892
- .action(async (datalake: string, slug: string, key: string, tenant: string | undefined) => {
893
- await run(async () => {
894
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
895
- const { data } = await api.dataActivationClients.ingestFile(
896
- resolveTenant(tenant, resolved.tenantSlug),
897
- datalake,
898
- slug,
899
- { key },
900
- );
901
- return data;
902
- });
903
- });
904
-
905
- dac
906
- .command('logs <datalake> <slug> [tenant]')
907
- .description('List execution logs for a data activation client')
908
- .action(async (datalake: string, slug: string, tenant: string | undefined) => {
909
- await run(async () => {
910
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
911
- const { data } = await api.dataActivationClients.logs.list(
912
- resolveTenant(tenant, resolved.tenantSlug),
913
- datalake,
914
- slug,
915
- );
916
- return data;
917
- });
918
- });
919
-
920
- dac
921
- .command('log-get <datalake> <slug> <id> [tenant]')
922
- .description('Get a single execution log by id')
923
- .action(async (datalake: string, slug: string, id: string, tenant: string | undefined) => {
924
- await run(async () => {
925
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
926
- const { data } = await api.dataActivationClients.logs.get(
927
- resolveTenant(tenant, resolved.tenantSlug),
928
- datalake,
929
- slug,
930
- id,
931
- );
932
- return data;
933
- });
934
- });
935
-
936
- datalakes
937
- .command('upload-link <datalake> <filename> [tenant]')
938
- .description('Create a presigned upload link for a datalake')
939
- .addOption(
940
- new Option('--content-type <type>', 'MIME type of the file')
941
- .choices(['application/x-ndjson', 'text/csv'])
942
- .default('application/x-ndjson'),
943
- )
944
- .action(
945
- async (
946
- datalake: string,
947
- filename: string,
948
- tenant: string | undefined,
949
- opts: Record<string, string>,
950
- ) => {
951
- await run(async () => {
952
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
953
- const { data } = await api.datalakes.createUploadLink(
954
- resolveTenant(tenant, resolved.tenantSlug),
955
- datalake,
956
- {
957
- content_type: opts.contentType as 'application/x-ndjson' | 'text/csv',
958
- filename,
959
- },
960
- );
961
- return data;
962
- });
963
- },
964
- );
965
-
966
- datalakes
967
- .command('download-link <datalake> <bucket> <key> [tenant]')
968
- .description('Create a presigned download URL for a datalake object')
969
- .action(
970
- async (
971
- datalake: string,
972
- bucket: string,
973
- key: string,
974
- tenant: string | undefined,
975
- ) => {
976
- await run(async () => {
977
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
978
- const { data } = await api.datalakes.createDownloadLink(
979
- resolveTenant(tenant, resolved.tenantSlug),
980
- datalake,
981
- { bucket, key },
982
- );
983
- return data;
984
- });
985
- },
986
- );
987
-
988
- // -- mdm --------------------------------------------------------------------
989
- const mdm = program.command('mdm').description('Master data management');
990
-
991
- bodyOption(
992
- mdm.command('verify <datalake> [tenant]').description('Fuzzy-verify an identity against MDM'),
993
- )
994
- .action(async (datalake: string, tenant: string | undefined, opts: Record<string, string>) => {
995
- await run(async () => {
996
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
997
- const { data } = await api.mdm.verify(
998
- resolveTenant(tenant, resolved.tenantSlug),
999
- datalake,
1000
- readBody(opts.body, opts.bodyFile),
1001
- );
1002
- return data;
1003
- });
1004
- });
1005
-
1006
- // -- datalakes metadata + datasets metadata --------------------------------
1007
- datalakes
1008
- .command('metadata <datalake> [tenant]')
1009
- .description('Get markdown metadata for a datalake')
1010
- .action(async (datalake: string, tenant: string | undefined) => {
1011
- await run(async () => {
1012
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1013
- const { data } = await api.datalakes.metadata(
1014
- resolveTenant(tenant, resolved.tenantSlug),
1015
- datalake,
1016
- );
1017
- return data;
1018
- });
1019
- });
1020
-
1021
- datasets
1022
- .command('metadata <dataset-type>')
1023
- .description('Get markdown schema metadata for a dataset type')
1024
- .option('--datalake-id <id>', 'restrict to a specific datalake')
1025
- .option('--generic-table-id <id>', 'required when dataset-type is generic_table')
1026
- .action(async (datasetType: string, opts: Record<string, string>) => {
1027
- await run(async () => {
1028
- const { api } = authedApi(program.opts<GlobalOpts>());
1029
- const { data } = await api.datasets.metadata(datasetType, {
1030
- datalakeId: opts.datalakeId,
1031
- genericTableId: opts.genericTableId,
1032
- });
1033
- return data;
1034
- });
1035
- });
1036
-
1037
- // -- interoperability-contracts --------------------------------------------
1038
- const interop = program
1039
- .command('interoperability-contracts')
1040
- .alias('interop')
1041
- .description('Manage interoperability contracts');
1042
-
1043
- interop
1044
- .command('list <datalake> [tenant]')
1045
- .description('List interoperability contracts in a datalake')
1046
- .action(async (datalake: string, tenant: string | undefined) => {
1047
- await run(async () => {
1048
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1049
- const { data } = await api.interoperabilityContracts.list(
1050
- resolveTenant(tenant, resolved.tenantSlug),
1051
- datalake,
1052
- );
1053
- return data;
1054
- });
1055
- });
1056
-
1057
- interop
1058
- .command('get <datalake> <slug> [tenant]')
1059
- .description('Get a contract by slug')
1060
- .action(async (datalake: string, slug: string, tenant: string | undefined) => {
1061
- await run(async () => {
1062
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1063
- const { data } = await api.interoperabilityContracts.get(
1064
- resolveTenant(tenant, resolved.tenantSlug),
1065
- datalake,
1066
- slug,
1067
- );
1068
- return data;
1069
- });
1070
- });
1071
-
1072
- bodyOption(interop.command('create <datalake> [tenant]').description('Create a contract'))
1073
- .action(async (datalake: string, tenant: string | undefined, opts: Record<string, string>) => {
1074
- await run(async () => {
1075
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1076
- const { data } = await api.interoperabilityContracts.create(
1077
- resolveTenant(tenant, resolved.tenantSlug),
1078
- datalake,
1079
- readBody(opts.body, opts.bodyFile),
1080
- );
1081
- return data;
1082
- });
1083
- });
1084
-
1085
- bodyOption(interop.command('update <datalake> <slug> [tenant]').description('Update a contract'))
1086
- .action(async (datalake: string, slug: string, tenant: string | undefined, opts: Record<string, string>) => {
1087
- await run(async () => {
1088
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1089
- const { data } = await api.interoperabilityContracts.update(
1090
- resolveTenant(tenant, resolved.tenantSlug),
1091
- datalake,
1092
- slug,
1093
- readBody(opts.body, opts.bodyFile),
1094
- );
1095
- return data;
1096
- });
1097
- });
1098
-
1099
- interop
1100
- .command('delete <datalake> <slug> [tenant]')
1101
- .description('Delete a contract')
1102
- .action(async (datalake: string, slug: string, tenant: string | undefined) => {
1103
- await run(async () => {
1104
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1105
- const { data } = await api.interoperabilityContracts.delete(
1106
- resolveTenant(tenant, resolved.tenantSlug),
1107
- datalake,
1108
- slug,
1109
- );
1110
- return data;
1111
- });
1112
- });
1113
-
1114
- interop
1115
- .command('metadata <datalake> <slug> [tenant]')
1116
- .description('Get markdown metadata for a contract')
1117
- .action(async (datalake: string, slug: string, tenant: string | undefined) => {
1118
- await run(async () => {
1119
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1120
- const { data } = await api.interoperabilityContracts.metadata(
1121
- resolveTenant(tenant, resolved.tenantSlug),
1122
- datalake,
1123
- slug,
1124
- );
1125
- return data;
1126
- });
1127
- });
1128
-
1129
- bodyOption(
1130
- interop
1131
- .command('run <datalake> <slug> [tenant]')
1132
- .description('Execute a contract against a raw source row'),
1133
- )
1134
- .action(async (datalake: string, slug: string, tenant: string | undefined, opts: Record<string, string>) => {
1135
- await run(async () => {
1136
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1137
- const { data } = await api.interoperabilityContracts.run(
1138
- resolveTenant(tenant, resolved.tenantSlug),
1139
- datalake,
1140
- slug,
1141
- readBody(opts.body, opts.bodyFile),
1142
- );
1143
- return data;
1144
- });
1145
- });
1146
-
1147
- // -- workflows --------------------------------------------------------------
1148
- const workflows = program.command('workflows').description('Agentic workflows');
1149
-
1150
- workflows
1151
- .command('list <datalake> [tenant]')
1152
- .description('List workflow definitions in a datalake')
1153
- .action(async (datalake: string, tenant: string | undefined) => {
1154
- await run(async () => {
1155
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1156
- const { data } = await api.workflows.list(
1157
- resolveTenant(tenant, resolved.tenantSlug),
1158
- datalake,
1159
- );
1160
- return data;
1161
- });
1162
- });
1163
-
1164
- workflows
1165
- .command('get <datalake> <id> [tenant]')
1166
- .description('Get a workflow by id')
1167
- .action(async (datalake: string, id: string, tenant: string | undefined) => {
1168
- await run(async () => {
1169
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1170
- const { data } = await api.workflows.get(
1171
- resolveTenant(tenant, resolved.tenantSlug),
1172
- datalake,
1173
- id,
1174
- );
1175
- return data;
1176
- });
1177
- });
1178
-
1179
- bodyOption(workflows.command('create <datalake> [tenant]').description('Create a workflow'))
1180
- .action(async (datalake: string, tenant: string | undefined, opts: Record<string, string>) => {
1181
- await run(async () => {
1182
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1183
- const { data } = await api.workflows.create(
1184
- resolveTenant(tenant, resolved.tenantSlug),
1185
- datalake,
1186
- readBody(opts.body, opts.bodyFile),
1187
- );
1188
- return data;
1189
- });
1190
- });
1191
-
1192
- bodyOption(workflows.command('update <datalake> <id> [tenant]').description('Update a workflow'))
1193
- .action(async (datalake: string, id: string, tenant: string | undefined, opts: Record<string, string>) => {
1194
- await run(async () => {
1195
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1196
- const { data } = await api.workflows.update(
1197
- resolveTenant(tenant, resolved.tenantSlug),
1198
- datalake,
1199
- id,
1200
- readBody(opts.body, opts.bodyFile),
1201
- );
1202
- return data;
1203
- });
1204
- });
1205
-
1206
- workflows
1207
- .command('delete <datalake> <id> [tenant]')
1208
- .description('Delete a workflow')
1209
- .action(async (datalake: string, id: string, tenant: string | undefined) => {
1210
- await run(async () => {
1211
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1212
- const { data } = await api.workflows.delete(
1213
- resolveTenant(tenant, resolved.tenantSlug),
1214
- datalake,
1215
- id,
1216
- );
1217
- return data;
1218
- });
1219
- });
1220
-
1221
- workflows
1222
- .command('metadata <datalake> <id> [tenant]')
1223
- .description('Get markdown metadata for a workflow')
1224
- .action(async (datalake: string, id: string, tenant: string | undefined) => {
1225
- await run(async () => {
1226
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1227
- const { data } = await api.workflows.metadata(
1228
- resolveTenant(tenant, resolved.tenantSlug),
1229
- datalake,
1230
- id,
1231
- );
1232
- return data;
1233
- });
1234
- });
1235
-
1236
- bodyOption(
1237
- workflows.command('execute <workflow-slug> [tenant]').description('Execute an agentic workflow'),
1238
- )
1239
- .action(async (workflowSlug: string, tenant: string | undefined, opts: Record<string, string>) => {
1240
- await run(async () => {
1241
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1242
- const { data } = await api.workflows.execute(
1243
- resolveTenant(tenant, resolved.tenantSlug),
1244
- workflowSlug,
1245
- readBody(opts.body, opts.bodyFile),
1246
- );
1247
- return data;
1248
- });
1249
- });
1250
-
1251
- bodyOption(
1252
- workflows
1253
- .command('run <workflow-slug> [tenant]')
1254
- .description('Run a workflow across records matched by a SQL WHERE clause'),
1255
- )
1256
- .action(async (workflowSlug: string, tenant: string | undefined, opts: Record<string, string>) => {
1257
- await run(async () => {
1258
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1259
- const { data } = await api.workflows.run(
1260
- resolveTenant(tenant, resolved.tenantSlug),
1261
- workflowSlug,
1262
- readBody(opts.body, opts.bodyFile),
1263
- );
1264
- return data;
1265
- });
1266
- });
1267
-
1268
- workflows
1269
- .command('batch-logs <workflow-slug> [tenant]')
1270
- .description('List batch logs for a workflow')
1271
- .action(async (workflowSlug: string, tenant: string | undefined) => {
1272
- await run(async () => {
1273
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1274
- const { data } = await api.workflows.batchLogs.list(
1275
- resolveTenant(tenant, resolved.tenantSlug),
1276
- workflowSlug,
1277
- );
1278
- return data;
1279
- });
1280
- });
1281
-
1282
- workflows
1283
- .command('batch-log <workflow-slug> <id> [tenant]')
1284
- .description('Get a single batch log by id')
1285
- .action(async (workflowSlug: string, id: string, tenant: string | undefined) => {
1286
- await run(async () => {
1287
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1288
- const { data } = await api.workflows.batchLogs.get(
1289
- resolveTenant(tenant, resolved.tenantSlug),
1290
- workflowSlug,
1291
- id,
1292
- );
1293
- return data;
1294
- });
1295
- });
1296
-
1297
- workflows
1298
- .command('batch-log-start <workflow-slug> <id> [tenant]')
1299
- .description('Start polling a batch log')
1300
- .action(async (workflowSlug: string, id: string, tenant: string | undefined) => {
1301
- await run(async () => {
1302
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1303
- const { data } = await api.workflows.batchLogs.start(
1304
- resolveTenant(tenant, resolved.tenantSlug),
1305
- workflowSlug,
1306
- id,
1307
- );
1308
- return data;
1309
- });
1310
- });
1311
-
1312
- workflows
1313
- .command('batch-log-stop <workflow-slug> <id> [tenant]')
1314
- .description('Stop polling a batch log')
1315
- .action(async (workflowSlug: string, id: string, tenant: string | undefined) => {
1316
- await run(async () => {
1317
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1318
- const { data } = await api.workflows.batchLogs.stop(
1319
- resolveTenant(tenant, resolved.tenantSlug),
1320
- workflowSlug,
1321
- id,
1322
- );
1323
- return data;
1324
- });
1325
- });
1326
-
1327
- workflows
1328
- .command('batch-log-refresh <workflow-slug> <id> [tenant]')
1329
- .description('Force-refresh a batch log')
1330
- .action(async (workflowSlug: string, id: string, tenant: string | undefined) => {
1331
- await run(async () => {
1332
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1333
- const { data } = await api.workflows.batchLogs.refresh(
1334
- resolveTenant(tenant, resolved.tenantSlug),
1335
- workflowSlug,
1336
- id,
1337
- );
1338
- return data;
1339
- });
1340
- });
1341
-
1342
- workflows
1343
- .command('workflow-logs <workflow-slug> [tenant]')
1344
- .description('List execution logs for a workflow')
1345
- .action(async (workflowSlug: string, tenant: string | undefined) => {
1346
- await run(async () => {
1347
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1348
- const { data } = await api.workflows.workflowLogs.list(
1349
- resolveTenant(tenant, resolved.tenantSlug),
1350
- workflowSlug,
1351
- );
1352
- return data;
1353
- });
1354
- });
1355
-
1356
- workflows
1357
- .command('workflow-log <workflow-slug> <id> [tenant]')
1358
- .description('Get a single execution log by id')
1359
- .action(async (workflowSlug: string, id: string, tenant: string | undefined) => {
1360
- await run(async () => {
1361
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1362
- const { data } = await api.workflows.workflowLogs.get(
1363
- resolveTenant(tenant, resolved.tenantSlug),
1364
- workflowSlug,
1365
- id,
1366
- );
1367
- return data;
1368
- });
1369
- });
1370
-
1371
- workflows
1372
- .command('workflow-log-download <workflow-slug> <id> [tenant]')
1373
- .description('Get a presigned download URL for an execution log')
1374
- .action(async (workflowSlug: string, id: string, tenant: string | undefined) => {
1375
- await run(async () => {
1376
- const { api, resolved } = authedApi(program.opts<GlobalOpts>());
1377
- const { data } = await api.workflows.workflowLogs.download(
1378
- resolveTenant(tenant, resolved.tenantSlug),
1379
- workflowSlug,
1380
- id,
1381
- );
1382
- return data;
1383
- });
1384
- });
47
+ registerAuth(program);
48
+ registerEnv(program);
49
+ registerInit(program);
50
+ registerRaw(program);
51
+ registerResources(program);
52
+ registerWorkflows(program);
1385
53
 
1386
54
  program.parseAsync();