@neta-art/cohub-cli 3.5.1 → 3.5.2
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 +4 -0
- package/dist/commands/sandbox.d.ts +1 -0
- package/dist/commands/sandbox.js +3 -2
- package/dist/commands/spaces.d.ts +14 -0
- package/dist/commands/spaces.js +56 -32
- package/dist/commands/tasks.d.ts +7 -1
- package/dist/commands/tasks.js +7 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -63,6 +63,7 @@ cohub spaces get <spaceId> --json
|
|
|
63
63
|
cohub -s <spaceId> spaces get
|
|
64
64
|
COHUB_SPACE_ID=<spaceId> cohub spaces get
|
|
65
65
|
cohub spaces create --name "<name>" --description "<description>" --json
|
|
66
|
+
cohub spaces create --name "<name>" --checkpoint <checkpointId> --json
|
|
66
67
|
cohub spaces update <spaceId> --slug <space-slug>
|
|
67
68
|
cohub spaces rename <spaceId> "<new name>"
|
|
68
69
|
cohub -s <spaceId> spaces invites create --role builder --days 7
|
|
@@ -291,6 +292,9 @@ cohub works resolve <workSlug> --owner <username> --space-slug <spaceSlug>
|
|
|
291
292
|
|
|
292
293
|
Use `--json` for machine-readable output. The resolve command requires both `--owner` and `--space-slug` so missing public profile data fails with a clear message.
|
|
293
294
|
|
|
295
|
+
Realtime rooms use a published Work's runtime identity, so they are available
|
|
296
|
+
through `client.work.realtime` in the SDK rather than as CLI commands.
|
|
297
|
+
|
|
294
298
|
## Saves
|
|
295
299
|
|
|
296
300
|
```bash
|
package/dist/commands/sandbox.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { stat } from "node:fs/promises";
|
|
3
3
|
import { createInterface } from "node:readline";
|
|
4
|
-
import { resolve } from "node:path";
|
|
4
|
+
import { basename, resolve } from "node:path";
|
|
5
5
|
import { resolveCohubEnvironment, resolveWebsocketUrl } from "@neta-art/cohub";
|
|
6
6
|
import { requireAccessToken } from "../auth.js";
|
|
7
7
|
import { createClient } from "../client.js";
|
|
@@ -28,6 +28,7 @@ const confirm = async (question) => {
|
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
30
|
const webBaseUrl = () => resolveCohubEnvironment() === "prod" ? "https://cohub.run" : "https://dev.cohub.run";
|
|
31
|
+
export const resolveLocalSpaceName = (rootDir, requestedName) => requestedName?.trim() || basename(rootDir) || "local-space";
|
|
31
32
|
// Consent copy is deliberately explicit: a local sandbox runs agent-issued
|
|
32
33
|
// shell commands as the current OS user. File RPCs are fenced to the folder,
|
|
33
34
|
// but shell commands are NOT — they can read/write anything the user can
|
|
@@ -97,7 +98,7 @@ export function registerSandbox(program) {
|
|
|
97
98
|
return error("Aborted", "No space was created");
|
|
98
99
|
}
|
|
99
100
|
const created = await client.spaces.create({
|
|
100
|
-
name: opts.name,
|
|
101
|
+
name: resolveLocalSpaceName(rootDir, opts.name),
|
|
101
102
|
config: { sandbox: { provider: "local" } },
|
|
102
103
|
});
|
|
103
104
|
spaceId = created.space.id;
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import type { CohubHttpClient, CreateSpaceInput } from "@neta-art/cohub";
|
|
1
2
|
import type { Command } from "commander";
|
|
3
|
+
export type SpaceCreateOptions = {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
checkpoint?: string;
|
|
7
|
+
autoDestroy?: string;
|
|
8
|
+
idleTtl?: string;
|
|
9
|
+
spec?: string;
|
|
10
|
+
json?: boolean;
|
|
11
|
+
};
|
|
12
|
+
export declare function buildSpaceCreateInput(opts: SpaceCreateOptions): CreateSpaceInput;
|
|
2
13
|
export declare function registerPrompt(program: Command): void;
|
|
14
|
+
export declare function registerSpaceCreate(spacesCmd: Command, dependencies?: {
|
|
15
|
+
createClient?: () => CohubHttpClient;
|
|
16
|
+
}): Command;
|
|
3
17
|
export declare function registerSpaces(program: Command): void;
|
package/dist/commands/spaces.js
CHANGED
|
@@ -67,6 +67,31 @@ const parseAutoDestroy = (opts) => {
|
|
|
67
67
|
return { mode: "idle", ttlSeconds };
|
|
68
68
|
};
|
|
69
69
|
const parseSandboxSpec = (value) => value ? parseChoice(value, "sandbox spec", SANDBOX_SPEC_IDS) : undefined;
|
|
70
|
+
export function buildSpaceCreateInput(opts) {
|
|
71
|
+
const autoDestroy = parseAutoDestroy(opts);
|
|
72
|
+
const spec = parseSandboxSpec(opts.spec);
|
|
73
|
+
const checkpointId = opts.checkpoint?.trim();
|
|
74
|
+
if (opts.checkpoint !== undefined && !checkpointId) {
|
|
75
|
+
return error("Invalid checkpoint", "Checkpoint ID is required");
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
name: opts.name,
|
|
79
|
+
description: opts.description,
|
|
80
|
+
...(checkpointId
|
|
81
|
+
? { bootstrapSource: { type: "checkpoint", checkpointId } }
|
|
82
|
+
: {}),
|
|
83
|
+
...((autoDestroy || spec)
|
|
84
|
+
? {
|
|
85
|
+
config: {
|
|
86
|
+
sandbox: {
|
|
87
|
+
...(autoDestroy ? { autoDestroy } : {}),
|
|
88
|
+
...(spec ? { spec } : {}),
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
: {}),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
70
95
|
const formatAutoDestroy = (policy) => {
|
|
71
96
|
if (!policy)
|
|
72
97
|
return `${cliEnv === "prod" ? "12h" : "10m"} (default)`;
|
|
@@ -376,6 +401,36 @@ export function registerPrompt(program) {
|
|
|
376
401
|
.option("--json", "Output as JSON")
|
|
377
402
|
.action((words, opts) => runCompletionCommand(program, words, opts));
|
|
378
403
|
}
|
|
404
|
+
export function registerSpaceCreate(spacesCmd, dependencies = {}) {
|
|
405
|
+
const getClient = dependencies.createClient ?? createClient;
|
|
406
|
+
return spacesCmd
|
|
407
|
+
.command("create")
|
|
408
|
+
.description("Create a new space")
|
|
409
|
+
.requiredOption("-n, --name <name>", "Space name")
|
|
410
|
+
.option("-d, --description <desc>", "Space description")
|
|
411
|
+
.option("--checkpoint <id>", "Create from a checkpoint")
|
|
412
|
+
.option("--auto-destroy <mode>", "Sandbox auto destroy mode: idle or never")
|
|
413
|
+
.option("--idle-ttl <seconds>", "Idle auto destroy TTL in seconds, max 2592000 (30d)")
|
|
414
|
+
.option("--spec <spec>", "Sandbox spec: standard, boost, or ultra")
|
|
415
|
+
.option("--json", "Output as JSON")
|
|
416
|
+
.action(async (opts) => {
|
|
417
|
+
const client = getClient();
|
|
418
|
+
try {
|
|
419
|
+
const result = await client.spaces.create(buildSpaceCreateInput(opts));
|
|
420
|
+
if (jsonRequested(opts))
|
|
421
|
+
return outJson(result);
|
|
422
|
+
ok(`Space created: ${result.space.id}`);
|
|
423
|
+
table([{ ...result.space, taskRunId: result.taskRunId }], [
|
|
424
|
+
{ key: "id", label: "ID" },
|
|
425
|
+
{ key: "name", label: "Name" },
|
|
426
|
+
{ key: "taskRunId", label: "Task" },
|
|
427
|
+
]);
|
|
428
|
+
}
|
|
429
|
+
catch (e) {
|
|
430
|
+
handleHttp(e);
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
}
|
|
379
434
|
export function registerSpaces(program) {
|
|
380
435
|
const spacesCmd = program.command("spaces").description("Space management");
|
|
381
436
|
registerSpaceInvitations(spacesCmd);
|
|
@@ -441,38 +496,7 @@ export function registerSpaces(program) {
|
|
|
441
496
|
}
|
|
442
497
|
});
|
|
443
498
|
// ── spaces create ──
|
|
444
|
-
spacesCmd
|
|
445
|
-
.command("create")
|
|
446
|
-
.description("Create a new space")
|
|
447
|
-
.option("-n, --name <name>", "Space name")
|
|
448
|
-
.option("-d, --description <desc>", "Space description")
|
|
449
|
-
.option("--auto-destroy <mode>", "Sandbox auto destroy mode: idle or never")
|
|
450
|
-
.option("--idle-ttl <seconds>", "Idle auto destroy TTL in seconds, max 2592000 (30d)")
|
|
451
|
-
.option("--spec <spec>", "Sandbox spec: standard, boost, or ultra")
|
|
452
|
-
.option("--json", "Output as JSON")
|
|
453
|
-
.action(async (opts) => {
|
|
454
|
-
const client = createClient();
|
|
455
|
-
try {
|
|
456
|
-
const autoDestroy = parseAutoDestroy(opts);
|
|
457
|
-
const spec = parseSandboxSpec(opts.spec);
|
|
458
|
-
const result = await client.spaces.create({
|
|
459
|
-
name: opts.name,
|
|
460
|
-
description: opts.description,
|
|
461
|
-
...((autoDestroy || spec) ? { config: { sandbox: { ...(autoDestroy ? { autoDestroy } : {}), ...(spec ? { spec } : {}) } } } : {}),
|
|
462
|
-
});
|
|
463
|
-
if (jsonRequested(opts))
|
|
464
|
-
return outJson(result);
|
|
465
|
-
ok(`Space created: ${result.space.id}`);
|
|
466
|
-
table([result.space], [
|
|
467
|
-
{ key: "id", label: "ID" },
|
|
468
|
-
{ key: "name", label: "Name" },
|
|
469
|
-
{ key: "taskRunId", label: "Task" },
|
|
470
|
-
]);
|
|
471
|
-
}
|
|
472
|
-
catch (e) {
|
|
473
|
-
handleHttp(e);
|
|
474
|
-
}
|
|
475
|
-
});
|
|
499
|
+
registerSpaceCreate(spacesCmd);
|
|
476
500
|
// ── spaces update ──
|
|
477
501
|
spacesCmd
|
|
478
502
|
.command("update <id>")
|
package/dist/commands/tasks.d.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
|
-
|
|
2
|
+
import { createClient } from "../client.js";
|
|
3
|
+
type TasksClient = ReturnType<typeof createClient>;
|
|
4
|
+
type RegisterTasksDependencies = {
|
|
5
|
+
createClient?: () => TasksClient;
|
|
6
|
+
};
|
|
7
|
+
export declare function registerTasks(program: Command, dependencies?: RegisterTasksDependencies): void;
|
|
8
|
+
export {};
|
package/dist/commands/tasks.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createClient } from "../client.js";
|
|
2
2
|
import { table, json as outJson, jsonRequested, handleHttp } from "../output.js";
|
|
3
|
-
export function registerTasks(program) {
|
|
3
|
+
export function registerTasks(program, dependencies = {}) {
|
|
4
|
+
const getClient = dependencies.createClient ?? createClient;
|
|
4
5
|
const cmd = program.command("tasks", { hidden: true }).description("Task runs");
|
|
5
6
|
cmd
|
|
6
7
|
.command("ls")
|
|
@@ -15,16 +16,17 @@ export function registerTasks(program) {
|
|
|
15
16
|
.option("--cursor <cursor>", "Page cursor")
|
|
16
17
|
.option("--json", "Output as JSON")
|
|
17
18
|
.action(async (opts) => {
|
|
18
|
-
const client =
|
|
19
|
+
const client = getClient();
|
|
19
20
|
try {
|
|
20
21
|
const limit = opts.limit ? Number(opts.limit) : 50;
|
|
21
22
|
if (!Number.isFinite(limit) || limit < 1)
|
|
22
23
|
throw new Error("limit must be a positive number");
|
|
23
24
|
const filters = { limit: Math.floor(limit) };
|
|
25
|
+
const spaceId = opts.space ?? program.opts().space;
|
|
24
26
|
if (opts.cronJob)
|
|
25
27
|
filters.cronJobId = opts.cronJob;
|
|
26
|
-
if (
|
|
27
|
-
filters.spaceId =
|
|
28
|
+
if (spaceId)
|
|
29
|
+
filters.spaceId = spaceId;
|
|
28
30
|
if (opts.session)
|
|
29
31
|
filters.sessionId = opts.session;
|
|
30
32
|
if (opts.type)
|
|
@@ -58,7 +60,7 @@ export function registerTasks(program) {
|
|
|
58
60
|
.description("Task run details")
|
|
59
61
|
.option("--json", "Output as JSON")
|
|
60
62
|
.action(async (id, opts) => {
|
|
61
|
-
const client =
|
|
63
|
+
const client = getClient();
|
|
62
64
|
try {
|
|
63
65
|
const result = await client.tasks.get(id);
|
|
64
66
|
if (jsonRequested(opts))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neta-art/cohub-cli",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.2",
|
|
4
4
|
"description": "CLI for Cohub — spaces, sessions, and agent collaboration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"commander": "^15.0.0",
|
|
20
20
|
"pixi.js": "^8.19.0",
|
|
21
21
|
"sharp": "^0.35.3",
|
|
22
|
-
"@neta-art/cohub": "
|
|
22
|
+
"@neta-art/cohub": "5.0.0"
|
|
23
23
|
},
|
|
24
24
|
"publishConfig": {
|
|
25
25
|
"access": "public"
|