@duyquangnvx/agent-cli 0.2.1 → 0.3.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 (124) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/dist/abort.d.ts +2 -0
  3. package/dist/abort.js +11 -0
  4. package/dist/abort.js.map +1 -0
  5. package/dist/agent-cli.d.ts +17 -0
  6. package/dist/agent-cli.js +28 -0
  7. package/dist/agent-cli.js.map +1 -0
  8. package/dist/agent.d.ts +4 -0
  9. package/dist/agent.js +14 -0
  10. package/dist/agent.js.map +1 -0
  11. package/dist/built-ins.d.ts +1 -2
  12. package/dist/built-ins.js +0 -10
  13. package/dist/built-ins.js.map +1 -1
  14. package/dist/clock.d.ts +10 -0
  15. package/dist/clock.js +35 -0
  16. package/dist/clock.js.map +1 -0
  17. package/dist/command-spec.js +8 -1
  18. package/dist/command-spec.js.map +1 -1
  19. package/dist/confirm.d.ts +2 -0
  20. package/dist/confirm.js +4 -2
  21. package/dist/confirm.js.map +1 -1
  22. package/dist/cost.d.ts +9 -0
  23. package/dist/cost.js +16 -0
  24. package/dist/cost.js.map +1 -0
  25. package/dist/define.d.ts +133 -32
  26. package/dist/define.js +5 -1
  27. package/dist/define.js.map +1 -1
  28. package/dist/doctor-rows.d.ts +2 -2
  29. package/dist/doctor-rows.js +42 -5
  30. package/dist/doctor-rows.js.map +1 -1
  31. package/dist/doctor.d.ts +2 -1
  32. package/dist/doctor.js +26 -28
  33. package/dist/doctor.js.map +1 -1
  34. package/dist/errno.d.ts +12 -0
  35. package/dist/errno.js +40 -0
  36. package/dist/errno.js.map +1 -0
  37. package/dist/error-table.d.ts +34 -0
  38. package/dist/error-table.js +10 -0
  39. package/dist/error-table.js.map +1 -0
  40. package/dist/errors.d.ts +17 -12
  41. package/dist/errors.js +59 -38
  42. package/dist/errors.js.map +1 -1
  43. package/dist/execute.d.ts +9 -3
  44. package/dist/execute.js +38 -5
  45. package/dist/execute.js.map +1 -1
  46. package/dist/exit-classes.d.ts +31 -0
  47. package/dist/exit-classes.js +107 -0
  48. package/dist/exit-classes.js.map +1 -0
  49. package/dist/files.d.ts +9 -0
  50. package/dist/files.js +59 -0
  51. package/dist/files.js.map +1 -0
  52. package/dist/flags.d.ts +17 -3
  53. package/dist/flags.js +26 -4
  54. package/dist/flags.js.map +1 -1
  55. package/dist/global-install.d.ts +1 -0
  56. package/dist/global-install.js +2 -2
  57. package/dist/global-install.js.map +1 -1
  58. package/dist/help-json.d.ts +2 -1
  59. package/dist/help-json.js +18 -2
  60. package/dist/help-json.js.map +1 -1
  61. package/dist/help.d.ts +4 -2
  62. package/dist/help.js +62 -6
  63. package/dist/help.js.map +1 -1
  64. package/dist/index.d.ts +10 -4
  65. package/dist/index.js +2 -2
  66. package/dist/index.js.map +1 -1
  67. package/dist/interrupts.d.ts +17 -3
  68. package/dist/interrupts.js +43 -25
  69. package/dist/interrupts.js.map +1 -1
  70. package/dist/invocation.d.ts +7 -2
  71. package/dist/invocation.js +11 -3
  72. package/dist/invocation.js.map +1 -1
  73. package/dist/list.d.ts +1 -0
  74. package/dist/list.js +4 -2
  75. package/dist/list.js.map +1 -1
  76. package/dist/npm.d.ts +5 -0
  77. package/dist/npm.js +19 -17
  78. package/dist/npm.js.map +1 -1
  79. package/dist/output.d.ts +18 -4
  80. package/dist/output.js +65 -23
  81. package/dist/output.js.map +1 -1
  82. package/dist/outputs.d.ts +11 -0
  83. package/dist/outputs.js +22 -0
  84. package/dist/outputs.js.map +1 -0
  85. package/dist/package-root.d.ts +6 -0
  86. package/dist/package-root.js +17 -0
  87. package/dist/package-root.js.map +1 -0
  88. package/dist/parse-input.d.ts +2 -0
  89. package/dist/parse-input.js +5 -3
  90. package/dist/parse-input.js.map +1 -1
  91. package/dist/project.d.ts +4 -0
  92. package/dist/project.js +48 -0
  93. package/dist/project.js.map +1 -0
  94. package/dist/route.d.ts +2 -0
  95. package/dist/route.js +2 -1
  96. package/dist/route.js.map +1 -1
  97. package/dist/run-cli.d.ts +24 -5
  98. package/dist/run-cli.js +122 -17
  99. package/dist/run-cli.js.map +1 -1
  100. package/dist/run-process.js +6 -3
  101. package/dist/run-process.js.map +1 -1
  102. package/dist/secrets.d.ts +13 -0
  103. package/dist/secrets.js +29 -0
  104. package/dist/secrets.js.map +1 -0
  105. package/dist/spawn.d.ts +29 -0
  106. package/dist/spawn.js +79 -0
  107. package/dist/spawn.js.map +1 -0
  108. package/dist/spill.d.ts +16 -0
  109. package/dist/spill.js +60 -0
  110. package/dist/spill.js.map +1 -0
  111. package/dist/style.js +5 -12
  112. package/dist/style.js.map +1 -1
  113. package/dist/tail.d.ts +2 -0
  114. package/dist/tail.js +5 -0
  115. package/dist/tail.js.map +1 -0
  116. package/dist/tools.d.ts +6 -0
  117. package/dist/tools.js +69 -0
  118. package/dist/tools.js.map +1 -0
  119. package/dist/update.js +7 -7
  120. package/dist/update.js.map +1 -1
  121. package/dist/usage.d.ts +3 -0
  122. package/dist/usage.js +6 -3
  123. package/dist/usage.js.map +1 -1
  124. package/package.json +1 -1
