@asteroidai/cli 1.8.197 → 1.9.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/dist/asteroid.js +36 -10
- package/dist/core.js +35 -9
- package/package.json +1 -1
- package/src/output.test.ts +26 -0
- package/src/output.ts +24 -3
- package/src/program.test.ts +37 -0
- package/src/program.ts +19 -8
package/dist/asteroid.js
CHANGED
|
@@ -57,7 +57,7 @@ function columns(rows) {
|
|
|
57
57
|
const scalarKeys = [];
|
|
58
58
|
for (const row of rows) {
|
|
59
59
|
for (const [key, value2] of Object.entries(row)) {
|
|
60
|
-
if (isScalar(value2) && !HIDDEN.test(key) && !scalarKeys.includes(key))
|
|
60
|
+
if (isScalar(value2) && !HIDDEN.test(key.split(".").at(-1) ?? key) && !scalarKeys.includes(key))
|
|
61
61
|
scalarKeys.push(key);
|
|
62
62
|
}
|
|
63
63
|
}
|
|
@@ -70,8 +70,21 @@ function columns(rows) {
|
|
|
70
70
|
function style(format, value2, options) {
|
|
71
71
|
return options.styled ? styleText(format, value2, { validateStream: false }) : value2;
|
|
72
72
|
}
|
|
73
|
-
function
|
|
74
|
-
|
|
73
|
+
function flatten(row) {
|
|
74
|
+
const flat = {};
|
|
75
|
+
for (const [key, value2] of Object.entries(row)) {
|
|
76
|
+
if (!isObject(value2)) {
|
|
77
|
+
flat[key] = value2;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
for (const [inner, v] of Object.entries(value2))
|
|
81
|
+
flat[`${key}.${inner}`] = v;
|
|
82
|
+
}
|
|
83
|
+
return flat;
|
|
84
|
+
}
|
|
85
|
+
function table(input, options = {}) {
|
|
86
|
+
if (input.length === 0) return "No results.";
|
|
87
|
+
const rows = input.map(flatten);
|
|
75
88
|
const keys = columns(rows);
|
|
76
89
|
if (keys.length === 0) return rows.map((row) => text(row)).join("\n");
|
|
77
90
|
const cells = rows.map((row) => keys.map((key) => cell(row[key])));
|
|
@@ -108,6 +121,10 @@ ${indent(table(v, options))}`;
|
|
|
108
121
|
if (Array.isArray(v) && v.length > 0 && v.every(isScalar)) {
|
|
109
122
|
return `${label(key)} ${v.map(text).join(`
|
|
110
123
|
${" ".repeat(width + 2)}`)}`;
|
|
124
|
+
}
|
|
125
|
+
if (isObject(v) && Object.keys(v).length > 0) {
|
|
126
|
+
return `${style("bold", key, options)}:
|
|
127
|
+
${indent(record(v, options))}`;
|
|
111
128
|
}
|
|
112
129
|
return `${label(key)} ${isScalar(v) ? text(v) : summary(v)}`;
|
|
113
130
|
}).join("\n");
|
|
@@ -4875,16 +4892,25 @@ function defineCommands(root, options, dotted = /* @__PURE__ */ new Map(), onInv
|
|
|
4875
4892
|
const defaults = command.args.map(
|
|
4876
4893
|
(arg) => options.defaultArg?.(command, arg)
|
|
4877
4894
|
);
|
|
4878
|
-
|
|
4895
|
+
const defaulted = defaults[0] !== void 0;
|
|
4896
|
+
command.args.forEach((arg) => {
|
|
4879
4897
|
leaf.argument(
|
|
4880
|
-
|
|
4898
|
+
defaulted ? `[${arg.flag}]` : `<${arg.flag}>`,
|
|
4881
4899
|
arg.description ?? ""
|
|
4882
4900
|
);
|
|
4883
4901
|
});
|
|
4884
|
-
if (
|
|
4885
|
-
|
|
4886
|
-
${
|
|
4902
|
+
if (defaulted) {
|
|
4903
|
+
const names = command.args.map(
|
|
4904
|
+
(arg, i) => i === 0 ? `[${arg.flag}]` : `<${arg.flag}>`
|
|
4905
|
+
);
|
|
4906
|
+
leaf.usage(`[options] ${names.join(" ")}`);
|
|
4887
4907
|
}
|
|
4908
|
+
const notes = [
|
|
4909
|
+
defaults.some((value2) => value2 !== void 0) ? options.defaultArgNote : void 0,
|
|
4910
|
+
options.helpNote?.(command)
|
|
4911
|
+
].filter(Boolean);
|
|
4912
|
+
if (notes.length > 0) leaf.addHelpText("after", `
|
|
4913
|
+
${notes.join("\n")}`);
|
|
4888
4914
|
leafOptions(leaf, command);
|
|
4889
4915
|
leaf.action((...args) => {
|
|
4890
4916
|
const cmd = args.at(-1);
|
|
@@ -4893,7 +4919,7 @@ ${options.defaultArgNote}`);
|
|
|
4893
4919
|
positionals = [defaults[0], ...positionals];
|
|
4894
4920
|
}
|
|
4895
4921
|
if (positionals.length !== command.args.length) {
|
|
4896
|
-
const expected = command.args.map((a) => `<${a.flag}>`).join(" ");
|
|
4922
|
+
const expected = command.args.map((a, i) => i === 0 && defaulted ? `[${a.flag}]` : `<${a.flag}>`).join(" ");
|
|
4897
4923
|
throw new UsageError(
|
|
4898
4924
|
`expected ${expected}, got ${cmd.args.length} argument(s)`
|
|
4899
4925
|
);
|
|
@@ -5303,7 +5329,7 @@ var ApiError = class extends Error {
|
|
|
5303
5329
|
status;
|
|
5304
5330
|
body;
|
|
5305
5331
|
};
|
|
5306
|
-
var VERSION = "1.
|
|
5332
|
+
var VERSION = "1.9.2";
|
|
5307
5333
|
function problem(status, body, fallback) {
|
|
5308
5334
|
if (body && typeof body === "object") {
|
|
5309
5335
|
const record2 = body;
|
package/dist/core.js
CHANGED
|
@@ -4569,7 +4569,7 @@ function columns(rows) {
|
|
|
4569
4569
|
const scalarKeys = [];
|
|
4570
4570
|
for (const row of rows) {
|
|
4571
4571
|
for (const [key, value2] of Object.entries(row)) {
|
|
4572
|
-
if (isScalar(value2) && !HIDDEN.test(key) && !scalarKeys.includes(key))
|
|
4572
|
+
if (isScalar(value2) && !HIDDEN.test(key.split(".").at(-1) ?? key) && !scalarKeys.includes(key))
|
|
4573
4573
|
scalarKeys.push(key);
|
|
4574
4574
|
}
|
|
4575
4575
|
}
|
|
@@ -4582,8 +4582,21 @@ function columns(rows) {
|
|
|
4582
4582
|
function style(format, value2, options) {
|
|
4583
4583
|
return options.styled ? styleText(format, value2, { validateStream: false }) : value2;
|
|
4584
4584
|
}
|
|
4585
|
-
function
|
|
4586
|
-
|
|
4585
|
+
function flatten(row) {
|
|
4586
|
+
const flat = {};
|
|
4587
|
+
for (const [key, value2] of Object.entries(row)) {
|
|
4588
|
+
if (!isObject(value2)) {
|
|
4589
|
+
flat[key] = value2;
|
|
4590
|
+
continue;
|
|
4591
|
+
}
|
|
4592
|
+
for (const [inner, v] of Object.entries(value2))
|
|
4593
|
+
flat[`${key}.${inner}`] = v;
|
|
4594
|
+
}
|
|
4595
|
+
return flat;
|
|
4596
|
+
}
|
|
4597
|
+
function table(input, options = {}) {
|
|
4598
|
+
if (input.length === 0) return "No results.";
|
|
4599
|
+
const rows = input.map(flatten);
|
|
4587
4600
|
const keys = columns(rows);
|
|
4588
4601
|
if (keys.length === 0) return rows.map((row) => text(row)).join("\n");
|
|
4589
4602
|
const cells = rows.map((row) => keys.map((key) => cell(row[key])));
|
|
@@ -4620,6 +4633,10 @@ ${indent(table(v, options))}`;
|
|
|
4620
4633
|
if (Array.isArray(v) && v.length > 0 && v.every(isScalar)) {
|
|
4621
4634
|
return `${label(key)} ${v.map(text).join(`
|
|
4622
4635
|
${" ".repeat(width + 2)}`)}`;
|
|
4636
|
+
}
|
|
4637
|
+
if (isObject(v) && Object.keys(v).length > 0) {
|
|
4638
|
+
return `${style("bold", key, options)}:
|
|
4639
|
+
${indent(record(v, options))}`;
|
|
4623
4640
|
}
|
|
4624
4641
|
return `${label(key)} ${isScalar(v) ? text(v) : summary(v)}`;
|
|
4625
4642
|
}).join("\n");
|
|
@@ -4808,16 +4825,25 @@ function defineCommands(root, options, dotted = /* @__PURE__ */ new Map(), onInv
|
|
|
4808
4825
|
const defaults = command.args.map(
|
|
4809
4826
|
(arg) => options.defaultArg?.(command, arg)
|
|
4810
4827
|
);
|
|
4811
|
-
|
|
4828
|
+
const defaulted = defaults[0] !== void 0;
|
|
4829
|
+
command.args.forEach((arg) => {
|
|
4812
4830
|
leaf.argument(
|
|
4813
|
-
|
|
4831
|
+
defaulted ? `[${arg.flag}]` : `<${arg.flag}>`,
|
|
4814
4832
|
arg.description ?? ""
|
|
4815
4833
|
);
|
|
4816
4834
|
});
|
|
4817
|
-
if (
|
|
4818
|
-
|
|
4819
|
-
${
|
|
4835
|
+
if (defaulted) {
|
|
4836
|
+
const names = command.args.map(
|
|
4837
|
+
(arg, i) => i === 0 ? `[${arg.flag}]` : `<${arg.flag}>`
|
|
4838
|
+
);
|
|
4839
|
+
leaf.usage(`[options] ${names.join(" ")}`);
|
|
4820
4840
|
}
|
|
4841
|
+
const notes = [
|
|
4842
|
+
defaults.some((value2) => value2 !== void 0) ? options.defaultArgNote : void 0,
|
|
4843
|
+
options.helpNote?.(command)
|
|
4844
|
+
].filter(Boolean);
|
|
4845
|
+
if (notes.length > 0) leaf.addHelpText("after", `
|
|
4846
|
+
${notes.join("\n")}`);
|
|
4821
4847
|
leafOptions(leaf, command);
|
|
4822
4848
|
leaf.action((...args) => {
|
|
4823
4849
|
const cmd = args.at(-1);
|
|
@@ -4826,7 +4852,7 @@ ${options.defaultArgNote}`);
|
|
|
4826
4852
|
positionals = [defaults[0], ...positionals];
|
|
4827
4853
|
}
|
|
4828
4854
|
if (positionals.length !== command.args.length) {
|
|
4829
|
-
const expected = command.args.map((a) => `<${a.flag}>`).join(" ");
|
|
4855
|
+
const expected = command.args.map((a, i) => i === 0 && defaulted ? `[${a.flag}]` : `<${a.flag}>`).join(" ");
|
|
4830
4856
|
throw new UsageError(
|
|
4831
4857
|
`expected ${expected}, got ${cmd.args.length} argument(s)`
|
|
4832
4858
|
);
|
package/package.json
CHANGED
package/src/output.test.ts
CHANGED
|
@@ -23,4 +23,30 @@ describe("render", () => {
|
|
|
23
23
|
expect(render(rows)).not.toContain("┌");
|
|
24
24
|
expect(render(rows, { styled: true })).toContain("┌");
|
|
25
25
|
});
|
|
26
|
+
|
|
27
|
+
it("prints nested objects in full, not as cut JSON", () => {
|
|
28
|
+
const out = render({
|
|
29
|
+
workflow: { id: "3cfc3c1d-e38d-4132-a5ee-8847136d491d", name: "Nebula" },
|
|
30
|
+
version: { version: 3, isPublished: true },
|
|
31
|
+
});
|
|
32
|
+
expect(out).toContain("3cfc3c1d-e38d-4132-a5ee-8847136d491d");
|
|
33
|
+
expect(out).toMatch(/workflow:\n {2}id +3cfc3c1d/);
|
|
34
|
+
expect(out).not.toContain("…");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("flattens one level of nested fields into table columns", () => {
|
|
38
|
+
const out = render([
|
|
39
|
+
{ date: "2026-10-09", outcomes: { success: 3, failure: 1 } },
|
|
40
|
+
]);
|
|
41
|
+
expect(out).toContain("OUTCOMES.SUCCESS");
|
|
42
|
+
expect(out).toMatch(/2026-10-09 +3 +1/);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("hides nested fields that are hidden at the top level", () => {
|
|
46
|
+
const out = render([
|
|
47
|
+
{ id: "1", execution: { agentId: "a-1", status: "failed" } },
|
|
48
|
+
]);
|
|
49
|
+
expect(out).toContain("EXECUTION.STATUS");
|
|
50
|
+
expect(out).not.toContain("AGENTID");
|
|
51
|
+
});
|
|
26
52
|
});
|
package/src/output.ts
CHANGED
|
@@ -59,7 +59,11 @@ function columns(rows: Row[]): string[] {
|
|
|
59
59
|
const scalarKeys: string[] = [];
|
|
60
60
|
for (const row of rows) {
|
|
61
61
|
for (const [key, value] of Object.entries(row)) {
|
|
62
|
-
if (
|
|
62
|
+
if (
|
|
63
|
+
isScalar(value) &&
|
|
64
|
+
!HIDDEN.test(key.split(".").at(-1) ?? key) &&
|
|
65
|
+
!scalarKeys.includes(key)
|
|
66
|
+
)
|
|
63
67
|
scalarKeys.push(key);
|
|
64
68
|
}
|
|
65
69
|
}
|
|
@@ -80,8 +84,22 @@ function style(
|
|
|
80
84
|
: value;
|
|
81
85
|
}
|
|
82
86
|
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
function flatten(row: Row): Row {
|
|
88
|
+
const flat: Row = {};
|
|
89
|
+
for (const [key, value] of Object.entries(row)) {
|
|
90
|
+
if (!isObject(value)) {
|
|
91
|
+
flat[key] = value;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
for (const [inner, v] of Object.entries(value as Row))
|
|
95
|
+
flat[`${key}.${inner}`] = v;
|
|
96
|
+
}
|
|
97
|
+
return flat;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function table(input: Row[], options: RenderOptions = {}): string {
|
|
101
|
+
if (input.length === 0) return "No results.";
|
|
102
|
+
const rows = input.map(flatten);
|
|
85
103
|
const keys = columns(rows);
|
|
86
104
|
if (keys.length === 0) return rows.map((row) => text(row)).join("\n");
|
|
87
105
|
const cells = rows.map((row) => keys.map((key) => cell(row[key])));
|
|
@@ -124,6 +142,9 @@ function record(value: Row, options: RenderOptions): string {
|
|
|
124
142
|
if (Array.isArray(v) && v.length > 0 && v.every(isScalar)) {
|
|
125
143
|
return `${label(key)} ${v.map(text).join(`\n${" ".repeat(width + 2)}`)}`;
|
|
126
144
|
}
|
|
145
|
+
if (isObject(v) && Object.keys(v as Row).length > 0) {
|
|
146
|
+
return `${style("bold", key, options)}:\n${indent(record(v as Row, options))}`;
|
|
147
|
+
}
|
|
127
148
|
return `${label(key)} ${isScalar(v) ? text(v) : summary(v)}`;
|
|
128
149
|
})
|
|
129
150
|
.join("\n");
|
package/src/program.test.ts
CHANGED
|
@@ -96,4 +96,41 @@ describe("parseInvocation", () => {
|
|
|
96
96
|
);
|
|
97
97
|
expect(got.parsed.positionals).toEqual(["chat-wf"]);
|
|
98
98
|
});
|
|
99
|
+
|
|
100
|
+
it("adds a per-command help note", async () => {
|
|
101
|
+
const help = await parseInvocation(["workflow", "get", "--help"], {
|
|
102
|
+
commands: COMMANDS,
|
|
103
|
+
helpNote: (command) =>
|
|
104
|
+
command.tool === "workflow_get" ? "Note for get." : undefined,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
expect(help.kind === "exit" && help.stdout).toContain("Note for get.");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("fills a defaulted first argument ahead of a required one", async () => {
|
|
111
|
+
const options = {
|
|
112
|
+
commands: COMMANDS,
|
|
113
|
+
defaultArg: (_: unknown, arg: { name: string }) =>
|
|
114
|
+
arg.name === "workflowId" ? "chat-wf" : undefined,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const short = command(
|
|
118
|
+
await parseInvocation(["schedule", "get", "s-1"], options),
|
|
119
|
+
);
|
|
120
|
+
expect(short.parsed.positionals).toEqual(["chat-wf", "s-1"]);
|
|
121
|
+
|
|
122
|
+
const full = command(
|
|
123
|
+
await parseInvocation(["schedule", "get", "wf-2", "s-1"], options),
|
|
124
|
+
);
|
|
125
|
+
expect(full.parsed.positionals).toEqual(["wf-2", "s-1"]);
|
|
126
|
+
|
|
127
|
+
const help = await parseInvocation(["schedule", "get", "--help"], options);
|
|
128
|
+
expect(help.kind === "exit" && help.stdout).toContain(
|
|
129
|
+
"[workflow-id] <schedule-id>",
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
await expect(parseInvocation(["schedule", "get"], options)).rejects.toThrow(
|
|
133
|
+
"expected [workflow-id] <schedule-id>, got 0 argument(s)",
|
|
134
|
+
);
|
|
135
|
+
});
|
|
99
136
|
});
|
package/src/program.ts
CHANGED
|
@@ -16,6 +16,7 @@ export interface ProgramOptions {
|
|
|
16
16
|
description?: string;
|
|
17
17
|
defaultArg?: (command: CliCommand, arg: Option) => string | undefined;
|
|
18
18
|
defaultArgNote?: string;
|
|
19
|
+
helpNote?: (command: CliCommand) => string | undefined;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
const DOTTED = /^--([a-z0-9-]+\.[a-z0-9.-]+)(?:=(.*))?$/;
|
|
@@ -155,18 +156,26 @@ export function defineCommands(
|
|
|
155
156
|
const defaults = command.args.map((arg) =>
|
|
156
157
|
options.defaultArg?.(command, arg),
|
|
157
158
|
);
|
|
158
|
-
|
|
159
|
+
const defaulted = defaults[0] !== undefined;
|
|
160
|
+
command.args.forEach((arg) => {
|
|
159
161
|
leaf.argument(
|
|
160
|
-
|
|
162
|
+
defaulted ? `[${arg.flag}]` : `<${arg.flag}>`,
|
|
161
163
|
arg.description ?? "",
|
|
162
164
|
);
|
|
163
165
|
});
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
leaf.
|
|
166
|
+
if (defaulted) {
|
|
167
|
+
const names = command.args.map((arg, i) =>
|
|
168
|
+
i === 0 ? `[${arg.flag}]` : `<${arg.flag}>`,
|
|
169
|
+
);
|
|
170
|
+
leaf.usage(`[options] ${names.join(" ")}`);
|
|
169
171
|
}
|
|
172
|
+
const notes = [
|
|
173
|
+
defaults.some((value) => value !== undefined)
|
|
174
|
+
? options.defaultArgNote
|
|
175
|
+
: undefined,
|
|
176
|
+
options.helpNote?.(command),
|
|
177
|
+
].filter(Boolean);
|
|
178
|
+
if (notes.length > 0) leaf.addHelpText("after", `\n${notes.join("\n")}`);
|
|
170
179
|
leafOptions(leaf, command);
|
|
171
180
|
leaf.action((...args: unknown[]) => {
|
|
172
181
|
const cmd = args.at(-1) as Command;
|
|
@@ -178,7 +187,9 @@ export function defineCommands(
|
|
|
178
187
|
positionals = [defaults[0], ...positionals];
|
|
179
188
|
}
|
|
180
189
|
if (positionals.length !== command.args.length) {
|
|
181
|
-
const expected = command.args
|
|
190
|
+
const expected = command.args
|
|
191
|
+
.map((a, i) => (i === 0 && defaulted ? `[${a.flag}]` : `<${a.flag}>`))
|
|
192
|
+
.join(" ");
|
|
182
193
|
throw new UsageError(
|
|
183
194
|
`expected ${expected}, got ${cmd.args.length} argument(s)`,
|
|
184
195
|
);
|