@duyquangnvx/agent-cli 0.0.0-stage → 0.1.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/built-ins.d.ts +4 -0
  3. package/dist/built-ins.js +20 -0
  4. package/dist/built-ins.js.map +1 -0
  5. package/dist/confirm.d.ts +8 -0
  6. package/dist/confirm.js +22 -0
  7. package/dist/confirm.js.map +1 -0
  8. package/dist/define.d.ts +108 -0
  9. package/dist/define.js +8 -0
  10. package/dist/define.js.map +1 -0
  11. package/dist/doctor-rows.d.ts +3 -0
  12. package/dist/doctor-rows.js +115 -0
  13. package/dist/doctor-rows.js.map +1 -0
  14. package/dist/doctor.d.ts +3 -0
  15. package/dist/doctor.js +100 -0
  16. package/dist/doctor.js.map +1 -0
  17. package/dist/errors.d.ts +34 -0
  18. package/dist/errors.js +72 -0
  19. package/dist/errors.js.map +1 -0
  20. package/dist/execute.d.ts +12 -0
  21. package/dist/execute.js +18 -0
  22. package/dist/execute.js.map +1 -0
  23. package/dist/fields.d.ts +14 -0
  24. package/dist/fields.js +71 -0
  25. package/dist/fields.js.map +1 -0
  26. package/dist/flags.d.ts +12 -0
  27. package/dist/flags.js +22 -0
  28. package/dist/flags.js.map +1 -0
  29. package/dist/global-install.d.ts +11 -0
  30. package/dist/global-install.js +50 -0
  31. package/dist/global-install.js.map +1 -0
  32. package/dist/help-json.d.ts +4 -0
  33. package/dist/help-json.js +60 -0
  34. package/dist/help-json.js.map +1 -0
  35. package/dist/help.d.ts +6 -0
  36. package/dist/help.js +61 -0
  37. package/dist/help.js.map +1 -0
  38. package/dist/index.d.ts +11 -0
  39. package/dist/index.js +7 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/input.d.ts +22 -0
  42. package/dist/input.js +70 -0
  43. package/dist/input.js.map +1 -0
  44. package/dist/interrupts.d.ts +18 -0
  45. package/dist/interrupts.js +118 -0
  46. package/dist/interrupts.js.map +1 -0
  47. package/dist/invocation.d.ts +9 -0
  48. package/dist/invocation.js +37 -0
  49. package/dist/invocation.js.map +1 -0
  50. package/dist/npm.d.ts +24 -0
  51. package/dist/npm.js +181 -0
  52. package/dist/npm.js.map +1 -0
  53. package/dist/page.d.ts +26 -0
  54. package/dist/page.js +49 -0
  55. package/dist/page.js.map +1 -0
  56. package/dist/parse-input.d.ts +5 -0
  57. package/dist/parse-input.js +114 -0
  58. package/dist/parse-input.js.map +1 -0
  59. package/dist/run-cli.d.ts +20 -0
  60. package/dist/run-cli.js +211 -0
  61. package/dist/run-cli.js.map +1 -0
  62. package/dist/run-process.d.ts +2 -0
  63. package/dist/run-process.js +37 -0
  64. package/dist/run-process.js.map +1 -0
  65. package/dist/semver.d.ts +9 -0
  66. package/dist/semver.js +70 -0
  67. package/dist/semver.js.map +1 -0
  68. package/dist/skills.d.ts +11 -0
  69. package/dist/skills.js +58 -0
  70. package/dist/skills.js.map +1 -0
  71. package/dist/style.d.ts +13 -0
  72. package/dist/style.js +38 -0
  73. package/dist/style.js.map +1 -0
  74. package/dist/suggest.d.ts +2 -0
  75. package/dist/suggest.js +41 -0
  76. package/dist/suggest.js.map +1 -0
  77. package/dist/update.d.ts +3 -0
  78. package/dist/update.js +91 -0
  79. package/dist/update.js.map +1 -0
  80. package/dist/upgrade-notes.d.ts +9 -0
  81. package/dist/upgrade-notes.js +41 -0
  82. package/dist/upgrade-notes.js.map +1 -0
  83. package/dist/usage.d.ts +13 -0
  84. package/dist/usage.js +72 -0
  85. package/dist/usage.js.map +1 -0
  86. package/package.json +32 -3
  87. package/README.md +0 -3
