@neta-art/cohub-cli 1.4.2 → 1.5.1
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/dist/commands/spaces.js +125 -0
- package/dist/index.js +1 -0
- package/dist/output.js +32 -8
- package/package.json +2 -2
package/dist/commands/spaces.js
CHANGED
|
@@ -95,6 +95,21 @@ async function uploadFiles(command, paths, opts) {
|
|
|
95
95
|
handleHttp(e);
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
+
async function confirmRestart(opts) {
|
|
99
|
+
if (opts.yes)
|
|
100
|
+
return;
|
|
101
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
102
|
+
return error("Confirmation required", "Pass --yes to restart the sandbox automatically.");
|
|
103
|
+
process.stdout.write("Changing mods restarts the sandbox and may interrupt running work. Continue? [y/N] ");
|
|
104
|
+
const chunks = [];
|
|
105
|
+
for await (const chunk of process.stdin) {
|
|
106
|
+
chunks.push(chunk);
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
const answer = Buffer.concat(chunks).toString().trim().toLowerCase();
|
|
110
|
+
if (answer !== "y" && answer !== "yes")
|
|
111
|
+
return error("Cancelled");
|
|
112
|
+
}
|
|
98
113
|
async function readPromptContent(words) {
|
|
99
114
|
let content = words.join(" ");
|
|
100
115
|
if (!content && !process.stdin.isTTY) {
|
|
@@ -272,6 +287,8 @@ export function registerSpaces(program) {
|
|
|
272
287
|
registerAccess(spacesCmd);
|
|
273
288
|
// ── spaces checkpoints ──
|
|
274
289
|
registerCheckpoints(spacesCmd);
|
|
290
|
+
// ── spaces mods ──
|
|
291
|
+
registerMods(spacesCmd);
|
|
275
292
|
// ── spaces usage ──
|
|
276
293
|
spacesCmd
|
|
277
294
|
.command("usage [days]")
|
|
@@ -298,6 +315,114 @@ export function registerSpaces(program) {
|
|
|
298
315
|
}
|
|
299
316
|
});
|
|
300
317
|
}
|
|
318
|
+
function registerMods(spacesCmd) {
|
|
319
|
+
const modsCmd = spacesCmd
|
|
320
|
+
.command("mods")
|
|
321
|
+
.description("Manage space mods")
|
|
322
|
+
.hook("preAction", () => { requireSpace(spacesCmd); });
|
|
323
|
+
modsCmd
|
|
324
|
+
.command("ls")
|
|
325
|
+
.alias("list")
|
|
326
|
+
.description("List mods")
|
|
327
|
+
.option("--json", "Output as JSON")
|
|
328
|
+
.action(async (opts) => {
|
|
329
|
+
const spaceId = requireSpace(spacesCmd);
|
|
330
|
+
const client = createClient();
|
|
331
|
+
try {
|
|
332
|
+
const result = await client.space(spaceId).mods.list();
|
|
333
|
+
if (opts.json)
|
|
334
|
+
return outJson(result.items);
|
|
335
|
+
table(result.items, [
|
|
336
|
+
{ key: "id", label: "ID" },
|
|
337
|
+
{ key: "modSpaceName", label: "Name" },
|
|
338
|
+
{ key: "mountPath", label: "Mount" },
|
|
339
|
+
{ key: "enabled", label: "On" },
|
|
340
|
+
]);
|
|
341
|
+
}
|
|
342
|
+
catch (e) {
|
|
343
|
+
handleHttp(e);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
modsCmd
|
|
347
|
+
.command("add <modSpaceId>")
|
|
348
|
+
.description("Add a mod")
|
|
349
|
+
.option("--name <name>", "Display name")
|
|
350
|
+
.option("--slug <slug>", "Mount slug")
|
|
351
|
+
.option("-y, --yes", "Confirm sandbox restart")
|
|
352
|
+
.option("--json", "Output as JSON")
|
|
353
|
+
.action(async (modSpaceId, opts) => {
|
|
354
|
+
await confirmRestart(opts);
|
|
355
|
+
const spaceId = requireSpace(spacesCmd);
|
|
356
|
+
const client = createClient();
|
|
357
|
+
try {
|
|
358
|
+
const result = await client.space(spaceId).mods.create({ modSpaceId, name: opts.name, mountSlug: opts.slug });
|
|
359
|
+
if (opts.json)
|
|
360
|
+
return outJson(result);
|
|
361
|
+
ok(`Mod added — ${result.item.mountPath}; sandbox restarting`);
|
|
362
|
+
}
|
|
363
|
+
catch (e) {
|
|
364
|
+
handleHttp(e);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
modsCmd
|
|
368
|
+
.command("enable <modId>")
|
|
369
|
+
.description("Enable a mod")
|
|
370
|
+
.option("-y, --yes", "Confirm sandbox restart")
|
|
371
|
+
.option("--json", "Output as JSON")
|
|
372
|
+
.action(async (modId, opts) => {
|
|
373
|
+
await confirmRestart(opts);
|
|
374
|
+
const spaceId = requireSpace(spacesCmd);
|
|
375
|
+
const client = createClient();
|
|
376
|
+
try {
|
|
377
|
+
const result = await client.space(spaceId).mods.update(modId, { enabled: true });
|
|
378
|
+
if (opts.json)
|
|
379
|
+
return outJson(result);
|
|
380
|
+
ok("Mod enabled; sandbox restarting");
|
|
381
|
+
}
|
|
382
|
+
catch (e) {
|
|
383
|
+
handleHttp(e);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
modsCmd
|
|
387
|
+
.command("disable <modId>")
|
|
388
|
+
.description("Disable a mod")
|
|
389
|
+
.option("-y, --yes", "Confirm sandbox restart")
|
|
390
|
+
.option("--json", "Output as JSON")
|
|
391
|
+
.action(async (modId, opts) => {
|
|
392
|
+
await confirmRestart(opts);
|
|
393
|
+
const spaceId = requireSpace(spacesCmd);
|
|
394
|
+
const client = createClient();
|
|
395
|
+
try {
|
|
396
|
+
const result = await client.space(spaceId).mods.update(modId, { enabled: false });
|
|
397
|
+
if (opts.json)
|
|
398
|
+
return outJson(result);
|
|
399
|
+
ok("Mod disabled; sandbox restarting");
|
|
400
|
+
}
|
|
401
|
+
catch (e) {
|
|
402
|
+
handleHttp(e);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
modsCmd
|
|
406
|
+
.command("rm <modId>")
|
|
407
|
+
.alias("remove")
|
|
408
|
+
.description("Remove a mod")
|
|
409
|
+
.option("-y, --yes", "Confirm sandbox restart")
|
|
410
|
+
.option("--json", "Output as JSON")
|
|
411
|
+
.action(async (modId, opts) => {
|
|
412
|
+
await confirmRestart(opts);
|
|
413
|
+
const spaceId = requireSpace(spacesCmd);
|
|
414
|
+
const client = createClient();
|
|
415
|
+
try {
|
|
416
|
+
const result = await client.space(spaceId).mods.remove(modId);
|
|
417
|
+
if (opts.json)
|
|
418
|
+
return outJson(result);
|
|
419
|
+
ok("Mod removed; sandbox restarting");
|
|
420
|
+
}
|
|
421
|
+
catch (e) {
|
|
422
|
+
handleHttp(e);
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
}
|
|
301
426
|
// ── File operations ──
|
|
302
427
|
function registerFiles(spacesCmd) {
|
|
303
428
|
const filesCmd = spacesCmd
|
package/dist/index.js
CHANGED
|
@@ -63,6 +63,7 @@ try {
|
|
|
63
63
|
catch (error) {
|
|
64
64
|
const message = error instanceof Error ? error.message : String(error);
|
|
65
65
|
process.stderr.write(`cohub self-update failed: ${message}\n`);
|
|
66
|
+
process.stderr.write("run with --version to skip self-update\n");
|
|
66
67
|
process.exit(1);
|
|
67
68
|
}
|
|
68
69
|
program.parse();
|
package/dist/output.js
CHANGED
|
@@ -46,20 +46,44 @@ export function error(msg, detail) {
|
|
|
46
46
|
process.exit(1);
|
|
47
47
|
}
|
|
48
48
|
// -- HTTP error handler ------------------------------------------------------
|
|
49
|
+
function errorMessageFromBody(body) {
|
|
50
|
+
if (!body || typeof body !== "object")
|
|
51
|
+
return null;
|
|
52
|
+
const errorBody = body;
|
|
53
|
+
if (typeof errorBody.message === "string" && errorBody.message.trim())
|
|
54
|
+
return errorBody.message;
|
|
55
|
+
if (typeof errorBody.error?.message === "string" && errorBody.error.message.trim())
|
|
56
|
+
return errorBody.error.message;
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
function debugErrorMetaFromBody(body) {
|
|
60
|
+
if (!body || typeof body !== "object")
|
|
61
|
+
return [];
|
|
62
|
+
const errorBody = body;
|
|
63
|
+
const items = [];
|
|
64
|
+
const code = typeof errorBody.code === "string" ? errorBody.code : typeof errorBody.error?.code === "string" ? errorBody.error.code : null;
|
|
65
|
+
if (code)
|
|
66
|
+
items.push(code);
|
|
67
|
+
if (typeof errorBody.requestId === "string")
|
|
68
|
+
items.push(`requestId: ${errorBody.requestId}`);
|
|
69
|
+
if (typeof errorBody.traceId === "string")
|
|
70
|
+
items.push(`traceId: ${errorBody.traceId}`);
|
|
71
|
+
return items;
|
|
72
|
+
}
|
|
49
73
|
export function handleHttp(e) {
|
|
50
74
|
if (e instanceof Error && e.name === "AuthRequiredError") {
|
|
51
|
-
return error("
|
|
75
|
+
return error("not authenticated", "run `cohub auth login`");
|
|
52
76
|
}
|
|
53
77
|
const status = e.status;
|
|
54
78
|
const body = e.body;
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
79
|
+
const message = errorMessageFromBody(body) ?? (e instanceof Error ? e.message : String(e));
|
|
80
|
+
const detailParts = [];
|
|
81
|
+
if (process.env.COHUB_DEBUG_ERRORS) {
|
|
82
|
+
if (status)
|
|
83
|
+
detailParts.push(`HTTP ${status}`);
|
|
84
|
+
detailParts.push(...debugErrorMetaFromBody(body));
|
|
61
85
|
}
|
|
62
|
-
error(
|
|
86
|
+
error(message, detailParts.length > 0 ? detailParts.join(" · ") : undefined);
|
|
63
87
|
}
|
|
64
88
|
// -- Spinner -----------------------------------------------------------------
|
|
65
89
|
export function spinner() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neta-art/cohub-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "CLI for Cohub — spaces, sessions, and agent collaboration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"commander": "^13.1.0",
|
|
17
|
-
"@neta-art/cohub": "1.
|
|
17
|
+
"@neta-art/cohub": "1.12.0"
|
|
18
18
|
},
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"access": "public"
|