@duyquangnvx/agent-cli 0.0.0-stage → 0.2.0
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/CHANGELOG.md +34 -0
- package/README.md +10 -2
- package/dist/built-ins.d.ts +4 -0
- package/dist/built-ins.js +20 -0
- package/dist/built-ins.js.map +1 -0
- package/dist/command-spec.d.ts +28 -0
- package/dist/command-spec.js +31 -0
- package/dist/command-spec.js.map +1 -0
- package/dist/confirm.d.ts +7 -0
- package/dist/confirm.js +22 -0
- package/dist/confirm.js.map +1 -0
- package/dist/define.d.ts +132 -0
- package/dist/define.js +10 -0
- package/dist/define.js.map +1 -0
- package/dist/doctor-rows.d.ts +3 -0
- package/dist/doctor-rows.js +115 -0
- package/dist/doctor-rows.js.map +1 -0
- package/dist/doctor.d.ts +3 -0
- package/dist/doctor.js +100 -0
- package/dist/doctor.js.map +1 -0
- package/dist/errors.d.ts +34 -0
- package/dist/errors.js +72 -0
- package/dist/errors.js.map +1 -0
- package/dist/execute.d.ts +21 -0
- package/dist/execute.js +26 -0
- package/dist/execute.js.map +1 -0
- package/dist/flags.d.ts +50 -0
- package/dist/flags.js +59 -0
- package/dist/flags.js.map +1 -0
- package/dist/global-install.d.ts +13 -0
- package/dist/global-install.js +51 -0
- package/dist/global-install.js.map +1 -0
- package/dist/help-json.d.ts +4 -0
- package/dist/help-json.js +44 -0
- package/dist/help-json.js.map +1 -0
- package/dist/help.d.ts +5 -0
- package/dist/help.js +64 -0
- package/dist/help.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/input.d.ts +22 -0
- package/dist/input.js +63 -0
- package/dist/input.js.map +1 -0
- package/dist/interrupts.d.ts +18 -0
- package/dist/interrupts.js +118 -0
- package/dist/interrupts.js.map +1 -0
- package/dist/invocation.d.ts +9 -0
- package/dist/invocation.js +37 -0
- package/dist/invocation.js.map +1 -0
- package/dist/list.d.ts +44 -0
- package/dist/list.js +126 -0
- package/dist/list.js.map +1 -0
- package/dist/npm.d.ts +24 -0
- package/dist/npm.js +181 -0
- package/dist/npm.js.map +1 -0
- package/dist/output.d.ts +33 -0
- package/dist/output.js +65 -0
- package/dist/output.js.map +1 -0
- package/dist/parse-input.d.ts +19 -0
- package/dist/parse-input.js +147 -0
- package/dist/parse-input.js.map +1 -0
- package/dist/route.d.ts +25 -0
- package/dist/route.js +75 -0
- package/dist/route.js.map +1 -0
- package/dist/run-cli.d.ts +16 -0
- package/dist/run-cli.js +85 -0
- package/dist/run-cli.js.map +1 -0
- package/dist/run-process.d.ts +2 -0
- package/dist/run-process.js +37 -0
- package/dist/run-process.js.map +1 -0
- package/dist/semver.d.ts +9 -0
- package/dist/semver.js +70 -0
- package/dist/semver.js.map +1 -0
- package/dist/skills.d.ts +11 -0
- package/dist/skills.js +58 -0
- package/dist/skills.js.map +1 -0
- package/dist/style.d.ts +13 -0
- package/dist/style.js +38 -0
- package/dist/style.js.map +1 -0
- package/dist/suggest.d.ts +6 -0
- package/dist/suggest.js +49 -0
- package/dist/suggest.js.map +1 -0
- package/dist/tokenize.d.ts +20 -0
- package/dist/tokenize.js +79 -0
- package/dist/tokenize.js.map +1 -0
- package/dist/update.d.ts +3 -0
- package/dist/update.js +91 -0
- package/dist/update.js.map +1 -0
- package/dist/upgrade-notes.d.ts +9 -0
- package/dist/upgrade-notes.js +41 -0
- package/dist/upgrade-notes.js.map +1 -0
- package/dist/usage.d.ts +5 -0
- package/dist/usage.js +37 -0
- package/dist/usage.js.map +1 -0
- package/package.json +29 -3
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { CliError } from "./errors.js";
|
|
2
|
+
/** How long an interrupted Command may take to settle before the run ends without it. */
|
|
3
|
+
export const GRACE_MS = 3000;
|
|
4
|
+
const GRACE_OVER = Symbol("grace over");
|
|
5
|
+
export const INTERRUPTED = "INTERRUPTED";
|
|
6
|
+
function interruptedError() {
|
|
7
|
+
return new CliError({
|
|
8
|
+
code: INTERRUPTED,
|
|
9
|
+
message: "interrupted before it finished",
|
|
10
|
+
hint: "run the command again",
|
|
11
|
+
retryable: true,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function deadlineError(commandLine, ms) {
|
|
15
|
+
return new CliError({
|
|
16
|
+
code: "DEADLINE_EXCEEDED",
|
|
17
|
+
message: `${commandLine} ran past its ${ms} ms deadline`,
|
|
18
|
+
hint: "run it again later, when the service it waits on may answer faster",
|
|
19
|
+
retryable: true,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/** One Command run's cancellation: its signal, its deadlines and the steps it must finish. */
|
|
23
|
+
export class RunControl {
|
|
24
|
+
signal;
|
|
25
|
+
#controller = new AbortController();
|
|
26
|
+
#commandLine;
|
|
27
|
+
#outer;
|
|
28
|
+
#onOuterAbort = () => this.#controller.abort(interruptedError());
|
|
29
|
+
#steps = new Set();
|
|
30
|
+
#deadlineTimers = new Set();
|
|
31
|
+
#deadlineHit;
|
|
32
|
+
#graceTimer;
|
|
33
|
+
#endGrace = () => { };
|
|
34
|
+
#graceOver = new Promise((resolve) => {
|
|
35
|
+
this.#endGrace = resolve;
|
|
36
|
+
});
|
|
37
|
+
constructor(commandLine, outer) {
|
|
38
|
+
this.#commandLine = commandLine;
|
|
39
|
+
this.#outer = outer;
|
|
40
|
+
this.signal = this.#controller.signal;
|
|
41
|
+
this.signal.addEventListener("abort", () => this.#startGrace(), { once: true });
|
|
42
|
+
if (outer?.aborted === true) {
|
|
43
|
+
this.#onOuterAbort();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
outer?.addEventListener("abort", this.#onOuterAbort, { once: true });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
deadline(ms) {
|
|
50
|
+
const controller = new AbortController();
|
|
51
|
+
const timer = setTimeout(() => {
|
|
52
|
+
this.#deadlineHit ??= deadlineError(this.#commandLine, ms);
|
|
53
|
+
controller.abort(this.#deadlineHit);
|
|
54
|
+
}, ms);
|
|
55
|
+
this.#deadlineTimers.add(timer);
|
|
56
|
+
return AbortSignal.any([this.signal, controller.signal]);
|
|
57
|
+
}
|
|
58
|
+
async runToEnd(work) {
|
|
59
|
+
clearTimeout(this.#graceTimer);
|
|
60
|
+
const step = work();
|
|
61
|
+
// Only tracks when the step settles; the step's own error reaches the caller below.
|
|
62
|
+
const settled = step.then(() => { }, () => { });
|
|
63
|
+
this.#steps.add(settled);
|
|
64
|
+
try {
|
|
65
|
+
return await step;
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
this.#steps.delete(settled);
|
|
69
|
+
this.#startGrace();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Waits for the Command, its must-finish steps, and no longer than the grace once interrupted. */
|
|
73
|
+
async settle(work) {
|
|
74
|
+
try {
|
|
75
|
+
const value = await Promise.race([work, this.#graceOver]);
|
|
76
|
+
if (this.signal.aborted || value === GRACE_OVER) {
|
|
77
|
+
throw this.signal.reason;
|
|
78
|
+
}
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
await this.#stepsDone();
|
|
83
|
+
this.#dispose();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The error a run ends with: an interrupt or a missed deadline outranks what the Command threw,
|
|
88
|
+
* unless the Command threw its own `INTERRUPTED`, saying what it finished before it stopped.
|
|
89
|
+
*/
|
|
90
|
+
errorAfter(error) {
|
|
91
|
+
if (this.signal.aborted) {
|
|
92
|
+
return error instanceof CliError && error.code === INTERRUPTED ? error : this.signal.reason;
|
|
93
|
+
}
|
|
94
|
+
if (this.#deadlineHit !== undefined && !(error instanceof CliError)) {
|
|
95
|
+
return this.#deadlineHit;
|
|
96
|
+
}
|
|
97
|
+
return error;
|
|
98
|
+
}
|
|
99
|
+
#startGrace() {
|
|
100
|
+
if (this.signal.aborted && this.#steps.size === 0) {
|
|
101
|
+
clearTimeout(this.#graceTimer);
|
|
102
|
+
this.#graceTimer = setTimeout(() => this.#endGrace(GRACE_OVER), GRACE_MS);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async #stepsDone() {
|
|
106
|
+
while (this.#steps.size > 0) {
|
|
107
|
+
await Promise.all(this.#steps);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
#dispose() {
|
|
111
|
+
clearTimeout(this.#graceTimer);
|
|
112
|
+
for (const timer of this.#deadlineTimers) {
|
|
113
|
+
clearTimeout(timer);
|
|
114
|
+
}
|
|
115
|
+
this.#outer?.removeEventListener("abort", this.#onOuterAbort);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=interrupts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interrupts.js","sourceRoot":"","sources":["../src/interrupts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const END_OF_OPTIONS = "--";
|
|
2
|
+
export interface Invocation {
|
|
3
|
+
readonly cliName: string;
|
|
4
|
+
readonly argv: readonly string[];
|
|
5
|
+
}
|
|
6
|
+
/** The caller's command line, ready to paste, with `flag value` replacing any value they gave. */
|
|
7
|
+
export declare function commandLineWith({ cliName, argv }: Invocation, flag: string, value: string): string;
|
|
8
|
+
/** The caller's command line, ready to paste, with each flag in `renames` typed as its new name. */
|
|
9
|
+
export declare function commandLineRenaming({ cliName, argv }: Invocation, renames: ReadonlyMap<string, string>): string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const END_OF_OPTIONS = "--";
|
|
2
|
+
const SHELL_SAFE = /^[\w@%+=:,./-]+$/;
|
|
3
|
+
// POSIX quoting: Agent harnesses run commands in a POSIX shell, Git Bash included on Windows.
|
|
4
|
+
function quoted(token) {
|
|
5
|
+
return SHELL_SAFE.test(token) ? token : `'${token.replaceAll("'", `'\\''`)}'`;
|
|
6
|
+
}
|
|
7
|
+
function pasteable(cliName, tokens) {
|
|
8
|
+
return [cliName, ...tokens].map(quoted).join(" ");
|
|
9
|
+
}
|
|
10
|
+
function split(argv) {
|
|
11
|
+
const end = argv.indexOf(END_OF_OPTIONS);
|
|
12
|
+
return end === -1
|
|
13
|
+
? { options: [...argv], operands: [] }
|
|
14
|
+
: { options: argv.slice(0, end), operands: argv.slice(end) };
|
|
15
|
+
}
|
|
16
|
+
function without(flag, tokens) {
|
|
17
|
+
return tokens.filter((token, index) => token !== flag && !token.startsWith(`${flag}=`) && tokens[index - 1] !== flag);
|
|
18
|
+
}
|
|
19
|
+
/** The caller's command line, ready to paste, with `flag value` replacing any value they gave. */
|
|
20
|
+
export function commandLineWith({ cliName, argv }, flag, value) {
|
|
21
|
+
const { options, operands } = split(argv);
|
|
22
|
+
return pasteable(cliName, [...without(flag, options), flag, value, ...operands]);
|
|
23
|
+
}
|
|
24
|
+
function renamed(token, renames) {
|
|
25
|
+
const [flag = token, ...value] = token.split("=");
|
|
26
|
+
const name = renames.get(flag);
|
|
27
|
+
if (name === undefined) {
|
|
28
|
+
return token;
|
|
29
|
+
}
|
|
30
|
+
return value.length === 0 ? name : `${name}=${value.join("=")}`;
|
|
31
|
+
}
|
|
32
|
+
/** The caller's command line, ready to paste, with each flag in `renames` typed as its new name. */
|
|
33
|
+
export function commandLineRenaming({ cliName, argv }, renames) {
|
|
34
|
+
const { options, operands } = split(argv);
|
|
35
|
+
return pasteable(cliName, [...options.map((token) => renamed(token, renames)), ...operands]);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=invocation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invocation.js","sourceRoot":"","sources":["../src/invocation.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AACnC,MAAM,UAAU,GAAG,kBAAkB,CAAC;AAOtC,8FAA8F;AAC9F,SAAS,MAAM,CAAC,KAAa;IAC3B,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC;AAChF,CAAC;AAED,SAAS,SAAS,CAAC,OAAe,EAAE,MAAyB;IAC3D,OAAO,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,KAAK,CAAC,IAAuB;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACzC,OAAO,GAAG,KAAK,CAAC,CAAC;QACf,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;QACtC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,SAAS,OAAO,CAAC,IAAY,EAAE,MAAyB;IACtD,OAAO,MAAM,CAAC,MAAM,CAClB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAChG,CAAC;AACJ,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,eAAe,CAC7B,EAAE,OAAO,EAAE,IAAI,EAAc,EAC7B,IAAY,EACZ,KAAa;IAEb,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1C,OAAO,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC;AACnF,CAAC;AAED,SAAS,OAAO,CAAC,KAAa,EAAE,OAAoC;IAClE,MAAM,CAAC,IAAI,GAAG,KAAK,EAAE,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AAClE,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,mBAAmB,CACjC,EAAE,OAAO,EAAE,IAAI,EAAc,EAC7B,OAAoC;IAEpC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1C,OAAO,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC;AAC/F,CAAC"}
|
package/dist/list.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import type { NameOf, StandardFlag } from "./flags.js";
|
|
3
|
+
import { type InputField } from "./input.js";
|
|
4
|
+
import { type Invocation } from "./invocation.js";
|
|
5
|
+
declare const FIELDS_FLAG = "--fields";
|
|
6
|
+
export declare const PAGE_INPUT: z.ZodObject<{
|
|
7
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
8
|
+
cursor: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
export type PageInput = z.output<typeof PAGE_INPUT>;
|
|
11
|
+
export type ListFlagName = keyof PageInput | NameOf<typeof FIELDS_FLAG>;
|
|
12
|
+
export type RowSchema = z.ZodObject;
|
|
13
|
+
export declare class Page<Item> {
|
|
14
|
+
readonly items: readonly Item[];
|
|
15
|
+
readonly nextCursor: number | undefined;
|
|
16
|
+
constructor(items: readonly Item[], nextCursor: number | undefined);
|
|
17
|
+
}
|
|
18
|
+
export declare function paginate<Item>(items: readonly Item[], { limit, cursor }: PageInput): Page<Item>;
|
|
19
|
+
/** What the Runtime adds to a List Command, derived from its row schema. */
|
|
20
|
+
export interface ListSpec {
|
|
21
|
+
readonly rowFields: readonly string[];
|
|
22
|
+
/** `--limit` and `--cursor`, read and validated as the Command's options are. */
|
|
23
|
+
readonly pageFields: readonly InputField[];
|
|
24
|
+
readonly standardFlags: readonly StandardFlag[];
|
|
25
|
+
/** The printed page, for help JSON. */
|
|
26
|
+
readonly output: z.ZodType;
|
|
27
|
+
}
|
|
28
|
+
/** The Standard flags every List Command gets, as the caller types them. */
|
|
29
|
+
export declare const LIST_FLAGS: readonly string[];
|
|
30
|
+
export declare function listSpec(rows: RowSchema): ListSpec;
|
|
31
|
+
/** The fields the caller asked for, in their order, or undefined when they gave no `--fields`. */
|
|
32
|
+
export declare function selectedFields(values: ReadonlyMap<string, string | true>, rowFields: readonly string[], commandLine: string): readonly string[] | undefined;
|
|
33
|
+
type Row = Readonly<Record<string, unknown>>;
|
|
34
|
+
export declare function projected(rows: readonly unknown[], fields: readonly string[]): Row[];
|
|
35
|
+
/** Selected rows as text: a header line of the field names, then one tab-separated line per row. */
|
|
36
|
+
export declare function renderRows(rows: readonly Row[], fields: readonly string[]): string;
|
|
37
|
+
export interface PrintedPage {
|
|
38
|
+
readonly items: readonly unknown[];
|
|
39
|
+
readonly next?: string;
|
|
40
|
+
}
|
|
41
|
+
export declare function printedPage(page: Page<unknown>, invocation: Invocation): PrintedPage;
|
|
42
|
+
/** The line that ends a rendered page, so the caller always knows whether and how to get more. */
|
|
43
|
+
export declare function pageFooter({ items, next }: PrintedPage): string;
|
|
44
|
+
export {};
|
package/dist/list.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { UsageError } from "./errors.js";
|
|
3
|
+
import { optionField, optionFields } from "./input.js";
|
|
4
|
+
import { commandLineWith } from "./invocation.js";
|
|
5
|
+
const DEFAULT_PAGE_LIMIT = 20;
|
|
6
|
+
const FIELDS_FLAG = "--fields";
|
|
7
|
+
const SEPARATOR = ",";
|
|
8
|
+
const COLUMN_SEPARATOR = "\t";
|
|
9
|
+
const UNSAFE_IN_COLUMN = /[\t\n\r]/;
|
|
10
|
+
export const PAGE_INPUT = z.object({
|
|
11
|
+
limit: z.number().int().positive().default(DEFAULT_PAGE_LIMIT),
|
|
12
|
+
cursor: z.number().int().nonnegative().optional(),
|
|
13
|
+
});
|
|
14
|
+
export class Page {
|
|
15
|
+
items;
|
|
16
|
+
nextCursor;
|
|
17
|
+
constructor(items, nextCursor) {
|
|
18
|
+
this.items = items;
|
|
19
|
+
this.nextCursor = nextCursor;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function paginate(items, { limit, cursor = 0 }) {
|
|
23
|
+
const end = cursor + limit;
|
|
24
|
+
return new Page(items.slice(cursor, end), end < items.length ? end : undefined);
|
|
25
|
+
}
|
|
26
|
+
const PAGE_FLAG_DESCRIPTIONS = {
|
|
27
|
+
limit: `how many rows to show, a positive whole number (default: ${DEFAULT_PAGE_LIMIT})`,
|
|
28
|
+
cursor: "where to start, as given by the previous page's next",
|
|
29
|
+
};
|
|
30
|
+
function pageFlag(key) {
|
|
31
|
+
const field = optionField(key, PAGE_INPUT.shape[key]);
|
|
32
|
+
return {
|
|
33
|
+
flag: field.label,
|
|
34
|
+
usage: field.usage,
|
|
35
|
+
description: PAGE_FLAG_DESCRIPTIONS[key],
|
|
36
|
+
takes: "optional value",
|
|
37
|
+
schema: field.schema,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function fieldsFlag(rowFields) {
|
|
41
|
+
return {
|
|
42
|
+
flag: FIELDS_FLAG,
|
|
43
|
+
usage: `${FIELDS_FLAG} <a,b>`,
|
|
44
|
+
description: `print only these comma-separated fields of each row (any of: ${rowFields.join(", ")})`,
|
|
45
|
+
takes: "optional value",
|
|
46
|
+
schema: z.string(),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const PAGE_FIELDS = optionFields(PAGE_INPUT);
|
|
50
|
+
const PAGE_FLAGS = {
|
|
51
|
+
limit: pageFlag("limit"),
|
|
52
|
+
cursor: pageFlag("cursor"),
|
|
53
|
+
};
|
|
54
|
+
/** The Standard flags every List Command gets, as the caller types them. */
|
|
55
|
+
export const LIST_FLAGS = [
|
|
56
|
+
...Object.values(PAGE_FLAGS).map(({ flag }) => flag),
|
|
57
|
+
FIELDS_FLAG,
|
|
58
|
+
];
|
|
59
|
+
export function listSpec(rows) {
|
|
60
|
+
const rowFields = Object.keys(rows.shape);
|
|
61
|
+
return {
|
|
62
|
+
rowFields,
|
|
63
|
+
pageFields: PAGE_FIELDS,
|
|
64
|
+
standardFlags: [...Object.values(PAGE_FLAGS), fieldsFlag(rowFields)],
|
|
65
|
+
output: z.object({ items: z.array(rows), next: z.string().optional() }),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function quoted(names) {
|
|
69
|
+
return names.map((name) => `'${name}'`).join(", ");
|
|
70
|
+
}
|
|
71
|
+
/** The fields the caller asked for, in their order, or undefined when they gave no `--fields`. */
|
|
72
|
+
export function selectedFields(values, rowFields, commandLine) {
|
|
73
|
+
const raw = values.get(FIELDS_FLAG);
|
|
74
|
+
if (raw === undefined) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
const hint = `pass ${FIELDS_FLAG} with any of: ${rowFields.join(", ")}`;
|
|
78
|
+
const names = typeof raw === "string" ? raw.split(SEPARATOR).filter((name) => name !== "") : [];
|
|
79
|
+
if (names.length === 0) {
|
|
80
|
+
throw new UsageError({
|
|
81
|
+
code: "INVALID_INPUT",
|
|
82
|
+
message: `${FIELDS_FLAG}: missing value for \`${commandLine}\``,
|
|
83
|
+
hint,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const unknown = names.filter((name) => !rowFields.includes(name));
|
|
87
|
+
if (unknown.length > 0) {
|
|
88
|
+
throw new UsageError({
|
|
89
|
+
code: "UNKNOWN_FIELD",
|
|
90
|
+
message: `unknown field ${quoted(unknown)} for \`${commandLine}\``,
|
|
91
|
+
hint,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return names;
|
|
95
|
+
}
|
|
96
|
+
function fieldOf(row, field) {
|
|
97
|
+
return typeof row === "object" && row !== null ? row[field] : undefined;
|
|
98
|
+
}
|
|
99
|
+
export function projected(rows, fields) {
|
|
100
|
+
return rows.map((row) => Object.fromEntries(fields.map((field) => [field, fieldOf(row, field)])));
|
|
101
|
+
}
|
|
102
|
+
function cell(value) {
|
|
103
|
+
if (value === undefined || value === null) {
|
|
104
|
+
return "";
|
|
105
|
+
}
|
|
106
|
+
return typeof value === "string" && !UNSAFE_IN_COLUMN.test(value) ? value : JSON.stringify(value);
|
|
107
|
+
}
|
|
108
|
+
/** Selected rows as text: a header line of the field names, then one tab-separated line per row. */
|
|
109
|
+
export function renderRows(rows, fields) {
|
|
110
|
+
const lines = [fields, ...rows.map((row) => fields.map((field) => cell(row[field])))];
|
|
111
|
+
return `${lines.map((line) => line.join(COLUMN_SEPARATOR)).join("\n")}\n`;
|
|
112
|
+
}
|
|
113
|
+
export function printedPage(page, invocation) {
|
|
114
|
+
return page.nextCursor === undefined
|
|
115
|
+
? { items: page.items }
|
|
116
|
+
: {
|
|
117
|
+
items: page.items,
|
|
118
|
+
next: commandLineWith(invocation, PAGE_FLAGS.cursor.flag, String(page.nextCursor)),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/** The line that ends a rendered page, so the caller always knows whether and how to get more. */
|
|
122
|
+
export function pageFooter({ items, next }) {
|
|
123
|
+
const more = next === undefined ? "no more pages" : `next page: \`${next}\``;
|
|
124
|
+
return `${items.length} shown; ${more}\n`;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=list.js.map
|
package/dist/list.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../src/list.ts"],"names":[],"mappings":"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"}
|
package/dist/npm.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CommandTreeCli, Context, Env, GlobalInstall } from "./define.js";
|
|
2
|
+
/** What every npm call needs: the CLI it serves, its package, and the caller's env and signal. */
|
|
3
|
+
export interface NpmContext {
|
|
4
|
+
readonly cliName: string;
|
|
5
|
+
readonly install: GlobalInstall;
|
|
6
|
+
readonly env: Env;
|
|
7
|
+
readonly signal: AbortSignal;
|
|
8
|
+
}
|
|
9
|
+
/** Which kind of npm call failed, since the same npm code means different things for each. */
|
|
10
|
+
export type NpmCall = "prefix" | "view" | "install";
|
|
11
|
+
export declare function npmContext(cli: CommandTreeCli, install: GlobalInstall, ctx: Context): NpmContext;
|
|
12
|
+
/** The flag that points npm at the CLI's registry; none for npmjs, npm's default. */
|
|
13
|
+
export declare function registryFlags({ package: name, registry }: GlobalInstall): string[];
|
|
14
|
+
/** The command a person runs to install the CLI globally from its registry. */
|
|
15
|
+
export declare function installCommandLine(install: GlobalInstall, version?: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Runs npm with a fresh cache, so a stale cache never answers for the registry; maps its failures to codes.
|
|
18
|
+
* `signal` kills npm when it aborts; pass null for a step that must finish.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runNpm(call: NpmCall, args: readonly string[], ctx: NpmContext, signal?: AbortSignal | null): Promise<string>;
|
|
21
|
+
export declare function globalPrefix(ctx: NpmContext): Promise<string>;
|
|
22
|
+
/** Installs `version` globally; never killed by the signal, so run it inside `ctx.runToEnd`. */
|
|
23
|
+
export declare function installGlobally(version: string, ctx: NpmContext): Promise<void>;
|
|
24
|
+
export declare function latestVersion(ctx: NpmContext): Promise<string>;
|
package/dist/npm.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { CliError, messageOf } from "./errors.js";
|
|
6
|
+
import { isVersion } from "./semver.js";
|
|
7
|
+
export function npmContext(cli, install, ctx) {
|
|
8
|
+
return { cliName: cli.name, install, env: ctx.env, signal: ctx.signal };
|
|
9
|
+
}
|
|
10
|
+
const NPMJS = "https://registry.npmjs.org/";
|
|
11
|
+
const STDERR_TAIL_LINES = 10;
|
|
12
|
+
const RM_RETRIES = 3;
|
|
13
|
+
const NETWORK_CODES = new Set([
|
|
14
|
+
"ENOTFOUND",
|
|
15
|
+
"EAI_AGAIN",
|
|
16
|
+
"ECONNREFUSED",
|
|
17
|
+
"ECONNRESET",
|
|
18
|
+
"ETIMEDOUT",
|
|
19
|
+
"ENETUNREACH",
|
|
20
|
+
"EHOSTUNREACH",
|
|
21
|
+
"ERR_SOCKET_TIMEOUT",
|
|
22
|
+
]);
|
|
23
|
+
const AUTH_CODES = new Set(["E401", "E403"]);
|
|
24
|
+
const NPM_CODE = /^npm (?:error|ERR!) code (\S+)$/m;
|
|
25
|
+
/** The flag that points npm at the CLI's registry; none for npmjs, npm's default. */
|
|
26
|
+
export function registryFlags({ package: name, registry }) {
|
|
27
|
+
if (registry === NPMJS)
|
|
28
|
+
return [];
|
|
29
|
+
const scope = /^(@[^/]+)\//.exec(name)?.[1];
|
|
30
|
+
return [scope === undefined ? `--registry=${registry}` : `--${scope}:registry=${registry}`];
|
|
31
|
+
}
|
|
32
|
+
/** The command a person runs to install the CLI globally from its registry. */
|
|
33
|
+
export function installCommandLine(install, version = "latest") {
|
|
34
|
+
return [
|
|
35
|
+
"npm",
|
|
36
|
+
"install",
|
|
37
|
+
"--global",
|
|
38
|
+
`${install.package}@${version}`,
|
|
39
|
+
...registryFlags(install),
|
|
40
|
+
].join(" ");
|
|
41
|
+
}
|
|
42
|
+
// npm.cmd needs cmd.exe on Windows, so there the arguments go through a shell, quoted. A step
|
|
43
|
+
// without a signal must finish, so on POSIX it leaves the terminal's process group and its Ctrl-C.
|
|
44
|
+
function spawnNpm(args, ctx, signal) {
|
|
45
|
+
const windows = process.platform === "win32";
|
|
46
|
+
const command = windows
|
|
47
|
+
? ["npm", ...args].map((arg) => `"${arg.replaceAll('"', '""')}"`).join(" ")
|
|
48
|
+
: "npm";
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const child = spawn(command, windows ? [] : args, {
|
|
51
|
+
env: ctx.env,
|
|
52
|
+
shell: windows,
|
|
53
|
+
windowsHide: true,
|
|
54
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
55
|
+
detached: signal === null && !windows,
|
|
56
|
+
signal: signal ?? undefined,
|
|
57
|
+
});
|
|
58
|
+
let stdout = "";
|
|
59
|
+
let stderr = "";
|
|
60
|
+
child.stdout.setEncoding("utf8").on("data", (chunk) => {
|
|
61
|
+
stdout += chunk;
|
|
62
|
+
});
|
|
63
|
+
child.stderr.setEncoding("utf8").on("data", (chunk) => {
|
|
64
|
+
stderr += chunk;
|
|
65
|
+
});
|
|
66
|
+
child.on("error", reject);
|
|
67
|
+
child.on("close", (exitCode) => resolve({ exitCode, stdout, stderr }));
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function tail(stderr) {
|
|
71
|
+
const lines = stderr.trim().split("\n").slice(-STDERR_TAIL_LINES);
|
|
72
|
+
return lines.length === 0 || lines[0] === "" ? "" : `\n${lines.join("\n")}`;
|
|
73
|
+
}
|
|
74
|
+
function failureOf(call, answer, ctx) {
|
|
75
|
+
const { registry, package: name } = ctx.install;
|
|
76
|
+
const code = NPM_CODE.exec(answer.stderr)?.[1];
|
|
77
|
+
const output = tail(answer.stderr);
|
|
78
|
+
if (code !== undefined && NETWORK_CODES.has(code)) {
|
|
79
|
+
return new CliError({
|
|
80
|
+
code: "REGISTRY_UNREACHABLE",
|
|
81
|
+
message: `npm could not reach ${registry} (${code})${output}`,
|
|
82
|
+
hint: "check the network or VPN, then run it again",
|
|
83
|
+
retryable: true,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (code !== undefined && AUTH_CODES.has(code)) {
|
|
87
|
+
return new CliError({
|
|
88
|
+
code: "REGISTRY_AUTH",
|
|
89
|
+
message: `${registry} refused npm's credentials (${code})${output}`,
|
|
90
|
+
hint: `log in to ${registry} (npm login --registry=${registry}) or set its token in ~/.npmrc, then run it again`,
|
|
91
|
+
retryable: false,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (call === "view" && code === "E404") {
|
|
95
|
+
return noLatest(ctx, `npm found no ${name}@latest on ${registry}: no version of it is published there`);
|
|
96
|
+
}
|
|
97
|
+
if (call === "install") {
|
|
98
|
+
return new CliError({
|
|
99
|
+
code: "INSTALL_FAILED",
|
|
100
|
+
message: `npm could not install ${name}${code === undefined ? "" : ` (${code})`}${output}`,
|
|
101
|
+
hint: `fix what npm reports, then run it again, or install it yourself: ${installCommandLine(ctx.install)}`,
|
|
102
|
+
retryable: false,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return new CliError({
|
|
106
|
+
code: "NPM_FAILED",
|
|
107
|
+
message: `npm ${call} failed with exit code ${answer.exitCode}${output}`,
|
|
108
|
+
hint: "fix what npm reports, then run it again",
|
|
109
|
+
retryable: false,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function noLatest(ctx, message) {
|
|
113
|
+
return new CliError({
|
|
114
|
+
code: "NO_LATEST",
|
|
115
|
+
message,
|
|
116
|
+
hint: `check that ${ctx.install.package} is published on ${ctx.install.registry}`,
|
|
117
|
+
retryable: false,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Runs npm with a fresh cache, so a stale cache never answers for the registry; maps its failures to codes.
|
|
122
|
+
* `signal` kills npm when it aborts; pass null for a step that must finish.
|
|
123
|
+
*/
|
|
124
|
+
export async function runNpm(call, args, ctx, signal = ctx.signal) {
|
|
125
|
+
const cache = await mkdtemp(join(tmpdir(), `${ctx.cliName}-npm-`));
|
|
126
|
+
try {
|
|
127
|
+
const answer = await spawnNpm([...args, `--cache=${join(cache, "cache")}`, "--logs-max=0"], ctx, signal).catch((error) => {
|
|
128
|
+
if (signal?.aborted === true)
|
|
129
|
+
throw signal.reason;
|
|
130
|
+
throw new CliError({
|
|
131
|
+
code: "NPM_FAILED",
|
|
132
|
+
message: `npm could not be started: ${messageOf(error)}`,
|
|
133
|
+
hint: "install Node with npm, or put npm on PATH",
|
|
134
|
+
retryable: false,
|
|
135
|
+
}, { cause: error });
|
|
136
|
+
});
|
|
137
|
+
if (answer.exitCode !== 0) {
|
|
138
|
+
throw failureOf(call, answer, ctx);
|
|
139
|
+
}
|
|
140
|
+
return answer.stdout;
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
// A cache left behind in the temp dir costs disk space only, never the call's result.
|
|
144
|
+
await rm(cache, { recursive: true, force: true, maxRetries: RM_RETRIES }).catch(() => { });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export async function globalPrefix(ctx) {
|
|
148
|
+
return (await runNpm("prefix", ["prefix", "--global"], ctx)).trim();
|
|
149
|
+
}
|
|
150
|
+
// npm 12 answers `["X.Y.Z"]` and npm 11 a bare `"X.Y.Z"`.
|
|
151
|
+
function versionInViewAnswer(answer) {
|
|
152
|
+
try {
|
|
153
|
+
const parsed = JSON.parse(answer);
|
|
154
|
+
const version = Array.isArray(parsed) ? parsed.at(-1) : parsed;
|
|
155
|
+
return typeof version === "string" && isVersion(version) ? version : undefined;
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** Installs `version` globally; never killed by the signal, so run it inside `ctx.runToEnd`. */
|
|
162
|
+
export async function installGlobally(version, ctx) {
|
|
163
|
+
await runNpm("install", [
|
|
164
|
+
"install",
|
|
165
|
+
"--global",
|
|
166
|
+
"--no-audit",
|
|
167
|
+
"--no-fund",
|
|
168
|
+
`${ctx.install.package}@${version}`,
|
|
169
|
+
...registryFlags(ctx.install),
|
|
170
|
+
], ctx, null);
|
|
171
|
+
}
|
|
172
|
+
export async function latestVersion(ctx) {
|
|
173
|
+
const { package: name, registry } = ctx.install;
|
|
174
|
+
const answer = await runNpm("view", ["view", `${name}@latest`, "version", "--json", ...registryFlags(ctx.install)], ctx);
|
|
175
|
+
const version = versionInViewAnswer(answer);
|
|
176
|
+
if (version === undefined) {
|
|
177
|
+
throw noLatest(ctx, `npm answered no version for ${name}@latest on ${registry}: ${answer.trim()}`);
|
|
178
|
+
}
|
|
179
|
+
return version;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=npm.js.map
|
package/dist/npm.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm.js","sourceRoot":"","sources":["../src/npm.ts"],"names":[],"mappings":"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"}
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { SpecNode } from "./command-spec.js";
|
|
2
|
+
import type { Cli, Env } from "./define.js";
|
|
3
|
+
import type { Outcome } from "./execute.js";
|
|
4
|
+
import type { Invocation } from "./invocation.js";
|
|
5
|
+
import type { Style } from "./style.js";
|
|
6
|
+
export interface RunResult {
|
|
7
|
+
readonly stdout: string;
|
|
8
|
+
readonly stderr: string;
|
|
9
|
+
readonly exitCode: number;
|
|
10
|
+
}
|
|
11
|
+
export interface OutputFormat {
|
|
12
|
+
readonly cliName: string;
|
|
13
|
+
readonly env: Env;
|
|
14
|
+
readonly style: Style;
|
|
15
|
+
readonly invocation: Invocation;
|
|
16
|
+
readonly json: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface DataFormat extends OutputFormat {
|
|
19
|
+
readonly fields: readonly string[] | undefined;
|
|
20
|
+
}
|
|
21
|
+
/** How a Command's run ended; a thrown error carries the Command's render for any data it holds. */
|
|
22
|
+
export type Settled = {
|
|
23
|
+
readonly ok: true;
|
|
24
|
+
readonly outcome: Outcome;
|
|
25
|
+
} | {
|
|
26
|
+
readonly ok: false;
|
|
27
|
+
readonly error: unknown;
|
|
28
|
+
readonly render: (data: unknown, style: Style) => string;
|
|
29
|
+
};
|
|
30
|
+
export declare function errorResult(error: unknown, format: OutputFormat): RunResult;
|
|
31
|
+
export declare function commandResult(settled: Settled, format: DataFormat): RunResult;
|
|
32
|
+
export declare function helpResult(node: SpecNode, root: SpecNode, cli: Cli, { style, json }: OutputFormat): RunResult;
|
|
33
|
+
export declare function versionResult({ version, build }: Cli): RunResult;
|