@@ -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/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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"npm.js","sourceRoot":"","sources":["../src/npm.ts"],"names":[],"mappings":"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"}
package/dist/page.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ import * as z from "zod";
2
+ import { type Invocation } from "./invocation.js";
3
+ export declare const pageOptions: z.ZodObject<{
4
+ limit: z.ZodDefault<z.ZodNumber>;
5
+ cursor: z.ZodOptional<z.ZodNumber>;
6
+ }, z.core.$strip>;
7
+ export type PageInput = z.output<typeof pageOptions>;
8
+ /** The output schema of a list Command: the printed page of `row`s. It earns the Command `--fields`. */
9
+ export declare function pageOf<Row extends z.ZodObject>(row: Row): z.ZodObject<{
10
+ items: z.ZodArray<Row>;
11
+ next: z.ZodOptional<z.ZodString>;
12
+ }>;
13
+ export declare function rowSchemaOf(output: z.ZodType | undefined): z.ZodObject | undefined;
14
+ export declare class Page<Item> {
15
+ readonly items: readonly Item[];
16
+ readonly nextCursor: number | undefined;
17
+ constructor(items: readonly Item[], nextCursor: number | undefined);
18
+ }
19
+ export declare function paginate<Item>(items: readonly Item[], { limit, cursor }: PageInput): Page<Item>;
20
+ export interface PrintedPage {
21
+ readonly items: readonly unknown[];
22
+ readonly next?: string;
23
+ }
24
+ export declare function printedPage(page: Page<unknown>, invocation: Invocation): PrintedPage;
25
+ /** The line that ends a rendered page, so the caller always knows whether and how to get more. */
26
+ export declare function pageFooter({ items, next }: PrintedPage): string;
package/dist/page.js ADDED
@@ -0,0 +1,49 @@
1
+ import * as z from "zod";
2
+ import { commandLineWith } from "./invocation.js";
3
+ const DEFAULT_PAGE_LIMIT = 20;
4
+ const CURSOR_FLAG = "--cursor";
5
+ export const pageOptions = z.object({
6
+ limit: z.number().int().positive().default(DEFAULT_PAGE_LIMIT).describe("how many to show"),
7
+ cursor: z
8
+ .number()
9
+ .int()
10
+ .nonnegative()
11
+ .optional()
12
+ .describe("where to start, as given by the previous page"),
13
+ });
14
+ const rowSchemas = new WeakMap();
15
+ /** The output schema of a list Command: the printed page of `row`s. It earns the Command `--fields`. */
16
+ export function pageOf(row) {
17
+ const page = z.object({ items: z.array(row), next: z.string().optional() });
18
+ rowSchemas.set(page, row);
19
+ return page;
20
+ }
21
+ export function rowSchemaOf(output) {
22
+ return output === undefined ? undefined : rowSchemas.get(output);
23
+ }
24
+ export class Page {
25
+ items;
26
+ nextCursor;
27
+ constructor(items, nextCursor) {
28
+ this.items = items;
29
+ this.nextCursor = nextCursor;
30
+ }
31
+ }
32
+ export function paginate(items, { limit, cursor = 0 }) {
33
+ const end = cursor + limit;
34
+ return new Page(items.slice(cursor, end), end < items.length ? end : undefined);
35
+ }
36
+ export function printedPage(page, invocation) {
37
+ return page.nextCursor === undefined
38
+ ? { items: page.items }
39
+ : {
40
+ items: page.items,
41
+ next: commandLineWith(invocation, CURSOR_FLAG, String(page.nextCursor)),
42
+ };
43
+ }
44
+ /** The line that ends a rendered page, so the caller always knows whether and how to get more. */
45
+ export function pageFooter({ items, next }) {
46
+ const more = next === undefined ? "no more pages" : `next page: \`${next}\``;
47
+ return `${items.length} shown; ${more}\n`;
48
+ }
49
+ //# sourceMappingURL=page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page.js","sourceRoot":"","sources":["../src/page.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,eAAe,EAAmB,MAAM,iBAAiB,CAAC;AAEnE,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAC9B,MAAM,WAAW,GAAG,UAAU,CAAC;AAE/B,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,QAAQ,CAAC,kBAAkB,CAAC;IAC3F,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,EAAE;SACL,WAAW,EAAE;SACb,QAAQ,EAAE;SACV,QAAQ,CAAC,+CAA+C,CAAC;CAC7D,CAAC,CAAC;AAIH,MAAM,UAAU,GAAG,IAAI,OAAO,EAA0B,CAAC;AAEzD,wGAAwG;AACxG,MAAM,UAAU,MAAM,CACpB,GAAQ;IAER,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC5E,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC1B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAA6B;IACvD,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,OAAO,IAAI;IACN,KAAK,CAAkB;IACvB,UAAU,CAAqB;IAExC,YAAY,KAAsB,EAAE,UAA8B;QAChE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,UAAU,QAAQ,CACtB,KAAsB,EACtB,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,EAAa;IAEhC,MAAM,GAAG,GAAG,MAAM,GAAG,KAAK,CAAC;IAC3B,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAClF,CAAC;AAOD,MAAM,UAAU,WAAW,CAAC,IAAmB,EAAE,UAAsB;IACrE,OAAO,IAAI,CAAC,UAAU,KAAK,SAAS;QAClC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE;QACvB,CAAC,CAAC;YACE,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,eAAe,CAAC,UAAU,EAAE,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SACxE,CAAC;AACR,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,EAAe;IACrD,MAAM,IAAI,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,gBAAgB,IAAI,IAAI,CAAC;IAC7E,OAAO,GAAG,KAAK,CAAC,MAAM,WAAW,IAAI,IAAI,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Command as Commander } from "commander";
2
+ import type { Command } from "./define.js";
3
+ import type { InputFields } from "./input.js";
4
+ import { type Invocation } from "./invocation.js";
5
+ export declare function parseInput(command: Command, sub: Commander, fields: InputFields, invocation: Invocation): Record<string, unknown>;
@@ -0,0 +1,114 @@
1
+ import * as z from "zod";
2
+ import { UsageError } from "./errors.js";
3
+ import { commandLineRenaming, END_OF_OPTIONS } from "./invocation.js";
4
+ import { closestFlag } from "./suggest.js";
5
+ import { commandLine, unknownOptionError } from "./usage.js";
6
+ const HELP_FLAG = "--help";
7
+ const NEGATIVE_NUMBER = /^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/;
8
+ function isOptionLike(token) {
9
+ return (token !== undefined && token.length > 1 && token[0] === "-" && !NEGATIVE_NUMBER.test(token));
10
+ }
11
+ // Commander keeps `--` only after an unknown option, so the words after it are counted from the
12
+ // caller's own command line.
13
+ function leftoversOf(tokens, argv) {
14
+ const end = argv.indexOf(END_OF_OPTIONS);
15
+ const split = end === -1 ? tokens.length : Math.max(0, tokens.length - (argv.length - end - 1));
16
+ const head = tokens.slice(0, split);
17
+ const parsed = end !== -1 && head.at(-1) === END_OF_OPTIONS ? head.slice(0, -1) : head;
18
+ const literal = tokens.slice(split).map((value) => ({ value, afterUnknownOption: false }));
19
+ return {
20
+ operands: [
21
+ ...parsed.flatMap((value, index) => isOptionLike(value) ? [] : [{ value, afterUnknownOption: isOptionLike(parsed[index - 1]) }]),
22
+ ...literal,
23
+ ],
24
+ unknownOptions: parsed.filter(isOptionLike),
25
+ };
26
+ }
27
+ function flagsOf(cmd) {
28
+ const own = cmd.options.flatMap((option) => (option.long === undefined ? [] : [option.long]));
29
+ return cmd.parent === null ? [...own, HELP_FLAG] : [...own, ...flagsOf(cmd.parent)];
30
+ }
31
+ function unknownOptionsOf(tokens, sub) {
32
+ return tokens.map((token) => {
33
+ const flag = token.split("=")[0] ?? token;
34
+ return { flag, suggestion: closestFlag(flag, flagsOf(sub)) };
35
+ });
36
+ }
37
+ // Strings that read as numbers are converted so authors can write `z.number()`; anything else
38
+ // stays a string for Zod to reject with the caller's own value.
39
+ function converted(field, raw) {
40
+ if (field.type !== "number" || typeof raw !== "string" || raw.trim() === "") {
41
+ return raw;
42
+ }
43
+ const number = Number(raw);
44
+ return Number.isNaN(number) ? raw : number;
45
+ }
46
+ function parse(schema, values) {
47
+ const input = Object.fromEntries([...values]
48
+ .filter(([, raw]) => raw !== undefined)
49
+ .map(([field, raw]) => [field.key, converted(field, raw)]));
50
+ return (schema ?? z.object({})).safeParse(input);
51
+ }
52
+ function issueLines(result, values, howToPass, reported) {
53
+ if (result.success) {
54
+ return [];
55
+ }
56
+ return result.error.issues.flatMap((issue) => {
57
+ const field = [...values.keys()].find((candidate) => candidate.key === issue.path[0]);
58
+ if (field === undefined) {
59
+ return [` ${issue.message}`];
60
+ }
61
+ if (reported.includes(field)) {
62
+ return [];
63
+ }
64
+ const raw = values.get(field);
65
+ return raw === undefined
66
+ ? [` ${field.label}: required, ${howToPass(field)}`]
67
+ : [` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`];
68
+ });
69
+ }
70
+ function unknownLine({ flag, suggestion }) {
71
+ return ` unknown option '${flag}'${suggestion === undefined ? "" : ` (did you mean ${suggestion}?)`}`;
72
+ }
73
+ function invalidInput(line, invocation, unknown, otherLines) {
74
+ const renames = new Map(unknown.flatMap(({ flag, suggestion }) => suggestion === undefined ? [] : [[flag, suggestion]]));
75
+ const correctable = otherLines.length === 0 && renames.size === unknown.length;
76
+ return new UsageError({
77
+ code: "INVALID_INPUT",
78
+ message: [`invalid input for \`${line}\``, ...unknown.map(unknownLine), ...otherLines].join("\n"),
79
+ hint: correctable
80
+ ? `did you mean \`${commandLineRenaming(invocation, renames)}\`?`
81
+ : `run \`${line} --help\` to see the expected input`,
82
+ });
83
+ }
84
+ export function parseInput(command, sub, fields, invocation) {
85
+ const { operands, unknownOptions } = leftoversOf(sub.args, invocation.argv);
86
+ const opts = sub.opts();
87
+ // A value option given without a value is collected as `true`.
88
+ const missing = fields.options.filter((field) => field.type !== "boolean" && opts[field.key] === true);
89
+ const argValues = new Map(fields.args.map((field, index) => [field, operands[index]?.value]));
90
+ const optionValues = new Map(fields.options.map((field) => [field, missing.includes(field) ? undefined : opts[field.key]]));
91
+ const args = parse(command.args, argValues);
92
+ const options = parse(command.options, optionValues);
93
+ const unknown = unknownOptionsOf(unknownOptions, sub);
94
+ const otherLines = [
95
+ ...missing.map((field) => ` ${field.label}: missing value, pass ${field.usage}`),
96
+ ...operands
97
+ .slice(fields.args.length)
98
+ // A word right after an unknown flag may be its value, so it isn't an extra arg.
99
+ .filter((operand) => !operand.afterUnknownOption)
100
+ .map((operand) => ` unexpected argument ${JSON.stringify(operand.value)}`),
101
+ ...issueLines(args, argValues, (field) => `pass it as argument ${fields.args.indexOf(field) + 1}`, []),
102
+ ...issueLines(options, optionValues, (field) => `pass ${field.usage}`, missing),
103
+ ];
104
+ if (unknown.length === 0 && otherLines.length === 0 && args.success && options.success) {
105
+ return { ...args.data, ...options.data };
106
+ }
107
+ const line = commandLine(sub);
108
+ const [only] = unknown;
109
+ if (only !== undefined && unknown.length === 1 && otherLines.length === 0) {
110
+ throw unknownOptionError(line, invocation, only.flag, only.suggestion === undefined ? [] : [only.suggestion]);
111
+ }
112
+ throw invalidInput(line, invocation, unknown, otherLines);
113
+ }
114
+ //# sourceMappingURL=parse-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-input.js","sourceRoot":"","sources":["../src/parse-input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type Cli, type Env } from "./define.js";
2
+ export interface RunOptions {
3
+ readonly env: Env;
4
+ readonly cwd: string;
5
+ readonly stdoutIsTTY?: boolean;
6
+ /** Aborting it interrupts the running Command, which then ends with `INTERRUPTED`. */
7
+ readonly signal?: AbortSignal;
8
+ /**
9
+ * The script that started the CLI, as `process.argv[1]`; `doctor` checks it is inside npm's
10
+ * global install. Absent, the CLI counts as run from source.
11
+ */
12
+ readonly bin?: string;
13
+ }
14
+ export interface RunResult {
15
+ readonly stdout: string;
16
+ readonly stderr: string;
17
+ readonly exitCode: number;
18
+ }
19
+ export declare function runCli(cli: Cli, argv: readonly string[], options: RunOptions): Promise<RunResult>;
20
+ export declare function runWithProgress(cli: Cli, argv: readonly string[], options: RunOptions, writeProgress: (line: string) => void): Promise<RunResult>;