@neta-art/cohub-cli 1.7.1 → 1.9.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 +8 -0
- package/dist/auth.d.ts +3 -1
- package/dist/auth.js +2 -2
- package/dist/commands/auth.js +68 -13
- package/dist/commands/channels.js +3 -3
- package/dist/commands/cron-jobs.js +5 -3
- package/dist/commands/generations.js +101 -28
- package/dist/commands/models.js +93 -5
- package/dist/commands/profile.js +2 -2
- package/dist/commands/prompts.js +2 -2
- package/dist/commands/search.js +2 -2
- package/dist/commands/session-access.js +12 -4
- package/dist/commands/spaces.js +113 -101
- package/dist/commands/tasks.js +3 -3
- package/dist/output.d.ts +4 -0
- package/dist/output.js +25 -4
- package/dist/space.d.ts +2 -0
- package/dist/space.js +14 -0
- package/package.json +3 -2
package/dist/commands/spaces.js
CHANGED
|
@@ -2,21 +2,36 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { createReadStream } from "node:fs";
|
|
3
3
|
import { readdir, stat } from "node:fs/promises";
|
|
4
4
|
import { basename, dirname, relative, resolve, sep } from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { resolveCohubEnvironment } from "@neta-art/cohub";
|
|
6
6
|
import { uploadAvatarAsset } from "../avatar.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const opts = current.opts();
|
|
12
|
-
if (opts.space)
|
|
13
|
-
return String(opts.space);
|
|
14
|
-
current = current.parent ?? null;
|
|
15
|
-
}
|
|
16
|
-
return error("Missing required option", "Add -s, --space <id> to target a space");
|
|
17
|
-
}
|
|
18
|
-
const cliEnv = (process.env.ENV === "prod" ? "prod" : "dev");
|
|
7
|
+
import { createClient } from "../client.js";
|
|
8
|
+
import { table, json as outJson, jsonRequested, ok, error, handleHttp } from "../output.js";
|
|
9
|
+
import { resolveSpace } from "../space.js";
|
|
10
|
+
const cliEnv = resolveCohubEnvironment();
|
|
19
11
|
const defaultIdleTtlSeconds = cliEnv === "prod" ? 12 * 60 * 60 : 10 * 60;
|
|
12
|
+
const SPACE_ROLES = ["host", "builder", "guest"];
|
|
13
|
+
function parseInteger(value, name, options = {}) {
|
|
14
|
+
if (!/^-?\d+$/.test(value.trim()))
|
|
15
|
+
return error(`Invalid ${name}`, `${name} must be an integer`);
|
|
16
|
+
const parsed = Number.parseInt(value, 10);
|
|
17
|
+
if (!Number.isSafeInteger(parsed))
|
|
18
|
+
return error(`Invalid ${name}`, `${name} must be a safe integer`);
|
|
19
|
+
if (options.min !== undefined && parsed < options.min)
|
|
20
|
+
return error(`Invalid ${name}`, `${name} must be at least ${options.min}`);
|
|
21
|
+
if (options.max !== undefined && parsed > options.max)
|
|
22
|
+
return error(`Invalid ${name}`, `${name} must be at most ${options.max}`);
|
|
23
|
+
return parsed;
|
|
24
|
+
}
|
|
25
|
+
function parseChoice(value, name, choices) {
|
|
26
|
+
if (choices.includes(value))
|
|
27
|
+
return value;
|
|
28
|
+
return error(`Invalid ${name}`, `Use one of: ${choices.join(", ")}`);
|
|
29
|
+
}
|
|
30
|
+
function parseNullableRole(value, name) {
|
|
31
|
+
if (value === undefined || value === "null")
|
|
32
|
+
return null;
|
|
33
|
+
return parseChoice(value, name, SPACE_ROLES);
|
|
34
|
+
}
|
|
20
35
|
const parseAutoDestroy = (opts) => {
|
|
21
36
|
const mode = opts.autoDestroy ?? (opts.idleTtl ? "idle" : undefined);
|
|
22
37
|
if (!mode)
|
|
@@ -25,10 +40,7 @@ const parseAutoDestroy = (opts) => {
|
|
|
25
40
|
return { mode: "never" };
|
|
26
41
|
if (mode !== "idle")
|
|
27
42
|
return error("Invalid auto destroy mode", "Use --auto-destroy idle or --auto-destroy never");
|
|
28
|
-
const ttlSeconds =
|
|
29
|
-
if (!Number.isSafeInteger(ttlSeconds) || ttlSeconds < 60 || ttlSeconds > 30 * 24 * 60 * 60) {
|
|
30
|
-
return error("Invalid idle TTL", "--idle-ttl must be an integer between 60 and 2592000 seconds");
|
|
31
|
-
}
|
|
43
|
+
const ttlSeconds = parseInteger(opts.idleTtl ?? String(defaultIdleTtlSeconds), "idle TTL", { min: 60, max: 30 * 24 * 60 * 60 });
|
|
32
44
|
return { mode: "idle", ttlSeconds };
|
|
33
45
|
};
|
|
34
46
|
const formatAutoDestroy = (policy) => {
|
|
@@ -93,7 +105,7 @@ async function putUploadEntry(entry, uploadUrl, headers) {
|
|
|
93
105
|
}
|
|
94
106
|
}
|
|
95
107
|
async function uploadFiles(command, paths, opts) {
|
|
96
|
-
const spaceId =
|
|
108
|
+
const spaceId = resolveSpace(command);
|
|
97
109
|
const client = createClient();
|
|
98
110
|
try {
|
|
99
111
|
const files = await collectUploadFiles(paths);
|
|
@@ -117,7 +129,7 @@ async function uploadFiles(command, paths, opts) {
|
|
|
117
129
|
const result = await client.space(spaceId).files.completeUpload(plan.uploadId, {
|
|
118
130
|
entries: plan.entries.map((entry) => ({ id: entry.id })),
|
|
119
131
|
});
|
|
120
|
-
if (opts
|
|
132
|
+
if (jsonRequested(opts))
|
|
121
133
|
return outJson({ ...result, uploadId: plan.uploadId, files: files.length });
|
|
122
134
|
ok(`Uploaded ${files.length} file${files.length === 1 ? "" : "s"}`);
|
|
123
135
|
}
|
|
@@ -159,11 +171,11 @@ async function sendPrompt(command, words, opts) {
|
|
|
159
171
|
return error("Conflicting schedule", "Use only one of --delay-ms, --at, or --cron");
|
|
160
172
|
if (opts.cron && !opts.timezone)
|
|
161
173
|
return error("Missing timezone", "--timezone is required with --cron");
|
|
162
|
-
const spaceId =
|
|
174
|
+
const spaceId = resolveSpace(command);
|
|
163
175
|
const client = createClient();
|
|
164
176
|
try {
|
|
165
177
|
const schedule = opts.delayMs
|
|
166
|
-
? { mode: "delay", delayMs:
|
|
178
|
+
? { mode: "delay", delayMs: parseInteger(opts.delayMs, "delay", { min: 1 }) }
|
|
167
179
|
: opts.at
|
|
168
180
|
? { mode: "at", sendAt: opts.at }
|
|
169
181
|
: opts.cron
|
|
@@ -177,7 +189,7 @@ async function sendPrompt(command, words, opts) {
|
|
|
177
189
|
provider: opts.provider,
|
|
178
190
|
schedule,
|
|
179
191
|
});
|
|
180
|
-
if (opts
|
|
192
|
+
if (jsonRequested(opts))
|
|
181
193
|
return outJson(result);
|
|
182
194
|
if (result.mode === "immediate")
|
|
183
195
|
return ok(`Prompt sent — sessionId: ${result.sessionId}, turnId: ${result.turnId}`);
|
|
@@ -216,7 +228,7 @@ export function registerSpaces(program) {
|
|
|
216
228
|
const client = createClient();
|
|
217
229
|
try {
|
|
218
230
|
const items = await client.spaces.list();
|
|
219
|
-
if (opts
|
|
231
|
+
if (jsonRequested(opts))
|
|
220
232
|
return outJson(items);
|
|
221
233
|
table(items, [
|
|
222
234
|
{ key: "id", label: "ID" },
|
|
@@ -237,7 +249,7 @@ export function registerSpaces(program) {
|
|
|
237
249
|
const client = createClient();
|
|
238
250
|
try {
|
|
239
251
|
const space = await client.spaces.get(id);
|
|
240
|
-
if (opts
|
|
252
|
+
if (jsonRequested(opts))
|
|
241
253
|
return outJson(space);
|
|
242
254
|
table([space], [
|
|
243
255
|
{ key: "id", label: "ID" },
|
|
@@ -269,7 +281,7 @@ export function registerSpaces(program) {
|
|
|
269
281
|
description: opts.description,
|
|
270
282
|
...(autoDestroy ? { config: { sandbox: { autoDestroy } } } : {}),
|
|
271
283
|
});
|
|
272
|
-
if (opts
|
|
284
|
+
if (jsonRequested(opts))
|
|
273
285
|
return outJson(result);
|
|
274
286
|
ok(`Space created: ${result.space.id}`);
|
|
275
287
|
table([result.space], [
|
|
@@ -302,12 +314,12 @@ export function registerSpaces(program) {
|
|
|
302
314
|
.description("Upload the space avatar")
|
|
303
315
|
.option("--json", "Output as JSON")
|
|
304
316
|
.action(async (path, opts) => {
|
|
305
|
-
const spaceId =
|
|
317
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
306
318
|
const client = createClient();
|
|
307
319
|
try {
|
|
308
320
|
const asset = await uploadAvatarAsset({ client, purpose: "space_avatar", spaceId, path });
|
|
309
321
|
const result = await client.space(spaceId).profile({ avatarUrl: asset.publicUrl });
|
|
310
|
-
if (opts
|
|
322
|
+
if (jsonRequested(opts))
|
|
311
323
|
return outJson({ ...result, asset });
|
|
312
324
|
ok("Space avatar updated");
|
|
313
325
|
}
|
|
@@ -328,13 +340,13 @@ export function registerSpaces(program) {
|
|
|
328
340
|
const autoDestroy = parseAutoDestroy(opts);
|
|
329
341
|
if (autoDestroy) {
|
|
330
342
|
const result = await client.space(id).updateConfig({ sandbox: { autoDestroy } });
|
|
331
|
-
if (opts
|
|
343
|
+
if (jsonRequested(opts))
|
|
332
344
|
return outJson(result);
|
|
333
345
|
ok(`Space config updated — sandbox auto destroy: ${formatAutoDestroy(autoDestroy)}`);
|
|
334
346
|
return;
|
|
335
347
|
}
|
|
336
348
|
const result = await client.space(id).getConfig();
|
|
337
|
-
if (opts
|
|
349
|
+
if (jsonRequested(opts))
|
|
338
350
|
return outJson(result);
|
|
339
351
|
table([{ key: "sandbox.autoDestroy", value: formatAutoDestroy(result.config.sandbox.autoDestroy) }], [
|
|
340
352
|
{ key: "key", label: "Key" },
|
|
@@ -378,11 +390,11 @@ export function registerSpaces(program) {
|
|
|
378
390
|
.description("Space usage statistics (default: 30 days)")
|
|
379
391
|
.option("--json", "Output as JSON")
|
|
380
392
|
.action(async (days, opts) => {
|
|
381
|
-
const spaceId =
|
|
393
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
382
394
|
const client = createClient();
|
|
383
395
|
try {
|
|
384
|
-
const usage = await client.space(spaceId).usage.get(
|
|
385
|
-
if (opts
|
|
396
|
+
const usage = await client.space(spaceId).usage.get(parseInteger(days ?? "30", "days", { min: 1 }));
|
|
397
|
+
if (jsonRequested(opts))
|
|
386
398
|
return outJson(usage);
|
|
387
399
|
console.log("\n Summary:");
|
|
388
400
|
table([usage.summary], [
|
|
@@ -402,18 +414,18 @@ function registerMods(spacesCmd) {
|
|
|
402
414
|
const modsCmd = spacesCmd
|
|
403
415
|
.command("mods")
|
|
404
416
|
.description("Manage space mods")
|
|
405
|
-
.hook("preAction", () => {
|
|
417
|
+
.hook("preAction", () => { resolveSpace(spacesCmd); });
|
|
406
418
|
modsCmd
|
|
407
419
|
.command("ls")
|
|
408
420
|
.alias("list")
|
|
409
421
|
.description("List mods")
|
|
410
422
|
.option("--json", "Output as JSON")
|
|
411
423
|
.action(async (opts) => {
|
|
412
|
-
const spaceId =
|
|
424
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
413
425
|
const client = createClient();
|
|
414
426
|
try {
|
|
415
427
|
const result = await client.space(spaceId).mods.list();
|
|
416
|
-
if (opts
|
|
428
|
+
if (jsonRequested(opts))
|
|
417
429
|
return outJson(result.items);
|
|
418
430
|
table(result.items, [
|
|
419
431
|
{ key: "id", label: "ID" },
|
|
@@ -435,11 +447,11 @@ function registerMods(spacesCmd) {
|
|
|
435
447
|
.option("--json", "Output as JSON")
|
|
436
448
|
.action(async (modSpaceId, opts) => {
|
|
437
449
|
await confirmRestart(opts);
|
|
438
|
-
const spaceId =
|
|
450
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
439
451
|
const client = createClient();
|
|
440
452
|
try {
|
|
441
453
|
const result = await client.space(spaceId).mods.create({ modSpaceId, name: opts.name, mountSlug: opts.slug });
|
|
442
|
-
if (opts
|
|
454
|
+
if (jsonRequested(opts))
|
|
443
455
|
return outJson(result);
|
|
444
456
|
ok(`Mod added — ${result.item.mountPath}; sandbox restarting`);
|
|
445
457
|
}
|
|
@@ -454,11 +466,11 @@ function registerMods(spacesCmd) {
|
|
|
454
466
|
.option("--json", "Output as JSON")
|
|
455
467
|
.action(async (modId, opts) => {
|
|
456
468
|
await confirmRestart(opts);
|
|
457
|
-
const spaceId =
|
|
469
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
458
470
|
const client = createClient();
|
|
459
471
|
try {
|
|
460
472
|
const result = await client.space(spaceId).mods.update(modId, { enabled: true });
|
|
461
|
-
if (opts
|
|
473
|
+
if (jsonRequested(opts))
|
|
462
474
|
return outJson(result);
|
|
463
475
|
ok("Mod enabled; sandbox restarting");
|
|
464
476
|
}
|
|
@@ -473,11 +485,11 @@ function registerMods(spacesCmd) {
|
|
|
473
485
|
.option("--json", "Output as JSON")
|
|
474
486
|
.action(async (modId, opts) => {
|
|
475
487
|
await confirmRestart(opts);
|
|
476
|
-
const spaceId =
|
|
488
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
477
489
|
const client = createClient();
|
|
478
490
|
try {
|
|
479
491
|
const result = await client.space(spaceId).mods.update(modId, { enabled: false });
|
|
480
|
-
if (opts
|
|
492
|
+
if (jsonRequested(opts))
|
|
481
493
|
return outJson(result);
|
|
482
494
|
ok("Mod disabled; sandbox restarting");
|
|
483
495
|
}
|
|
@@ -493,11 +505,11 @@ function registerMods(spacesCmd) {
|
|
|
493
505
|
.option("--json", "Output as JSON")
|
|
494
506
|
.action(async (modId, opts) => {
|
|
495
507
|
await confirmRestart(opts);
|
|
496
|
-
const spaceId =
|
|
508
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
497
509
|
const client = createClient();
|
|
498
510
|
try {
|
|
499
511
|
const result = await client.space(spaceId).mods.remove(modId);
|
|
500
|
-
if (opts
|
|
512
|
+
if (jsonRequested(opts))
|
|
501
513
|
return outJson(result);
|
|
502
514
|
ok("Mod removed; sandbox restarting");
|
|
503
515
|
}
|
|
@@ -511,18 +523,18 @@ function registerFiles(spacesCmd) {
|
|
|
511
523
|
const filesCmd = spacesCmd
|
|
512
524
|
.command("files")
|
|
513
525
|
.description("File operations")
|
|
514
|
-
.hook("preAction", () => {
|
|
526
|
+
.hook("preAction", () => { resolveSpace(spacesCmd); });
|
|
515
527
|
filesCmd
|
|
516
528
|
.command("ls [path]")
|
|
517
529
|
.alias("list")
|
|
518
530
|
.description("List directory tree")
|
|
519
531
|
.option("--json", "Output as JSON")
|
|
520
532
|
.action(async (path, opts) => {
|
|
521
|
-
const spaceId =
|
|
533
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
522
534
|
const client = createClient();
|
|
523
535
|
try {
|
|
524
536
|
const tree = await client.space(spaceId).files.list(path ?? "");
|
|
525
|
-
if (opts
|
|
537
|
+
if (jsonRequested(opts))
|
|
526
538
|
return outJson(tree);
|
|
527
539
|
if (tree.entries.length === 0) {
|
|
528
540
|
console.log(" (empty)");
|
|
@@ -543,7 +555,7 @@ function registerFiles(spacesCmd) {
|
|
|
543
555
|
.command("cat <path>")
|
|
544
556
|
.description("Read file content")
|
|
545
557
|
.action(async (path) => {
|
|
546
|
-
const spaceId =
|
|
558
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
547
559
|
const client = createClient();
|
|
548
560
|
try {
|
|
549
561
|
const file = await client.space(spaceId).files.read(path);
|
|
@@ -573,7 +585,7 @@ function registerFiles(spacesCmd) {
|
|
|
573
585
|
}
|
|
574
586
|
if (!content)
|
|
575
587
|
return error("No content provided", "Use -c or pipe via stdin");
|
|
576
|
-
const spaceId =
|
|
588
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
577
589
|
const client = createClient();
|
|
578
590
|
try {
|
|
579
591
|
const result = await client.space(spaceId).files.write({
|
|
@@ -597,7 +609,7 @@ function registerFiles(spacesCmd) {
|
|
|
597
609
|
.command("mkdir <path>")
|
|
598
610
|
.description("Create a directory")
|
|
599
611
|
.action(async (path) => {
|
|
600
|
-
const spaceId =
|
|
612
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
601
613
|
const client = createClient();
|
|
602
614
|
try {
|
|
603
615
|
await client.space(spaceId).files.createDir(path);
|
|
@@ -612,7 +624,7 @@ function registerFiles(spacesCmd) {
|
|
|
612
624
|
.description("Delete a file or directory")
|
|
613
625
|
.option("-r, --recursive", "Delete recursively")
|
|
614
626
|
.action(async (path, opts) => {
|
|
615
|
-
const spaceId =
|
|
627
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
616
628
|
const client = createClient();
|
|
617
629
|
try {
|
|
618
630
|
await client.space(spaceId).files.delete(path, opts.recursive ?? false);
|
|
@@ -626,7 +638,7 @@ function registerFiles(spacesCmd) {
|
|
|
626
638
|
.command("mv <from> <to>")
|
|
627
639
|
.description("Move or rename")
|
|
628
640
|
.action(async (from, to) => {
|
|
629
|
-
const spaceId =
|
|
641
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
630
642
|
const client = createClient();
|
|
631
643
|
try {
|
|
632
644
|
await client.space(spaceId).files.move({ fromPath: from, toPath: to });
|
|
@@ -642,18 +654,18 @@ function registerSessions(spacesCmd) {
|
|
|
642
654
|
const sessionsCmd = spacesCmd
|
|
643
655
|
.command("sessions")
|
|
644
656
|
.description("Browse sessions and turns")
|
|
645
|
-
.hook("preAction", () => {
|
|
657
|
+
.hook("preAction", () => { resolveSpace(spacesCmd); });
|
|
646
658
|
sessionsCmd
|
|
647
659
|
.command("ls")
|
|
648
660
|
.alias("list")
|
|
649
661
|
.description("List sessions")
|
|
650
662
|
.option("--json", "Output as JSON")
|
|
651
663
|
.action(async (opts) => {
|
|
652
|
-
const spaceId =
|
|
664
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
653
665
|
const client = createClient();
|
|
654
666
|
try {
|
|
655
667
|
const result = await client.space(spaceId).sessions.list();
|
|
656
|
-
if (opts
|
|
668
|
+
if (jsonRequested(opts))
|
|
657
669
|
return outJson(result);
|
|
658
670
|
if (result.sessions.length === 0) {
|
|
659
671
|
console.log(" (empty)");
|
|
@@ -675,11 +687,11 @@ function registerSessions(spacesCmd) {
|
|
|
675
687
|
.description("Create a session")
|
|
676
688
|
.option("--json", "Output as JSON")
|
|
677
689
|
.action(async (title, opts) => {
|
|
678
|
-
const spaceId =
|
|
690
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
679
691
|
const client = createClient();
|
|
680
692
|
try {
|
|
681
693
|
const result = await client.space(spaceId).sessions.create({ title });
|
|
682
|
-
if (opts
|
|
694
|
+
if (jsonRequested(opts))
|
|
683
695
|
return outJson(result);
|
|
684
696
|
ok(`Session created: ${result.session.id}`);
|
|
685
697
|
table([result.session], [
|
|
@@ -696,11 +708,11 @@ function registerSessions(spacesCmd) {
|
|
|
696
708
|
.description("Session details")
|
|
697
709
|
.option("--json", "Output as JSON")
|
|
698
710
|
.action(async (id, opts) => {
|
|
699
|
-
const spaceId =
|
|
711
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
700
712
|
const client = createClient();
|
|
701
713
|
try {
|
|
702
714
|
const result = await client.space(spaceId).session(id).get();
|
|
703
|
-
if (opts
|
|
715
|
+
if (jsonRequested(opts))
|
|
704
716
|
return outJson(result);
|
|
705
717
|
table([result.session], [
|
|
706
718
|
{ key: "id", label: "ID" },
|
|
@@ -718,7 +730,7 @@ function registerSessions(spacesCmd) {
|
|
|
718
730
|
.command("rename <id> <name>")
|
|
719
731
|
.description("Rename a session")
|
|
720
732
|
.action(async (id, name) => {
|
|
721
|
-
const spaceId =
|
|
733
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
722
734
|
const client = createClient();
|
|
723
735
|
try {
|
|
724
736
|
await client.space(spaceId).session(id).rename(name);
|
|
@@ -734,13 +746,13 @@ function registerSessions(spacesCmd) {
|
|
|
734
746
|
.description("Stream realtime session events")
|
|
735
747
|
.option("--json", "Output as JSON")
|
|
736
748
|
.action(async (id, opts) => {
|
|
737
|
-
const spaceId =
|
|
749
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
738
750
|
const client = createClient();
|
|
739
751
|
const session = client.space(spaceId).session(id);
|
|
740
752
|
process.stdout.write(" Listening for events...\n\n");
|
|
741
753
|
let lastAppendPath = null;
|
|
742
754
|
session.on("turn.patch", (e) => {
|
|
743
|
-
if (opts
|
|
755
|
+
if (jsonRequested(opts)) {
|
|
744
756
|
console.log(JSON.stringify(e));
|
|
745
757
|
}
|
|
746
758
|
else {
|
|
@@ -767,7 +779,7 @@ function registerSessions(spacesCmd) {
|
|
|
767
779
|
});
|
|
768
780
|
session.on("turn.error", (e) => {
|
|
769
781
|
process.stderr.write(`\n ✗ Error\n`);
|
|
770
|
-
if (opts
|
|
782
|
+
if (jsonRequested(opts))
|
|
771
783
|
process.stderr.write(`${JSON.stringify(e)}\n`);
|
|
772
784
|
process.exit(1);
|
|
773
785
|
});
|
|
@@ -789,15 +801,15 @@ function registerTurns(sessionsCmd) {
|
|
|
789
801
|
.option("--limit <n>", "Page size", "30")
|
|
790
802
|
.option("--json", "Output as JSON")
|
|
791
803
|
.action(async (sessionId, opts) => {
|
|
792
|
-
const spaceId =
|
|
804
|
+
const spaceId = resolveSpace(sessionsCmd);
|
|
793
805
|
const client = createClient();
|
|
794
806
|
try {
|
|
795
807
|
const result = await client.space(spaceId).session(sessionId).turns.listPaginated({
|
|
796
|
-
cursor: opts.cursor === undefined ? undefined :
|
|
797
|
-
direction: opts.direction,
|
|
798
|
-
limit:
|
|
808
|
+
cursor: opts.cursor === undefined ? undefined : parseInteger(opts.cursor, "cursor", { min: 0 }),
|
|
809
|
+
direction: parseChoice(opts.direction ?? "older", "direction", ["older", "newer"]),
|
|
810
|
+
limit: parseInteger(opts.limit ?? "30", "limit", { min: 1, max: 100 }),
|
|
799
811
|
});
|
|
800
|
-
if (opts
|
|
812
|
+
if (jsonRequested(opts))
|
|
801
813
|
return outJson(result);
|
|
802
814
|
if (result.turns.length === 0)
|
|
803
815
|
return console.log(" No turns found");
|
|
@@ -821,11 +833,11 @@ function registerTurns(sessionsCmd) {
|
|
|
821
833
|
.description("Show turn details")
|
|
822
834
|
.option("--json", "Output as JSON")
|
|
823
835
|
.action(async (sessionId, turnId, opts) => {
|
|
824
|
-
const spaceId =
|
|
836
|
+
const spaceId = resolveSpace(sessionsCmd);
|
|
825
837
|
const client = createClient();
|
|
826
838
|
try {
|
|
827
839
|
const result = await client.space(spaceId).session(sessionId).turns.get(turnId);
|
|
828
|
-
if (opts
|
|
840
|
+
if (jsonRequested(opts))
|
|
829
841
|
return outJson(result);
|
|
830
842
|
table([result.turn], [
|
|
831
843
|
{ key: "sequence", label: "Seq" },
|
|
@@ -852,14 +864,14 @@ function registerTurns(sessionsCmd) {
|
|
|
852
864
|
.option("--limit <n>", "Page size", "100")
|
|
853
865
|
.option("--json", "Output as JSON")
|
|
854
866
|
.action(async (sessionId, opts) => {
|
|
855
|
-
const spaceId =
|
|
867
|
+
const spaceId = resolveSpace(sessionsCmd);
|
|
856
868
|
const client = createClient();
|
|
857
869
|
try {
|
|
858
870
|
const result = await client.space(spaceId).session(sessionId).turns.index({
|
|
859
|
-
cursor: opts.cursor === undefined ? undefined :
|
|
860
|
-
limit:
|
|
871
|
+
cursor: opts.cursor === undefined ? undefined : parseInteger(opts.cursor, "cursor", { min: 0 }),
|
|
872
|
+
limit: parseInteger(opts.limit ?? "100", "limit", { min: 1, max: 500 }),
|
|
861
873
|
});
|
|
862
|
-
if (opts
|
|
874
|
+
if (jsonRequested(opts))
|
|
863
875
|
return outJson(result);
|
|
864
876
|
if (result.turns.length === 0)
|
|
865
877
|
return console.log(" No turns found");
|
|
@@ -886,18 +898,18 @@ function registerTurns(sessionsCmd) {
|
|
|
886
898
|
.option("--after <n>", "Turns after anchor", "20")
|
|
887
899
|
.option("--json", "Output as JSON")
|
|
888
900
|
.action(async (sessionId, opts) => {
|
|
889
|
-
const spaceId =
|
|
901
|
+
const spaceId = resolveSpace(sessionsCmd);
|
|
890
902
|
if (!opts.sequence && !opts.turn)
|
|
891
903
|
return error("Missing anchor", "Use --sequence <n> or --turn <id>");
|
|
892
904
|
const client = createClient();
|
|
893
905
|
try {
|
|
894
906
|
const result = await client.space(spaceId).session(sessionId).turns.window({
|
|
895
|
-
sequence: opts.sequence === undefined ? undefined :
|
|
907
|
+
sequence: opts.sequence === undefined ? undefined : parseInteger(opts.sequence, "sequence", { min: 0 }),
|
|
896
908
|
turnId: opts.turn,
|
|
897
|
-
before:
|
|
898
|
-
after:
|
|
909
|
+
before: parseInteger(opts.before ?? "10", "before", { min: 0, max: 200 }),
|
|
910
|
+
after: parseInteger(opts.after ?? "20", "after", { min: 0, max: 200 }),
|
|
899
911
|
});
|
|
900
|
-
if (opts
|
|
912
|
+
if (jsonRequested(opts))
|
|
901
913
|
return outJson(result);
|
|
902
914
|
if (result.turns.length === 0)
|
|
903
915
|
return console.log(" No turns found");
|
|
@@ -926,7 +938,7 @@ function registerSessionAccess(sessionsCmd) {
|
|
|
926
938
|
const client = createClient();
|
|
927
939
|
try {
|
|
928
940
|
const policy = await client.sessionAccess.get(id);
|
|
929
|
-
if (opts
|
|
941
|
+
if (jsonRequested(opts))
|
|
930
942
|
return outJson(policy);
|
|
931
943
|
table([policy], [
|
|
932
944
|
{ key: "signed_in_user", label: "Signed-in" },
|
|
@@ -946,9 +958,9 @@ function registerSessionAccess(sessionsCmd) {
|
|
|
946
958
|
const client = createClient();
|
|
947
959
|
try {
|
|
948
960
|
const policy = await client.sessionAccess.set(id, {
|
|
949
|
-
anonymous_user: (opts.anonymous
|
|
961
|
+
anonymous_user: parseNullableRole(opts.anonymous, "anonymous role"),
|
|
950
962
|
});
|
|
951
|
-
if (opts
|
|
963
|
+
if (jsonRequested(opts))
|
|
952
964
|
return outJson(policy);
|
|
953
965
|
ok("Session access updated");
|
|
954
966
|
table([policy], [
|
|
@@ -979,18 +991,18 @@ function registerMembers(spacesCmd) {
|
|
|
979
991
|
const memCmd = spacesCmd
|
|
980
992
|
.command("members")
|
|
981
993
|
.description("Member management")
|
|
982
|
-
.hook("preAction", () => {
|
|
994
|
+
.hook("preAction", () => { resolveSpace(spacesCmd); });
|
|
983
995
|
memCmd
|
|
984
996
|
.command("ls")
|
|
985
997
|
.alias("list")
|
|
986
998
|
.description("List space members")
|
|
987
999
|
.option("--json", "Output as JSON")
|
|
988
1000
|
.action(async (opts) => {
|
|
989
|
-
const spaceId =
|
|
1001
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
990
1002
|
const client = createClient();
|
|
991
1003
|
try {
|
|
992
1004
|
const result = await client.space(spaceId).members.list();
|
|
993
|
-
if (opts
|
|
1005
|
+
if (jsonRequested(opts))
|
|
994
1006
|
return outJson(result);
|
|
995
1007
|
if (result.items.length === 0) {
|
|
996
1008
|
console.log(" (empty)");
|
|
@@ -1010,10 +1022,10 @@ function registerMembers(spacesCmd) {
|
|
|
1010
1022
|
.command("update <userId> <role>")
|
|
1011
1023
|
.description("Change member role (host | builder | guest)")
|
|
1012
1024
|
.action(async (userId, role) => {
|
|
1013
|
-
const spaceId =
|
|
1025
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
1014
1026
|
const client = createClient();
|
|
1015
1027
|
try {
|
|
1016
|
-
await client.space(spaceId).members.update(userId, role);
|
|
1028
|
+
await client.space(spaceId).members.update(userId, parseChoice(role, "role", SPACE_ROLES));
|
|
1017
1029
|
ok(`${userId} → ${role}`);
|
|
1018
1030
|
}
|
|
1019
1031
|
catch (e) {
|
|
@@ -1024,7 +1036,7 @@ function registerMembers(spacesCmd) {
|
|
|
1024
1036
|
.command("remove <userId>")
|
|
1025
1037
|
.description("Remove a member")
|
|
1026
1038
|
.action(async (userId) => {
|
|
1027
|
-
const spaceId =
|
|
1039
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
1028
1040
|
const client = createClient();
|
|
1029
1041
|
try {
|
|
1030
1042
|
await client.space(spaceId).members.remove(userId);
|
|
@@ -1040,17 +1052,17 @@ function registerAccess(spacesCmd) {
|
|
|
1040
1052
|
const accCmd = spacesCmd
|
|
1041
1053
|
.command("access")
|
|
1042
1054
|
.description("Access control")
|
|
1043
|
-
.hook("preAction", () => {
|
|
1055
|
+
.hook("preAction", () => { resolveSpace(spacesCmd); });
|
|
1044
1056
|
accCmd
|
|
1045
1057
|
.command("get")
|
|
1046
1058
|
.description("Get access policy")
|
|
1047
1059
|
.option("--json", "Output as JSON")
|
|
1048
1060
|
.action(async (opts) => {
|
|
1049
|
-
const spaceId =
|
|
1061
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
1050
1062
|
const client = createClient();
|
|
1051
1063
|
try {
|
|
1052
1064
|
const policy = await client.space(spaceId).access.get();
|
|
1053
|
-
if (opts
|
|
1065
|
+
if (jsonRequested(opts))
|
|
1054
1066
|
return outJson(policy);
|
|
1055
1067
|
table([policy], [
|
|
1056
1068
|
{ key: "signed_in_user", label: "Signed-in" },
|
|
@@ -1068,14 +1080,14 @@ function registerAccess(spacesCmd) {
|
|
|
1068
1080
|
.option("--anonymous <role>", "Role for anonymous users (host|builder|guest|null)")
|
|
1069
1081
|
.option("--json", "Output as JSON")
|
|
1070
1082
|
.action(async (opts) => {
|
|
1071
|
-
const spaceId =
|
|
1083
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
1072
1084
|
const client = createClient();
|
|
1073
1085
|
try {
|
|
1074
1086
|
const policy = await client.space(spaceId).access.set({
|
|
1075
|
-
signed_in_user: (opts.signedIn
|
|
1076
|
-
anonymous_user: (opts.anonymous
|
|
1087
|
+
signed_in_user: parseNullableRole(opts.signedIn, "signed-in role"),
|
|
1088
|
+
anonymous_user: parseNullableRole(opts.anonymous, "anonymous role"),
|
|
1077
1089
|
});
|
|
1078
|
-
if (opts
|
|
1090
|
+
if (jsonRequested(opts))
|
|
1079
1091
|
return outJson(policy);
|
|
1080
1092
|
ok("Access policy updated");
|
|
1081
1093
|
table([policy], [
|
|
@@ -1093,18 +1105,18 @@ function registerCheckpoints(spacesCmd) {
|
|
|
1093
1105
|
const cpCmd = spacesCmd
|
|
1094
1106
|
.command("checkpoints")
|
|
1095
1107
|
.description("Checkpoint management")
|
|
1096
|
-
.hook("preAction", () => {
|
|
1108
|
+
.hook("preAction", () => { resolveSpace(spacesCmd); });
|
|
1097
1109
|
cpCmd
|
|
1098
1110
|
.command("ls")
|
|
1099
1111
|
.alias("list")
|
|
1100
1112
|
.description("List checkpoints")
|
|
1101
1113
|
.option("--json", "Output as JSON")
|
|
1102
1114
|
.action(async (opts) => {
|
|
1103
|
-
const spaceId =
|
|
1115
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
1104
1116
|
const client = createClient();
|
|
1105
1117
|
try {
|
|
1106
1118
|
const result = await client.space(spaceId).checkpoints.list();
|
|
1107
|
-
if (opts
|
|
1119
|
+
if (jsonRequested(opts))
|
|
1108
1120
|
return outJson(result);
|
|
1109
1121
|
if (result.checkpoints.length === 0) {
|
|
1110
1122
|
console.log(" (empty)");
|
|
@@ -1126,11 +1138,11 @@ function registerCheckpoints(spacesCmd) {
|
|
|
1126
1138
|
.description("Checkpoint details")
|
|
1127
1139
|
.option("--json", "Output as JSON")
|
|
1128
1140
|
.action(async (id, opts) => {
|
|
1129
|
-
const spaceId =
|
|
1141
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
1130
1142
|
const client = createClient();
|
|
1131
1143
|
try {
|
|
1132
1144
|
const result = await client.space(spaceId).checkpoints.get(id);
|
|
1133
|
-
if (opts
|
|
1145
|
+
if (jsonRequested(opts))
|
|
1134
1146
|
return outJson(result);
|
|
1135
1147
|
table([result.checkpoint], [
|
|
1136
1148
|
{ key: "id", label: "ID" },
|
|
@@ -1149,11 +1161,11 @@ function registerCheckpoints(spacesCmd) {
|
|
|
1149
1161
|
.description("Create a checkpoint")
|
|
1150
1162
|
.option("--json", "Output as JSON")
|
|
1151
1163
|
.action(async (description, opts) => {
|
|
1152
|
-
const spaceId =
|
|
1164
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
1153
1165
|
const client = createClient();
|
|
1154
1166
|
try {
|
|
1155
1167
|
const result = await client.space(spaceId).checkpoints.create(description ?? null);
|
|
1156
|
-
if (opts
|
|
1168
|
+
if (jsonRequested(opts))
|
|
1157
1169
|
return outJson(result);
|
|
1158
1170
|
ok(`Checkpoint created — taskRunId: ${result.taskRunId}`);
|
|
1159
1171
|
}
|
package/dist/commands/tasks.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createClient } from "../client.js";
|
|
2
|
-
import { table, json as outJson, handleHttp } from "../output.js";
|
|
2
|
+
import { table, json as outJson, jsonRequested, handleHttp } from "../output.js";
|
|
3
3
|
export function registerTasks(program) {
|
|
4
4
|
const cmd = program.command("tasks", { hidden: true }).description("Task runs");
|
|
5
5
|
cmd
|
|
@@ -18,7 +18,7 @@ export function registerTasks(program) {
|
|
|
18
18
|
if (opts.space)
|
|
19
19
|
filters.spaceId = opts.space;
|
|
20
20
|
const result = await client.tasks.list(filters);
|
|
21
|
-
if (opts
|
|
21
|
+
if (jsonRequested(opts))
|
|
22
22
|
return outJson(result);
|
|
23
23
|
if (result.runs.length === 0)
|
|
24
24
|
return console.log(" (empty)");
|
|
@@ -41,7 +41,7 @@ export function registerTasks(program) {
|
|
|
41
41
|
const client = createClient();
|
|
42
42
|
try {
|
|
43
43
|
const result = await client.tasks.get(id);
|
|
44
|
-
if (opts
|
|
44
|
+
if (jsonRequested(opts))
|
|
45
45
|
return outJson(result);
|
|
46
46
|
table([result.run], [
|
|
47
47
|
{ key: "id", label: "ID" },
|
package/dist/output.d.ts
CHANGED
|
@@ -4,10 +4,14 @@ export declare function table(rows: Row[], columns: {
|
|
|
4
4
|
label: string;
|
|
5
5
|
}[]): void;
|
|
6
6
|
export declare function json(data: unknown): void;
|
|
7
|
+
export declare function jsonRequested(opts?: {
|
|
8
|
+
json?: boolean;
|
|
9
|
+
}): boolean;
|
|
7
10
|
export declare function ok(msg: string): void;
|
|
8
11
|
export declare function error(msg: string, detail?: string): never;
|
|
9
12
|
export declare function handleHttp(e: unknown): never;
|
|
10
13
|
export declare function spinner(): {
|
|
11
14
|
start(msg: string): void;
|
|
15
|
+
update(msg: string): void;
|
|
12
16
|
stop(msg: string): void;
|
|
13
17
|
};
|