@asteroidai/cli 1.9.2 → 1.9.4
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/asteroid.js +16 -12
- package/dist/core.js +10 -9
- package/package.json +1 -1
- package/src/output.test.ts +19 -0
- package/src/output.ts +11 -9
- package/src/reference.ts +1 -0
- package/src/run.test.ts +20 -0
- package/src/run.ts +9 -2
package/dist/asteroid.js
CHANGED
|
@@ -48,12 +48,13 @@ function indent(text2) {
|
|
|
48
48
|
function text(value2) {
|
|
49
49
|
return clean(isScalar(value2) ? String(value2) : JSON.stringify(value2));
|
|
50
50
|
}
|
|
51
|
-
function cell(value2) {
|
|
51
|
+
function cell(value2, options = {}) {
|
|
52
52
|
if (value2 === null || value2 === void 0) return "";
|
|
53
53
|
const line = text(value2).replace(/\s+/g, " ");
|
|
54
|
-
|
|
54
|
+
if (options.full || line.length <= MAX_CELL) return line;
|
|
55
|
+
return `${line.slice(0, MAX_CELL - 1)}\u2026`;
|
|
55
56
|
}
|
|
56
|
-
function columns(rows) {
|
|
57
|
+
function columns(rows, options) {
|
|
57
58
|
const scalarKeys = [];
|
|
58
59
|
for (const row of rows) {
|
|
59
60
|
for (const [key, value2] of Object.entries(row)) {
|
|
@@ -65,7 +66,7 @@ function columns(rows) {
|
|
|
65
66
|
...PREFERRED.filter((key) => scalarKeys.includes(key)),
|
|
66
67
|
...scalarKeys.filter((key) => !PREFERRED.includes(key))
|
|
67
68
|
];
|
|
68
|
-
return ordered.slice(0, MAX_COLUMNS);
|
|
69
|
+
return options.full ? ordered : ordered.slice(0, MAX_COLUMNS);
|
|
69
70
|
}
|
|
70
71
|
function style(format, value2, options) {
|
|
71
72
|
return options.styled ? styleText(format, value2, { validateStream: false }) : value2;
|
|
@@ -85,9 +86,9 @@ function flatten(row) {
|
|
|
85
86
|
function table(input, options = {}) {
|
|
86
87
|
if (input.length === 0) return "No results.";
|
|
87
88
|
const rows = input.map(flatten);
|
|
88
|
-
const keys = columns(rows);
|
|
89
|
+
const keys = columns(rows, options);
|
|
89
90
|
if (keys.length === 0) return rows.map((row) => text(row)).join("\n");
|
|
90
|
-
const cells = rows.map((row) => keys.map((key) => cell(row[key])));
|
|
91
|
+
const cells = rows.map((row) => keys.map((key) => cell(row[key], options)));
|
|
91
92
|
if (options.styled) {
|
|
92
93
|
const grid = new Table({
|
|
93
94
|
head: keys.map((key) => style("bold", key, options)),
|
|
@@ -104,10 +105,10 @@ function table(input, options = {}) {
|
|
|
104
105
|
"\n"
|
|
105
106
|
);
|
|
106
107
|
}
|
|
107
|
-
function summary(value2) {
|
|
108
|
+
function summary(value2, options) {
|
|
108
109
|
if (Array.isArray(value2))
|
|
109
110
|
return `[${value2.length} item${value2.length === 1 ? "" : "s"}]`;
|
|
110
|
-
if (value2 && typeof value2 === "object") return cell(value2);
|
|
111
|
+
if (value2 && typeof value2 === "object") return cell(value2, options);
|
|
111
112
|
return text(value2);
|
|
112
113
|
}
|
|
113
114
|
function record(value2, options) {
|
|
@@ -126,7 +127,7 @@ ${" ".repeat(width + 2)}`)}`;
|
|
|
126
127
|
return `${style("bold", key, options)}:
|
|
127
128
|
${indent(record(v, options))}`;
|
|
128
129
|
}
|
|
129
|
-
return `${label(key)} ${isScalar(v) ? text(v) : summary(v)}`;
|
|
130
|
+
return `${label(key)} ${isScalar(v) ? text(v) : summary(v, options)}`;
|
|
130
131
|
}).join("\n");
|
|
131
132
|
}
|
|
132
133
|
function render(value2, options = {}) {
|
|
@@ -5329,7 +5330,7 @@ var ApiError = class extends Error {
|
|
|
5329
5330
|
status;
|
|
5330
5331
|
body;
|
|
5331
5332
|
};
|
|
5332
|
-
var VERSION = "1.9.
|
|
5333
|
+
var VERSION = "1.9.4";
|
|
5333
5334
|
function problem(status, body, fallback) {
|
|
5334
5335
|
if (body && typeof body === "object") {
|
|
5335
5336
|
const record2 = body;
|
|
@@ -5878,7 +5879,10 @@ async function runCommand(command, parsed, deps) {
|
|
|
5878
5879
|
}
|
|
5879
5880
|
if (response.json !== void 0) {
|
|
5880
5881
|
deps.stdout(
|
|
5881
|
-
`${parsed.json ? JSON.stringify(response.json, null, 2) : render(response.json, {
|
|
5882
|
+
`${parsed.json ? JSON.stringify(response.json, null, 2) : render(response.json, {
|
|
5883
|
+
styled: deps.styled,
|
|
5884
|
+
full: !deps.stdoutIsTTY
|
|
5885
|
+
})}
|
|
5882
5886
|
`
|
|
5883
5887
|
);
|
|
5884
5888
|
return 0;
|
|
@@ -5887,7 +5891,7 @@ async function runCommand(command, parsed, deps) {
|
|
|
5887
5891
|
`);
|
|
5888
5892
|
return 0;
|
|
5889
5893
|
}
|
|
5890
|
-
var DESCRIPTION = "The Asteroid CLI. Sign in with `asteroid login`, or set ASTEROID_API_KEY.";
|
|
5894
|
+
var DESCRIPTION = "The Asteroid CLI. Sign in with `asteroid login`, or set ASTEROID_API_KEY.\nAt a terminal, tables show up to 6 columns and cut long cells to fit; when output is piped, they show every column in full. Use `--json` for every field.";
|
|
5891
5895
|
async function run(argv2, deps) {
|
|
5892
5896
|
try {
|
|
5893
5897
|
const invocation = await parseInvocation(argv2, {
|
package/dist/core.js
CHANGED
|
@@ -4560,12 +4560,13 @@ function indent(text2) {
|
|
|
4560
4560
|
function text(value2) {
|
|
4561
4561
|
return clean(isScalar(value2) ? String(value2) : JSON.stringify(value2));
|
|
4562
4562
|
}
|
|
4563
|
-
function cell(value2) {
|
|
4563
|
+
function cell(value2, options = {}) {
|
|
4564
4564
|
if (value2 === null || value2 === void 0) return "";
|
|
4565
4565
|
const line = text(value2).replace(/\s+/g, " ");
|
|
4566
|
-
|
|
4566
|
+
if (options.full || line.length <= MAX_CELL) return line;
|
|
4567
|
+
return `${line.slice(0, MAX_CELL - 1)}\u2026`;
|
|
4567
4568
|
}
|
|
4568
|
-
function columns(rows) {
|
|
4569
|
+
function columns(rows, options) {
|
|
4569
4570
|
const scalarKeys = [];
|
|
4570
4571
|
for (const row of rows) {
|
|
4571
4572
|
for (const [key, value2] of Object.entries(row)) {
|
|
@@ -4577,7 +4578,7 @@ function columns(rows) {
|
|
|
4577
4578
|
...PREFERRED.filter((key) => scalarKeys.includes(key)),
|
|
4578
4579
|
...scalarKeys.filter((key) => !PREFERRED.includes(key))
|
|
4579
4580
|
];
|
|
4580
|
-
return ordered.slice(0, MAX_COLUMNS);
|
|
4581
|
+
return options.full ? ordered : ordered.slice(0, MAX_COLUMNS);
|
|
4581
4582
|
}
|
|
4582
4583
|
function style(format, value2, options) {
|
|
4583
4584
|
return options.styled ? styleText(format, value2, { validateStream: false }) : value2;
|
|
@@ -4597,9 +4598,9 @@ function flatten(row) {
|
|
|
4597
4598
|
function table(input, options = {}) {
|
|
4598
4599
|
if (input.length === 0) return "No results.";
|
|
4599
4600
|
const rows = input.map(flatten);
|
|
4600
|
-
const keys = columns(rows);
|
|
4601
|
+
const keys = columns(rows, options);
|
|
4601
4602
|
if (keys.length === 0) return rows.map((row) => text(row)).join("\n");
|
|
4602
|
-
const cells = rows.map((row) => keys.map((key) => cell(row[key])));
|
|
4603
|
+
const cells = rows.map((row) => keys.map((key) => cell(row[key], options)));
|
|
4603
4604
|
if (options.styled) {
|
|
4604
4605
|
const grid = new Table({
|
|
4605
4606
|
head: keys.map((key) => style("bold", key, options)),
|
|
@@ -4616,10 +4617,10 @@ function table(input, options = {}) {
|
|
|
4616
4617
|
"\n"
|
|
4617
4618
|
);
|
|
4618
4619
|
}
|
|
4619
|
-
function summary(value2) {
|
|
4620
|
+
function summary(value2, options) {
|
|
4620
4621
|
if (Array.isArray(value2))
|
|
4621
4622
|
return `[${value2.length} item${value2.length === 1 ? "" : "s"}]`;
|
|
4622
|
-
if (value2 && typeof value2 === "object") return cell(value2);
|
|
4623
|
+
if (value2 && typeof value2 === "object") return cell(value2, options);
|
|
4623
4624
|
return text(value2);
|
|
4624
4625
|
}
|
|
4625
4626
|
function record(value2, options) {
|
|
@@ -4638,7 +4639,7 @@ ${" ".repeat(width + 2)}`)}`;
|
|
|
4638
4639
|
return `${style("bold", key, options)}:
|
|
4639
4640
|
${indent(record(v, options))}`;
|
|
4640
4641
|
}
|
|
4641
|
-
return `${label(key)} ${isScalar(v) ? text(v) : summary(v)}`;
|
|
4642
|
+
return `${label(key)} ${isScalar(v) ? text(v) : summary(v, options)}`;
|
|
4642
4643
|
}).join("\n");
|
|
4643
4644
|
}
|
|
4644
4645
|
function render(value2, options = {}) {
|
package/package.json
CHANGED
package/src/output.test.ts
CHANGED
|
@@ -49,4 +49,23 @@ describe("render", () => {
|
|
|
49
49
|
expect(out).toContain("EXECUTION.STATUS");
|
|
50
50
|
expect(out).not.toContain("AGENTID");
|
|
51
51
|
});
|
|
52
|
+
|
|
53
|
+
it("keeps long cells whole when asked", () => {
|
|
54
|
+
const secrets = `ECW(51d1db07-a6e1-4b1d-8303-a472b78923e8)[PASSWORD=##ECW_PASSWORD##]`;
|
|
55
|
+
const rows = [{ id: "p-1", secrets }];
|
|
56
|
+
expect(render(rows)).toContain("…");
|
|
57
|
+
expect(render(rows, { full: true })).toContain(secrets);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("shows every column when asked, six otherwise", () => {
|
|
61
|
+
const row = Object.fromEntries(
|
|
62
|
+
["id", "a", "b", "c", "d", "e", "f", "g"].map((key) => [
|
|
63
|
+
key,
|
|
64
|
+
key.toUpperCase(),
|
|
65
|
+
]),
|
|
66
|
+
);
|
|
67
|
+
const header = (out: string) => out.split("\n")[0].trim().split(/\s+/);
|
|
68
|
+
expect(header(render([row]))).toHaveLength(6);
|
|
69
|
+
expect(header(render([row], { full: true }))).toHaveLength(8);
|
|
70
|
+
});
|
|
52
71
|
});
|
package/src/output.ts
CHANGED
|
@@ -22,6 +22,7 @@ type Row = Record<string, unknown>;
|
|
|
22
22
|
|
|
23
23
|
export interface RenderOptions {
|
|
24
24
|
styled?: boolean;
|
|
25
|
+
full?: boolean;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export function clean(text: string): string {
|
|
@@ -49,13 +50,14 @@ function text(value: unknown): string {
|
|
|
49
50
|
return clean(isScalar(value) ? String(value) : JSON.stringify(value));
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
function cell(value: unknown): string {
|
|
53
|
+
function cell(value: unknown, options: RenderOptions = {}): string {
|
|
53
54
|
if (value === null || value === undefined) return "";
|
|
54
55
|
const line = text(value).replace(/\s+/g, " ");
|
|
55
|
-
|
|
56
|
+
if (options.full || line.length <= MAX_CELL) return line;
|
|
57
|
+
return `${line.slice(0, MAX_CELL - 1)}…`;
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
function columns(rows: Row[]): string[] {
|
|
60
|
+
function columns(rows: Row[], options: RenderOptions): string[] {
|
|
59
61
|
const scalarKeys: string[] = [];
|
|
60
62
|
for (const row of rows) {
|
|
61
63
|
for (const [key, value] of Object.entries(row)) {
|
|
@@ -71,7 +73,7 @@ function columns(rows: Row[]): string[] {
|
|
|
71
73
|
...PREFERRED.filter((key) => scalarKeys.includes(key)),
|
|
72
74
|
...scalarKeys.filter((key) => !PREFERRED.includes(key)),
|
|
73
75
|
];
|
|
74
|
-
return ordered.slice(0, MAX_COLUMNS);
|
|
76
|
+
return options.full ? ordered : ordered.slice(0, MAX_COLUMNS);
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
function style(
|
|
@@ -100,9 +102,9 @@ function flatten(row: Row): Row {
|
|
|
100
102
|
export function table(input: Row[], options: RenderOptions = {}): string {
|
|
101
103
|
if (input.length === 0) return "No results.";
|
|
102
104
|
const rows = input.map(flatten);
|
|
103
|
-
const keys = columns(rows);
|
|
105
|
+
const keys = columns(rows, options);
|
|
104
106
|
if (keys.length === 0) return rows.map((row) => text(row)).join("\n");
|
|
105
|
-
const cells = rows.map((row) => keys.map((key) => cell(row[key])));
|
|
107
|
+
const cells = rows.map((row) => keys.map((key) => cell(row[key], options)));
|
|
106
108
|
if (options.styled) {
|
|
107
109
|
const grid = new Table({
|
|
108
110
|
head: keys.map((key) => style("bold", key, options)),
|
|
@@ -124,10 +126,10 @@ export function table(input: Row[], options: RenderOptions = {}): string {
|
|
|
124
126
|
);
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
function summary(value: unknown): string {
|
|
129
|
+
function summary(value: unknown, options: RenderOptions): string {
|
|
128
130
|
if (Array.isArray(value))
|
|
129
131
|
return `[${value.length} item${value.length === 1 ? "" : "s"}]`;
|
|
130
|
-
if (value && typeof value === "object") return cell(value);
|
|
132
|
+
if (value && typeof value === "object") return cell(value, options);
|
|
131
133
|
return text(value);
|
|
132
134
|
}
|
|
133
135
|
|
|
@@ -145,7 +147,7 @@ function record(value: Row, options: RenderOptions): string {
|
|
|
145
147
|
if (isObject(v) && Object.keys(v as Row).length > 0) {
|
|
146
148
|
return `${style("bold", key, options)}:\n${indent(record(v as Row, options))}`;
|
|
147
149
|
}
|
|
148
|
-
return `${label(key)} ${isScalar(v) ? text(v) : summary(v)}`;
|
|
150
|
+
return `${label(key)} ${isScalar(v) ? text(v) : summary(v, options)}`;
|
|
149
151
|
})
|
|
150
152
|
.join("\n");
|
|
151
153
|
}
|
package/src/reference.ts
CHANGED
|
@@ -138,6 +138,7 @@ export function renderReference(commands: CliCommand[]): string {
|
|
|
138
138
|
"Sign in with `asteroid login`, or set `ASTEROID_API_KEY` for CI and agents.",
|
|
139
139
|
"Commands that return data print compact text. Add `--json` to get the response as JSON.",
|
|
140
140
|
"The text output may change between releases. Scripts should read `--json`.",
|
|
141
|
+
"At a terminal, tables show up to 6 columns and cut long cells to fit; when output is piped, they show every column in full. Use `--json` for every field.",
|
|
141
142
|
"Downloads write raw bytes. `login`, `logout` and `use` only report status on stderr.",
|
|
142
143
|
"Exit codes: 0 ok, 1 API error, 2 usage error.",
|
|
143
144
|
"",
|
package/src/run.test.ts
CHANGED
|
@@ -269,6 +269,26 @@ describe("guards", () => {
|
|
|
269
269
|
});
|
|
270
270
|
});
|
|
271
271
|
|
|
272
|
+
describe("cell width", () => {
|
|
273
|
+
const long = "x".repeat(80);
|
|
274
|
+
const reply = () => json({ items: [{ id: "w-1", name: long }] });
|
|
275
|
+
|
|
276
|
+
it("keeps cells whole when stdout is not a terminal", async () => {
|
|
277
|
+
const h = harness({ ASTEROID_API_KEY: "sk_test" }, reply);
|
|
278
|
+
await run(["workflow", "list"], h.deps);
|
|
279
|
+
expect(h.out.join("")).toContain(long);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it("cuts long cells at a terminal", async () => {
|
|
283
|
+
const h = harness({ ASTEROID_API_KEY: "sk_test" }, reply);
|
|
284
|
+
h.deps.stdoutIsTTY = true;
|
|
285
|
+
await run(["workflow", "list"], h.deps);
|
|
286
|
+
const out = h.out.join("");
|
|
287
|
+
expect(out).toContain(`${"x".repeat(59)}…`);
|
|
288
|
+
expect(out).not.toContain(long);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
272
292
|
describe("terminal safety", () => {
|
|
273
293
|
it("refuses to print a download to a terminal", async () => {
|
|
274
294
|
const h = harness(
|
package/src/run.ts
CHANGED
|
@@ -138,7 +138,14 @@ async function runCommand(
|
|
|
138
138
|
}
|
|
139
139
|
if (response.json !== undefined) {
|
|
140
140
|
deps.stdout(
|
|
141
|
-
`${
|
|
141
|
+
`${
|
|
142
|
+
parsed.json
|
|
143
|
+
? JSON.stringify(response.json, null, 2)
|
|
144
|
+
: render(response.json, {
|
|
145
|
+
styled: deps.styled,
|
|
146
|
+
full: !deps.stdoutIsTTY,
|
|
147
|
+
})
|
|
148
|
+
}\n`,
|
|
142
149
|
);
|
|
143
150
|
return 0;
|
|
144
151
|
}
|
|
@@ -147,7 +154,7 @@ async function runCommand(
|
|
|
147
154
|
}
|
|
148
155
|
|
|
149
156
|
const DESCRIPTION =
|
|
150
|
-
"The Asteroid CLI. Sign in with `asteroid login`, or set ASTEROID_API_KEY.";
|
|
157
|
+
"The Asteroid CLI. Sign in with `asteroid login`, or set ASTEROID_API_KEY.\nAt a terminal, tables show up to 6 columns and cut long cells to fit; when output is piped, they show every column in full. Use `--json` for every field.";
|
|
151
158
|
|
|
152
159
|
export async function run(argv: string[], deps: Deps): Promise<number> {
|
|
153
160
|
try {
|