@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 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
@@ -1,2 +1,3 @@
1
1
  import type { Command } from "commander";
2
+ export declare const resolveLocalSpaceName: (rootDir: string, requestedName?: string) => string;
2
3
  export declare function registerSandbox(program: Command): void;
@@ -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;
@@ -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>")
@@ -1,2 +1,8 @@
1
1
  import type { Command } from "commander";
2
- export declare function registerTasks(program: Command): void;
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 {};
@@ -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 = createClient();
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 (opts.space)
27
- filters.spaceId = opts.space;
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 = createClient();
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.1",
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": "4.9.0"
22
+ "@neta-art/cohub": "5.0.0"
23
23
  },
24
24
  "publishConfig": {
25
25
  "access": "public"