@alvera-ai/platform-sdk 0.5.3 → 0.7.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/README.md +34 -0
- package/package.json +10 -11
- package/src/cli.ts +1386 -0
- package/src/client.ts +930 -0
- package/src/config.ts +205 -0
- package/src/environments.generated.ts +16 -0
- package/src/generated/client/client.gen.ts +298 -0
- package/src/generated/client/index.ts +25 -0
- package/src/generated/client/types.gen.ts +214 -0
- package/src/generated/client/utils.gen.ts +316 -0
- package/{dist/generated/client.gen.d.ts → src/generated/client.gen.ts} +6 -3
- package/src/generated/core/auth.gen.ts +41 -0
- package/src/generated/core/bodySerializer.gen.ts +82 -0
- package/src/generated/core/params.gen.ts +169 -0
- package/src/generated/core/pathSerializer.gen.ts +171 -0
- package/src/generated/core/queryKeySerializer.gen.ts +117 -0
- package/src/generated/core/serverSentEvents.gen.ts +242 -0
- package/src/generated/core/types.gen.ts +104 -0
- package/src/generated/core/utils.gen.ts +140 -0
- package/src/generated/index.ts +4 -0
- package/src/generated/sdk.gen.ts +1756 -0
- package/{dist/generated/types.gen.d.ts → src/generated/types.gen.ts} +2243 -131
- package/{dist/generated/valibot.gen.js → src/generated/valibot.gen.ts} +1362 -53
- package/src/index.ts +69 -0
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -1008
- package/dist/cli.js.map +0 -1
- package/dist/client.d.ts +0 -529
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -421
- package/dist/client.js.map +0 -1
- package/dist/config.d.ts +0 -34
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -146
- package/dist/config.js.map +0 -1
- package/dist/environments.generated.d.ts +0 -21
- package/dist/environments.generated.d.ts.map +0 -1
- package/dist/environments.generated.js +0 -8
- package/dist/environments.generated.js.map +0 -1
- package/dist/generated/client/client.gen.d.ts +0 -3
- package/dist/generated/client/client.gen.d.ts.map +0 -1
- package/dist/generated/client/client.gen.js +0 -236
- package/dist/generated/client/client.gen.js.map +0 -1
- package/dist/generated/client/index.d.ts +0 -9
- package/dist/generated/client/index.d.ts.map +0 -1
- package/dist/generated/client/index.js +0 -7
- package/dist/generated/client/index.js.map +0 -1
- package/dist/generated/client/types.gen.d.ts +0 -118
- package/dist/generated/client/types.gen.d.ts.map +0 -1
- package/dist/generated/client/types.gen.js +0 -3
- package/dist/generated/client/types.gen.js.map +0 -1
- package/dist/generated/client/utils.gen.d.ts +0 -34
- package/dist/generated/client/utils.gen.d.ts.map +0 -1
- package/dist/generated/client/utils.gen.js +0 -229
- package/dist/generated/client/utils.gen.js.map +0 -1
- package/dist/generated/client.gen.d.ts.map +0 -1
- package/dist/generated/client.gen.js +0 -4
- package/dist/generated/client.gen.js.map +0 -1
- package/dist/generated/core/auth.gen.d.ts +0 -19
- package/dist/generated/core/auth.gen.d.ts.map +0 -1
- package/dist/generated/core/auth.gen.js +0 -15
- package/dist/generated/core/auth.gen.js.map +0 -1
- package/dist/generated/core/bodySerializer.gen.d.ts +0 -26
- package/dist/generated/core/bodySerializer.gen.d.ts.map +0 -1
- package/dist/generated/core/bodySerializer.gen.js +0 -58
- package/dist/generated/core/bodySerializer.gen.js.map +0 -1
- package/dist/generated/core/params.gen.d.ts +0 -44
- package/dist/generated/core/params.gen.d.ts.map +0 -1
- package/dist/generated/core/params.gen.js +0 -101
- package/dist/generated/core/params.gen.js.map +0 -1
- package/dist/generated/core/pathSerializer.gen.d.ts +0 -34
- package/dist/generated/core/pathSerializer.gen.d.ts.map +0 -1
- package/dist/generated/core/pathSerializer.gen.js +0 -107
- package/dist/generated/core/pathSerializer.gen.js.map +0 -1
- package/dist/generated/core/queryKeySerializer.gen.d.ts +0 -19
- package/dist/generated/core/queryKeySerializer.gen.d.ts.map +0 -1
- package/dist/generated/core/queryKeySerializer.gen.js +0 -93
- package/dist/generated/core/queryKeySerializer.gen.js.map +0 -1
- package/dist/generated/core/serverSentEvents.gen.d.ts +0 -72
- package/dist/generated/core/serverSentEvents.gen.d.ts.map +0 -1
- package/dist/generated/core/serverSentEvents.gen.js +0 -133
- package/dist/generated/core/serverSentEvents.gen.js.map +0 -1
- package/dist/generated/core/types.gen.d.ts +0 -79
- package/dist/generated/core/types.gen.d.ts.map +0 -1
- package/dist/generated/core/types.gen.js +0 -3
- package/dist/generated/core/types.gen.js.map +0 -1
- package/dist/generated/core/utils.gen.d.ts +0 -20
- package/dist/generated/core/utils.gen.d.ts.map +0 -1
- package/dist/generated/core/utils.gen.js +0 -88
- package/dist/generated/core/utils.gen.js.map +0 -1
- package/dist/generated/index.d.ts +0 -3
- package/dist/generated/index.d.ts.map +0 -1
- package/dist/generated/index.js +0 -3
- package/dist/generated/index.js.map +0 -1
- package/dist/generated/sdk.gen.d.ts +0 -519
- package/dist/generated/sdk.gen.d.ts.map +0 -1
- package/dist/generated/sdk.gen.js +0 -1382
- package/dist/generated/sdk.gen.js.map +0 -1
- package/dist/generated/types.gen.d.ts.map +0 -1
- package/dist/generated/types.gen.js +0 -3
- package/dist/generated/types.gen.js.map +0 -1
- package/dist/generated/valibot.gen.d.ts +0 -35016
- package/dist/generated/valibot.gen.d.ts.map +0 -1
- package/dist/generated/valibot.gen.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
package/src/cli.ts
ADDED
|
@@ -0,0 +1,1386 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { createInterface } from 'node:readline';
|
|
5
|
+
import { dirname, resolve } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { Command, Option } from 'commander';
|
|
8
|
+
import { ValiError } from 'valibot';
|
|
9
|
+
import { createPlatformApi, createSession, revokeSession } from './client.js';
|
|
10
|
+
|
|
11
|
+
const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'package.json');
|
|
12
|
+
const { version: packageVersion } = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as {
|
|
13
|
+
version: string;
|
|
14
|
+
};
|
|
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
|
+
|
|
27
|
+
const ENVIRONMENT_NAMES = Object.keys(ENVIRONMENTS);
|
|
28
|
+
|
|
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
|
+
const program = new Command();
|
|
144
|
+
program
|
|
145
|
+
.name('alvera')
|
|
146
|
+
.description('Alvera platform CLI')
|
|
147
|
+
.version(packageVersion, '-v, --version', 'print the installed version')
|
|
148
|
+
.addOption(new Option('--profile <name>', 'config profile to use').default('default'))
|
|
149
|
+
.addOption(
|
|
150
|
+
new Option(
|
|
151
|
+
'--env <name>',
|
|
152
|
+
`environment from spec/openapi.yaml (${ENVIRONMENT_NAMES.join(', ')})`,
|
|
153
|
+
),
|
|
154
|
+
)
|
|
155
|
+
.showHelpAfterError()
|
|
156
|
+
.hook('preAction', (thisCommand) => {
|
|
157
|
+
const env = thisCommand.optsWithGlobals<GlobalOpts>().env;
|
|
158
|
+
if (env !== undefined) process.env.ALVERA_ENV = env;
|
|
159
|
+
const candidate = process.env.ALVERA_ENV;
|
|
160
|
+
if (candidate !== undefined && !ENVIRONMENT_NAMES.includes(candidate)) {
|
|
161
|
+
die(
|
|
162
|
+
`unknown environment "${candidate}". Valid: ${ENVIRONMENT_NAMES.join(', ')}`,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
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
|
+
});
|
|
1385
|
+
|
|
1386
|
+
program.parseAsync();
|