agents.yaml 0.2.3 → 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.
- package/AGENTS.md +4 -0
- package/README.md +25 -9
- package/dist/index.mjs +128 -74
- package/package.json +6 -5
- package/src/cli.ts +140 -0
- package/src/index.ts +1 -1
- package/src/run.test.ts +226 -0
- package/src/run.ts +36 -97
- package/dist/index.d.mts +0 -1
package/AGENTS.md
CHANGED
|
@@ -21,3 +21,7 @@ The CLI can help discover package and local `AGENTS.md` files, add selected path
|
|
|
21
21
|
Discovery only considers direct dependencies under a project's `node_modules`; nested dependency `AGENTS.md` files are not automatically activated.
|
|
22
22
|
|
|
23
23
|
Discovery skips dot-prefixed directories by default. Use `agents discover --include-dot-directories` when hidden project directories should be scanned too.
|
|
24
|
+
|
|
25
|
+
The CLI uses Comline for command definitions, options, variadic path arguments, help, and shell completion. Clack handles the interactive flow. Pass full runtime argv to `run`; Comline removes the runtime and entry-point arguments.
|
|
26
|
+
|
|
27
|
+
`add` and `remove` require one or more paths. Use `--` before dash-prefixed paths. Unknown or misplaced options fail before command execution. Both text and JSON validation set a nonzero exit status when the index is invalid.
|
package/README.md
CHANGED
|
@@ -19,14 +19,35 @@ agents init
|
|
|
19
19
|
agents discover
|
|
20
20
|
agents discover --include-dot-directories
|
|
21
21
|
agents add ./node_modules/react/AGENTS.md
|
|
22
|
+
agents add ./react/AGENTS.md "./my package/AGENTS.md"
|
|
23
|
+
agents remove ./react/AGENTS.md "./my package/AGENTS.md"
|
|
22
24
|
agents validate
|
|
25
|
+
agents validate --json
|
|
26
|
+
agents --help
|
|
27
|
+
agents --version
|
|
23
28
|
```
|
|
24
29
|
|
|
25
30
|
Run `agents` with no command for the interactive flow.
|
|
26
31
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
`add` and `remove` accept one or more paths. Use `--` before paths that start with a dash. Unknown commands and flags, flags used with the wrong command, and missing required paths produce an error before the command runs.
|
|
33
|
+
|
|
34
|
+
Boolean switches accept `true`, `false`, `1`, and `0`, either with `=` or as the next argument. Repeated switches use the last value. Validation exits with status 1 for an invalid document index, including with `--json`.
|
|
35
|
+
|
|
36
|
+
Discovery skips dot-prefixed directories by default so local caches and tool state do not dominate scan time. Use `--include-dot-directories` when you need to search those directories too.
|
|
37
|
+
|
|
38
|
+
## Shell Completion
|
|
39
|
+
|
|
40
|
+
Generate a completion script with `agents completion <target>`, or install it into your shell's configured completion directory:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
agents completion install bash
|
|
44
|
+
agents completion install zsh
|
|
45
|
+
agents completion install fish
|
|
46
|
+
agents completion install nushell
|
|
47
|
+
agents completion install carapace
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Choose the target you use, then open a new shell. Completion setup requires the target shell's completion system to be enabled; setup errors explain any missing requirements. Commands and flags complete automatically. `add` completes filesystem paths, and `remove` suggests paths listed in `agents.yaml`, including after the first path.
|
|
30
51
|
|
|
31
52
|
## Benchmark
|
|
32
53
|
|
|
@@ -34,12 +55,7 @@ to search those directories too.
|
|
|
34
55
|
pnpm --filter agents.yaml bench
|
|
35
56
|
```
|
|
36
57
|
|
|
37
|
-
The benchmark creates a temporary discovery fixture, compares default discovery
|
|
38
|
-
against `--include-dot-directories`, prints median/min/max timings, and removes
|
|
39
|
-
the fixture when it exits. Fixture size can be tuned with
|
|
40
|
-
`AGENTS_BENCH_HIDDEN_DIRS`, `AGENTS_BENCH_FILES_PER_HIDDEN_DIR`,
|
|
41
|
-
`AGENTS_BENCH_VISIBLE_PACKAGES`, `AGENTS_BENCH_ITERATIONS`, and
|
|
42
|
-
`AGENTS_BENCH_WARMUPS`.
|
|
58
|
+
The benchmark creates a temporary discovery fixture, compares default discovery against `--include-dot-directories`, prints median/min/max timings, and removes the fixture when it exits. Fixture size can be tuned with `AGENTS_BENCH_HIDDEN_DIRS`, `AGENTS_BENCH_FILES_PER_HIDDEN_DIR`, `AGENTS_BENCH_VISIBLE_PACKAGES`, `AGENTS_BENCH_ITERATIONS`, and `AGENTS_BENCH_WARMUPS`.
|
|
43
59
|
|
|
44
60
|
## File Format
|
|
45
61
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { MultiSelectPrompt } from "@clack/core";
|
|
3
3
|
import * as clack from "@clack/prompts";
|
|
4
|
+
import { cli, completionResponse, help, interpretArguments, optional, options, parseBooleanOption, required } from "comline";
|
|
4
5
|
import { styleText } from "node:util";
|
|
5
6
|
import { access, opendir, readFile, writeFile } from "node:fs/promises";
|
|
6
7
|
import path from "node:path";
|
|
7
8
|
import * as YAML from "yaml";
|
|
8
9
|
import { z } from "zod";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
9
11
|
//#region src/paths.ts
|
|
10
12
|
function cwd() {
|
|
11
13
|
return process.cwd();
|
|
@@ -164,6 +166,102 @@ function isNotFound(error) {
|
|
|
164
166
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
165
167
|
}
|
|
166
168
|
//#endregion
|
|
169
|
+
//#region src/cli.ts
|
|
170
|
+
function parseBooleanSwitch(value) {
|
|
171
|
+
const last = value.split(",").at(-1) ?? "";
|
|
172
|
+
if (![
|
|
173
|
+
"",
|
|
174
|
+
"true",
|
|
175
|
+
"false",
|
|
176
|
+
"0",
|
|
177
|
+
"1"
|
|
178
|
+
].includes(last)) throw new Error(`Expected a boolean switch, received ${JSON.stringify(last)}`);
|
|
179
|
+
return parseBooleanOption(last);
|
|
180
|
+
}
|
|
181
|
+
function booleanSwitch(description, example) {
|
|
182
|
+
return {
|
|
183
|
+
description,
|
|
184
|
+
example,
|
|
185
|
+
parse: parseBooleanSwitch,
|
|
186
|
+
required: false
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
const commonSchema = z.object({
|
|
190
|
+
help: z.boolean().default(false),
|
|
191
|
+
version: z.boolean().default(false)
|
|
192
|
+
});
|
|
193
|
+
const commonOptions = {
|
|
194
|
+
help: {
|
|
195
|
+
...booleanSwitch("Show usage", "--help"),
|
|
196
|
+
flag: "h"
|
|
197
|
+
},
|
|
198
|
+
version: {
|
|
199
|
+
...booleanSwitch("Show the installed version", "--version"),
|
|
200
|
+
flag: "v"
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
const jsonOption = booleanSwitch("Print JSON", "--json");
|
|
204
|
+
function common(description) {
|
|
205
|
+
return options(description, commonSchema, commonOptions);
|
|
206
|
+
}
|
|
207
|
+
const agents = cli({
|
|
208
|
+
cliName: "agents",
|
|
209
|
+
cliDescription: "Discover and curate agent-readable documentation in agents.yaml.",
|
|
210
|
+
routes: optional({
|
|
211
|
+
init: null,
|
|
212
|
+
discover: null,
|
|
213
|
+
add: required({ "$...paths": null }),
|
|
214
|
+
remove: required({ "$...paths": null }),
|
|
215
|
+
validate: null,
|
|
216
|
+
help: null,
|
|
217
|
+
version: null
|
|
218
|
+
}),
|
|
219
|
+
routeOptions: {
|
|
220
|
+
"": common("Choose an action interactively"),
|
|
221
|
+
init: options("Initialize breadcrumb files", commonSchema.extend({ force: z.boolean().default(false) }), {
|
|
222
|
+
...commonOptions,
|
|
223
|
+
force: booleanSwitch("Append the breadcrumb even if already mentioned", "--force")
|
|
224
|
+
}),
|
|
225
|
+
discover: options("Discover supplemental AGENTS.md files", commonSchema.extend({
|
|
226
|
+
json: z.boolean().default(false),
|
|
227
|
+
"include-dot-directories": z.boolean().default(false)
|
|
228
|
+
}), {
|
|
229
|
+
...commonOptions,
|
|
230
|
+
json: jsonOption,
|
|
231
|
+
"include-dot-directories": booleanSwitch("Search hidden directories", "--include-dot-directories")
|
|
232
|
+
}),
|
|
233
|
+
"add/$...paths": common("Promote one or more AGENTS.md files"),
|
|
234
|
+
"remove/$...paths": common("Remove one or more promoted paths"),
|
|
235
|
+
validate: options("Validate agents.yaml", commonSchema.extend({ json: z.boolean().default(false) }), {
|
|
236
|
+
...commonOptions,
|
|
237
|
+
json: jsonOption
|
|
238
|
+
}),
|
|
239
|
+
help: common("Show usage"),
|
|
240
|
+
version: common("Show the installed version")
|
|
241
|
+
},
|
|
242
|
+
positionalCompletions: {
|
|
243
|
+
"add/$...paths": { fileSystem: "files" },
|
|
244
|
+
"remove/$...paths": { provide: async () => {
|
|
245
|
+
const { documents } = await loadAgentsFile(cwd());
|
|
246
|
+
return documents.map(({ path, description }) => ({
|
|
247
|
+
value: path,
|
|
248
|
+
...description ? { description } : {}
|
|
249
|
+
}));
|
|
250
|
+
} }
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
function earlyCommand(argv) {
|
|
254
|
+
const { options: occurrences } = interpretArguments(agents.definition, argv.slice(2));
|
|
255
|
+
for (const key of ["help", "version"]) {
|
|
256
|
+
const occurrence = occurrences.findLast((option) => option.key === key);
|
|
257
|
+
if (occurrence && parseBooleanSwitch(occurrence.value)) return key;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function packageVersion() {
|
|
261
|
+
const source = readFileSync(new URL("../package.json", import.meta.url), "utf8");
|
|
262
|
+
return z.object({ version: z.string() }).parse(JSON.parse(source)).version;
|
|
263
|
+
}
|
|
264
|
+
//#endregion
|
|
167
265
|
//#region src/discover.ts
|
|
168
266
|
const skippedDirectories = /* @__PURE__ */ new Set([
|
|
169
267
|
".git",
|
|
@@ -263,98 +361,54 @@ function isPackageJson(value) {
|
|
|
263
361
|
}
|
|
264
362
|
//#endregion
|
|
265
363
|
//#region src/run.ts
|
|
266
|
-
const helpText = `agents
|
|
267
|
-
|
|
268
|
-
Usage:
|
|
269
|
-
agents
|
|
270
|
-
agents init [--force]
|
|
271
|
-
agents discover [--json] [--include-dot-directories]
|
|
272
|
-
agents add <path...>
|
|
273
|
-
agents remove <path...>
|
|
274
|
-
agents validate [--json]
|
|
275
|
-
|
|
276
|
-
agents.yaml is a curated table of contents for promoted AGENTS.md guidance.`;
|
|
277
364
|
async function run(argv) {
|
|
278
|
-
const
|
|
365
|
+
const completion = await completionResponse(agents.definition, argv);
|
|
366
|
+
if (completion !== void 0) {
|
|
367
|
+
process.stdout.write(completion);
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const early = earlyCommand(argv);
|
|
371
|
+
if (early === "help") {
|
|
372
|
+
console.log(help(agents.definition));
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
if (early === "version") {
|
|
376
|
+
console.log(packageVersion());
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
const { inputs, warnings } = agents(argv);
|
|
380
|
+
if (warnings.length > 0) throw new Error(warnings.map((warning) => warning.message).join("\n"));
|
|
279
381
|
const root = cwd();
|
|
280
|
-
switch (
|
|
281
|
-
case
|
|
382
|
+
switch (inputs.case) {
|
|
383
|
+
case "":
|
|
282
384
|
await interactive(root);
|
|
283
385
|
return;
|
|
284
386
|
case "help":
|
|
285
|
-
console.log(
|
|
387
|
+
console.log(help(agents.definition));
|
|
286
388
|
return;
|
|
287
389
|
case "version":
|
|
288
|
-
console.log(
|
|
390
|
+
console.log(packageVersion());
|
|
289
391
|
return;
|
|
290
392
|
case "init":
|
|
291
|
-
await commandInit(root,
|
|
393
|
+
await commandInit(root, inputs.opts.force);
|
|
292
394
|
return;
|
|
293
395
|
case "discover":
|
|
294
396
|
await commandDiscover(root, {
|
|
295
|
-
json:
|
|
296
|
-
includeDotDirectories:
|
|
397
|
+
json: inputs.opts.json,
|
|
398
|
+
includeDotDirectories: inputs.opts["include-dot-directories"]
|
|
297
399
|
});
|
|
298
400
|
return;
|
|
299
|
-
case "add":
|
|
300
|
-
await commandAdd(root,
|
|
401
|
+
case "add/$...paths":
|
|
402
|
+
await commandAdd(root, inputs.params.paths);
|
|
301
403
|
return;
|
|
302
|
-
case "remove":
|
|
303
|
-
await commandRemove(root,
|
|
404
|
+
case "remove/$...paths":
|
|
405
|
+
await commandRemove(root, inputs.params.paths);
|
|
304
406
|
return;
|
|
305
407
|
case "validate":
|
|
306
|
-
await commandValidate(root,
|
|
408
|
+
await commandValidate(root, inputs.opts.json);
|
|
307
409
|
return;
|
|
308
410
|
}
|
|
309
411
|
}
|
|
310
|
-
function parseArgs(argv) {
|
|
311
|
-
const flags = /* @__PURE__ */ new Map();
|
|
312
|
-
const values = [];
|
|
313
|
-
let command;
|
|
314
|
-
for (let index = 0; index < argv.length; index += 1) {
|
|
315
|
-
const arg = argv[index];
|
|
316
|
-
if (!arg) continue;
|
|
317
|
-
if (arg === "--help" || arg === "-h") {
|
|
318
|
-
command = "help";
|
|
319
|
-
continue;
|
|
320
|
-
}
|
|
321
|
-
if (arg === "--version" || arg === "-v") {
|
|
322
|
-
command = "version";
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
|
-
if (arg.startsWith("--")) {
|
|
326
|
-
const [rawName, inlineValue] = arg.slice(2).split("=", 2);
|
|
327
|
-
if (!rawName) continue;
|
|
328
|
-
if (inlineValue !== void 0) {
|
|
329
|
-
flags.set(rawName, inlineValue);
|
|
330
|
-
continue;
|
|
331
|
-
}
|
|
332
|
-
flags.set(rawName, true);
|
|
333
|
-
continue;
|
|
334
|
-
}
|
|
335
|
-
if (!command && isCommand(arg)) {
|
|
336
|
-
command = arg;
|
|
337
|
-
continue;
|
|
338
|
-
}
|
|
339
|
-
values.push(arg);
|
|
340
|
-
}
|
|
341
|
-
return {
|
|
342
|
-
command,
|
|
343
|
-
values,
|
|
344
|
-
flags
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
function isCommand(value) {
|
|
348
|
-
return [
|
|
349
|
-
"add",
|
|
350
|
-
"discover",
|
|
351
|
-
"help",
|
|
352
|
-
"init",
|
|
353
|
-
"remove",
|
|
354
|
-
"validate",
|
|
355
|
-
"version"
|
|
356
|
-
].includes(value);
|
|
357
|
-
}
|
|
358
412
|
async function commandInit(root, force) {
|
|
359
413
|
clack.intro("agents init");
|
|
360
414
|
const result = await initProject(root, { force });
|
|
@@ -395,6 +449,7 @@ async function commandRemove(root, paths) {
|
|
|
395
449
|
}
|
|
396
450
|
async function commandValidate(root, json) {
|
|
397
451
|
const result = await validateAgentsFile(root);
|
|
452
|
+
if (!result.ok) process.exitCode = 1;
|
|
398
453
|
if (json) {
|
|
399
454
|
console.log(JSON.stringify(result, null, 2));
|
|
400
455
|
return;
|
|
@@ -403,7 +458,6 @@ async function commandValidate(root, json) {
|
|
|
403
458
|
if (result.errors.length > 0) clack.note(result.errors.join("\n"), "Errors");
|
|
404
459
|
if (result.warnings.length > 0) clack.note(result.warnings.join("\n"), "Warnings");
|
|
405
460
|
clack.outro(result.ok ? "agents.yaml is valid." : "agents.yaml needs attention.");
|
|
406
|
-
if (!result.ok) process.exitCode = 1;
|
|
407
461
|
}
|
|
408
462
|
async function interactive(root) {
|
|
409
463
|
clack.intro("agents");
|
|
@@ -484,7 +538,7 @@ function styleDocumentOption(option, state) {
|
|
|
484
538
|
}
|
|
485
539
|
//#endregion
|
|
486
540
|
//#region src/index.ts
|
|
487
|
-
run(process.argv
|
|
541
|
+
run(process.argv).catch((error) => {
|
|
488
542
|
const message = error instanceof Error ? error.message : String(error);
|
|
489
543
|
console.error(`agents: ${message}`);
|
|
490
544
|
process.exitCode = 1;
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents.yaml",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A CLI for discovering and curating agent-readable documentation in agents.yaml.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/jeremybanka/agents.yaml.git"
|
|
8
8
|
},
|
|
9
|
+
"type": "module",
|
|
9
10
|
"bin": {
|
|
10
11
|
"agents": "./dist/index.mjs"
|
|
11
12
|
},
|
|
@@ -15,20 +16,20 @@
|
|
|
15
16
|
"README.md",
|
|
16
17
|
"AGENTS.md"
|
|
17
18
|
],
|
|
18
|
-
"type": "module",
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@clack/core": "1.5.1",
|
|
21
21
|
"@clack/prompts": "1.8.1",
|
|
22
|
+
"comline": "0.8.1",
|
|
22
23
|
"yaml": "2.9.1",
|
|
23
24
|
"zod": "4.6.5"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
|
-
"@types/node": "
|
|
27
|
+
"@types/node": "26.6.1",
|
|
27
28
|
"typescript": "7.0.2"
|
|
28
29
|
},
|
|
29
30
|
"engines": {
|
|
30
|
-
"node": "26.
|
|
31
|
-
"pnpm": "12.4.
|
|
31
|
+
"node": "26.9.0",
|
|
32
|
+
"pnpm": "12.4.2"
|
|
32
33
|
},
|
|
33
34
|
"scripts": {
|
|
34
35
|
"bench": "node src/discover.bench.ts",
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cli,
|
|
3
|
+
interpretArguments,
|
|
4
|
+
optional,
|
|
5
|
+
options,
|
|
6
|
+
parseBooleanOption,
|
|
7
|
+
required,
|
|
8
|
+
type CliOption,
|
|
9
|
+
} from "comline"
|
|
10
|
+
import { readFileSync } from "node:fs"
|
|
11
|
+
import { z } from "zod"
|
|
12
|
+
import { loadAgentsFile } from "./agents-file.ts"
|
|
13
|
+
import { cwd } from "./paths.ts"
|
|
14
|
+
|
|
15
|
+
function parseBooleanSwitch(value: string): boolean {
|
|
16
|
+
// Comline joins repeated occurrences with commas. The last switch wins.
|
|
17
|
+
const last = value.split(",").at(-1) ?? ""
|
|
18
|
+
if (!["", "true", "false", "0", "1"].includes(last)) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`Expected a boolean switch, received ${JSON.stringify(last)}`,
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
return parseBooleanOption(last)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function booleanSwitch(
|
|
27
|
+
description: string,
|
|
28
|
+
example: string,
|
|
29
|
+
): CliOption<boolean> {
|
|
30
|
+
return { description, example, parse: parseBooleanSwitch, required: false }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const commonSchema = z.object({
|
|
34
|
+
help: z.boolean().default(false),
|
|
35
|
+
version: z.boolean().default(false),
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const commonOptions = {
|
|
39
|
+
help: {
|
|
40
|
+
...booleanSwitch("Show usage", "--help"),
|
|
41
|
+
flag: "h",
|
|
42
|
+
},
|
|
43
|
+
version: {
|
|
44
|
+
...booleanSwitch("Show the installed version", "--version"),
|
|
45
|
+
flag: "v",
|
|
46
|
+
},
|
|
47
|
+
} satisfies Record<string, CliOption<boolean>>
|
|
48
|
+
|
|
49
|
+
const jsonOption = booleanSwitch("Print JSON", "--json")
|
|
50
|
+
|
|
51
|
+
function common(description: string) {
|
|
52
|
+
return options(description, commonSchema, commonOptions)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const agents = cli({
|
|
56
|
+
cliName: "agents",
|
|
57
|
+
cliDescription:
|
|
58
|
+
"Discover and curate agent-readable documentation in agents.yaml.",
|
|
59
|
+
routes: optional({
|
|
60
|
+
init: null,
|
|
61
|
+
discover: null,
|
|
62
|
+
add: required({ "$...paths": null }),
|
|
63
|
+
remove: required({ "$...paths": null }),
|
|
64
|
+
validate: null,
|
|
65
|
+
help: null,
|
|
66
|
+
version: null,
|
|
67
|
+
}),
|
|
68
|
+
routeOptions: {
|
|
69
|
+
"": common("Choose an action interactively"),
|
|
70
|
+
init: options(
|
|
71
|
+
"Initialize breadcrumb files",
|
|
72
|
+
commonSchema.extend({ force: z.boolean().default(false) }),
|
|
73
|
+
{
|
|
74
|
+
...commonOptions,
|
|
75
|
+
force: booleanSwitch(
|
|
76
|
+
"Append the breadcrumb even if already mentioned",
|
|
77
|
+
"--force",
|
|
78
|
+
),
|
|
79
|
+
},
|
|
80
|
+
),
|
|
81
|
+
discover: options(
|
|
82
|
+
"Discover supplemental AGENTS.md files",
|
|
83
|
+
commonSchema.extend({
|
|
84
|
+
json: z.boolean().default(false),
|
|
85
|
+
"include-dot-directories": z.boolean().default(false),
|
|
86
|
+
}),
|
|
87
|
+
{
|
|
88
|
+
...commonOptions,
|
|
89
|
+
json: jsonOption,
|
|
90
|
+
"include-dot-directories": booleanSwitch(
|
|
91
|
+
"Search hidden directories",
|
|
92
|
+
"--include-dot-directories",
|
|
93
|
+
),
|
|
94
|
+
},
|
|
95
|
+
),
|
|
96
|
+
"add/$...paths": common("Promote one or more AGENTS.md files"),
|
|
97
|
+
"remove/$...paths": common("Remove one or more promoted paths"),
|
|
98
|
+
validate: options(
|
|
99
|
+
"Validate agents.yaml",
|
|
100
|
+
commonSchema.extend({ json: z.boolean().default(false) }),
|
|
101
|
+
{ ...commonOptions, json: jsonOption },
|
|
102
|
+
),
|
|
103
|
+
help: common("Show usage"),
|
|
104
|
+
version: common("Show the installed version"),
|
|
105
|
+
},
|
|
106
|
+
positionalCompletions: {
|
|
107
|
+
"add/$...paths": { fileSystem: "files" },
|
|
108
|
+
"remove/$...paths": {
|
|
109
|
+
provide: async () => {
|
|
110
|
+
const { documents } = await loadAgentsFile(cwd())
|
|
111
|
+
return documents.map(({ path, description }) => ({
|
|
112
|
+
value: path,
|
|
113
|
+
...(description ? { description } : {}),
|
|
114
|
+
}))
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
export function earlyCommand(argv: string[]): "help" | "version" | undefined {
|
|
121
|
+
// Interpret before validation so `add --help` does not require a path.
|
|
122
|
+
// Using Comline's occurrences also respects grouped flags and literal `--`.
|
|
123
|
+
const { options: occurrences } = interpretArguments(
|
|
124
|
+
agents.definition,
|
|
125
|
+
argv.slice(2),
|
|
126
|
+
)
|
|
127
|
+
for (const key of ["help", "version"] as const) {
|
|
128
|
+
const occurrence = occurrences.findLast((option) => option.key === key)
|
|
129
|
+
if (occurrence && parseBooleanSwitch(occurrence.value)) return key
|
|
130
|
+
}
|
|
131
|
+
return undefined
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function packageVersion(): string {
|
|
135
|
+
const source = readFileSync(
|
|
136
|
+
new URL("../package.json", import.meta.url),
|
|
137
|
+
"utf8",
|
|
138
|
+
)
|
|
139
|
+
return z.object({ version: z.string() }).parse(JSON.parse(source)).version
|
|
140
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { run } from "./run.ts"
|
|
4
4
|
|
|
5
|
-
run(process.argv
|
|
5
|
+
run(process.argv).catch((error: unknown) => {
|
|
6
6
|
const message = error instanceof Error ? error.message : String(error)
|
|
7
7
|
console.error(`agents: ${message}`)
|
|
8
8
|
process.exitCode = 1
|
package/src/run.test.ts
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import * as clack from "@clack/prompts"
|
|
2
|
+
import { spawnSync } from "node:child_process"
|
|
3
|
+
import {
|
|
4
|
+
mkdir,
|
|
5
|
+
mkdtemp,
|
|
6
|
+
readFile,
|
|
7
|
+
readdir,
|
|
8
|
+
rm,
|
|
9
|
+
writeFile,
|
|
10
|
+
} from "node:fs/promises"
|
|
11
|
+
import { tmpdir } from "node:os"
|
|
12
|
+
import path from "node:path"
|
|
13
|
+
import { fileURLToPath } from "node:url"
|
|
14
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
|
|
15
|
+
import { loadAgentsFile, saveAgentsFile } from "./agents-file.ts"
|
|
16
|
+
import { agents } from "./cli.ts"
|
|
17
|
+
import { run } from "./run.ts"
|
|
18
|
+
|
|
19
|
+
vi.mock("@clack/prompts", async (importOriginal) => ({
|
|
20
|
+
...(await importOriginal<typeof import("@clack/prompts")>()),
|
|
21
|
+
intro: vi.fn(),
|
|
22
|
+
select: vi.fn(),
|
|
23
|
+
cancel: vi.fn(),
|
|
24
|
+
}))
|
|
25
|
+
|
|
26
|
+
const entry = fileURLToPath(new URL("./index.ts", import.meta.url))
|
|
27
|
+
let root: string
|
|
28
|
+
|
|
29
|
+
beforeEach(async () => {
|
|
30
|
+
root = await mkdtemp(path.join(tmpdir(), "agents-cli-"))
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
afterEach(async () => {
|
|
34
|
+
vi.clearAllMocks()
|
|
35
|
+
await rm(root, { recursive: true, force: true })
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
function invoke(...args: string[]) {
|
|
39
|
+
const result = spawnSync(process.execPath, [entry, ...args], {
|
|
40
|
+
cwd: root,
|
|
41
|
+
encoding: "utf8",
|
|
42
|
+
env: { ...process.env, NO_COLOR: "1", FORCE_COLOR: undefined },
|
|
43
|
+
timeout: 10_000,
|
|
44
|
+
})
|
|
45
|
+
if (result.error) throw result.error
|
|
46
|
+
return result
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
describe("agents command-line interface", () => {
|
|
50
|
+
it("keeps the no-command interactive flow and cancellation", async () => {
|
|
51
|
+
vi.mocked(clack.select).mockResolvedValueOnce(clack.CANCEL_SYMBOL)
|
|
52
|
+
await run([process.execPath, entry])
|
|
53
|
+
expect(clack.select).toHaveBeenCalledWith(
|
|
54
|
+
expect.objectContaining({ message: "What would you like to do?" }),
|
|
55
|
+
)
|
|
56
|
+
expect(clack.cancel).toHaveBeenCalledWith("Cancelled.")
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it("adds and removes multiple paths without splitting special characters", async () => {
|
|
60
|
+
const paths = ["./space name/AGENTS.md", "./comma,equals=/AGENTS.md"]
|
|
61
|
+
for (const document of paths) {
|
|
62
|
+
await mkdir(path.dirname(path.join(root, document)), { recursive: true })
|
|
63
|
+
await writeFile(path.join(root, document), "# Instructions\n")
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
expect(invoke("init").status).toBe(0)
|
|
67
|
+
expect(invoke("add", ...paths).status).toBe(0)
|
|
68
|
+
const added = await loadAgentsFile(root)
|
|
69
|
+
expect(added.documents.map((document) => document.path).sort()).toEqual(
|
|
70
|
+
paths.toSorted(),
|
|
71
|
+
)
|
|
72
|
+
expect(invoke("remove", ...paths).status).toBe(0)
|
|
73
|
+
expect((await loadAgentsFile(root)).documents).toEqual([])
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it("treats help and version spellings after -- as literal paths", async () => {
|
|
77
|
+
const paths = ["--help", "-v", "-dash/AGENTS.md"]
|
|
78
|
+
expect(invoke("add", "--", ...paths).status).toBe(0)
|
|
79
|
+
expect(
|
|
80
|
+
(await loadAgentsFile(root)).documents
|
|
81
|
+
.map((document) => document.path)
|
|
82
|
+
.sort(),
|
|
83
|
+
).toEqual(paths.map((document) => `./${document}`).sort())
|
|
84
|
+
expect(invoke("remove", "--", ...paths).status).toBe(0)
|
|
85
|
+
expect((await loadAgentsFile(root)).documents).toEqual([])
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it.each([
|
|
89
|
+
["add"],
|
|
90
|
+
["remove"],
|
|
91
|
+
["discovr"],
|
|
92
|
+
["--unknown"],
|
|
93
|
+
["init", "--json"],
|
|
94
|
+
["init", "--force=maybe"],
|
|
95
|
+
["add", "./AGENTS.md", "--typo"],
|
|
96
|
+
["validate", "--json", "--force"],
|
|
97
|
+
])(
|
|
98
|
+
"rejects invalid usage without executing a command: %j",
|
|
99
|
+
async (...args) => {
|
|
100
|
+
const result = invoke(...args)
|
|
101
|
+
expect(result.status).toBe(1)
|
|
102
|
+
expect(result.stdout).toBe("")
|
|
103
|
+
expect(result.stderr).toContain("agents:")
|
|
104
|
+
expect(await readdir(root)).toEqual([])
|
|
105
|
+
},
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
it.each([
|
|
109
|
+
["help"],
|
|
110
|
+
["--help"],
|
|
111
|
+
["-h"],
|
|
112
|
+
["add", "--help"],
|
|
113
|
+
["remove", "-h"],
|
|
114
|
+
["add", "-vh"],
|
|
115
|
+
])("shows generated help without requiring paths: %j", async (...args) => {
|
|
116
|
+
// Help must work even in a project with an invalid document index.
|
|
117
|
+
await writeFile(path.join(root, "agents.yaml"), "not: [valid yaml")
|
|
118
|
+
const result = invoke(...args)
|
|
119
|
+
expect(result.status).toBe(0)
|
|
120
|
+
expect(result.stderr).toBe("")
|
|
121
|
+
expect(result.stdout).toContain("add <paths...>")
|
|
122
|
+
expect(result.stdout).toContain("remove <paths...>")
|
|
123
|
+
expect(result.stdout).toContain("--include-dot-directories")
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it.each([["version"], ["--version"], ["-v"], ["add", "--version"]])(
|
|
127
|
+
"prints the package version: %j",
|
|
128
|
+
async (...args) => {
|
|
129
|
+
const manifest = JSON.parse(
|
|
130
|
+
await readFile(new URL("../package.json", import.meta.url), "utf8"),
|
|
131
|
+
) as { version: string }
|
|
132
|
+
const result = invoke(...args)
|
|
133
|
+
expect(result.status).toBe(0)
|
|
134
|
+
expect(result.stderr).toBe("")
|
|
135
|
+
expect(result.stdout).toBe(`${manifest.version}\n`)
|
|
136
|
+
},
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
it("honors explicit booleans and the last repeated switch", async () => {
|
|
140
|
+
expect(invoke("init").status).toBe(0)
|
|
141
|
+
const breadcrumb = await readFile(path.join(root, "AGENTS.md"), "utf8")
|
|
142
|
+
expect(
|
|
143
|
+
invoke("init", "--force", "--force=false", "--force=false").status,
|
|
144
|
+
).toBe(0)
|
|
145
|
+
expect(await readFile(path.join(root, "AGENTS.md"), "utf8")).toBe(
|
|
146
|
+
breadcrumb,
|
|
147
|
+
)
|
|
148
|
+
expect(invoke("init", "--force=false", "--force").status).toBe(0)
|
|
149
|
+
expect(
|
|
150
|
+
(await readFile(path.join(root, "AGENTS.md"), "utf8")).match(/Consult/g),
|
|
151
|
+
).toHaveLength(2)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it("discovers hidden directories on request and keeps JSON output clean", async () => {
|
|
155
|
+
await mkdir(path.join(root, ".hidden"))
|
|
156
|
+
await writeFile(
|
|
157
|
+
path.join(root, ".hidden", "AGENTS.md"),
|
|
158
|
+
"# Hidden instructions\n",
|
|
159
|
+
)
|
|
160
|
+
const ordinary = invoke("discover", "--json")
|
|
161
|
+
expect(ordinary.status).toBe(0)
|
|
162
|
+
expect(JSON.parse(ordinary.stdout)).toEqual([])
|
|
163
|
+
const hidden = invoke("--json", "discover", "--include-dot-directories")
|
|
164
|
+
expect(hidden.status).toBe(0)
|
|
165
|
+
expect(hidden.stderr).toBe("")
|
|
166
|
+
expect(JSON.parse(hidden.stdout)).toEqual([{ path: "./.hidden/AGENTS.md" }])
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it("sets the validation exit status in both text and JSON modes", async () => {
|
|
170
|
+
expect(invoke("init").status).toBe(0)
|
|
171
|
+
const valid = invoke("validate", "--json")
|
|
172
|
+
expect(valid.status).toBe(0)
|
|
173
|
+
expect(JSON.parse(valid.stdout)).toMatchObject({ ok: true, errors: [] })
|
|
174
|
+
await saveAgentsFile(root, {
|
|
175
|
+
version: 1,
|
|
176
|
+
documents: [{ path: "./missing/AGENTS.md" }],
|
|
177
|
+
})
|
|
178
|
+
const invalid = invoke("validate", "--json")
|
|
179
|
+
expect(invalid.status).toBe(1)
|
|
180
|
+
expect(invalid.stderr).toBe("")
|
|
181
|
+
expect(JSON.parse(invalid.stdout)).toMatchObject({
|
|
182
|
+
ok: false,
|
|
183
|
+
errors: [expect.stringContaining("file does not exist")],
|
|
184
|
+
})
|
|
185
|
+
expect(invoke("validate").status).toBe(1)
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it("generates completion scripts without loading the document index or changing files", async () => {
|
|
189
|
+
await writeFile(path.join(root, "agents.yaml"), "not: [valid yaml")
|
|
190
|
+
const result = invoke("completion", "bash")
|
|
191
|
+
expect(result.status).toBe(0)
|
|
192
|
+
expect(result.stderr).toBe("")
|
|
193
|
+
expect(result.stdout).toContain("_comline")
|
|
194
|
+
expect(result.stdout).not.toContain("What would you like to do?")
|
|
195
|
+
expect(await readdir(root)).toEqual(["agents.yaml"])
|
|
196
|
+
expect(await readFile(path.join(root, "agents.yaml"), "utf8")).toBe(
|
|
197
|
+
"not: [valid yaml",
|
|
198
|
+
)
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
it("completes listed paths after each remove argument without removing documents", async () => {
|
|
202
|
+
const file = {
|
|
203
|
+
version: 1 as const,
|
|
204
|
+
documents: [
|
|
205
|
+
{ path: "./one/AGENTS.md" },
|
|
206
|
+
{ path: "./two/AGENTS.md", description: "Second document" },
|
|
207
|
+
],
|
|
208
|
+
}
|
|
209
|
+
await saveAgentsFile(root, file)
|
|
210
|
+
const result = invoke("__complete", "remove", "./one/AGENTS.md", "./t")
|
|
211
|
+
expect(result.status).toBe(0)
|
|
212
|
+
expect(result.stderr).toBe("")
|
|
213
|
+
expect(result.stdout).toContain("./two/AGENTS.md\tSecond document")
|
|
214
|
+
expect(await loadAgentsFile(root)).toEqual(file)
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
it("offers filesystem completion for every add argument", async () => {
|
|
218
|
+
for (const words of [
|
|
219
|
+
["add", ""],
|
|
220
|
+
["add", "./one/AGENTS.md", ""],
|
|
221
|
+
]) {
|
|
222
|
+
const result = await agents.complete({ words })
|
|
223
|
+
expect(result.fileSystem).toBe("files")
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
})
|
package/src/run.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MultiSelectPrompt } from "@clack/core"
|
|
2
2
|
import * as clack from "@clack/prompts"
|
|
3
|
+
import { completionResponse, help } from "comline"
|
|
3
4
|
import { styleText } from "node:util"
|
|
4
5
|
import {
|
|
5
6
|
addDocuments,
|
|
@@ -8,132 +9,70 @@ import {
|
|
|
8
9
|
removeDocuments,
|
|
9
10
|
validateAgentsFile,
|
|
10
11
|
} from "./agents-file.ts"
|
|
12
|
+
import { agents, earlyCommand, packageVersion } from "./cli.ts"
|
|
11
13
|
import { describeAgentDocument, discoverAgentDocuments } from "./discover.ts"
|
|
12
14
|
import { cwd, formatProjectPath, resolveFromRoot } from "./paths.ts"
|
|
13
15
|
|
|
14
|
-
type Command =
|
|
15
|
-
| "add"
|
|
16
|
-
| "discover"
|
|
17
|
-
| "help"
|
|
18
|
-
| "init"
|
|
19
|
-
| "remove"
|
|
20
|
-
| "validate"
|
|
21
|
-
| "version"
|
|
22
|
-
|
|
23
|
-
type ParsedArgs = {
|
|
24
|
-
command: Command | undefined
|
|
25
|
-
values: string[]
|
|
26
|
-
flags: Map<string, string | boolean>
|
|
27
|
-
}
|
|
28
|
-
|
|
29
16
|
type DocumentOption = {
|
|
30
17
|
value: string
|
|
31
18
|
label: string
|
|
32
19
|
disabled?: boolean
|
|
33
20
|
}
|
|
34
21
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
agents add <path...>
|
|
42
|
-
agents remove <path...>
|
|
43
|
-
agents validate [--json]
|
|
22
|
+
export async function run(argv: string[]): Promise<void> {
|
|
23
|
+
const completion = await completionResponse(agents.definition, argv)
|
|
24
|
+
if (completion !== undefined) {
|
|
25
|
+
process.stdout.write(completion)
|
|
26
|
+
return
|
|
27
|
+
}
|
|
44
28
|
|
|
45
|
-
|
|
29
|
+
const early = earlyCommand(argv)
|
|
30
|
+
if (early === "help") {
|
|
31
|
+
console.log(help(agents.definition))
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
if (early === "version") {
|
|
35
|
+
console.log(packageVersion())
|
|
36
|
+
return
|
|
37
|
+
}
|
|
46
38
|
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
const { inputs, warnings } = agents(argv)
|
|
40
|
+
if (warnings.length > 0) {
|
|
41
|
+
throw new Error(warnings.map((warning) => warning.message).join("\n"))
|
|
42
|
+
}
|
|
49
43
|
const root = cwd()
|
|
50
44
|
|
|
51
|
-
switch (
|
|
52
|
-
case
|
|
45
|
+
switch (inputs.case) {
|
|
46
|
+
case "":
|
|
53
47
|
await interactive(root)
|
|
54
48
|
return
|
|
55
49
|
case "help":
|
|
56
|
-
console.log(
|
|
50
|
+
console.log(help(agents.definition))
|
|
57
51
|
return
|
|
58
52
|
case "version":
|
|
59
|
-
console.log(
|
|
53
|
+
console.log(packageVersion())
|
|
60
54
|
return
|
|
61
55
|
case "init":
|
|
62
|
-
await commandInit(root,
|
|
56
|
+
await commandInit(root, inputs.opts.force)
|
|
63
57
|
return
|
|
64
58
|
case "discover":
|
|
65
59
|
await commandDiscover(root, {
|
|
66
|
-
json:
|
|
67
|
-
includeDotDirectories:
|
|
68
|
-
parsed.flags.get("include-dot-directories") === true,
|
|
60
|
+
json: inputs.opts.json,
|
|
61
|
+
includeDotDirectories: inputs.opts["include-dot-directories"],
|
|
69
62
|
})
|
|
70
63
|
return
|
|
71
|
-
case "add":
|
|
72
|
-
await commandAdd(root,
|
|
64
|
+
case "add/$...paths":
|
|
65
|
+
await commandAdd(root, inputs.params.paths)
|
|
73
66
|
return
|
|
74
|
-
case "remove":
|
|
75
|
-
await commandRemove(root,
|
|
67
|
+
case "remove/$...paths":
|
|
68
|
+
await commandRemove(root, inputs.params.paths)
|
|
76
69
|
return
|
|
77
70
|
case "validate":
|
|
78
|
-
await commandValidate(root,
|
|
71
|
+
await commandValidate(root, inputs.opts.json)
|
|
79
72
|
return
|
|
80
73
|
}
|
|
81
74
|
}
|
|
82
75
|
|
|
83
|
-
function parseArgs(argv: string[]): ParsedArgs {
|
|
84
|
-
const flags = new Map<string, string | boolean>()
|
|
85
|
-
const values: string[] = []
|
|
86
|
-
let command: Command | undefined
|
|
87
|
-
|
|
88
|
-
for (let index = 0; index < argv.length; index += 1) {
|
|
89
|
-
const arg = argv[index]
|
|
90
|
-
if (!arg) continue
|
|
91
|
-
|
|
92
|
-
if (arg === "--help" || arg === "-h") {
|
|
93
|
-
command = "help"
|
|
94
|
-
continue
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (arg === "--version" || arg === "-v") {
|
|
98
|
-
command = "version"
|
|
99
|
-
continue
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (arg.startsWith("--")) {
|
|
103
|
-
const [rawName, inlineValue] = arg.slice(2).split("=", 2)
|
|
104
|
-
if (!rawName) continue
|
|
105
|
-
if (inlineValue !== undefined) {
|
|
106
|
-
flags.set(rawName, inlineValue)
|
|
107
|
-
continue
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
flags.set(rawName, true)
|
|
111
|
-
continue
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (!command && isCommand(arg)) {
|
|
115
|
-
command = arg
|
|
116
|
-
continue
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
values.push(arg)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return { command, values, flags }
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function isCommand(value: string): value is Command {
|
|
126
|
-
return [
|
|
127
|
-
"add",
|
|
128
|
-
"discover",
|
|
129
|
-
"help",
|
|
130
|
-
"init",
|
|
131
|
-
"remove",
|
|
132
|
-
"validate",
|
|
133
|
-
"version",
|
|
134
|
-
].includes(value)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
76
|
async function commandInit(root: string, force: boolean): Promise<void> {
|
|
138
77
|
clack.intro("agents init")
|
|
139
78
|
const result = await initProject(root, { force })
|
|
@@ -216,6 +155,9 @@ async function commandRemove(root: string, paths: string[]): Promise<void> {
|
|
|
216
155
|
|
|
217
156
|
async function commandValidate(root: string, json: boolean): Promise<void> {
|
|
218
157
|
const result = await validateAgentsFile(root)
|
|
158
|
+
if (!result.ok) {
|
|
159
|
+
process.exitCode = 1
|
|
160
|
+
}
|
|
219
161
|
if (json) {
|
|
220
162
|
console.log(JSON.stringify(result, null, 2))
|
|
221
163
|
return
|
|
@@ -232,9 +174,6 @@ async function commandValidate(root: string, json: boolean): Promise<void> {
|
|
|
232
174
|
clack.outro(
|
|
233
175
|
result.ok ? "agents.yaml is valid." : "agents.yaml needs attention.",
|
|
234
176
|
)
|
|
235
|
-
if (!result.ok) {
|
|
236
|
-
process.exitCode = 1
|
|
237
|
-
}
|
|
238
177
|
}
|
|
239
178
|
|
|
240
179
|
async function interactive(root: string): Promise<void> {
|
package/dist/index.d.mts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {}
|