@neta-art/cohub-cli 2.2.8 → 2.2.9
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/generations.js +11 -0
- package/dist/commands/spaces.js +127 -2
- package/dist/output.js +10 -3
- package/package.json +3 -3
|
@@ -333,6 +333,17 @@ Examples:
|
|
|
333
333
|
if (jsonRequested(opts))
|
|
334
334
|
return outJson(savedPaths.length > 0 ? { ...result, taskRunId: created.taskRunId, savedPaths } : { ...result, taskRunId: created.taskRunId });
|
|
335
335
|
printGeneration(result.output);
|
|
336
|
+
if (result.requestId || result.cost !== undefined || result.billing) {
|
|
337
|
+
const details = [
|
|
338
|
+
result.requestId ? `request ID: ${result.requestId}` : null,
|
|
339
|
+
result.cost !== undefined ? `cost: ${result.cost}` : null,
|
|
340
|
+
result.billing
|
|
341
|
+
? `billing: ${result.billing.status}${result.billing.amountUsd > 0 ? ` ${result.billing.amountUsd}` : ""}${result.billing.reason ? ` (${result.billing.reason})` : ""}`
|
|
342
|
+
: null,
|
|
343
|
+
].filter(Boolean).join(", ");
|
|
344
|
+
if (details)
|
|
345
|
+
process.stderr.write(` ${details}\n`);
|
|
346
|
+
}
|
|
336
347
|
if (savedPaths.length > 0)
|
|
337
348
|
ok(`Saved to ${savedPaths.join(", ")}`);
|
|
338
349
|
}
|
package/dist/commands/spaces.js
CHANGED
|
@@ -436,7 +436,7 @@ export function registerSpaces(program) {
|
|
|
436
436
|
const result = await client.space(id).updateConfig({ sandbox: { ...(autoDestroy ? { autoDestroy } : {}), ...(spec ? { spec } : {}) } });
|
|
437
437
|
if (jsonRequested(opts))
|
|
438
438
|
return outJson(result);
|
|
439
|
-
ok(`Space config updated${autoDestroy ? ` — sandbox auto destroy: ${formatAutoDestroy(autoDestroy)}` : ""}${spec ? ` — sandbox spec: ${spec}` : ""}`);
|
|
439
|
+
ok(`Space config updated${autoDestroy ? ` — sandbox auto destroy: ${formatAutoDestroy(autoDestroy)}` : ""}${spec ? ` — sandbox spec: ${spec}` : ""}${result.sandbox?.pendingRestart ? " — restart the sandbox to apply" : ""}`);
|
|
440
440
|
return;
|
|
441
441
|
}
|
|
442
442
|
const result = await client.space(id).getConfig();
|
|
@@ -839,7 +839,73 @@ function registerMods(spacesCmd) {
|
|
|
839
839
|
}
|
|
840
840
|
});
|
|
841
841
|
}
|
|
842
|
-
|
|
842
|
+
function formatDiffBytes(value) {
|
|
843
|
+
if (value === null || value === undefined)
|
|
844
|
+
return "—";
|
|
845
|
+
if (value < 1024)
|
|
846
|
+
return `${value} B`;
|
|
847
|
+
if (value < 1024 * 1024)
|
|
848
|
+
return `${(value / 1024).toFixed(value >= 10 * 1024 ? 0 : 1)} KB`;
|
|
849
|
+
return `${(value / (1024 * 1024)).toFixed(1)} MB`;
|
|
850
|
+
}
|
|
851
|
+
function printDiffFile(file) {
|
|
852
|
+
if (file.kind !== "text") {
|
|
853
|
+
const size = file.oldSize !== undefined || file.newSize !== undefined
|
|
854
|
+
? ` (${formatDiffBytes(file.oldSize)} → ${formatDiffBytes(file.newSize)})`
|
|
855
|
+
: "";
|
|
856
|
+
console.log(`${file.status ?? "?"} ${file.path} (${file.kind})${size}`);
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
if (file.lines.length === 0) {
|
|
860
|
+
console.log(`${file.status ?? "?"} ${file.path} (no textual changes)`);
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
for (const line of file.lines) {
|
|
864
|
+
if (line.type === "add")
|
|
865
|
+
console.log(`+${line.text}`);
|
|
866
|
+
else if (line.type === "del")
|
|
867
|
+
console.log(`-${line.text}`);
|
|
868
|
+
else if (line.type === "hunk")
|
|
869
|
+
console.log(line.text);
|
|
870
|
+
else if (line.type === "meta")
|
|
871
|
+
continue;
|
|
872
|
+
else
|
|
873
|
+
console.log(` ${line.text}`);
|
|
874
|
+
}
|
|
875
|
+
if (file.truncated)
|
|
876
|
+
console.log(" … truncated");
|
|
877
|
+
}
|
|
878
|
+
function printDiffSummary(summary, options) {
|
|
879
|
+
if (summary.files.length === 0) {
|
|
880
|
+
console.log(options?.emptyLabel ?? " (no changes)");
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
if (summary.stats) {
|
|
884
|
+
const parts = [`${summary.stats.changedFileCount} file(s)`];
|
|
885
|
+
if (summary.stats.additions > 0)
|
|
886
|
+
parts.push(`+${summary.stats.additions}`);
|
|
887
|
+
if (summary.stats.deletions > 0)
|
|
888
|
+
parts.push(`-${summary.stats.deletions}`);
|
|
889
|
+
console.log(` ${parts.join(" · ")}`);
|
|
890
|
+
}
|
|
891
|
+
table(summary.files.map((file) => ({
|
|
892
|
+
status: file.status,
|
|
893
|
+
path: file.oldPath ? `${file.oldPath} → ${file.path}` : file.path,
|
|
894
|
+
plus: file.additions ?? (file.binary || file.asset ? "-" : "0"),
|
|
895
|
+
minus: file.deletions ?? (file.binary || file.asset ? "-" : "0"),
|
|
896
|
+
})), [
|
|
897
|
+
{ key: "status", label: "St" },
|
|
898
|
+
{ key: "path", label: "Path" },
|
|
899
|
+
{ key: "plus", label: "+" },
|
|
900
|
+
{ key: "minus", label: "-" },
|
|
901
|
+
]);
|
|
902
|
+
if (options?.footer)
|
|
903
|
+
console.log(options.footer);
|
|
904
|
+
else if (summary.incomplete)
|
|
905
|
+
console.log(" … partial scan");
|
|
906
|
+
else if (summary.truncated)
|
|
907
|
+
console.log(" … truncated");
|
|
908
|
+
}
|
|
843
909
|
function registerFiles(spacesCmd) {
|
|
844
910
|
const filesCmd = spacesCmd
|
|
845
911
|
.command("files")
|
|
@@ -969,6 +1035,37 @@ function registerFiles(spacesCmd) {
|
|
|
969
1035
|
handleHttp(e);
|
|
970
1036
|
}
|
|
971
1037
|
});
|
|
1038
|
+
filesCmd
|
|
1039
|
+
.command("diff [path]")
|
|
1040
|
+
.description("Show pending workspace changes vs last checkpoint")
|
|
1041
|
+
.option("--json", "Output as JSON")
|
|
1042
|
+
.action(async (path, opts) => {
|
|
1043
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
1044
|
+
const client = createClient();
|
|
1045
|
+
try {
|
|
1046
|
+
if (path) {
|
|
1047
|
+
const file = await client.space(spaceId).files.diffFile(path);
|
|
1048
|
+
if (jsonRequested(opts))
|
|
1049
|
+
return outJson(file);
|
|
1050
|
+
printDiffFile(file);
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
const summary = await client.space(spaceId).files.diff();
|
|
1054
|
+
if (jsonRequested(opts))
|
|
1055
|
+
return outJson(summary);
|
|
1056
|
+
printDiffSummary(summary, {
|
|
1057
|
+
emptyLabel: " (no pending changes)",
|
|
1058
|
+
footer: summary.incomplete
|
|
1059
|
+
? " … partial scan"
|
|
1060
|
+
: summary.truncated
|
|
1061
|
+
? " … truncated"
|
|
1062
|
+
: null,
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
catch (e) {
|
|
1066
|
+
handleHttp(e);
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
972
1069
|
}
|
|
973
1070
|
function registerSessions(spacesCmd) {
|
|
974
1071
|
const sessionsCmd = spacesCmd
|
|
@@ -1585,4 +1682,32 @@ function registerCheckpoints(spacesCmd) {
|
|
|
1585
1682
|
handleHttp(e);
|
|
1586
1683
|
}
|
|
1587
1684
|
});
|
|
1685
|
+
cpCmd
|
|
1686
|
+
.command("diff <checkpointId> [path]")
|
|
1687
|
+
.description("Show checkpoint diff vs parent (or --base)")
|
|
1688
|
+
.option("--base <checkpointId>", "Compare against another checkpoint")
|
|
1689
|
+
.option("--json", "Output as JSON")
|
|
1690
|
+
.action(async (checkpointId, path, opts) => {
|
|
1691
|
+
const spaceId = resolveSpace(spacesCmd);
|
|
1692
|
+
const client = createClient();
|
|
1693
|
+
try {
|
|
1694
|
+
if (path) {
|
|
1695
|
+
const file = await client.space(spaceId).checkpoints(checkpointId).diff.file(path, { base: opts.base ?? null });
|
|
1696
|
+
if (jsonRequested(opts))
|
|
1697
|
+
return outJson(file);
|
|
1698
|
+
printDiffFile(file);
|
|
1699
|
+
return;
|
|
1700
|
+
}
|
|
1701
|
+
const summary = await client.space(spaceId).checkpoints(checkpointId).diff.summary({ base: opts.base ?? null });
|
|
1702
|
+
if (jsonRequested(opts))
|
|
1703
|
+
return outJson(summary);
|
|
1704
|
+
printDiffSummary(summary, {
|
|
1705
|
+
emptyLabel: " (no changes)",
|
|
1706
|
+
footer: summary.truncated ? " … truncated" : null,
|
|
1707
|
+
});
|
|
1708
|
+
}
|
|
1709
|
+
catch (e) {
|
|
1710
|
+
handleHttp(e);
|
|
1711
|
+
}
|
|
1712
|
+
});
|
|
1588
1713
|
}
|
package/dist/output.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
|
+
import { extractBillingPayload } from "@neta-art/cohub";
|
|
2
3
|
function colWidth(rows, key, label) {
|
|
3
4
|
const maxVal = rows.reduce((m, r) => {
|
|
4
5
|
const v = r[key] ?? "";
|
|
@@ -55,8 +56,6 @@ function errorMessageFromBody(body) {
|
|
|
55
56
|
const errorBody = body;
|
|
56
57
|
if (typeof errorBody.message === "string" && errorBody.message.trim())
|
|
57
58
|
return errorBody.message;
|
|
58
|
-
if (typeof errorBody.error?.message === "string" && errorBody.error.message.trim())
|
|
59
|
-
return errorBody.error.message;
|
|
60
59
|
return null;
|
|
61
60
|
}
|
|
62
61
|
function debugErrorMetaFromBody(body) {
|
|
@@ -64,7 +63,7 @@ function debugErrorMetaFromBody(body) {
|
|
|
64
63
|
return [];
|
|
65
64
|
const errorBody = body;
|
|
66
65
|
const items = [];
|
|
67
|
-
const code = typeof errorBody.code === "string" ? errorBody.code :
|
|
66
|
+
const code = typeof errorBody.code === "string" ? errorBody.code : null;
|
|
68
67
|
if (code)
|
|
69
68
|
items.push(code);
|
|
70
69
|
if (typeof errorBody.requestId === "string")
|
|
@@ -101,6 +100,14 @@ export function handleHttp(e) {
|
|
|
101
100
|
}
|
|
102
101
|
const status = e.status;
|
|
103
102
|
const body = e.body;
|
|
103
|
+
if (status === 402) {
|
|
104
|
+
const conversion = extractBillingPayload(body)?.conversion;
|
|
105
|
+
if (conversion) {
|
|
106
|
+
return error(conversion.title || "Upgrade required", [conversion.message, "Manage billing at your Cohub account settings."]
|
|
107
|
+
.filter(Boolean)
|
|
108
|
+
.join(" · "));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
104
111
|
const presentation = errorPresentationFromHttpError(e);
|
|
105
112
|
const message = presentation?.message ?? errorMessageFromBody(body) ?? (e instanceof Error ? e.message : String(e));
|
|
106
113
|
const fetchDetail = fetchFailureDetail(e);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neta-art/cohub-cli",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.9",
|
|
4
4
|
"description": "CLI for Cohub — spaces, sessions, and agent collaboration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
"README.md"
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@neta-art/generation": "^0.1.
|
|
16
|
+
"@neta-art/generation": "^0.1.12",
|
|
17
17
|
"commander": "^14.0.3",
|
|
18
18
|
"sharp": "^0.34.5",
|
|
19
|
-
"@neta-art/cohub": "2.
|
|
19
|
+
"@neta-art/cohub": "2.8.0"
|
|
20
20
|
},
|
|
21
21
|
"publishConfig": {
|
|
22
22
|
"access": "public"
|