package/dist/define.d.ts CHANGED
@@ -1,83 +1,174 @@
1
1
  import type * as z from "zod";
2
+ import type { Clock } from "./clock.js";
3
+ import type { ErrorTable } from "./error-table.js";
4
+ import type { Files } from "./files.js";
2
5
  import { type StandardFlagName } from "./flags.js";
3
6
  import type { Page, PageInput, RowSchema } from "./list.js";
7
+ import type { Secret } from "./secrets.js";
8
+ import type { ContextSpawn } from "./spawn.js";
4
9
  import type { Style } from "./style.js";
5
10
  export type Env = Readonly<Record<string, string | undefined>>;
6
11
  export interface Example {
7
12
  readonly command: string;
8
13
  readonly note: string;
9
14
  }
10
- export interface Context {
15
+ export interface PollOptions {
16
+ readonly intervalMs: number;
17
+ }
18
+ export interface Context<Ports = unknown, Settings = unknown> {
11
19
  readonly cwd: string;
12
20
  readonly env: Env;
21
+ /** The folder holding this CLI's `package.json`, for reading files shipped in the package. */
22
+ readonly packageRoot: string;
13
23
  /** Writes a plain line to stderr, for long work; it never reaches stdout. */
14
24
  progress(message: string): void;
15
- /** Aborts when the run is interrupted (Ctrl-C); pass it to `fetch` and child processes. */
25
+ /**
26
+ * Aborts when the run is interrupted (Ctrl-C) or hits the Command's run deadline; pass it to
27
+ * `fetch` and child processes.
28
+ */
16
29
  readonly signal: AbortSignal;
17
30
  /** Returns a signal that also aborts, with `DEADLINE_EXCEEDED`, once `ms` have passed. */
18
31
  deadline(ms: number): AbortSignal;
19
- /** Runs a step that must not stop halfway: the run waits for it even when interrupted. */
20
- runToEnd<T>(work: () => Promise<T>): Promise<T>;
32
+ /**
33
+ * Runs a step that must not stop halfway: the run waits for it even when stopped, and then
34
+ * prints `finishing <name>` on stderr.
35
+ */
36
+ runToEnd<T>(name: string, work: () => Promise<T>): Promise<T>;
37
+ /**
38
+ * Records the data done so far, in the shape `render` takes; the last call wins. A run that then
39
+ * fails, hits a deadline or is interrupted prints it; a returned value replaces it.
40
+ */
41
+ deliver(data: unknown): void;
42
+ /** The outside systems the CLI declared with `agentCli<Ports>()`. */
43
+ readonly ports: Ports;
44
+ /** Writes files atomically and tells whether one exists; a failure fails the run with `PERMISSION_DENIED`, `DISK_FULL` or `NOT_FOUND`. */
45
+ readonly files: Files;
46
+ /**
47
+ * Runs a child process, killed when the run is interrupted; `check: true` fails the run with
48
+ * `TOOL_FAILED` and the tail of its stderr when it exits non-zero.
49
+ */
50
+ readonly spawn: ContextSpawn;
51
+ /** Deadlines, `poll` and the grace period after an interrupt run on it. */
52
+ readonly clock: Clock;
53
+ /**
54
+ * Calls `check` until it returns a value other than `undefined`, sleeping `intervalMs` between
55
+ * calls; it stops when `ctx.signal` aborts.
56
+ */
57
+ poll<T>(check: () => T | undefined | Promise<T | undefined>, options: PollOptions): Promise<T>;
58
+ /** The Project file found by walking up from `cwd`, parsed by the CLI's schema. */
59
+ readonly project: Project<Settings> | undefined;
60
+ /** Reads `name` from the env, then from `$XDG_CONFIG_HOME/<cli>/.env`, with where it came from. */
61
+ secret(name: string): Secret | undefined;
62
+ }
63
+ export interface Project<Settings = unknown> {
64
+ /** The folder holding the Project file. */
65
+ readonly root: string;
66
+ readonly settings: Settings;
67
+ }
68
+ /** Names the Project file and the schema its JSON must match. */
69
+ export interface ProjectFile<Settings = unknown> {
70
+ readonly file: string;
71
+ readonly schema: z.ZodType<Settings>;
21
72
  }
22
73
  export type InputSchema = z.ZodObject;
74
+ export type NoPorts = Record<never, never>;
23
75
  export type NoInput = z.ZodObject<Record<never, never>>;
24
76
  type OutputOf<Schema extends InputSchema> = keyof Schema["shape"] extends never ? unknown : z.output<Schema>;
25
77
  type Flatten<T> = {
26
78
  [K in keyof T]: T[K];
27
79
  };
28
80
  export type Input<Args extends InputSchema, Options extends InputSchema> = Flatten<OutputOf<Args> & OutputOf<Options>>;
81
+ /** A program a Command runs, looked up on `PATH` before the Command starts. */
82
+ export interface Tool {
83
+ readonly name: string;
84
+ /** The command that installs it, shown when it is missing. */
85
+ readonly install: string;
86
+ }
87
+ /** Bounds a whole run, so a long run stops before the caller's own timeout and can be continued. */
88
+ export interface RunDeadline<In> {
89
+ readonly ms: number;
90
+ /** The command line that continues the work, given as the hint of the run's `DEADLINE_EXCEEDED`. */
91
+ resume(input: In): string;
92
+ }
29
93
  interface CommandBase<Args extends InputSchema, Options extends InputSchema> {
30
94
  readonly name: string;
31
95
  readonly description: string;
32
96
  readonly examples: readonly Example[];
97
+ /** Missing ones fail the run with `TOOL_MISSING` before `plan`, `run` or `start`. */
98
+ readonly tools?: readonly Tool[];
33
99
  readonly args?: Args;
34
100
  readonly options?: Options;
101
+ /** At `ms`, `ctx.signal` aborts and the run ends with `DEADLINE_EXCEEDED` (exit 75). */
102
+ readonly deadline?: RunDeadline<Input<Args, Options>>;
35
103
  }
36
104
  interface UnpagedCommand<Args extends InputSchema, Options extends InputSchema> extends CommandBase<Args, Options> {
37
105
  readonly output?: z.ZodType;
38
106
  readonly rows?: never;
39
107
  }
40
- export interface ReadCommand<Args extends InputSchema, Options extends InputSchema, Data> extends UnpagedCommand<Args, Options> {
108
+ export interface ReadCommand<Args extends InputSchema, Options extends InputSchema, Data, Ports = unknown, Settings = unknown> extends UnpagedCommand<Args, Options> {
41
109
  readonly effect: "read";
42
- run(input: Input<Args, Options>, ctx: Context): Data | Promise<Data>;
110
+ run(input: Input<Args, Options>, ctx: Context<Ports, Settings>): Data | Promise<Data>;
43
111
  render(data: Data, style: Style): string;
44
112
  }
45
113
  /** A read Command whose data is a page of rows; the Runtime adds `--limit`, `--cursor` and `--fields`. */
46
- export interface ListCommand<Args extends InputSchema, Options extends InputSchema, Row extends RowSchema> extends CommandBase<Args, Options> {
114
+ export interface ListCommand<Args extends InputSchema, Options extends InputSchema, Row extends RowSchema, Ports = unknown, Settings = unknown> extends CommandBase<Args, Options> {
47
115
  readonly effect: "read";
48
116
  /** The schema of one row; the page's output schema is derived from it. */
49
117
  readonly rows: Row;
50
118
  readonly output?: never;
51
- run(input: Flatten<OutputOf<Args> & OutputOf<Options> & PageInput>, ctx: Context): Page<z.output<Row>> | Promise<Page<z.output<Row>>>;
119
+ run(input: Flatten<OutputOf<Args> & OutputOf<Options> & PageInput>, ctx: Context<Ports, Settings>): Page<z.output<Row>> | Promise<Page<z.output<Row>>>;
52
120
  render(page: Page<z.output<Row>>, style: Style): string;
53
121
  }
54
122
  /** A Command that changes something: `plan` has no side effects, `apply` performs the Plan. */
55
- interface PlannedCommand<Args extends InputSchema, Options extends InputSchema, Plan, Data> extends UnpagedCommand<Args, Options> {
56
- plan(input: Input<Args, Options>, ctx: Context): Plan | Promise<Plan>;
57
- apply(plan: Plan, ctx: Context): Data | Promise<Data>;
123
+ interface PlannedCommand<Args extends InputSchema, Options extends InputSchema, Plan, Data, Ports, Settings> extends UnpagedCommand<Args, Options> {
124
+ plan(input: Input<Args, Options>, ctx: Context<Ports, Settings>): Plan | Promise<Plan>;
125
+ apply(plan: Plan, ctx: Context<Ports, Settings>): Data | Promise<Data>;
58
126
  render(data: Data, style: Style): string;
59
127
  renderPlan(plan: Plan, style: Style): string;
60
- }
61
- export interface WriteCommand<Args extends InputSchema, Options extends InputSchema, Plan, Data> extends PlannedCommand<Args, Options, Plan, Data> {
128
+ /**
129
+ * A sentence stating what the Plan costs, or undefined when it is cheap. Declaring it adds
130
+ * `--yes`, which a run must pass whenever it returns a sentence.
131
+ */
132
+ cost?(plan: Plan): string | undefined;
133
+ /**
134
+ * The files the Plan writes, relative to `ctx.cwd`. Declaring it adds `--force`, without which
135
+ * a run refuses with `OUTPUT_EXISTS` when any of them exists.
136
+ */
137
+ outputs?(plan: Plan): readonly string[];
138
+ }
139
+ export interface WriteCommand<Args extends InputSchema, Options extends InputSchema, Plan, Data, Ports = unknown, Settings = unknown> extends PlannedCommand<Args, Options, Plan, Data, Ports, Settings> {
62
140
  readonly effect: "write";
63
141
  }
64
- export interface DestructiveCommand<Args extends InputSchema, Options extends InputSchema, Plan, Data> extends PlannedCommand<Args, Options, Plan, Data> {
142
+ export interface DestructiveCommand<Args extends InputSchema, Options extends InputSchema, Plan, Data, Ports = unknown, Settings = unknown> extends PlannedCommand<Args, Options, Plan, Data, Ports, Settings> {
65
143
  readonly effect: "destructive";
66
144
  /** The value the caller must repeat as `--confirm`, naming the target the Plan changes. */
67
145
  confirm(plan: Plan): string;
68
146
  }
69
- export type Command = ReadCommand<InputSchema, InputSchema, unknown> | ListCommand<InputSchema, InputSchema, RowSchema> | WriteCommand<InputSchema, InputSchema, unknown, unknown> | DestructiveCommand<InputSchema, InputSchema, unknown, unknown>;
70
- export interface Commands {
71
- readonly [key: string]: Command | Commands;
147
+ /** A Command that keeps running, such as a preview server, until Ctrl-C or SIGTERM stops it. */
148
+ export interface ServeCommand<Args extends InputSchema, Options extends InputSchema, Data, Ports = unknown, Settings = unknown> extends UnpagedCommand<Args, Options> {
149
+ readonly effect: "serve";
150
+ /** Starts the work and returns its data, which prints at once; stop the work on `ctx.signal`. */
151
+ start(input: Input<Args, Options>, ctx: Context<Ports, Settings>): Data | Promise<Data>;
152
+ render(data: Data, style: Style): string;
153
+ }
154
+ export type Command<Ports = unknown, Settings = unknown> = ReadCommand<InputSchema, InputSchema, unknown, Ports, Settings> | ListCommand<InputSchema, InputSchema, RowSchema, Ports, Settings> | WriteCommand<InputSchema, InputSchema, unknown, unknown, Ports, Settings> | DestructiveCommand<InputSchema, InputSchema, unknown, unknown, Ports, Settings> | ServeCommand<InputSchema, InputSchema, unknown, Ports, Settings>;
155
+ export interface Commands<Ports = unknown, Settings = unknown> {
156
+ readonly [key: string]: Command<Ports, Settings> | Commands<Ports, Settings>;
72
157
  }
73
- interface CliBase {
158
+ interface CliBase<Ports, Settings> {
74
159
  readonly name: string;
75
160
  readonly version: string;
76
- /** The commit the build was made from, stamped by the bundler; `--version` prints it. */
161
+ /** The commit the build was made from and when, stamped by the bundler; `--version` prints it. */
77
162
  readonly build?: {
78
163
  readonly sha: string;
79
164
  readonly dirty: boolean;
165
+ readonly builtAt: string;
80
166
  };
167
+ /** Every code the CLI throws; a code missing here exits 70, as a bug. */
168
+ readonly errors?: ErrorTable;
169
+ /** Builds the real ports when a Command runs; `runCli`'s `ports` replaces them in a test. */
170
+ readonly ports?: () => Ports;
171
+ readonly project?: ProjectFile<Settings>;
81
172
  }
82
173
  /** Where an Agent CLI is published and how it is installed; `doctor` and `update` read it. */
83
174
  export interface GlobalInstall {
@@ -92,14 +183,18 @@ export interface DoctorFinding {
92
183
  readonly fix?: string;
93
184
  }
94
185
  /** A row the CLI adds to `doctor`, for a system it depends on. */
95
- export interface DoctorCheck {
186
+ export interface DoctorCheck<Ports = unknown, Settings = unknown> {
96
187
  readonly name: string;
97
- /** `ctx.signal` aborts at the 10 s deadline. A thrown error is reported as this row's problem. */
98
- run(ctx: Context): DoctorFinding | Promise<DoctorFinding>;
188
+ /** How long the row may take before it is reported as a problem; 10 s when absent. */
189
+ readonly deadlineMs?: number;
190
+ /** A problem in an advisory row shows but never fails `doctor`. */
191
+ readonly advisory?: boolean;
192
+ /** `ctx.signal` aborts at the row's deadline. A thrown error is reported as this row's problem. */
193
+ run(ctx: Context<Ports, Settings>): DoctorFinding | Promise<DoctorFinding>;
99
194
  }
100
195
  /** An Agent CLI whose Commands are reached by name, as in `tool voices list`. */
101
- export interface CommandTreeCli extends CliBase {
102
- readonly commands: Commands;
196
+ export interface CommandTreeCli<Ports = unknown, Settings = unknown> extends CliBase<Ports, Settings> {
197
+ readonly commands: Commands<Ports, Settings>;
103
198
  readonly command?: never;
104
199
  /** Absent for a CLI that is not published: `doctor` then checks no install or registry. */
105
200
  readonly install?: GlobalInstall;
@@ -107,14 +202,14 @@ export interface CommandTreeCli extends CliBase {
107
202
  readonly engines?: {
108
203
  readonly node?: string;
109
204
  };
110
- readonly doctor?: readonly DoctorCheck[];
205
+ readonly doctor?: readonly DoctorCheck<Ports, Settings>[];
111
206
  }
112
207
  /** An Agent CLI that is one Command, run with no Command name, as in `tool <args>`. */
113
- export interface SingleCommandCli extends CliBase {
114
- readonly command: Command;
208
+ export interface SingleCommandCli<Ports = unknown, Settings = unknown> extends CliBase<Ports, Settings> {
209
+ readonly command: Command<Ports, Settings>;
115
210
  readonly commands?: never;
116
211
  }
117
- export type Cli = CommandTreeCli | SingleCommandCli;
212
+ export type Cli<Ports = unknown, Settings = unknown> = CommandTreeCli<Ports, Settings> | SingleCommandCli<Ports, Settings>;
118
213
  type Kebab<Key extends string> = Key extends `${infer Head}${infer Tail}` ? `${Head extends Lowercase<Head> ? Head : `-${Lowercase<Head>}`}${Kebab<Tail>}` : Key;
119
214
  type Taken<Schema extends InputSchema> = Extract<Kebab<Extract<keyof Schema["shape"], string>>, StandardFlagName>;
120
215
  type Unreserved<Schema extends InputSchema> = [Taken<Schema>] extends [never] ? unknown : {
@@ -124,9 +219,15 @@ interface WithoutStandardFlags<Args extends InputSchema, Options extends InputSc
124
219
  readonly args?: Unreserved<Args>;
125
220
  readonly options?: Unreserved<Options>;
126
221
  }
127
- export declare function defineCommand<Row extends RowSchema, Args extends InputSchema = NoInput, Options extends InputSchema = NoInput>(command: ListCommand<Args, Options, Row> & WithoutStandardFlags<Args, Options>): ListCommand<Args, Options, Row>;
128
- export declare function defineCommand<Data, Args extends InputSchema = NoInput, Options extends InputSchema = NoInput>(command: ReadCommand<Args, Options, Data> & WithoutStandardFlags<Args, Options>): ReadCommand<Args, Options, Data>;
129
- export declare function defineCommand<Plan, Data, Args extends InputSchema = NoInput, Options extends InputSchema = NoInput>(command: WriteCommand<Args, Options, Plan, Data> & WithoutStandardFlags<Args, Options>): WriteCommand<Args, Options, Plan, Data>;
130
- export declare function defineCommand<Plan, Data, Args extends InputSchema = NoInput, Options extends InputSchema = NoInput>(command: DestructiveCommand<Args, Options, Plan, Data> & WithoutStandardFlags<Args, Options>): DestructiveCommand<Args, Options, Plan, Data>;
222
+ /** Declares a Command whose `ctx.ports` is the CLI's `Ports`. */
223
+ export interface DefineCommand<Ports, Settings = unknown> {
224
+ <Row extends RowSchema, Args extends InputSchema = NoInput, Options extends InputSchema = NoInput>(command: ListCommand<Args, Options, Row, Ports, Settings> & WithoutStandardFlags<Args, Options>): ListCommand<Args, Options, Row, Ports, Settings>;
225
+ <Data, Args extends InputSchema = NoInput, Options extends InputSchema = NoInput>(command: ReadCommand<Args, Options, Data, Ports, Settings> & WithoutStandardFlags<Args, Options>): ReadCommand<Args, Options, Data, Ports, Settings>;
226
+ <Data, Args extends InputSchema = NoInput, Options extends InputSchema = NoInput>(command: ServeCommand<Args, Options, Data, Ports, Settings> & WithoutStandardFlags<Args, Options>): ServeCommand<Args, Options, Data, Ports, Settings>;
227
+ <Plan, Data, Args extends InputSchema = NoInput, Options extends InputSchema = NoInput>(command: WriteCommand<Args, Options, Plan, Data, Ports, Settings> & WithoutStandardFlags<Args, Options>): WriteCommand<Args, Options, Plan, Data, Ports, Settings>;
228
+ <Plan, Data, Args extends InputSchema = NoInput, Options extends InputSchema = NoInput>(command: DestructiveCommand<Args, Options, Plan, Data, Ports, Settings> & WithoutStandardFlags<Args, Options>): DestructiveCommand<Args, Options, Plan, Data, Ports, Settings>;
229
+ }
230
+ export declare function defineCommandFor<Ports, Settings>(): DefineCommand<Ports, Settings>;
231
+ export declare const defineCommand: DefineCommand<unknown>;
131
232
  export declare function isCommand(node: Command | Commands): node is Command;
132
233
  export {};
package/dist/define.js CHANGED
@@ -1,8 +1,12 @@
1
1
  import { checkNoStandardFlags } from "./flags.js";
2
- export function defineCommand(command) {
2
+ function checkedCommand(command) {
3
3
  checkNoStandardFlags(command);
4
4
  return command;
5
5
  }
6
+ export function defineCommandFor() {
7
+ return checkedCommand;
8
+ }
9
+ export const defineCommand = defineCommandFor();
6
10
  // A group's values are always objects, so a string `effect` can only belong to a Command.
7
11
  export function isCommand(node) {
8
12
  return typeof node.effect === "string";
@@ -1 +1 @@
1
- {"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAyB,MAAM,YAAY,CAAC;AAgNzE,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,SAAS,CAAC,IAAwB;IAChD,OAAO,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC;AACzC,CAAC"}
1
+ {"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,oBAAoB,EAAyB,MAAM,YAAY,CAAC;AA+UzE,SAAS,cAAc,CAA2B,OAAiB;IACjE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAA2B,gBAAgB,EAAE,CAAC;AAExE,0FAA0F;AAC1F,MAAM,UAAU,SAAS,CAAC,IAAwB;IAChD,OAAO,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC;AACzC,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import type { CommandTreeCli, DoctorCheck } from "./define.js";
2
- /** The rows every `doctor` reports first, in this order. */
3
- export declare function fixedRows(cli: CommandTreeCli, bin: string | undefined): DoctorCheck[];
2
+ /** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
3
+ export declare function doctorChecks(cli: CommandTreeCli, bin: string | undefined): DoctorCheck[];
@@ -1,11 +1,18 @@
1
+ import { join } from "node:path";
1
2
  import { CliError } from "./errors.js";
2
- import { globalInstallOf } from "./global-install.js";
3
+ import { globalInstallOf, NOT_GLOBAL_INSTALL } from "./global-install.js";
3
4
  import { installCommandLine, latestVersion, npmContext } from "./npm.js";
5
+ import { versionLine } from "./output.js";
6
+ import { PROJECT_INVALID, projectOf } from "./project.js";
4
7
  import { engineMinimum, meetsMinimum, standingOf } from "./semver.js";
5
8
  import { skillCopies, skillUpdateCommand } from "./skills.js";
9
+ import { toolRows } from "./tools.js";
6
10
  function ok(message) {
7
11
  return { state: "ok", message };
8
12
  }
13
+ function buildRow(cli) {
14
+ return { name: "build", run: () => ok(versionLine(cli)) };
15
+ }
9
16
  function nodeRow(cli) {
10
17
  return {
11
18
  name: "node",
@@ -34,6 +41,27 @@ function nodeRow(cli) {
34
41
  },
35
42
  };
36
43
  }
44
+ function projectRow(projectFile) {
45
+ const { file } = projectFile;
46
+ return {
47
+ name: "project",
48
+ run: (ctx) => {
49
+ let project;
50
+ try {
51
+ project = projectOf(projectFile, ctx.cwd);
52
+ }
53
+ catch (error) {
54
+ if (error instanceof CliError && error.code === PROJECT_INVALID) {
55
+ return { state: "problem", message: error.message };
56
+ }
57
+ throw error;
58
+ }
59
+ return ok(project === undefined
60
+ ? `none found: no ${file} at or above ${ctx.cwd}`
61
+ : join(project.root, file));
62
+ },
63
+ };
64
+ }
37
65
  function installRow(cli, bin) {
38
66
  return {
39
67
  name: "install",
@@ -47,7 +75,7 @@ function installRow(cli, bin) {
47
75
  return ok(`a global npm install under ${copy.prefix}`);
48
76
  }
49
77
  catch (error) {
50
- if (error instanceof CliError && error.code === "NOT_GLOBAL_INSTALL") {
78
+ if (error instanceof CliError && error.code === NOT_GLOBAL_INSTALL) {
51
79
  return { state: "problem", message: error.message, fix: installCommandLine(install) };
52
80
  }
53
81
  throw error;
@@ -108,8 +136,17 @@ function skillRow(cli) {
108
136
  },
109
137
  };
110
138
  }
111
- /** The rows every `doctor` reports first, in this order. */
112
- export function fixedRows(cli, bin) {
113
- return [nodeRow(cli), installRow(cli, bin), registryRow(cli), skillRow(cli)];
139
+ /** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
140
+ export function doctorChecks(cli, bin) {
141
+ return [
142
+ buildRow(cli),
143
+ nodeRow(cli),
144
+ ...(cli.project === undefined ? [] : [projectRow(cli.project)]),
145
+ ...(cli.doctor ?? []),
146
+ ...toolRows(cli.commands),
147
+ installRow(cli, bin),
148
+ registryRow(cli),
149
+ skillRow(cli),
150
+ ];
114
151
  }
115
152
  //# sourceMappingURL=doctor-rows.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor-rows.js","sourceRoot":"","sources":["../src/doctor-rows.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctor-rows.js","sourceRoot":"","sources":["../src/doctor-rows.ts"],"names":[],"mappings":"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"}
package/dist/doctor.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { type Command, type CommandTreeCli } from "./define.js";
2
- /** The built-in `doctor`: the fixed rows, then the CLI's own, each under its own deadline. */
2
+ export declare const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
3
+ /** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
3
4
  export declare function doctorCommand(cli: CommandTreeCli, bin: string | undefined): Command;
package/dist/doctor.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import * as z from "zod";
2
+ import { untilAborted } from "./abort.js";
2
3
  import { defineCommand, } from "./define.js";
3
- import { fixedRows } from "./doctor-rows.js";
4
- import { CliError, FailureWithData, messageOf } from "./errors.js";
5
- const PROBE_DEADLINE_MS = 10_000;
4
+ import { doctorChecks } from "./doctor-rows.js";
5
+ import { CliError, messageOf } from "./errors.js";
6
+ export const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
7
+ const DEFAULT_DEADLINE_MS = 10_000;
6
8
  const MS_PER_SECOND = 1000;
7
9
  const MIN_LABEL_WIDTH = 8;
8
10
  const rowSchema = z.object({
@@ -15,20 +17,11 @@ const reportSchema = z.object({
15
17
  rows: z.array(rowSchema),
16
18
  next: z.array(z.string()),
17
19
  });
18
- function untilAborted(signal) {
19
- return new Promise((_resolve, reject) => {
20
- if (signal.aborted) {
21
- reject(signal.reason);
22
- return;
23
- }
24
- signal.addEventListener("abort", () => reject(signal.reason), { once: true });
25
- });
26
- }
27
- function problemOf(check, error, { signal, deadline }) {
20
+ function problemOf(check, error, { signal, deadline, ms }) {
28
21
  if (!signal.aborted && deadline.aborted && error === deadline.reason) {
29
22
  return {
30
23
  state: "problem",
31
- message: `${check.name} did not answer within ${PROBE_DEADLINE_MS / MS_PER_SECOND} s`,
24
+ message: `${check.name} did not answer within ${ms / MS_PER_SECOND} s`,
32
25
  };
33
26
  }
34
27
  if (error instanceof CliError) {
@@ -38,7 +31,8 @@ function problemOf(check, error, { signal, deadline }) {
38
31
  }
39
32
  // Racing the deadline ends a row whose check ignores its signal.
40
33
  async function rowOf(check, ctx) {
41
- const signal = ctx.deadline(PROBE_DEADLINE_MS);
34
+ const ms = check.deadlineMs ?? DEFAULT_DEADLINE_MS;
35
+ const signal = ctx.deadline(ms);
42
36
  let finding;
43
37
  try {
44
38
  finding = await Promise.race([
@@ -47,9 +41,9 @@ async function rowOf(check, ctx) {
47
41
  ]);
48
42
  }
49
43
  catch (error) {
50
- finding = problemOf(check, error, { signal: ctx.signal, deadline: signal });
44
+ finding = problemOf(check, error, { signal: ctx.signal, deadline: signal, ms });
51
45
  }
52
- return { check: check.name, ...finding };
46
+ return { row: { check: check.name, ...finding }, advisory: check.advisory === true };
53
47
  }
54
48
  function nextOf(rows) {
55
49
  return [...new Set(rows.flatMap(({ fix }) => (fix === undefined ? [] : [fix])))];
@@ -63,18 +57,16 @@ function render({ rows, next }, style) {
63
57
  });
64
58
  return [...lines, ...next.map((fix) => `${"next".padEnd(width)}${fix}`)].join("\n");
65
59
  }
66
- function failure(cliName, report) {
67
- const problems = report.rows.filter(({ state }) => state === "problem").map(({ check }) => check);
68
- return new FailureWithData({
69
- code: "DOCTOR_PROBLEMS",
60
+ function failure(cliName, problems, report) {
61
+ return new CliError({
62
+ code: DOCTOR_PROBLEMS,
70
63
  message: `${cliName} doctor found ${problems.length === 1 ? "a problem" : `${problems.length} problems`}: ${problems.join(", ")}`,
71
64
  hint: report.next.length === 0
72
65
  ? "each problem row says what is wrong"
73
66
  : "run the commands under next, then run doctor again",
74
- retryable: false,
75
- }, report);
67
+ });
76
68
  }
77
- /** The built-in `doctor`: the fixed rows, then the CLI's own, each under its own deadline. */
69
+ /** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
78
70
  export function doctorCommand(cli, bin) {
79
71
  return defineCommand({
80
72
  name: "doctor",
@@ -86,11 +78,17 @@ export function doctorCommand(cli, bin) {
86
78
  effect: "read",
87
79
  output: reportSchema,
88
80
  run: async (_input, ctx) => {
89
- const checks = [...fixedRows(cli, bin), ...(cli.doctor ?? [])];
90
- const rows = await Promise.all(checks.map((check) => rowOf(check, ctx)));
81
+ const checked = await Promise.all(doctorChecks(cli, bin).map((check) => rowOf(check, ctx)));
82
+ // Rows cut short by an interrupt report it as their problem, which no row has.
83
+ ctx.signal.throwIfAborted();
84
+ const rows = checked.map(({ row }) => row);
91
85
  const report = { rows, next: nextOf(rows) };
92
- if (rows.some(({ state }) => state === "problem")) {
93
- throw failure(cli.name, report);
86
+ const problems = checked
87
+ .filter(({ row, advisory }) => row.state === "problem" && !advisory)
88
+ .map(({ row }) => row.check);
89
+ if (problems.length > 0) {
90
+ ctx.deliver(report);
91
+ throw failure(cli.name, problems, report);
94
92
  }
95
93
  return report;
96
94
  },
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Env } from "./define.js";
2
+ export declare const PERMISSION_DENIED = "PERMISSION_DENIED";
3
+ export declare const DISK_FULL = "DISK_FULL";
4
+ export declare const NOT_FOUND = "NOT_FOUND";
5
+ export interface ErrnoContext {
6
+ readonly path: string;
7
+ /** The caller's command line, ready to paste. */
8
+ readonly callerLine: string;
9
+ readonly env: Env;
10
+ }
11
+ /** The error a file system failure on `path` stands for; any other error comes back unchanged. */
12
+ export declare function classifyErrno(error: unknown, context: ErrnoContext): unknown;
package/dist/errno.js ADDED
@@ -0,0 +1,40 @@
1
+ import { isAgent } from "./agent.js";
2
+ import { CliError, errnoOf } from "./errors.js";
3
+ export const PERMISSION_DENIED = "PERMISSION_DENIED";
4
+ export const DISK_FULL = "DISK_FULL";
5
+ export const NOT_FOUND = "NOT_FOUND";
6
+ // The same errnos happen with no sandbox at all (a root-owned folder), so only a detected agent is
7
+ // pointed at its sandbox.
8
+ function permissionHint({ path, callerLine, env }) {
9
+ return isAgent(env)
10
+ ? `your sandbox may block it: ask your user to run \`! ${callerLine}\`, or to allow ${path} in the sandbox's write list`
11
+ : `check the permissions of ${path} and its folder`;
12
+ }
13
+ /** The error a file system failure on `path` stands for; any other error comes back unchanged. */
14
+ export function classifyErrno(error, context) {
15
+ const { path } = context;
16
+ switch (errnoOf(error)) {
17
+ case "EACCES":
18
+ case "EPERM":
19
+ return new CliError({
20
+ code: PERMISSION_DENIED,
21
+ message: `permission denied: ${path}`,
22
+ hint: permissionHint(context),
23
+ }, { cause: error });
24
+ case "ENOSPC":
25
+ return new CliError({
26
+ code: DISK_FULL,
27
+ message: `no space left on the disk holding ${path}`,
28
+ hint: "free space on that disk, then run the same command again",
29
+ }, { cause: error });
30
+ case "ENOENT":
31
+ return new CliError({
32
+ code: NOT_FOUND,
33
+ message: `not found: ${path}`,
34
+ hint: `check that ${path} and its folder exist`,
35
+ }, { cause: error });
36
+ default:
37
+ return error;
38
+ }
39
+ }
40
+ //# sourceMappingURL=errno.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errno.js","sourceRoot":"","sources":["../src/errno.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,CAAC,MAAM,iBAAiB,GAAG,mBAAmB,CAAC;AACrD,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,CAAC;AACrC,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,CAAC;AASrC,mGAAmG;AACnG,0BAA0B;AAC1B,SAAS,cAAc,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAgB;IAC7D,OAAO,OAAO,CAAC,GAAG,CAAC;QACjB,CAAC,CAAC,uDAAuD,UAAU,mBAAmB,IAAI,8BAA8B;QACxH,CAAC,CAAC,4BAA4B,IAAI,iBAAiB,CAAC;AACxD,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,aAAa,CAAC,KAAc,EAAE,OAAqB;IACjE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IACzB,QAAQ,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,KAAK,QAAQ,CAAC;QACd,KAAK,OAAO;YACV,OAAO,IAAI,QAAQ,CACjB;gBACE,IAAI,EAAE,iBAAiB;gBACvB,OAAO,EAAE,sBAAsB,IAAI,EAAE;gBACrC,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC;aAC9B,EACD,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;QACJ,KAAK,QAAQ;YACX,OAAO,IAAI,QAAQ,CACjB;gBACE,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,qCAAqC,IAAI,EAAE;gBACpD,IAAI,EAAE,0DAA0D;aACjE,EACD,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;QACJ,KAAK,QAAQ;YACX,OAAO,IAAI,QAAQ,CACjB;gBACE,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,cAAc,IAAI,EAAE;gBAC7B,IAAI,EAAE,cAAc,IAAI,uBAAuB;aAChD,EACD,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;QACJ;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type * as z from "zod";
2
+ import { CliError } from "./errors.js";
3
+ import type { ExitClass } from "./exit-classes.js";
4
+ /** The Exit classes a CLI's own code can have; a bug or an interrupt is the Runtime's to tell. */
5
+ export type DeclaredExitClass = Exclude<ExitClass, "bug" | "interrupted">;
6
+ export interface ErrorDeclaration {
7
+ readonly class: DeclaredExitClass;
8
+ readonly details?: z.ZodType;
9
+ }
10
+ /** A CLI's error codes, each with the class that must act on it and the facts it carries. */
11
+ export type ErrorTable = Readonly<Record<string, ErrorDeclaration>>;
12
+ /** Keeps each code's literal class and `details` schema, so `cliError` can type its throw sites. */
13
+ export declare function defineErrors<const Table extends ErrorTable>(table: Table): Table;
14
+ type DetailsInit<Declaration> = Declaration extends {
15
+ readonly details: infer Schema;
16
+ } ? Schema extends z.ZodType ? {
17
+ readonly details: z.output<Schema>;
18
+ } : never : {
19
+ readonly details?: never;
20
+ };
21
+ type RetryInit<Declaration> = Declaration extends {
22
+ readonly class: "wait";
23
+ } ? {
24
+ readonly retryAt?: string;
25
+ } : {
26
+ readonly retryAt?: never;
27
+ };
28
+ export type CliErrorInit<Declaration extends ErrorDeclaration> = {
29
+ readonly message: string;
30
+ readonly hint: string;
31
+ } & DetailsInit<Declaration> & RetryInit<Declaration>;
32
+ /** A `CliError` for a code of `table`, whose `details` must match the code's schema. */
33
+ export declare function cliError<Table extends ErrorTable, Code extends keyof Table & string>(_table: Table, code: Code, init: CliErrorInit<Table[Code]>, options?: ErrorOptions): CliError;
34
+ export {};