@darwinso/cli 0.1.0 → 0.3.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 +36 -16
- package/dist/index.js +1044 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
2
3
|
import { chmod, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
4
|
import { homedir } from 'node:os';
|
|
4
5
|
import { dirname, join } from 'node:path';
|
|
@@ -42,7 +43,11 @@ async function request(apiKey, baseUrl, path, options = {}) {
|
|
|
42
43
|
headers: {
|
|
43
44
|
Accept: 'application/json',
|
|
44
45
|
Authorization: `Bearer ${apiKey}`,
|
|
46
|
+
'X-Darwin-Access-Point': 'cli',
|
|
47
|
+
'X-Darwin-Client': '@darwinso/cli',
|
|
48
|
+
'X-Darwin-Client-Version': '0.3.0',
|
|
45
49
|
...(options.body === undefined ? {} : { 'Content-Type': 'application/json' }),
|
|
50
|
+
...options.headers,
|
|
46
51
|
},
|
|
47
52
|
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
|
48
53
|
});
|
|
@@ -82,6 +87,30 @@ function integerOption(args, name) {
|
|
|
82
87
|
}
|
|
83
88
|
return parsed;
|
|
84
89
|
}
|
|
90
|
+
function repeatedOption(args, name) {
|
|
91
|
+
const values = [];
|
|
92
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
93
|
+
if (args[index] !== name)
|
|
94
|
+
continue;
|
|
95
|
+
const value = args[index + 1];
|
|
96
|
+
if (!value || value.startsWith('--')) {
|
|
97
|
+
throw new Error(`${name} requires a value.`);
|
|
98
|
+
}
|
|
99
|
+
values.push(value);
|
|
100
|
+
index += 1;
|
|
101
|
+
}
|
|
102
|
+
return values;
|
|
103
|
+
}
|
|
104
|
+
function booleanOption(args, name) {
|
|
105
|
+
const value = option(args, name);
|
|
106
|
+
if (value === undefined)
|
|
107
|
+
return undefined;
|
|
108
|
+
if (value === 'true')
|
|
109
|
+
return true;
|
|
110
|
+
if (value === 'false')
|
|
111
|
+
return false;
|
|
112
|
+
throw new Error(`${name} must be true or false.`);
|
|
113
|
+
}
|
|
85
114
|
function jsonObjectOption(args, name) {
|
|
86
115
|
const value = option(args, name);
|
|
87
116
|
if (!value)
|
|
@@ -98,6 +127,114 @@ function jsonObjectOption(args, name) {
|
|
|
98
127
|
}
|
|
99
128
|
return parsed;
|
|
100
129
|
}
|
|
130
|
+
async function jsonObjectFileOption(args, name) {
|
|
131
|
+
const path = option(args, name);
|
|
132
|
+
if (!path)
|
|
133
|
+
return undefined;
|
|
134
|
+
let parsed;
|
|
135
|
+
try {
|
|
136
|
+
parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
throw new Error(`${name} must reference a readable JSON file.`);
|
|
140
|
+
}
|
|
141
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
142
|
+
throw new Error(`${name} must contain a JSON object.`);
|
|
143
|
+
}
|
|
144
|
+
return parsed;
|
|
145
|
+
}
|
|
146
|
+
function jsonArrayOption(args, name) {
|
|
147
|
+
const value = option(args, name);
|
|
148
|
+
if (!value)
|
|
149
|
+
return [];
|
|
150
|
+
let parsed;
|
|
151
|
+
try {
|
|
152
|
+
parsed = JSON.parse(value);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
throw new Error(`${name} must be valid JSON.`);
|
|
156
|
+
}
|
|
157
|
+
if (!Array.isArray(parsed)) {
|
|
158
|
+
throw new Error(`${name} must be a JSON array.`);
|
|
159
|
+
}
|
|
160
|
+
return parsed;
|
|
161
|
+
}
|
|
162
|
+
function dataOption(args) {
|
|
163
|
+
return args.includes('--data') ? jsonObjectOption(args, '--data') : {};
|
|
164
|
+
}
|
|
165
|
+
function requiredOption(args, name) {
|
|
166
|
+
const value = option(args, name)?.trim();
|
|
167
|
+
if (!value) {
|
|
168
|
+
throw new Error(`${name} is required.`);
|
|
169
|
+
}
|
|
170
|
+
return value;
|
|
171
|
+
}
|
|
172
|
+
function enumOption(args, name, values) {
|
|
173
|
+
const value = option(args, name);
|
|
174
|
+
if (value === undefined)
|
|
175
|
+
return undefined;
|
|
176
|
+
const normalized = value.toUpperCase();
|
|
177
|
+
if (!values.includes(normalized)) {
|
|
178
|
+
throw new Error(`${name} must be one of: ${values.join(', ')}.`);
|
|
179
|
+
}
|
|
180
|
+
return normalized;
|
|
181
|
+
}
|
|
182
|
+
function lowerEnumOption(args, name, values) {
|
|
183
|
+
const value = option(args, name);
|
|
184
|
+
if (value === undefined)
|
|
185
|
+
return undefined;
|
|
186
|
+
const normalized = value.toLowerCase();
|
|
187
|
+
if (!values.includes(normalized)) {
|
|
188
|
+
throw new Error(`${name} must be one of: ${values.join(', ')}.`);
|
|
189
|
+
}
|
|
190
|
+
return normalized;
|
|
191
|
+
}
|
|
192
|
+
function withOptionalString(body, key, value) {
|
|
193
|
+
if (value !== undefined)
|
|
194
|
+
body[key] = value;
|
|
195
|
+
}
|
|
196
|
+
function idempotencyHeaders(args) {
|
|
197
|
+
const supplied = option(args, '--idempotency-key')?.trim();
|
|
198
|
+
if (supplied && supplied.length > 200) {
|
|
199
|
+
throw new Error('--idempotency-key must be at most 200 characters.');
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
'Idempotency-Key': supplied || randomUUID(),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function id(value, usage) {
|
|
206
|
+
const normalized = value?.trim();
|
|
207
|
+
if (!normalized) {
|
|
208
|
+
throw new Error(usage);
|
|
209
|
+
}
|
|
210
|
+
return encodeURIComponent(normalized);
|
|
211
|
+
}
|
|
212
|
+
function textArgument(args, start, valueOptions) {
|
|
213
|
+
const options = new Set(valueOptions);
|
|
214
|
+
const words = [];
|
|
215
|
+
for (let index = start; index < args.length; index += 1) {
|
|
216
|
+
const value = args[index];
|
|
217
|
+
if (!value)
|
|
218
|
+
continue;
|
|
219
|
+
if (options.has(value)) {
|
|
220
|
+
index += 1;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (value.startsWith('--')) {
|
|
224
|
+
throw new Error(`Unknown option: ${value}`);
|
|
225
|
+
}
|
|
226
|
+
words.push(value);
|
|
227
|
+
}
|
|
228
|
+
return words.join(' ').trim();
|
|
229
|
+
}
|
|
230
|
+
function aiQuery(args) {
|
|
231
|
+
return { aiId: option(args, '--ai') };
|
|
232
|
+
}
|
|
233
|
+
function mergeFields(body, fields) {
|
|
234
|
+
for (const [key, value] of fields)
|
|
235
|
+
withOptionalString(body, key, value);
|
|
236
|
+
return body;
|
|
237
|
+
}
|
|
101
238
|
function redact(value) {
|
|
102
239
|
if (!value)
|
|
103
240
|
return null;
|
|
@@ -145,27 +282,73 @@ Usage:
|
|
|
145
282
|
darwin configure --api-key <key> [--base-url <url>]
|
|
146
283
|
darwin config show
|
|
147
284
|
darwin logout
|
|
148
|
-
darwin
|
|
149
|
-
darwin
|
|
150
|
-
darwin
|
|
151
|
-
darwin
|
|
152
|
-
darwin
|
|
153
|
-
darwin
|
|
154
|
-
darwin
|
|
155
|
-
darwin
|
|
156
|
-
darwin
|
|
157
|
-
darwin
|
|
285
|
+
darwin account show
|
|
286
|
+
darwin ais <list|get|create|update|activity> [...]
|
|
287
|
+
darwin ais skills
|
|
288
|
+
darwin ais integrations
|
|
289
|
+
darwin requests <list|action> [...]
|
|
290
|
+
darwin conversations <send|list|create|get|message> [...]
|
|
291
|
+
darwin goals <list|get|create|update|action|publish> [...]
|
|
292
|
+
darwin deals <list|get|create|update|action|payments> [...]
|
|
293
|
+
darwin transactions <list|get|action> [...]
|
|
294
|
+
darwin outcomes <list|get|evidence> [...]
|
|
295
|
+
darwin supply businesses <list|get|create|update> [...]
|
|
296
|
+
darwin supply listings <list|get|create|update|archive> [...]
|
|
297
|
+
darwin supply orders <list|get> [...]
|
|
298
|
+
darwin supply earnings get <business-id>
|
|
299
|
+
darwin connect applications <list|get|create|update|archive> [...]
|
|
300
|
+
darwin connect users resolve <application-id> --external-ref <reference> [...]
|
|
301
|
+
darwin connect enrollment <list|create|revoke> [...]
|
|
302
|
+
darwin connect webhooks <list|create|revoke|deliveries|retry> [...]
|
|
158
303
|
|
|
159
304
|
Options:
|
|
305
|
+
--ai <id> Explicitly target an accessible AI
|
|
306
|
+
--data <json> Supply or extend a JSON request body
|
|
160
307
|
-h, --help Show help
|
|
161
308
|
-v, --version Show the installed version
|
|
162
309
|
|
|
163
310
|
Set DARWIN_API_KEY and optionally DARWIN_API_URL instead of storing local
|
|
164
311
|
configuration when running in CI.
|
|
312
|
+
|
|
313
|
+
Run "darwin <resource> --help" for examples in the documentation:
|
|
314
|
+
https://docs.darwin.so/cli
|
|
165
315
|
`);
|
|
166
316
|
}
|
|
167
317
|
async function main() {
|
|
168
|
-
|
|
318
|
+
let args = process.argv.slice(2);
|
|
319
|
+
if (args[0] === 'agents')
|
|
320
|
+
args[0] = 'ais';
|
|
321
|
+
if (args[0] === 'agent')
|
|
322
|
+
args[0] = 'ai';
|
|
323
|
+
if ((args[0] === 'connect' || args[0] === 'applications') && args[1] === 'agents')
|
|
324
|
+
args[1] = 'ais';
|
|
325
|
+
if ((args[0] === 'connect' || args[0] === 'applications') && args[1] === 'link-agent')
|
|
326
|
+
args[1] = 'link-ai';
|
|
327
|
+
if ((args[0] === 'connect' || args[0] === 'applications') && args[1] === 'unlink-agent')
|
|
328
|
+
args[1] = 'unlink-ai';
|
|
329
|
+
args = args.map((value) => (value === '--agent' ? '--ai' : value === '--exclude-agent' ? '--exclude-ai' : value));
|
|
330
|
+
if (args[0] === 'connect' && args[1] === 'applications') {
|
|
331
|
+
args = ['connect', args[2] ?? 'list', ...args.slice(3)];
|
|
332
|
+
}
|
|
333
|
+
else if (args[0] === 'connect' && args[1] === 'users' && args[2] === 'resolve') {
|
|
334
|
+
args = ['connect', 'resolve-user', ...args.slice(3)];
|
|
335
|
+
}
|
|
336
|
+
else if (args[0] === 'connect' && args[1] === 'enrollment') {
|
|
337
|
+
const operation = args[2] === 'create' ? 'create-enrollment' : args[2] === 'revoke' ? 'revoke-enrollment' : 'enrollments';
|
|
338
|
+
args = ['connect', operation, ...args.slice(3)];
|
|
339
|
+
}
|
|
340
|
+
else if (args[0] === 'connect' && args[1] === 'webhooks') {
|
|
341
|
+
const operation = args[2] === 'create'
|
|
342
|
+
? 'create-webhook'
|
|
343
|
+
: args[2] === 'revoke'
|
|
344
|
+
? 'revoke-webhook'
|
|
345
|
+
: args[2] === 'deliveries'
|
|
346
|
+
? 'webhook-deliveries'
|
|
347
|
+
: args[2] === 'retry'
|
|
348
|
+
? 'retry-webhook'
|
|
349
|
+
: 'webhooks';
|
|
350
|
+
args = ['connect', operation, ...args.slice(3)];
|
|
351
|
+
}
|
|
169
352
|
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
|
170
353
|
help();
|
|
171
354
|
return;
|
|
@@ -186,84 +369,880 @@ async function main() {
|
|
|
186
369
|
await logout();
|
|
187
370
|
return;
|
|
188
371
|
}
|
|
372
|
+
if (args[0] === 'account' && args[1] === 'show') {
|
|
373
|
+
args = ['account'];
|
|
374
|
+
}
|
|
189
375
|
const auth = await credentials();
|
|
190
376
|
if (!auth.apiKey) {
|
|
191
377
|
throw new Error('No API key found. Run darwin configure --api-key <key> or set DARWIN_API_KEY.');
|
|
192
378
|
}
|
|
193
|
-
const resource = args[0];
|
|
194
|
-
const operation = args[1];
|
|
379
|
+
const resource = args[0] === 'applications' ? 'connect' : args[0];
|
|
380
|
+
const operation = resource === 'connect' && args[1] === 'disconnect' ? 'archive' : args[1];
|
|
195
381
|
let result;
|
|
196
|
-
if (resource === '
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
382
|
+
if (resource === 'account') {
|
|
383
|
+
result = await request(auth.apiKey, auth.baseUrl, '/account');
|
|
384
|
+
}
|
|
385
|
+
else if (resource === 'ais' && operation === 'skills') {
|
|
386
|
+
result = await request(auth.apiKey, auth.baseUrl, '/account/skills');
|
|
387
|
+
}
|
|
388
|
+
else if (resource === 'ais' && operation === 'integrations') {
|
|
389
|
+
result = await request(auth.apiKey, auth.baseUrl, '/integrations');
|
|
390
|
+
}
|
|
391
|
+
else if (resource === 'requests' && operation === 'list') {
|
|
392
|
+
result = await request(auth.apiKey, auth.baseUrl, '/requests', {
|
|
393
|
+
query: {
|
|
394
|
+
...aiQuery(args),
|
|
395
|
+
limit: integerOption(args, '--limit'),
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
else if (resource === 'requests' && operation === 'action') {
|
|
400
|
+
const action = args[3]?.toUpperCase();
|
|
401
|
+
if (action !== 'ACCEPT' && action !== 'DECLINE') {
|
|
402
|
+
throw new Error('Request action must be accept or decline.');
|
|
403
|
+
}
|
|
404
|
+
result = await request(auth.apiKey, auth.baseUrl, `/requests/${id(args[2], 'Pass a request ID after "darwin requests action".')}/actions`, {
|
|
405
|
+
method: 'POST',
|
|
406
|
+
body: {
|
|
407
|
+
action,
|
|
408
|
+
...(option(args, '--ai') ? { aiId: option(args, '--ai') } : {}),
|
|
409
|
+
},
|
|
410
|
+
headers: idempotencyHeaders(args),
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
else if ((resource === 'ai' && operation === 'message') || (resource === 'conversations' && operation === 'send')) {
|
|
414
|
+
const content = textArgument(args, 2, ['--ai', '--request-id']);
|
|
200
415
|
if (!content) {
|
|
201
|
-
throw new Error('Pass a message after "darwin
|
|
416
|
+
throw new Error('Pass a message after "darwin conversations send".');
|
|
202
417
|
}
|
|
203
|
-
result = await request(auth.apiKey, auth.baseUrl, '/
|
|
418
|
+
result = await request(auth.apiKey, auth.baseUrl, '/ai/messages', {
|
|
204
419
|
method: 'POST',
|
|
205
420
|
body: {
|
|
206
421
|
content,
|
|
422
|
+
aiId: option(args, '--ai'),
|
|
207
423
|
requestId: option(args, '--request-id'),
|
|
208
424
|
},
|
|
209
425
|
});
|
|
210
426
|
}
|
|
211
427
|
else if (resource === 'conversation') {
|
|
212
|
-
result = await request(auth.apiKey, auth.baseUrl, '/
|
|
428
|
+
result = await request(auth.apiKey, auth.baseUrl, '/ai/conversation', {
|
|
213
429
|
query: {
|
|
430
|
+
...aiQuery(args),
|
|
214
431
|
limit: integerOption(args, '--limit'),
|
|
215
432
|
cursor: option(args, '--cursor'),
|
|
216
433
|
},
|
|
217
434
|
});
|
|
218
435
|
}
|
|
219
|
-
else if (resource === '
|
|
220
|
-
result = await request(auth.apiKey, auth.baseUrl, '/
|
|
436
|
+
else if (resource === 'ais' && operation === 'list') {
|
|
437
|
+
result = await request(auth.apiKey, auth.baseUrl, '/ais');
|
|
438
|
+
}
|
|
439
|
+
else if (resource === 'ais' && operation === 'get') {
|
|
440
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID after "darwin ais get".')}`);
|
|
221
441
|
}
|
|
222
|
-
else if (resource === '
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
442
|
+
else if (resource === 'ais' && operation === 'create') {
|
|
443
|
+
const body = mergeFields(dataOption(args), [
|
|
444
|
+
['name', option(args, '--name')],
|
|
445
|
+
['handle', option(args, '--handle')],
|
|
446
|
+
['avatarUrl', option(args, '--avatar-url')],
|
|
447
|
+
['description', option(args, '--description')],
|
|
448
|
+
['visibility', enumOption(args, '--visibility', ['PUBLIC', 'RESTRICTED', 'PRIVATE'])],
|
|
449
|
+
]);
|
|
450
|
+
if (typeof body.name !== 'string' || !body.name.trim()) {
|
|
451
|
+
throw new Error('Pass an AI name with --name or in --data.');
|
|
226
452
|
}
|
|
227
|
-
result = await request(auth.apiKey, auth.baseUrl,
|
|
453
|
+
result = await request(auth.apiKey, auth.baseUrl, '/ais', { method: 'POST', body });
|
|
228
454
|
}
|
|
229
|
-
else if (resource === '
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
455
|
+
else if (resource === 'ais' && operation === 'update') {
|
|
456
|
+
const body = mergeFields(dataOption(args), [
|
|
457
|
+
['name', option(args, '--name')],
|
|
458
|
+
['handle', option(args, '--handle')],
|
|
459
|
+
['avatarUrl', option(args, '--avatar-url')],
|
|
460
|
+
['description', option(args, '--description')],
|
|
461
|
+
['visibility', enumOption(args, '--visibility', ['PUBLIC', 'RESTRICTED', 'PRIVATE'])],
|
|
462
|
+
]);
|
|
463
|
+
if (Object.keys(body).length === 0) {
|
|
464
|
+
throw new Error('Pass at least one editable field or --data.');
|
|
233
465
|
}
|
|
234
|
-
result = await request(auth.apiKey, auth.baseUrl, '
|
|
466
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID after "darwin ais update".')}`, { method: 'PATCH', body });
|
|
467
|
+
}
|
|
468
|
+
else if (resource === 'ais' && operation === 'activity') {
|
|
469
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID after "darwin ais activity".')}/activity`, {
|
|
470
|
+
query: {
|
|
471
|
+
limit: integerOption(args, '--limit'),
|
|
472
|
+
cursor: option(args, '--cursor'),
|
|
473
|
+
},
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
else if (resource === 'ais' && operation === 'members') {
|
|
477
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID after "darwin ais members".')}/members`);
|
|
478
|
+
}
|
|
479
|
+
else if (resource === 'ais' && operation === 'invite') {
|
|
480
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID after "darwin ais invite".')}/invitations`, {
|
|
235
481
|
method: 'POST',
|
|
236
482
|
body: {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
483
|
+
email: requiredOption(args, '--email'),
|
|
484
|
+
role: option(args, '--role'),
|
|
485
|
+
},
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
else if (resource === 'ais' && operation === 'invitations') {
|
|
489
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID after "darwin ais invitations".')}/invitations`);
|
|
490
|
+
}
|
|
491
|
+
else if (resource === 'ais' && operation === 'revoke-invitation') {
|
|
492
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID.')}/invitations/${id(args[3], 'Pass an invitation ID.')}`, { method: 'DELETE' });
|
|
493
|
+
}
|
|
494
|
+
else if (resource === 'ais' && operation === 'update-member') {
|
|
495
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID.')}/members/${id(args[3], 'Pass a membership ID.')}`, {
|
|
496
|
+
method: 'PATCH',
|
|
497
|
+
body: { role: requiredOption(args, '--role') },
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
else if (resource === 'ais' && operation === 'remove-member') {
|
|
501
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID.')}/members/${id(args[3], 'Pass a membership ID.')}`, { method: 'DELETE' });
|
|
502
|
+
}
|
|
503
|
+
else if (resource === 'ais' && operation === 'policies') {
|
|
504
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID after "darwin ais policies".')}/access-policies`);
|
|
505
|
+
}
|
|
506
|
+
else if (resource === 'ais' && operation === 'create-policy') {
|
|
507
|
+
const body = mergeFields(dataOption(args), [
|
|
508
|
+
['name', option(args, '--name')],
|
|
509
|
+
['visibility', enumOption(args, '--visibility', ['PUBLIC', 'RESTRICTED', 'PRIVATE'])],
|
|
510
|
+
['naturalLanguage', option(args, '--natural-language')],
|
|
511
|
+
]);
|
|
512
|
+
if (typeof body.name !== 'string' || typeof body.visibility !== 'string') {
|
|
513
|
+
throw new Error('Pass --name and --visibility, or provide both in --data.');
|
|
514
|
+
}
|
|
515
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID.')}/access-policies`, {
|
|
516
|
+
method: 'POST',
|
|
517
|
+
body,
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
else if (resource === 'ais' && operation === 'update-policy') {
|
|
521
|
+
const body = mergeFields(dataOption(args), [
|
|
522
|
+
['name', option(args, '--name')],
|
|
523
|
+
['visibility', enumOption(args, '--visibility', ['PUBLIC', 'RESTRICTED', 'PRIVATE'])],
|
|
524
|
+
['naturalLanguage', option(args, '--natural-language')],
|
|
525
|
+
]);
|
|
526
|
+
if (Object.keys(body).length === 0)
|
|
527
|
+
throw new Error('Pass editable policy fields or --data.');
|
|
528
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID.')}/access-policies/${id(args[3], 'Pass a policy ID.')}`, { method: 'PATCH', body });
|
|
529
|
+
}
|
|
530
|
+
else if (resource === 'ais' && operation === 'conversations') {
|
|
531
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID after "darwin ais conversations".')}/conversations`);
|
|
532
|
+
}
|
|
533
|
+
else if (resource === 'ais' && operation === 'create-conversation') {
|
|
534
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[2], 'Pass an AI ID after "darwin ais create-conversation".')}/conversations`, { method: 'POST' });
|
|
535
|
+
}
|
|
536
|
+
else if (resource === 'conversations' && operation === 'get') {
|
|
537
|
+
result = await request(auth.apiKey, auth.baseUrl, `/conversations/${id(args[2], 'Pass a conversation ID after "darwin conversations get".')}`, {
|
|
538
|
+
query: {
|
|
539
|
+
limit: integerOption(args, '--limit'),
|
|
540
|
+
cursor: option(args, '--cursor'),
|
|
240
541
|
},
|
|
241
542
|
});
|
|
242
543
|
}
|
|
243
|
-
else if (resource === '
|
|
244
|
-
|
|
245
|
-
|
|
544
|
+
else if (resource === 'conversations' && operation === 'message') {
|
|
545
|
+
const content = textArgument(args, 3, ['--request-id']);
|
|
546
|
+
if (!content)
|
|
547
|
+
throw new Error('Pass message text after the conversation ID.');
|
|
548
|
+
result = await request(auth.apiKey, auth.baseUrl, `/conversations/${id(args[2], 'Pass a conversation ID.')}/messages`, {
|
|
549
|
+
method: 'POST',
|
|
550
|
+
body: { content, requestId: option(args, '--request-id') },
|
|
246
551
|
});
|
|
247
552
|
}
|
|
248
|
-
else if (resource === '
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
553
|
+
else if (resource === 'conversations' && (operation === 'list' || operation === 'create')) {
|
|
554
|
+
const path = `/ais/${id(args[2], `Pass an AI ID after "darwin conversations ${operation}".`)}/conversations`;
|
|
555
|
+
result = await request(auth.apiKey, auth.baseUrl, path, {
|
|
556
|
+
method: operation === 'create' ? 'POST' : 'GET',
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
else if ((resource === 'tasks' || resource === 'goals') && operation === 'list') {
|
|
560
|
+
result = await request(auth.apiKey, auth.baseUrl, `/${resource}`, {
|
|
561
|
+
query: {
|
|
562
|
+
...aiQuery(args),
|
|
563
|
+
mode: enumOption(args, '--mode', ['BUY', 'SELL', 'CHAT']),
|
|
564
|
+
},
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
else if ((resource === 'tasks' || resource === 'goals') && operation === 'get') {
|
|
568
|
+
result = await request(auth.apiKey, auth.baseUrl, `/${resource}/${id(args[2], `Pass a goal ID after "darwin ${resource} get".`)}`, { query: aiQuery(args) });
|
|
569
|
+
}
|
|
570
|
+
else if ((resource === 'tasks' || resource === 'goals') && operation === 'create') {
|
|
571
|
+
const body = mergeFields(dataOption(args), [
|
|
572
|
+
['aiId', option(args, '--ai')],
|
|
573
|
+
['intent', option(args, '--intent')],
|
|
574
|
+
['title', option(args, '--title')],
|
|
575
|
+
['kind', option(args, '--kind')?.toUpperCase()],
|
|
576
|
+
['mode', enumOption(args, '--mode', ['BUY', 'SELL', 'CHAT'])],
|
|
577
|
+
['type', enumOption(args, '--type', ['DEMAND', 'SUPPLY', 'CHAT'])],
|
|
578
|
+
['lifecycleStatus', enumOption(args, '--status', ['DRAFT', 'ACTIVE', 'PAUSED', 'COMPLETED', 'ARCHIVED'])],
|
|
579
|
+
['visibility', enumOption(args, '--visibility', ['PUBLIC', 'RESTRICTED', 'PRIVATE'])],
|
|
580
|
+
]);
|
|
581
|
+
if (typeof body.intent !== 'string' || !body.intent.trim()) {
|
|
582
|
+
throw new Error('Pass a goal intent with --intent or in --data.');
|
|
252
583
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
584
|
+
result = await request(auth.apiKey, auth.baseUrl, `/${resource}`, {
|
|
585
|
+
method: 'POST',
|
|
586
|
+
body,
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
else if ((resource === 'tasks' || resource === 'goals') && operation === 'update') {
|
|
590
|
+
const body = mergeFields(dataOption(args), [
|
|
591
|
+
['intent', option(args, '--intent')],
|
|
592
|
+
['title', option(args, '--title')],
|
|
593
|
+
['mode', enumOption(args, '--mode', ['BUY', 'SELL', 'CHAT'])],
|
|
594
|
+
['type', enumOption(args, '--type', ['DEMAND', 'SUPPLY', 'CHAT'])],
|
|
595
|
+
['lifecycleStatus', enumOption(args, '--status', ['DRAFT', 'ACTIVE', 'PAUSED', 'COMPLETED', 'ARCHIVED'])],
|
|
596
|
+
['visibility', enumOption(args, '--visibility', ['PUBLIC', 'RESTRICTED', 'PRIVATE'])],
|
|
597
|
+
['pausedUntil', option(args, '--paused-until')],
|
|
598
|
+
]);
|
|
599
|
+
if (Object.keys(body).length === 0)
|
|
600
|
+
throw new Error('Pass editable goal fields or --data.');
|
|
601
|
+
result = await request(auth.apiKey, auth.baseUrl, `/${resource}/${id(args[2], `Pass a goal ID after "darwin ${resource} update".`)}`, { method: 'PATCH', body });
|
|
602
|
+
}
|
|
603
|
+
else if ((resource === 'tasks' || resource === 'goals') && operation === 'action') {
|
|
604
|
+
const action = args[3]?.toUpperCase();
|
|
605
|
+
if (!action || !['PAUSE', 'RESUME', 'COMPLETE', 'ARCHIVE'].includes(action)) {
|
|
606
|
+
throw new Error('Action must be pause, resume, complete, or archive.');
|
|
256
607
|
}
|
|
257
|
-
result = await request(auth.apiKey, auth.baseUrl,
|
|
608
|
+
result = await request(auth.apiKey, auth.baseUrl, `/${resource}/${id(args[2], `Pass a goal ID after "darwin ${resource} action".`)}/actions`, {
|
|
609
|
+
method: 'POST',
|
|
610
|
+
body: { action, pausedUntil: option(args, '--paused-until') },
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
else if ((resource === 'tasks' || resource === 'goals') && operation === 'publish') {
|
|
614
|
+
result = await request(auth.apiKey, auth.baseUrl, `/${resource}/${id(args[2], `Pass a goal ID after "darwin ${resource} publish".`)}/publication-requests`, { method: 'POST', body: dataOption(args) });
|
|
615
|
+
}
|
|
616
|
+
else if (resource === 'deals' && operation === 'list') {
|
|
617
|
+
result = await request(auth.apiKey, auth.baseUrl, '/deals', { query: aiQuery(args) });
|
|
618
|
+
}
|
|
619
|
+
else if (resource === 'deals' && operation === 'get') {
|
|
620
|
+
result = await request(auth.apiKey, auth.baseUrl, `/deals/${id(args[2], 'Pass a deal ID after "darwin deals get".')}`);
|
|
621
|
+
}
|
|
622
|
+
else if (resource === 'deals' && operation === 'create') {
|
|
623
|
+
const body = mergeFields(dataOption(args), [
|
|
624
|
+
['aiId', option(args, '--ai')],
|
|
625
|
+
['mode', enumOption(args, '--mode', ['BUY', 'SELL'])],
|
|
626
|
+
['direction', enumOption(args, '--direction', ['DEMAND', 'SUPPLY'])],
|
|
627
|
+
['title', option(args, '--title')],
|
|
628
|
+
['goalId', option(args, '--goal')],
|
|
629
|
+
['taskId', option(args, '--task')],
|
|
630
|
+
['visibility', enumOption(args, '--visibility', ['PUBLIC', 'RESTRICTED', 'PRIVATE'])],
|
|
631
|
+
]);
|
|
632
|
+
if ((typeof body.mode !== 'string' && typeof body.direction !== 'string') || typeof body.title !== 'string') {
|
|
633
|
+
throw new Error('Pass --mode and --title, or provide both in --data. --direction remains a deprecated alias.');
|
|
634
|
+
}
|
|
635
|
+
result = await request(auth.apiKey, auth.baseUrl, '/deals', { method: 'POST', body });
|
|
636
|
+
}
|
|
637
|
+
else if (resource === 'deals' && operation === 'update') {
|
|
638
|
+
const body = mergeFields(dataOption(args), [
|
|
639
|
+
['title', option(args, '--title')],
|
|
640
|
+
['visibility', enumOption(args, '--visibility', ['PUBLIC', 'RESTRICTED', 'PRIVATE'])],
|
|
641
|
+
]);
|
|
642
|
+
if (Object.keys(body).length === 0)
|
|
643
|
+
throw new Error('Pass editable deal fields or --data.');
|
|
644
|
+
result = await request(auth.apiKey, auth.baseUrl, `/deals/${id(args[2], 'Pass a deal ID after "darwin deals update".')}`, { method: 'PATCH', body });
|
|
645
|
+
}
|
|
646
|
+
else if (resource === 'deals' && operation === 'action') {
|
|
647
|
+
const action = args[3]?.toUpperCase();
|
|
648
|
+
if (!action || !['SEND', 'ACCEPT', 'REJECT', 'WITHDRAW'].includes(action)) {
|
|
649
|
+
throw new Error('Action must be send, accept, reject, or withdraw.');
|
|
650
|
+
}
|
|
651
|
+
result = await request(auth.apiKey, auth.baseUrl, `/deals/${id(args[2], 'Pass a deal ID after "darwin deals action".')}/actions`, { method: 'POST', body: { action } });
|
|
652
|
+
}
|
|
653
|
+
else if (resource === 'deals' && operation === 'payments') {
|
|
654
|
+
result = await request(auth.apiKey, auth.baseUrl, `/deals/${id(args[2], 'Pass a deal ID after "darwin deals payments".')}/payments`);
|
|
655
|
+
}
|
|
656
|
+
else if (resource === 'transactions' && operation === 'list') {
|
|
657
|
+
result = await request(auth.apiKey, auth.baseUrl, '/transactions', { query: aiQuery(args) });
|
|
658
|
+
}
|
|
659
|
+
else if (resource === 'transactions' && operation === 'get') {
|
|
660
|
+
result = await request(auth.apiKey, auth.baseUrl, `/transactions/${id(args[2], 'Pass a transaction ID after "darwin transactions get".')}`, { query: aiQuery(args) });
|
|
661
|
+
}
|
|
662
|
+
else if (resource === 'transactions' && operation === 'action') {
|
|
663
|
+
const action = args[3]?.toUpperCase();
|
|
664
|
+
if (!action || !['CANCEL', 'REQUEST_REFUND'].includes(action)) {
|
|
665
|
+
throw new Error('Transaction action must be cancel or request_refund.');
|
|
666
|
+
}
|
|
667
|
+
const body = mergeFields(dataOption(args), [
|
|
668
|
+
['action', action],
|
|
669
|
+
['amountMinor', integerOption(args, '--amount-minor')],
|
|
670
|
+
]);
|
|
671
|
+
result = await request(auth.apiKey, auth.baseUrl, `/transactions/${id(args[2], 'Pass a transaction ID after "darwin transactions action".')}/actions`, { method: 'POST', body, headers: idempotencyHeaders(args) });
|
|
672
|
+
}
|
|
673
|
+
else if (resource === 'outcomes' && operation === 'list') {
|
|
674
|
+
result = await request(auth.apiKey, auth.baseUrl, '/outcomes', { query: aiQuery(args) });
|
|
675
|
+
}
|
|
676
|
+
else if (resource === 'outcomes' && operation === 'get') {
|
|
677
|
+
result = await request(auth.apiKey, auth.baseUrl, `/outcomes/${id(args[2], 'Pass an outcome ID after "darwin outcomes get".')}`);
|
|
678
|
+
}
|
|
679
|
+
else if (resource === 'outcomes' && operation === 'evidence') {
|
|
680
|
+
const body = mergeFields(dataOption(args), [
|
|
681
|
+
['evidenceDigest', option(args, '--digest')],
|
|
682
|
+
['signedReference', option(args, '--signed-reference')],
|
|
683
|
+
['dealId', option(args, '--deal')],
|
|
684
|
+
]);
|
|
685
|
+
if (typeof body.evidenceDigest !== 'string')
|
|
686
|
+
throw new Error('Pass --digest or evidenceDigest in --data.');
|
|
687
|
+
result = await request(auth.apiKey, auth.baseUrl, `/outcomes/${id(args[2], 'Pass an outcome ID after "darwin outcomes evidence".')}/evidence`, { method: 'POST', body, headers: idempotencyHeaders(args) });
|
|
688
|
+
}
|
|
689
|
+
else if (resource === 'sessions' && operation === 'list') {
|
|
690
|
+
result = await request(auth.apiKey, auth.baseUrl, '/sessions', {
|
|
691
|
+
query: {
|
|
692
|
+
aiId: option(args, '--ai'),
|
|
693
|
+
status: lowerEnumOption(args, '--status', [
|
|
694
|
+
'pending_provider',
|
|
695
|
+
'planning',
|
|
696
|
+
'active',
|
|
697
|
+
'completed',
|
|
698
|
+
'canceled',
|
|
699
|
+
'failed',
|
|
700
|
+
]),
|
|
701
|
+
limit: integerOption(args, '--limit'),
|
|
702
|
+
cursor: option(args, '--cursor'),
|
|
703
|
+
},
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
else if (resource === 'sessions' && operation === 'invitations') {
|
|
707
|
+
result = await request(auth.apiKey, auth.baseUrl, '/session-invitations', {
|
|
708
|
+
query: {
|
|
709
|
+
aiId: option(args, '--ai'),
|
|
710
|
+
limit: integerOption(args, '--limit'),
|
|
711
|
+
},
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
else if (resource === 'sessions' && operation === 'invitation') {
|
|
715
|
+
const action = args[3]?.toLowerCase();
|
|
716
|
+
if (action !== 'accept' && action !== 'decline') {
|
|
717
|
+
throw new Error('Session invitation action must be accept or decline.');
|
|
718
|
+
}
|
|
719
|
+
result = await request(auth.apiKey, auth.baseUrl, `/session-invitations/${id(args[2], 'Pass an invitation ID after "darwin sessions invitation".')}/actions`, {
|
|
258
720
|
method: 'POST',
|
|
259
721
|
body: {
|
|
260
|
-
|
|
261
|
-
|
|
722
|
+
action,
|
|
723
|
+
...(option(args, '--ai') ? { aiId: option(args, '--ai') } : {}),
|
|
262
724
|
},
|
|
725
|
+
headers: idempotencyHeaders(args),
|
|
263
726
|
});
|
|
264
727
|
}
|
|
265
|
-
else if (resource === '
|
|
266
|
-
result = await request(auth.apiKey, auth.baseUrl, '
|
|
728
|
+
else if (resource === 'sessions' && operation === 'get') {
|
|
729
|
+
result = await request(auth.apiKey, auth.baseUrl, `/sessions/${id(args[2], 'Pass a session ID after "darwin sessions get".')}`);
|
|
730
|
+
}
|
|
731
|
+
else if (resource === 'sessions' && operation === 'participants') {
|
|
732
|
+
const sessionResult = await request(auth.apiKey, auth.baseUrl, `/sessions/${id(args[2], 'Pass a session ID after "darwin sessions participants".')}`);
|
|
733
|
+
const session = sessionResult &&
|
|
734
|
+
typeof sessionResult === 'object' &&
|
|
735
|
+
'session' in sessionResult &&
|
|
736
|
+
sessionResult.session &&
|
|
737
|
+
typeof sessionResult.session === 'object'
|
|
738
|
+
? sessionResult.session
|
|
739
|
+
: undefined;
|
|
740
|
+
result = {
|
|
741
|
+
participants: Array.isArray(session?.participants) ? session.participants : [],
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
else if (resource === 'sessions' && operation === 'create') {
|
|
745
|
+
const body = mergeFields(dataOption(args), [
|
|
746
|
+
['aiId', option(args, '--ai')],
|
|
747
|
+
['kind', lowerEnumOption(args, '--kind', ['direct', 'discovery', 'buy', 'sell', 'coordination'])],
|
|
748
|
+
['goalId', option(args, '--goal')],
|
|
749
|
+
['conversationId', option(args, '--conversation')],
|
|
750
|
+
['discoveryMode', lowerEnumOption(args, '--discovery-mode', ['none', 'if_needed', 'always'])],
|
|
751
|
+
['activationMode', lowerEnumOption(args, '--activation-mode', ['immediate', 'plan_only'])],
|
|
752
|
+
]);
|
|
753
|
+
const intentDescription = option(args, '--intent');
|
|
754
|
+
const intentTitle = option(args, '--title');
|
|
755
|
+
if (intentDescription || intentTitle) {
|
|
756
|
+
const existingIntent = body.intent && typeof body.intent === 'object' && !Array.isArray(body.intent)
|
|
757
|
+
? body.intent
|
|
758
|
+
: {};
|
|
759
|
+
const description = intentDescription ?? (typeof existingIntent.description === 'string' ? existingIntent.description : undefined);
|
|
760
|
+
if (!description) {
|
|
761
|
+
throw new Error('--title requires an intent description from --intent or --data.');
|
|
762
|
+
}
|
|
763
|
+
body.intent = {
|
|
764
|
+
...existingIntent,
|
|
765
|
+
title: intentTitle ?? (typeof existingIntent.title === 'string' ? existingIntent.title : description.slice(0, 120)),
|
|
766
|
+
description,
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
const targetAIIds = repeatedOption(args, '--target');
|
|
770
|
+
if (targetAIIds.length > 0)
|
|
771
|
+
body.targetAIIds = targetAIIds;
|
|
772
|
+
const descriptor = option(args, '--discovery-descriptor');
|
|
773
|
+
if (descriptor !== undefined) {
|
|
774
|
+
body.discoveryDescriptor = jsonObjectOption(args, '--discovery-descriptor');
|
|
775
|
+
}
|
|
776
|
+
const existingDataPolicy = body.dataPolicy && typeof body.dataPolicy === 'object' && !Array.isArray(body.dataPolicy)
|
|
777
|
+
? body.dataPolicy
|
|
778
|
+
: {};
|
|
779
|
+
const dataPolicy = mergeFields({ ...existingDataPolicy }, [
|
|
780
|
+
['contentMode', lowerEnumOption(args, '--content-mode', ['managed', 'sealed'])],
|
|
781
|
+
[
|
|
782
|
+
'learningMode',
|
|
783
|
+
lowerEnumOption(args, '--learning-mode', [
|
|
784
|
+
'none',
|
|
785
|
+
'outcomes_only',
|
|
786
|
+
'derived_and_outcomes',
|
|
787
|
+
'content_and_outcomes',
|
|
788
|
+
]),
|
|
789
|
+
],
|
|
790
|
+
['keyManagement', lowerEnumOption(args, '--key-management', ['darwin_managed', 'tenant_managed'])],
|
|
791
|
+
]);
|
|
792
|
+
if (Object.keys(dataPolicy).length > 0)
|
|
793
|
+
body.dataPolicy = dataPolicy;
|
|
794
|
+
const effectiveContentMode = typeof dataPolicy.contentMode === 'string' ? dataPolicy.contentMode.toLowerCase() : 'sealed';
|
|
795
|
+
if (effectiveContentMode === 'sealed' && body.intent !== undefined) {
|
|
796
|
+
throw new Error('Sealed sessions cannot include plaintext intent. Remove --intent/intent and use --discovery-descriptor only when discovery is needed.');
|
|
797
|
+
}
|
|
798
|
+
if (effectiveContentMode === 'managed' && body.discoveryDescriptor !== undefined && body.intent === undefined) {
|
|
799
|
+
throw new Error('Managed session discovery descriptors require a structured intent.');
|
|
800
|
+
}
|
|
801
|
+
if (typeof body.kind !== 'string') {
|
|
802
|
+
throw new Error('Pass a session kind with --kind or in --data.');
|
|
803
|
+
}
|
|
804
|
+
result = await request(auth.apiKey, auth.baseUrl, '/sessions', {
|
|
805
|
+
method: 'POST',
|
|
806
|
+
body,
|
|
807
|
+
headers: idempotencyHeaders(args),
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
else if (resource === 'sessions' && operation === 'send') {
|
|
811
|
+
const content = textArgument(args, 3, [
|
|
812
|
+
'--kind',
|
|
813
|
+
'--context-scope',
|
|
814
|
+
'--idempotency-key',
|
|
815
|
+
'--data',
|
|
816
|
+
'--protected-content',
|
|
817
|
+
'--protected-content-file',
|
|
818
|
+
'--sealed-content',
|
|
819
|
+
'--sealed-content-file',
|
|
820
|
+
]);
|
|
821
|
+
const body = mergeFields(dataOption(args), [
|
|
822
|
+
[
|
|
823
|
+
'kind',
|
|
824
|
+
lowerEnumOption(args, '--kind', [
|
|
825
|
+
'message',
|
|
826
|
+
'question',
|
|
827
|
+
'clarification',
|
|
828
|
+
'proposal',
|
|
829
|
+
'counterproposal',
|
|
830
|
+
'notice',
|
|
831
|
+
'result',
|
|
832
|
+
'artifact',
|
|
833
|
+
]),
|
|
834
|
+
],
|
|
835
|
+
['content', content || undefined],
|
|
836
|
+
['contextScopeId', option(args, '--context-scope')],
|
|
837
|
+
]);
|
|
838
|
+
if (args.includes('--protected-content') && args.includes('--sealed-content')) {
|
|
839
|
+
throw new Error('Pass only one of --sealed-content or --protected-content.');
|
|
840
|
+
}
|
|
841
|
+
if (args.includes('--protected-content-file') && args.includes('--sealed-content-file')) {
|
|
842
|
+
throw new Error('Pass only one of --sealed-content-file or --protected-content-file.');
|
|
843
|
+
}
|
|
844
|
+
const protectedContentOption = args.includes('--protected-content') ? '--protected-content' : '--sealed-content';
|
|
845
|
+
if (args.includes(protectedContentOption)) {
|
|
846
|
+
body.protectedContent = jsonObjectOption(args, protectedContentOption);
|
|
847
|
+
}
|
|
848
|
+
const protectedContentFileOption = args.includes('--protected-content-file')
|
|
849
|
+
? '--protected-content-file'
|
|
850
|
+
: '--sealed-content-file';
|
|
851
|
+
const protectedContentFile = await jsonObjectFileOption(args, protectedContentFileOption);
|
|
852
|
+
if (protectedContentFile) {
|
|
853
|
+
if (body.protectedContent) {
|
|
854
|
+
throw new Error('Pass only one sealed-content value or file.');
|
|
855
|
+
}
|
|
856
|
+
body.protectedContent = protectedContentFile;
|
|
857
|
+
}
|
|
858
|
+
if (!body.kind)
|
|
859
|
+
body.kind = 'message';
|
|
860
|
+
const hasContent = typeof body.content === 'string' && body.content.trim().length > 0;
|
|
861
|
+
const hasSealedContent = !!body.protectedContent && typeof body.protectedContent === 'object' && !Array.isArray(body.protectedContent);
|
|
862
|
+
if ((!hasContent && !hasSealedContent) || (hasContent && hasSealedContent)) {
|
|
863
|
+
throw new Error('Pass either message text or sealed content, but not both.');
|
|
864
|
+
}
|
|
865
|
+
result = await request(auth.apiKey, auth.baseUrl, `/sessions/${id(args[2], 'Pass a session ID after "darwin sessions send".')}/interactions`, { method: 'POST', body, headers: idempotencyHeaders(args) });
|
|
866
|
+
}
|
|
867
|
+
else if (resource === 'sessions' && operation === 'watch') {
|
|
868
|
+
result = await request(auth.apiKey, auth.baseUrl, `/sessions/${id(args[2], 'Pass a session ID after "darwin sessions watch".')}/interactions`, {
|
|
869
|
+
query: {
|
|
870
|
+
limit: integerOption(args, '--limit'),
|
|
871
|
+
cursor: option(args, '--cursor'),
|
|
872
|
+
contextScopeId: option(args, '--context-scope'),
|
|
873
|
+
},
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
else if (resource === 'sessions' && operation === 'mesh') {
|
|
877
|
+
result = await request(auth.apiKey, auth.baseUrl, `/sessions/${id(args[2], 'Pass a session ID after "darwin sessions mesh".')}/mesh`);
|
|
878
|
+
}
|
|
879
|
+
else if (resource === 'sessions' && operation === 'replan') {
|
|
880
|
+
const body = dataOption(args);
|
|
881
|
+
const limit = integerOption(args, '--limit');
|
|
882
|
+
if (limit !== undefined)
|
|
883
|
+
body.limit = limit;
|
|
884
|
+
const excludeAIIds = repeatedOption(args, '--exclude-ai');
|
|
885
|
+
if (excludeAIIds.length > 0)
|
|
886
|
+
body.excludeAIIds = excludeAIIds;
|
|
887
|
+
result = await request(auth.apiKey, auth.baseUrl, `/sessions/${id(args[2], 'Pass a session ID after "darwin sessions replan".')}/resolutions`, {
|
|
888
|
+
method: 'POST',
|
|
889
|
+
body,
|
|
890
|
+
headers: idempotencyHeaders(args),
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
else if (resource === 'sessions' && ['complete', 'cancel'].includes(operation ?? '')) {
|
|
894
|
+
result = await request(auth.apiKey, auth.baseUrl, `/sessions/${id(args[2], `Pass a session ID after "darwin sessions ${operation}".`)}/actions`, {
|
|
895
|
+
method: 'POST',
|
|
896
|
+
body: {
|
|
897
|
+
...dataOption(args),
|
|
898
|
+
action: operation?.toUpperCase(),
|
|
899
|
+
},
|
|
900
|
+
headers: idempotencyHeaders(args),
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
else if (resource === 'sessions' && operation === 'outcome') {
|
|
904
|
+
const body = mergeFields(dataOption(args), [
|
|
905
|
+
['completionState', lowerEnumOption(args, '--completion-state', ['completed', 'partial', 'failed', 'cancelled'])],
|
|
906
|
+
[
|
|
907
|
+
'durationBand',
|
|
908
|
+
lowerEnumOption(args, '--duration-band', ['seconds', 'minutes', 'hours', 'days', 'weeks', 'months']),
|
|
909
|
+
],
|
|
910
|
+
['disputeState', lowerEnumOption(args, '--dispute-state', ['none', 'open', 'resolved'])],
|
|
911
|
+
['refundState', lowerEnumOption(args, '--refund-state', ['none', 'partial', 'full'])],
|
|
912
|
+
[
|
|
913
|
+
'evaluatorType',
|
|
914
|
+
lowerEnumOption(args, '--evaluator-type', ['requester', 'provider', 'platform', 'third_party']),
|
|
915
|
+
],
|
|
916
|
+
]);
|
|
917
|
+
const confidence = option(args, '--confidence');
|
|
918
|
+
if (confidence !== undefined) {
|
|
919
|
+
const parsed = Number(confidence);
|
|
920
|
+
if (!Number.isFinite(parsed) || parsed < 0 || parsed > 1) {
|
|
921
|
+
throw new Error('--confidence must be a number from 0 to 1.');
|
|
922
|
+
}
|
|
923
|
+
body.confidence = parsed;
|
|
924
|
+
}
|
|
925
|
+
const success = booleanOption(args, '--success');
|
|
926
|
+
if (success !== undefined)
|
|
927
|
+
body.success = success;
|
|
928
|
+
if (args.includes('--scores'))
|
|
929
|
+
body.scores = jsonObjectOption(args, '--scores');
|
|
930
|
+
if (args.includes('--signals'))
|
|
931
|
+
body.signals = jsonArrayOption(args, '--signals');
|
|
932
|
+
if (args.includes('--cost-band'))
|
|
933
|
+
body.costBand = jsonObjectOption(args, '--cost-band');
|
|
934
|
+
const criterionResultsOption = args.includes('--criterion-results')
|
|
935
|
+
? '--criterion-results'
|
|
936
|
+
: '--success-criteria-results';
|
|
937
|
+
if (args.includes(criterionResultsOption)) {
|
|
938
|
+
body.criterionResults = jsonArrayOption(args, criterionResultsOption);
|
|
939
|
+
}
|
|
940
|
+
const decisionIds = repeatedOption(args, '--decision-id');
|
|
941
|
+
if (decisionIds.length > 0)
|
|
942
|
+
body.decisionIds = decisionIds;
|
|
943
|
+
const evidenceDigests = repeatedOption(args, '--evidence-digest');
|
|
944
|
+
if (evidenceDigests.some((value) => !/^[a-f0-9]{64}$/i.test(value))) {
|
|
945
|
+
throw new Error('--evidence-digest must be a 64-character SHA-256 hex digest.');
|
|
946
|
+
}
|
|
947
|
+
if (evidenceDigests.length > 0)
|
|
948
|
+
body.evidenceDigests = evidenceDigests;
|
|
949
|
+
if (typeof body.completionState !== 'string') {
|
|
950
|
+
throw new Error('Pass --completion-state or include completionState in --data.');
|
|
951
|
+
}
|
|
952
|
+
result = await request(auth.apiKey, auth.baseUrl, `/sessions/${id(args[2], 'Pass a session ID after "darwin sessions outcome".')}/outcomes`, { method: 'POST', body, headers: idempotencyHeaders(args) });
|
|
953
|
+
}
|
|
954
|
+
else if (resource === 'sessions' && operation === 'feedback') {
|
|
955
|
+
const content = textArgument(args, 3, [
|
|
956
|
+
'--rating',
|
|
957
|
+
'--outcome',
|
|
958
|
+
'--context-scope',
|
|
959
|
+
'--idempotency-key',
|
|
960
|
+
'--data',
|
|
961
|
+
'--protected-content',
|
|
962
|
+
'--protected-content-file',
|
|
963
|
+
'--sealed-content',
|
|
964
|
+
'--sealed-content-file',
|
|
965
|
+
]);
|
|
966
|
+
const body = mergeFields(dataOption(args), [
|
|
967
|
+
['outcomeId', option(args, '--outcome')],
|
|
968
|
+
['contextScopeId', option(args, '--context-scope')],
|
|
969
|
+
['content', content || undefined],
|
|
970
|
+
]);
|
|
971
|
+
const rating = integerOption(args, '--rating');
|
|
972
|
+
if (rating !== undefined) {
|
|
973
|
+
if (rating > 5)
|
|
974
|
+
throw new Error('--rating must be an integer from 1 to 5.');
|
|
975
|
+
body.rating = rating;
|
|
976
|
+
}
|
|
977
|
+
if (args.includes('--protected-content') && args.includes('--sealed-content')) {
|
|
978
|
+
throw new Error('Pass only one of --sealed-content or --protected-content.');
|
|
979
|
+
}
|
|
980
|
+
if (args.includes('--protected-content-file') && args.includes('--sealed-content-file')) {
|
|
981
|
+
throw new Error('Pass only one of --sealed-content-file or --protected-content-file.');
|
|
982
|
+
}
|
|
983
|
+
const protectedContentOption = args.includes('--protected-content') ? '--protected-content' : '--sealed-content';
|
|
984
|
+
if (args.includes(protectedContentOption)) {
|
|
985
|
+
body.protectedContent = jsonObjectOption(args, protectedContentOption);
|
|
986
|
+
}
|
|
987
|
+
const protectedContentFileOption = args.includes('--protected-content-file')
|
|
988
|
+
? '--protected-content-file'
|
|
989
|
+
: '--sealed-content-file';
|
|
990
|
+
const protectedContentFile = await jsonObjectFileOption(args, protectedContentFileOption);
|
|
991
|
+
if (protectedContentFile) {
|
|
992
|
+
if (body.protectedContent)
|
|
993
|
+
throw new Error('Pass only one sealed-content value or file.');
|
|
994
|
+
body.protectedContent = protectedContentFile;
|
|
995
|
+
}
|
|
996
|
+
const hasContent = typeof body.content === 'string' && body.content.trim().length > 0;
|
|
997
|
+
const hasProtectedContent = !!body.protectedContent && typeof body.protectedContent === 'object' && !Array.isArray(body.protectedContent);
|
|
998
|
+
if (hasContent && hasProtectedContent) {
|
|
999
|
+
throw new Error('Pass plaintext feedback or protected content, not both.');
|
|
1000
|
+
}
|
|
1001
|
+
if (body.rating === undefined && !hasContent && !hasProtectedContent) {
|
|
1002
|
+
throw new Error('Pass a rating, feedback text, or protected content.');
|
|
1003
|
+
}
|
|
1004
|
+
result = await request(auth.apiKey, auth.baseUrl, `/sessions/${id(args[2], 'Pass a session ID after "darwin sessions feedback".')}/feedback`, { method: 'POST', body, headers: idempotencyHeaders(args) });
|
|
1005
|
+
}
|
|
1006
|
+
else if (resource === 'directory' && operation === 'search') {
|
|
1007
|
+
result = await request(auth.apiKey, auth.baseUrl, '/directory/ais', {
|
|
1008
|
+
query: {
|
|
1009
|
+
query: textArgument(args, 2, ['--limit']) || undefined,
|
|
1010
|
+
limit: integerOption(args, '--limit'),
|
|
1011
|
+
},
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
else if (resource === 'directory' && operation === 'get') {
|
|
1015
|
+
result = await request(auth.apiKey, auth.baseUrl, `/directory/ais/${id(args[2], 'Pass a directory AI ID.')}`);
|
|
1016
|
+
}
|
|
1017
|
+
else if (resource === 'offers' && operation === 'list') {
|
|
1018
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(option(args, '--ai'), 'Pass an AI ID with --ai.')}/offers`);
|
|
1019
|
+
}
|
|
1020
|
+
else if (resource === 'offers' && operation === 'get') {
|
|
1021
|
+
result = await request(auth.apiKey, auth.baseUrl, `/offers/${id(args[2], 'Pass an offer ID after "darwin offers get".')}`);
|
|
1022
|
+
}
|
|
1023
|
+
else if (resource === 'offers' && operation === 'create') {
|
|
1024
|
+
const body = mergeFields(dataOption(args), [
|
|
1025
|
+
['direction', enumOption(args, '--direction', ['DEMAND', 'SUPPLY'])],
|
|
1026
|
+
['title', option(args, '--title')],
|
|
1027
|
+
['goalId', option(args, '--goal')],
|
|
1028
|
+
['visibility', enumOption(args, '--visibility', ['PUBLIC', 'RESTRICTED', 'PRIVATE'])],
|
|
1029
|
+
]);
|
|
1030
|
+
if (typeof body.direction !== 'string' || typeof body.title !== 'string') {
|
|
1031
|
+
throw new Error('Pass --direction and --title, or provide both in --data.');
|
|
1032
|
+
}
|
|
1033
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(option(args, '--ai'), 'Pass an AI ID with --ai.')}/offers`, { method: 'POST', body });
|
|
1034
|
+
}
|
|
1035
|
+
else if (resource === 'offers' && operation === 'update') {
|
|
1036
|
+
const body = mergeFields(dataOption(args), [
|
|
1037
|
+
['title', option(args, '--title')],
|
|
1038
|
+
['visibility', enumOption(args, '--visibility', ['PUBLIC', 'RESTRICTED', 'PRIVATE'])],
|
|
1039
|
+
]);
|
|
1040
|
+
if (Object.keys(body).length === 0)
|
|
1041
|
+
throw new Error('Pass editable offer fields or --data.');
|
|
1042
|
+
result = await request(auth.apiKey, auth.baseUrl, `/offers/${id(args[2], 'Pass an offer ID after "darwin offers update".')}`, { method: 'PATCH', body });
|
|
1043
|
+
}
|
|
1044
|
+
else if (resource === 'offers' && operation === 'action') {
|
|
1045
|
+
const action = args[3]?.toUpperCase();
|
|
1046
|
+
if (!action || !['SEND', 'ACCEPT', 'REJECT', 'WITHDRAW'].includes(action)) {
|
|
1047
|
+
throw new Error('Action must be send, accept, reject, or withdraw.');
|
|
1048
|
+
}
|
|
1049
|
+
result = await request(auth.apiKey, auth.baseUrl, `/offers/${id(args[2], 'Pass an offer ID after "darwin offers action".')}/actions`, { method: 'POST', body: { action } });
|
|
1050
|
+
}
|
|
1051
|
+
else if (resource === 'payments' && operation === 'account') {
|
|
1052
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(option(args, '--ai'), 'Pass an AI ID with --ai.')}/payment-account`);
|
|
1053
|
+
}
|
|
1054
|
+
else if (resource === 'payments' && operation === 'list') {
|
|
1055
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(option(args, '--ai'), 'Pass an AI ID with --ai.')}/payments`);
|
|
1056
|
+
}
|
|
1057
|
+
else if (resource === 'payments' && operation === 'get') {
|
|
1058
|
+
result = await request(auth.apiKey, auth.baseUrl, `/payments/${id(args[2], 'Pass a payment ID after "darwin payments get".')}`);
|
|
1059
|
+
}
|
|
1060
|
+
else if (resource === 'fee-quotes' && operation === 'create') {
|
|
1061
|
+
const body = dataOption(args);
|
|
1062
|
+
if (Object.keys(body).length === 0)
|
|
1063
|
+
throw new Error('Pass fee quote inputs with --data.');
|
|
1064
|
+
result = await request(auth.apiKey, auth.baseUrl, '/fee-quotes', { method: 'POST', body });
|
|
1065
|
+
}
|
|
1066
|
+
else if (resource === 'fee-quotes' && operation === 'get') {
|
|
1067
|
+
result = await request(auth.apiKey, auth.baseUrl, `/fee-quotes/${id(args[2], 'Pass a fee quote ID.')}`);
|
|
1068
|
+
}
|
|
1069
|
+
else if (resource === 'fee-quotes' && operation === 'accept') {
|
|
1070
|
+
result = await request(auth.apiKey, auth.baseUrl, `/fee-quotes/${id(args[2], 'Pass a fee quote ID.')}/accept`, {
|
|
1071
|
+
method: 'POST',
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
else if (resource === 'supply' && operation === 'businesses' && args[2] === 'list') {
|
|
1075
|
+
result = await request(auth.apiKey, auth.baseUrl, '/ais');
|
|
1076
|
+
}
|
|
1077
|
+
else if (resource === 'supply' && operation === 'businesses' && args[2] === 'get') {
|
|
1078
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[3], 'Pass a business ID.')}`);
|
|
1079
|
+
}
|
|
1080
|
+
else if (resource === 'supply' && operation === 'businesses' && args[2] === 'create') {
|
|
1081
|
+
const body = mergeFields({ type: 'business', ...dataOption(args) }, [
|
|
1082
|
+
['name', option(args, '--name')],
|
|
1083
|
+
['handle', option(args, '--handle')],
|
|
1084
|
+
['description', option(args, '--description')],
|
|
1085
|
+
]);
|
|
1086
|
+
if (typeof body.name !== 'string')
|
|
1087
|
+
throw new Error('Pass --name or include name in --data.');
|
|
1088
|
+
result = await request(auth.apiKey, auth.baseUrl, '/ais', { method: 'POST', body });
|
|
1089
|
+
}
|
|
1090
|
+
else if (resource === 'supply' && operation === 'businesses' && args[2] === 'update') {
|
|
1091
|
+
const body = mergeFields(dataOption(args), [
|
|
1092
|
+
['name', option(args, '--name')],
|
|
1093
|
+
['handle', option(args, '--handle')],
|
|
1094
|
+
['description', option(args, '--description')],
|
|
1095
|
+
]);
|
|
1096
|
+
if (Object.keys(body).length === 0)
|
|
1097
|
+
throw new Error('Pass editable business fields or --data.');
|
|
1098
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[3], 'Pass a business ID.')}`, {
|
|
1099
|
+
method: 'PATCH',
|
|
1100
|
+
body,
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
else if (resource === 'supply' && operation === 'listings' && args[2] === 'list') {
|
|
1104
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[3], 'Pass a business ID.')}/listings`, {
|
|
1105
|
+
query: {
|
|
1106
|
+
limit: integerOption(args, '--limit'),
|
|
1107
|
+
cursor: option(args, '--cursor'),
|
|
1108
|
+
q: option(args, '--query'),
|
|
1109
|
+
type: option(args, '--type'),
|
|
1110
|
+
status: option(args, '--status'),
|
|
1111
|
+
},
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
else if (resource === 'supply' && operation === 'listings' && args[2] === 'get') {
|
|
1115
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[3], 'Pass a business ID.')}/listings/${id(args[4], 'Pass a listing ID.')}`);
|
|
1116
|
+
}
|
|
1117
|
+
else if (resource === 'supply' && operation === 'listings' && args[2] === 'create') {
|
|
1118
|
+
const body = dataOption(args);
|
|
1119
|
+
if (Object.keys(body).length === 0)
|
|
1120
|
+
throw new Error('Pass listing fields with --data.');
|
|
1121
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[3], 'Pass a business ID.')}/listings`, {
|
|
1122
|
+
method: 'POST',
|
|
1123
|
+
body,
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
else if (resource === 'supply' && operation === 'listings' && args[2] === 'update') {
|
|
1127
|
+
const body = dataOption(args);
|
|
1128
|
+
if (Object.keys(body).length === 0)
|
|
1129
|
+
throw new Error('Pass listing fields with --data.');
|
|
1130
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[3], 'Pass a business ID.')}/listings/${id(args[4], 'Pass a listing ID.')}`, { method: 'PATCH', body });
|
|
1131
|
+
}
|
|
1132
|
+
else if (resource === 'supply' && operation === 'listings' && args[2] === 'archive') {
|
|
1133
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[3], 'Pass a business ID.')}/listings/${id(args[4], 'Pass a listing ID.')}`, { method: 'DELETE', query: { expectedRevision: integerOption(args, '--expected-revision') } });
|
|
1134
|
+
}
|
|
1135
|
+
else if (resource === 'supply' && operation === 'orders' && args[2] === 'list') {
|
|
1136
|
+
result = await request(auth.apiKey, auth.baseUrl, '/transactions', { query: { aiId: args[3] } });
|
|
1137
|
+
}
|
|
1138
|
+
else if (resource === 'supply' && operation === 'orders' && args[2] === 'get') {
|
|
1139
|
+
result = await request(auth.apiKey, auth.baseUrl, `/transactions/${id(args[4], 'Pass an order ID.')}`, {
|
|
1140
|
+
query: { aiId: args[3] },
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
else if (resource === 'supply' && operation === 'earnings' && args[2] === 'get') {
|
|
1144
|
+
result = await request(auth.apiKey, auth.baseUrl, `/ais/${id(args[3], 'Pass a business ID.')}/billing`);
|
|
1145
|
+
}
|
|
1146
|
+
else if (resource === 'connect' && operation === 'list') {
|
|
1147
|
+
result = await request(auth.apiKey, auth.baseUrl, '/applications');
|
|
1148
|
+
}
|
|
1149
|
+
else if (resource === 'connect' && operation === 'get') {
|
|
1150
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}`);
|
|
1151
|
+
}
|
|
1152
|
+
else if (resource === 'connect' && operation === 'create') {
|
|
1153
|
+
const body = mergeFields(dataOption(args), [
|
|
1154
|
+
['name', option(args, '--name')],
|
|
1155
|
+
['mode', enumOption(args, '--mode', ['HOSTED', 'EMBEDDED', 'HYBRID'])],
|
|
1156
|
+
]);
|
|
1157
|
+
if (typeof body.name !== 'string')
|
|
1158
|
+
throw new Error('Pass --name or include name in --data.');
|
|
1159
|
+
result = await request(auth.apiKey, auth.baseUrl, '/applications', { method: 'POST', body });
|
|
1160
|
+
}
|
|
1161
|
+
else if (resource === 'connect' && operation === 'update') {
|
|
1162
|
+
const body = mergeFields(dataOption(args), [
|
|
1163
|
+
['name', option(args, '--name')],
|
|
1164
|
+
['mode', enumOption(args, '--mode', ['HOSTED', 'EMBEDDED', 'HYBRID'])],
|
|
1165
|
+
]);
|
|
1166
|
+
if (Object.keys(body).length === 0)
|
|
1167
|
+
throw new Error('Pass editable application fields or --data.');
|
|
1168
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}`, {
|
|
1169
|
+
method: 'PATCH',
|
|
1170
|
+
body,
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
else if (resource === 'connect' && operation === 'archive') {
|
|
1174
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}`, {
|
|
1175
|
+
method: 'DELETE',
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
else if (resource === 'connect' && operation === 'ais') {
|
|
1179
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/ais`);
|
|
1180
|
+
}
|
|
1181
|
+
else if (resource === 'connect' && operation === 'link-ai') {
|
|
1182
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/ais`, {
|
|
1183
|
+
method: 'POST',
|
|
1184
|
+
body: {
|
|
1185
|
+
aiId: requiredOption(args, '--ai'),
|
|
1186
|
+
role: option(args, '--role'),
|
|
1187
|
+
},
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
else if (resource === 'connect' && operation === 'unlink-ai') {
|
|
1191
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/ais/${id(args[3], 'Pass an AI ID.')}`, { method: 'DELETE' });
|
|
1192
|
+
}
|
|
1193
|
+
else if (resource === 'connect' && operation === 'resolve-user') {
|
|
1194
|
+
const body = dataOption(args);
|
|
1195
|
+
const externalRef = option(args, '--external-ref');
|
|
1196
|
+
if (externalRef)
|
|
1197
|
+
body.externalRef = externalRef;
|
|
1198
|
+
if (!body.externalRef && !body.proof) {
|
|
1199
|
+
throw new Error('Pass --external-ref or include a supported proof in --data.');
|
|
1200
|
+
}
|
|
1201
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/users/resolve`, { method: 'POST', body });
|
|
1202
|
+
}
|
|
1203
|
+
else if (resource === 'connect' && operation === 'enrollments') {
|
|
1204
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/enrollment-links`);
|
|
1205
|
+
}
|
|
1206
|
+
else if (resource === 'connect' && operation === 'create-enrollment') {
|
|
1207
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/enrollment-links`, { method: 'POST', body: dataOption(args) });
|
|
1208
|
+
}
|
|
1209
|
+
else if (resource === 'connect' && operation === 'revoke-enrollment') {
|
|
1210
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/enrollment-links/${id(args[3], 'Pass an enrollment link ID.')}`, { method: 'DELETE' });
|
|
1211
|
+
}
|
|
1212
|
+
else if (resource === 'connect' && operation === 'service-accounts') {
|
|
1213
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/service-accounts`);
|
|
1214
|
+
}
|
|
1215
|
+
else if (resource === 'connect' && operation === 'create-service-account') {
|
|
1216
|
+
const body = mergeFields(dataOption(args), [['name', option(args, '--name')]]);
|
|
1217
|
+
if (typeof body.name !== 'string')
|
|
1218
|
+
throw new Error('Pass --name or include name in --data.');
|
|
1219
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/service-accounts`, { method: 'POST', body });
|
|
1220
|
+
}
|
|
1221
|
+
else if (resource === 'connect' && operation === 'revoke-service-account') {
|
|
1222
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/service-accounts/${id(args[3], 'Pass a service account ID.')}`, { method: 'DELETE' });
|
|
1223
|
+
}
|
|
1224
|
+
else if (resource === 'connect' && operation === 'webhooks') {
|
|
1225
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/webhooks`);
|
|
1226
|
+
}
|
|
1227
|
+
else if (resource === 'connect' && operation === 'create-webhook') {
|
|
1228
|
+
const body = mergeFields(dataOption(args), [['url', option(args, '--url')]]);
|
|
1229
|
+
if (typeof body.url !== 'string')
|
|
1230
|
+
throw new Error('Pass --url or include url in --data.');
|
|
1231
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/webhooks`, { method: 'POST', body });
|
|
1232
|
+
}
|
|
1233
|
+
else if (resource === 'connect' && operation === 'revoke-webhook') {
|
|
1234
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/webhooks/${id(args[3], 'Pass a webhook ID.')}`, { method: 'DELETE' });
|
|
1235
|
+
}
|
|
1236
|
+
else if (resource === 'connect' && operation === 'webhook-deliveries') {
|
|
1237
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/webhooks/${id(args[3], 'Pass a webhook ID.')}/deliveries`, {
|
|
1238
|
+
query: {
|
|
1239
|
+
limit: integerOption(args, '--limit'),
|
|
1240
|
+
cursor: option(args, '--cursor'),
|
|
1241
|
+
},
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
else if (resource === 'connect' && operation === 'retry-webhook') {
|
|
1245
|
+
result = await request(auth.apiKey, auth.baseUrl, `/applications/${id(args[2], 'Pass an application ID.')}/webhooks/${id(args[3], 'Pass a webhook ID.')}/deliveries/${id(args[4], 'Pass a delivery ID.')}/retry`, { method: 'POST' });
|
|
267
1246
|
}
|
|
268
1247
|
else if (resource === 'tools' && operation === 'list') {
|
|
269
1248
|
result = await request(auth.apiKey, auth.baseUrl, '/tools');
|
|
@@ -278,6 +1257,21 @@ async function main() {
|
|
|
278
1257
|
body: { input: jsonObjectOption(args, '--input') },
|
|
279
1258
|
});
|
|
280
1259
|
}
|
|
1260
|
+
else if (resource === 'api') {
|
|
1261
|
+
const method = operation?.toUpperCase();
|
|
1262
|
+
if (!method || !['GET', 'POST', 'PATCH', 'DELETE'].includes(method)) {
|
|
1263
|
+
throw new Error('API method must be GET, POST, PATCH, or DELETE.');
|
|
1264
|
+
}
|
|
1265
|
+
const path = args[2]?.trim();
|
|
1266
|
+
if (!path || path.includes('://')) {
|
|
1267
|
+
throw new Error('Pass a relative API path, such as /ais.');
|
|
1268
|
+
}
|
|
1269
|
+
const body = dataOption(args);
|
|
1270
|
+
result = await request(auth.apiKey, auth.baseUrl, path, {
|
|
1271
|
+
method: method,
|
|
1272
|
+
...(Object.keys(body).length > 0 ? { body } : {}),
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
281
1275
|
else {
|
|
282
1276
|
throw new Error(`Unknown command: ${args.join(' ')}`);
|
|
283
1277
|
}
|