@duyquangnvx/create-agent-cli 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -0
- package/README.md +1 -1
- package/dist/bin.js +1757 -681
- package/package.json +2 -2
- package/template/AGENTS.md +5 -3
- package/template/skills/{{binName}}/SKILL.md +20 -8
- package/template/src/cli.ts +55 -2
- package/template/src/errors.ts +5 -0
- package/template/src/ports.ts +23 -0
- package/template/test/cli.test.ts +98 -6
- package/template/tsdown.config.ts +1 -0
package/dist/bin.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { access, lstat, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
|
-
import { homedir, tmpdir } from "node:os";
|
|
6
|
-
import {
|
|
5
|
+
import { constants, homedir, tmpdir } from "node:os";
|
|
6
|
+
import { constants as constants$1, existsSync, readFileSync, realpathSync } from "node:fs";
|
|
7
|
+
import { parseArgs, parseEnv } from "node:util";
|
|
7
8
|
import { fileURLToPath } from "node:url";
|
|
8
9
|
//#region ../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/util.js
|
|
9
10
|
function getEnumValues(entries) {
|
|
@@ -761,6 +762,59 @@ function formatError(error, mapper = (issue) => issue.message) {
|
|
|
761
762
|
processError(error);
|
|
762
763
|
return fieldErrors;
|
|
763
764
|
}
|
|
765
|
+
/** Format a ZodError as a human-readable string in the following form.
|
|
766
|
+
*
|
|
767
|
+
* From
|
|
768
|
+
*
|
|
769
|
+
* ```ts
|
|
770
|
+
* ZodError {
|
|
771
|
+
* issues: [
|
|
772
|
+
* {
|
|
773
|
+
* expected: 'string',
|
|
774
|
+
* code: 'invalid_type',
|
|
775
|
+
* path: [ 'username' ],
|
|
776
|
+
* message: 'Invalid input: expected string'
|
|
777
|
+
* },
|
|
778
|
+
* {
|
|
779
|
+
* expected: 'number',
|
|
780
|
+
* code: 'invalid_type',
|
|
781
|
+
* path: [ 'favoriteNumbers', 1 ],
|
|
782
|
+
* message: 'Invalid input: expected number'
|
|
783
|
+
* }
|
|
784
|
+
* ];
|
|
785
|
+
* }
|
|
786
|
+
* ```
|
|
787
|
+
*
|
|
788
|
+
* to
|
|
789
|
+
*
|
|
790
|
+
* ```
|
|
791
|
+
* username
|
|
792
|
+
* ✖ Expected number, received string at "username
|
|
793
|
+
* favoriteNumbers[0]
|
|
794
|
+
* ✖ Invalid input: expected number
|
|
795
|
+
* ```
|
|
796
|
+
*/
|
|
797
|
+
function toDotPath(_path) {
|
|
798
|
+
const segs = [];
|
|
799
|
+
const path = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
800
|
+
for (const seg of path) if (typeof seg === "number") segs.push(`[${seg}]`);
|
|
801
|
+
else if (typeof seg === "symbol") segs.push(`[${JSON.stringify(String(seg))}]`);
|
|
802
|
+
else if (/[^\w$]/.test(seg)) segs.push(`[${JSON.stringify(seg)}]`);
|
|
803
|
+
else {
|
|
804
|
+
if (segs.length) segs.push(".");
|
|
805
|
+
segs.push(seg);
|
|
806
|
+
}
|
|
807
|
+
return segs.join("");
|
|
808
|
+
}
|
|
809
|
+
function prettifyError(error) {
|
|
810
|
+
const lines = [];
|
|
811
|
+
const issues = [...error.issues].sort((a, b) => (a.path ?? []).length - (b.path ?? []).length);
|
|
812
|
+
for (const issue of issues) {
|
|
813
|
+
lines.push(`✖ ${issue.message}`);
|
|
814
|
+
if (issue.path?.length) lines.push(` → at ${toDotPath(issue.path)}`);
|
|
815
|
+
}
|
|
816
|
+
return lines.join("\n");
|
|
817
|
+
}
|
|
764
818
|
//#endregion
|
|
765
819
|
//#region ../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/parse.js
|
|
766
820
|
function finalizeParams(callee, params) {
|
|
@@ -5515,6 +5569,18 @@ function superRefine(fn, params) {
|
|
|
5515
5569
|
return /* @__PURE__ */ _superRefine(fn, params);
|
|
5516
5570
|
}
|
|
5517
5571
|
//#endregion
|
|
5572
|
+
//#region ../agent-cli/dist/abort.js
|
|
5573
|
+
/** Never resolves; rejects with the signal's reason once it aborts. */
|
|
5574
|
+
function untilAborted(signal) {
|
|
5575
|
+
return new Promise((_resolve, reject) => {
|
|
5576
|
+
if (signal.aborted) {
|
|
5577
|
+
reject(signal.reason);
|
|
5578
|
+
return;
|
|
5579
|
+
}
|
|
5580
|
+
signal.addEventListener("abort", () => reject(signal.reason), { once: true });
|
|
5581
|
+
});
|
|
5582
|
+
}
|
|
5583
|
+
//#endregion
|
|
5518
5584
|
//#region ../agent-cli/dist/input.js
|
|
5519
5585
|
function isWrapper(schema) {
|
|
5520
5586
|
return schema instanceof ZodOptional || schema instanceof ZodNullable || schema instanceof ZodDefault || schema instanceof ZodPrefault;
|
|
@@ -5537,21 +5603,29 @@ function describe(schema) {
|
|
|
5537
5603
|
current = current.unwrap();
|
|
5538
5604
|
description ??= current.description;
|
|
5539
5605
|
}
|
|
5606
|
+
const variadic = current instanceof ZodArray;
|
|
5607
|
+
if (current instanceof ZodArray) current = current.element;
|
|
5540
5608
|
return {
|
|
5541
5609
|
type: typeOf(current),
|
|
5542
5610
|
required,
|
|
5543
5611
|
defaultValue,
|
|
5544
5612
|
description,
|
|
5545
|
-
choices: current instanceof ZodEnum ? current.options.map(String) : void 0
|
|
5613
|
+
choices: current instanceof ZodEnum ? current.options.map(String) : void 0,
|
|
5614
|
+
variadic
|
|
5546
5615
|
};
|
|
5547
5616
|
}
|
|
5617
|
+
function argLabel(key, { variadic, required }) {
|
|
5618
|
+
if (!variadic) return `<${key}>`;
|
|
5619
|
+
return required ? `<${key}...>` : `[${key}...]`;
|
|
5620
|
+
}
|
|
5548
5621
|
function argField(key, schema) {
|
|
5549
|
-
const
|
|
5622
|
+
const described = describe(schema);
|
|
5623
|
+
const label = argLabel(key, described);
|
|
5550
5624
|
return {
|
|
5551
5625
|
key,
|
|
5552
5626
|
name: key,
|
|
5553
5627
|
schema,
|
|
5554
|
-
...
|
|
5628
|
+
...described,
|
|
5555
5629
|
label,
|
|
5556
5630
|
usage: label
|
|
5557
5631
|
};
|
|
@@ -5571,42 +5645,52 @@ function optionField(key, schema) {
|
|
|
5571
5645
|
usage
|
|
5572
5646
|
};
|
|
5573
5647
|
}
|
|
5574
|
-
function fieldsOf(schema, toField) {
|
|
5648
|
+
function fieldsOf$1(schema, toField) {
|
|
5575
5649
|
return schema === void 0 ? [] : Object.entries(schema.shape).map(([key, value]) => toField(key, value));
|
|
5576
5650
|
}
|
|
5577
5651
|
function argFields(schema) {
|
|
5578
|
-
return fieldsOf(schema, argField);
|
|
5652
|
+
return fieldsOf$1(schema, argField);
|
|
5653
|
+
}
|
|
5654
|
+
/** Throws when an arg that takes every remaining operand is not the last arg. */
|
|
5655
|
+
function checkArrayArgLast(name, args) {
|
|
5656
|
+
const misplaced = argFields(args).slice(0, -1).filter((field) => field.variadic);
|
|
5657
|
+
if (misplaced.length > 0) {
|
|
5658
|
+
const keys = misplaced.map(({ key }) => `'${key}'`).join(", ");
|
|
5659
|
+
throw new Error(`Command '${name}' declares array arg ${keys} before its last arg; only the last arg may be an array`);
|
|
5660
|
+
}
|
|
5579
5661
|
}
|
|
5580
5662
|
function optionFields(schema) {
|
|
5581
|
-
return fieldsOf(schema, optionField);
|
|
5663
|
+
return fieldsOf$1(schema, optionField);
|
|
5582
5664
|
}
|
|
5583
5665
|
//#endregion
|
|
5584
5666
|
//#region ../agent-cli/dist/errors.js
|
|
5585
5667
|
var CliError = class extends Error {
|
|
5586
5668
|
code;
|
|
5587
5669
|
hint;
|
|
5588
|
-
|
|
5589
|
-
|
|
5670
|
+
details;
|
|
5671
|
+
retryAt;
|
|
5672
|
+
constructor({ code, message, hint, details, retryAt }, options) {
|
|
5590
5673
|
super(message, options);
|
|
5591
5674
|
this.name = "CliError";
|
|
5592
5675
|
this.code = code;
|
|
5593
5676
|
this.hint = hint;
|
|
5594
|
-
this.
|
|
5677
|
+
this.details = details;
|
|
5678
|
+
this.retryAt = retryAt;
|
|
5595
5679
|
}
|
|
5596
5680
|
};
|
|
5597
|
-
/** The caller called the Agent CLI wrong;
|
|
5681
|
+
/** The caller called the Agent CLI wrong; the same call can't succeed. */
|
|
5598
5682
|
var UsageError = class extends CliError {
|
|
5599
|
-
constructor(
|
|
5600
|
-
super(
|
|
5601
|
-
...details,
|
|
5602
|
-
retryable: false
|
|
5603
|
-
});
|
|
5683
|
+
constructor(fields) {
|
|
5684
|
+
super(fields);
|
|
5604
5685
|
this.name = "UsageError";
|
|
5605
5686
|
}
|
|
5606
5687
|
};
|
|
5607
5688
|
const INTERNAL_CODE = "INTERNAL";
|
|
5689
|
+
function errnoOf(error) {
|
|
5690
|
+
return error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
5691
|
+
}
|
|
5608
5692
|
function isMissingFile(error) {
|
|
5609
|
-
return error
|
|
5693
|
+
return errnoOf(error) === "ENOENT";
|
|
5610
5694
|
}
|
|
5611
5695
|
function debugVariable(cliName) {
|
|
5612
5696
|
return `${cliName.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_DEBUG`;
|
|
@@ -5617,47 +5701,61 @@ function messageOf(error) {
|
|
|
5617
5701
|
function isDebug({ env, cliName }) {
|
|
5618
5702
|
return Boolean(env[debugVariable(cliName)]);
|
|
5619
5703
|
}
|
|
5620
|
-
function
|
|
5704
|
+
function bugHint(format) {
|
|
5705
|
+
return isDebug(format) ? "the stack trace shows where it failed" : `rerun with ${debugVariable(format.cliName)}=1 to see the stack trace`;
|
|
5706
|
+
}
|
|
5707
|
+
function fieldsOf(error, format) {
|
|
5621
5708
|
if (error instanceof CliError) {
|
|
5622
|
-
const { code, message, hint,
|
|
5709
|
+
const { code, message, hint, details, retryAt } = error;
|
|
5623
5710
|
return {
|
|
5624
5711
|
code,
|
|
5625
5712
|
message,
|
|
5626
|
-
hint,
|
|
5627
|
-
|
|
5713
|
+
hint: format.isBug(error) ? bugHint(format) : hint,
|
|
5714
|
+
details,
|
|
5715
|
+
retryAt
|
|
5628
5716
|
};
|
|
5629
5717
|
}
|
|
5630
5718
|
return {
|
|
5631
5719
|
code: INTERNAL_CODE,
|
|
5632
5720
|
message: messageOf(error),
|
|
5633
|
-
hint:
|
|
5634
|
-
retryable: false
|
|
5721
|
+
hint: bugHint(format)
|
|
5635
5722
|
};
|
|
5636
5723
|
}
|
|
5637
|
-
function
|
|
5638
|
-
return
|
|
5724
|
+
function causesOf(error) {
|
|
5725
|
+
return error instanceof Error && error.cause !== void 0 ? [error.cause, ...causesOf(error.cause)] : [];
|
|
5639
5726
|
}
|
|
5640
|
-
function
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
})
|
|
5727
|
+
function traceOf(error) {
|
|
5728
|
+
return error instanceof Error ? error.stack ?? error.message : String(error);
|
|
5729
|
+
}
|
|
5730
|
+
/** Under debug: a bug's stack trace, then every error's cause chain. */
|
|
5731
|
+
function debugTrace(error, format) {
|
|
5732
|
+
if (!isDebug(format)) return void 0;
|
|
5733
|
+
const lines = [...format.isBug(error) ? [traceOf(error)] : [], ...causesOf(error).map((cause) => `caused by: ${traceOf(cause)}`)];
|
|
5734
|
+
return lines.length === 0 ? void 0 : lines.join("\n");
|
|
5735
|
+
}
|
|
5736
|
+
/** The errors a run failed with: each one an `AggregateError` holds, or the one it threw. */
|
|
5737
|
+
function errorsOf(error) {
|
|
5738
|
+
return error instanceof AggregateError && error.errors.length > 0 ? error.errors : [error];
|
|
5739
|
+
}
|
|
5740
|
+
function errorLines(error, format) {
|
|
5741
|
+
const fields = fieldsOf(error, format);
|
|
5742
|
+
const stack = debugTrace(error, format);
|
|
5647
5743
|
const { style } = format;
|
|
5648
|
-
const label = style.red(error
|
|
5744
|
+
const label = style.red(format.isBug(error) ? "internal error:" : "error:");
|
|
5649
5745
|
const trace = stack === void 0 ? "" : `${stack}\n`;
|
|
5650
|
-
return `${label} ${
|
|
5746
|
+
return `${label} ${fields.message}\n${trace}${style.cyan("hint:")} ${fields.hint}\n`;
|
|
5651
5747
|
}
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5748
|
+
function formatRuntimeError(error, format) {
|
|
5749
|
+
const errors = errorsOf(error);
|
|
5750
|
+
if (format.json) {
|
|
5751
|
+
const printed = errors.map((each) => ({
|
|
5752
|
+
...fieldsOf(each, format),
|
|
5753
|
+
stack: debugTrace(each, format)
|
|
5754
|
+
}));
|
|
5755
|
+
return `${JSON.stringify({ errors: printed })}\n`;
|
|
5659
5756
|
}
|
|
5660
|
-
|
|
5757
|
+
return errors.map((each) => errorLines(each, format)).join("");
|
|
5758
|
+
}
|
|
5661
5759
|
const SHELL_SAFE = /^[\w@%+=:,./-]+$/;
|
|
5662
5760
|
function quoted$1(token) {
|
|
5663
5761
|
return SHELL_SAFE.test(token) ? token : `'${token.replaceAll("'", `'\\''`)}'`;
|
|
@@ -5665,6 +5763,10 @@ function quoted$1(token) {
|
|
|
5665
5763
|
function pasteable(cliName, tokens) {
|
|
5666
5764
|
return [cliName, ...tokens].map(quoted$1).join(" ");
|
|
5667
5765
|
}
|
|
5766
|
+
/** The caller's command line as typed, ready to paste. */
|
|
5767
|
+
function commandLineOf({ cliName, argv }) {
|
|
5768
|
+
return pasteable(cliName, argv);
|
|
5769
|
+
}
|
|
5668
5770
|
function split(argv) {
|
|
5669
5771
|
const end = argv.indexOf("--");
|
|
5670
5772
|
return end === -1 ? {
|
|
@@ -5678,13 +5780,16 @@ function split(argv) {
|
|
|
5678
5780
|
function without(flag, tokens) {
|
|
5679
5781
|
return tokens.filter((token, index) => token !== flag && !token.startsWith(`${flag}=`) && tokens[index - 1] !== flag);
|
|
5680
5782
|
}
|
|
5681
|
-
/**
|
|
5783
|
+
/**
|
|
5784
|
+
* The caller's command line, ready to paste, with `flag value` (or `flag` alone, for a flag that
|
|
5785
|
+
* takes nothing) replacing any value they gave.
|
|
5786
|
+
*/
|
|
5682
5787
|
function commandLineWith({ cliName, argv }, flag, value) {
|
|
5683
5788
|
const { options, operands } = split(argv);
|
|
5789
|
+
const added = value === void 0 ? [flag] : [flag, value];
|
|
5684
5790
|
return pasteable(cliName, [
|
|
5685
5791
|
...without(flag, options),
|
|
5686
|
-
|
|
5687
|
-
value,
|
|
5792
|
+
...added,
|
|
5688
5793
|
...operands
|
|
5689
5794
|
]);
|
|
5690
5795
|
}
|
|
@@ -5700,7 +5805,45 @@ function commandLineRenaming({ cliName, argv }, renames) {
|
|
|
5700
5805
|
return pasteable(cliName, [...options.map((token) => renamed(token, renames)), ...operands]);
|
|
5701
5806
|
}
|
|
5702
5807
|
//#endregion
|
|
5808
|
+
//#region ../agent-cli/dist/usage.js
|
|
5809
|
+
const INVALID_INPUT = "INVALID_INPUT";
|
|
5810
|
+
const UNKNOWN_OPTION = "UNKNOWN_OPTION";
|
|
5811
|
+
const UNKNOWN_COMMAND = "UNKNOWN_COMMAND";
|
|
5812
|
+
function unknownError({ code, problem, commandLine, corrections, listed }) {
|
|
5813
|
+
return new UsageError({
|
|
5814
|
+
code,
|
|
5815
|
+
message: `${problem} for \`${commandLine}\``,
|
|
5816
|
+
hint: corrections.length === 0 ? `run \`${commandLine} --help\` to see the ${listed}` : `did you mean ${corrections.map((correction) => `\`${correction}\``).join(" or ")}?`
|
|
5817
|
+
});
|
|
5818
|
+
}
|
|
5819
|
+
function unknownOptionError(commandLine, invocation, flag, suggestions) {
|
|
5820
|
+
return unknownError({
|
|
5821
|
+
code: UNKNOWN_OPTION,
|
|
5822
|
+
problem: `unknown option '${flag}'`,
|
|
5823
|
+
commandLine,
|
|
5824
|
+
corrections: suggestions.map((name) => commandLineRenaming(invocation, /* @__PURE__ */ new Map([[flag, name]]))),
|
|
5825
|
+
listed: "options"
|
|
5826
|
+
});
|
|
5827
|
+
}
|
|
5828
|
+
function unknownCommandError(commandLine, name, suggestions) {
|
|
5829
|
+
return unknownError({
|
|
5830
|
+
code: UNKNOWN_COMMAND,
|
|
5831
|
+
problem: `unknown command '${name}'`,
|
|
5832
|
+
commandLine,
|
|
5833
|
+
corrections: suggestions.map((suggestion) => `${commandLine} ${suggestion}`),
|
|
5834
|
+
listed: "commands"
|
|
5835
|
+
});
|
|
5836
|
+
}
|
|
5837
|
+
function invalidInputError(commandLine, problem) {
|
|
5838
|
+
return new UsageError({
|
|
5839
|
+
code: INVALID_INPUT,
|
|
5840
|
+
message: problem,
|
|
5841
|
+
hint: `run \`${commandLine} --help\` to see the expected input`
|
|
5842
|
+
});
|
|
5843
|
+
}
|
|
5844
|
+
//#endregion
|
|
5703
5845
|
//#region ../agent-cli/dist/list.js
|
|
5846
|
+
const UNKNOWN_FIELD = "UNKNOWN_FIELD";
|
|
5704
5847
|
const DEFAULT_PAGE_LIMIT = 20;
|
|
5705
5848
|
const FIELDS_FLAG = "--fields";
|
|
5706
5849
|
const SEPARATOR = ",";
|
|
@@ -5770,13 +5913,13 @@ function selectedFields(values, rowFields, commandLine) {
|
|
|
5770
5913
|
const hint = `pass ${FIELDS_FLAG} with any of: ${rowFields.join(", ")}`;
|
|
5771
5914
|
const names = typeof raw === "string" ? raw.split(SEPARATOR).filter((name) => name !== "") : [];
|
|
5772
5915
|
if (names.length === 0) throw new UsageError({
|
|
5773
|
-
code:
|
|
5916
|
+
code: INVALID_INPUT,
|
|
5774
5917
|
message: `${FIELDS_FLAG}: missing value for \`${commandLine}\``,
|
|
5775
5918
|
hint
|
|
5776
5919
|
});
|
|
5777
5920
|
const unknown = names.filter((name) => !rowFields.includes(name));
|
|
5778
5921
|
if (unknown.length > 0) throw new UsageError({
|
|
5779
|
-
code:
|
|
5922
|
+
code: UNKNOWN_FIELD,
|
|
5780
5923
|
message: `unknown field ${quoted(unknown)} for \`${commandLine}\``,
|
|
5781
5924
|
hint
|
|
5782
5925
|
});
|
|
@@ -5808,6 +5951,12 @@ function pageFooter({ items, next }) {
|
|
|
5808
5951
|
return `${items.length} shown; ${more}\n`;
|
|
5809
5952
|
}
|
|
5810
5953
|
//#endregion
|
|
5954
|
+
//#region ../agent-cli/dist/planned.js
|
|
5955
|
+
/** Whether `command` changes something through a Plan: a write or destructive Command. */
|
|
5956
|
+
function hasPlan(command) {
|
|
5957
|
+
return command.effect === "write" || command.effect === "destructive";
|
|
5958
|
+
}
|
|
5959
|
+
//#endregion
|
|
5811
5960
|
//#region ../agent-cli/dist/flags.js
|
|
5812
5961
|
const HELP_FLAG = "--help";
|
|
5813
5962
|
const VERSION_FLAG = "--version";
|
|
@@ -5842,6 +5991,16 @@ const CONFIRM_FLAG = standardFlag("--confirm", {
|
|
|
5842
5991
|
takes: "value",
|
|
5843
5992
|
schema: string()
|
|
5844
5993
|
});
|
|
5994
|
+
const YES_FLAG = standardFlag("--yes", {
|
|
5995
|
+
description: "approve the cost the run states; --dry-run shows it",
|
|
5996
|
+
takes: "nothing",
|
|
5997
|
+
schema: boolean()
|
|
5998
|
+
});
|
|
5999
|
+
const FORCE_FLAG = standardFlag("--force", {
|
|
6000
|
+
description: "replace the files the run writes when they exist; --dry-run lists them",
|
|
6001
|
+
takes: "nothing",
|
|
6002
|
+
schema: boolean()
|
|
6003
|
+
});
|
|
5845
6004
|
const EFFECT_FLAGS = {
|
|
5846
6005
|
read: [JSON_FLAG],
|
|
5847
6006
|
write: [JSON_FLAG, DRY_RUN_FLAG],
|
|
@@ -5849,16 +6008,28 @@ const EFFECT_FLAGS = {
|
|
|
5849
6008
|
JSON_FLAG,
|
|
5850
6009
|
DRY_RUN_FLAG,
|
|
5851
6010
|
CONFIRM_FLAG
|
|
5852
|
-
]
|
|
6011
|
+
],
|
|
6012
|
+
serve: [JSON_FLAG]
|
|
5853
6013
|
};
|
|
5854
6014
|
const RESERVED = new Map([
|
|
5855
6015
|
...ROUTING_FLAGS,
|
|
5856
6016
|
...EFFECT_FLAGS.destructive.map(({ flag }) => flag),
|
|
6017
|
+
YES_FLAG.flag,
|
|
6018
|
+
FORCE_FLAG.flag,
|
|
5857
6019
|
...LIST_FLAGS
|
|
5858
6020
|
].map((flag) => [nameOf(flag), flag]));
|
|
5859
|
-
/** The Standard flags of a Command with this Effect, and of a List Command. */
|
|
5860
|
-
function standardFlagsFor(effect, list) {
|
|
5861
|
-
|
|
6021
|
+
/** The Standard flags of a Command with this Effect and declarations, and of a List Command. */
|
|
6022
|
+
function standardFlagsFor(effect, { outputs, force, cost }, list) {
|
|
6023
|
+
const forceFlag = force === void 0 ? FORCE_FLAG : {
|
|
6024
|
+
...FORCE_FLAG,
|
|
6025
|
+
description: force
|
|
6026
|
+
};
|
|
6027
|
+
return [
|
|
6028
|
+
...EFFECT_FLAGS[effect],
|
|
6029
|
+
...outputs || force !== void 0 ? [forceFlag] : [],
|
|
6030
|
+
...cost ? [YES_FLAG] : [],
|
|
6031
|
+
...list?.standardFlags ?? []
|
|
6032
|
+
];
|
|
5862
6033
|
}
|
|
5863
6034
|
/** Throws when the Command declares an arg or option under a Standard flag's name. */
|
|
5864
6035
|
function checkNoStandardFlags(command) {
|
|
@@ -5874,12 +6045,25 @@ function checkNoStandardFlags(command) {
|
|
|
5874
6045
|
});
|
|
5875
6046
|
if (lines.length > 0) throw new Error([`Command '${command.name}' declares Standard flags the Runtime adds; rename them:`, ...lines].join("\n"));
|
|
5876
6047
|
}
|
|
6048
|
+
/** Throws when `force` is declared on a Command with no Plan, or says nothing. */
|
|
6049
|
+
function checkForce(command) {
|
|
6050
|
+
const force = "force" in command ? command.force : void 0;
|
|
6051
|
+
if (force === void 0) return;
|
|
6052
|
+
if (!hasPlan(command)) throw new Error(`Command '${command.name}' declares force, which only a write or destructive Command may`);
|
|
6053
|
+
if (force.trim() === "") throw new Error(`Command '${command.name}' declares an empty force; say what ${FORCE_FLAG.flag} replaces`);
|
|
6054
|
+
}
|
|
5877
6055
|
//#endregion
|
|
5878
6056
|
//#region ../agent-cli/dist/define.js
|
|
5879
|
-
function
|
|
6057
|
+
function checkedCommand(command) {
|
|
5880
6058
|
checkNoStandardFlags(command);
|
|
6059
|
+
checkForce(command);
|
|
6060
|
+
checkArrayArgLast(command.name, command.args);
|
|
5881
6061
|
return command;
|
|
5882
6062
|
}
|
|
6063
|
+
function defineCommandFor() {
|
|
6064
|
+
return checkedCommand;
|
|
6065
|
+
}
|
|
6066
|
+
const defineCommand$1 = defineCommandFor();
|
|
5883
6067
|
function isCommand(node) {
|
|
5884
6068
|
return typeof node.effect === "string";
|
|
5885
6069
|
}
|
|
@@ -5945,7 +6129,18 @@ function meetsMinimum(version, minimum) {
|
|
|
5945
6129
|
return true;
|
|
5946
6130
|
}
|
|
5947
6131
|
//#endregion
|
|
6132
|
+
//#region ../agent-cli/dist/tail.js
|
|
6133
|
+
/** The last `count` lines of a child's output, trimmed; empty when it wrote nothing. */
|
|
6134
|
+
function lastLines(output, count) {
|
|
6135
|
+
return output.trim().split("\n").slice(-count).join("\n");
|
|
6136
|
+
}
|
|
6137
|
+
//#endregion
|
|
5948
6138
|
//#region ../agent-cli/dist/npm.js
|
|
6139
|
+
const REGISTRY_UNREACHABLE = "REGISTRY_UNREACHABLE";
|
|
6140
|
+
const REGISTRY_AUTH = "REGISTRY_AUTH";
|
|
6141
|
+
const INSTALL_FAILED = "INSTALL_FAILED";
|
|
6142
|
+
const NPM_FAILED = "NPM_FAILED";
|
|
6143
|
+
const NO_LATEST = "NO_LATEST";
|
|
5949
6144
|
function npmContext(cli, install, ctx) {
|
|
5950
6145
|
return {
|
|
5951
6146
|
cliName: cli.name,
|
|
@@ -5955,6 +6150,7 @@ function npmContext(cli, install, ctx) {
|
|
|
5955
6150
|
};
|
|
5956
6151
|
}
|
|
5957
6152
|
const NPMJS = "https://registry.npmjs.org/";
|
|
6153
|
+
const STDERR_TAIL_LINES$1 = 10;
|
|
5958
6154
|
const RM_RETRIES = 3;
|
|
5959
6155
|
const NETWORK_CODES = /* @__PURE__ */ new Set([
|
|
5960
6156
|
"ENOTFOUND",
|
|
@@ -5986,7 +6182,7 @@ function installCommandLine(install, version = "latest") {
|
|
|
5986
6182
|
}
|
|
5987
6183
|
function spawnNpm(args, ctx, signal) {
|
|
5988
6184
|
const windows = process.platform === "win32";
|
|
5989
|
-
const command = windows ? ["npm", ...args
|
|
6185
|
+
const command = windows ? ["npm", ...args.map((arg) => `"${arg.replaceAll("\"", "\"\"")}"`)].join(" ") : "npm";
|
|
5990
6186
|
return new Promise((resolve, reject) => {
|
|
5991
6187
|
const child = spawn(command, windows ? [] : args, {
|
|
5992
6188
|
env: ctx.env,
|
|
@@ -6017,45 +6213,40 @@ function spawnNpm(args, ctx, signal) {
|
|
|
6017
6213
|
});
|
|
6018
6214
|
}
|
|
6019
6215
|
function tail$1(stderr) {
|
|
6020
|
-
const lines = stderr
|
|
6021
|
-
return lines
|
|
6216
|
+
const lines = lastLines(stderr, STDERR_TAIL_LINES$1);
|
|
6217
|
+
return lines === "" ? "" : `\n${lines}`;
|
|
6022
6218
|
}
|
|
6023
6219
|
function failureOf(call, answer, ctx) {
|
|
6024
6220
|
const { registry, package: name } = ctx.install;
|
|
6025
6221
|
const code = NPM_CODE.exec(answer.stderr)?.[1];
|
|
6026
6222
|
const output = tail$1(answer.stderr);
|
|
6027
6223
|
if (code !== void 0 && NETWORK_CODES.has(code)) return new CliError({
|
|
6028
|
-
code:
|
|
6224
|
+
code: REGISTRY_UNREACHABLE,
|
|
6029
6225
|
message: `npm could not reach ${registry} (${code})${output}`,
|
|
6030
|
-
hint: "check the network or VPN, then run it again"
|
|
6031
|
-
retryable: true
|
|
6226
|
+
hint: "check the network or VPN, then run it again"
|
|
6032
6227
|
});
|
|
6033
6228
|
if (code !== void 0 && AUTH_CODES.has(code)) return new CliError({
|
|
6034
|
-
code:
|
|
6229
|
+
code: REGISTRY_AUTH,
|
|
6035
6230
|
message: `${registry} refused npm's credentials (${code})${output}`,
|
|
6036
|
-
hint: `log in to ${registry} (npm login --registry=${registry}) or set its token in ~/.npmrc, then run it again
|
|
6037
|
-
retryable: false
|
|
6231
|
+
hint: `log in to ${registry} (npm login --registry=${registry}) or set its token in ~/.npmrc, then run it again`
|
|
6038
6232
|
});
|
|
6039
6233
|
if (call === "view" && code === "E404") return noLatest(ctx, `npm found no ${name}@latest on ${registry}: no version of it is published there`);
|
|
6040
6234
|
if (call === "install") return new CliError({
|
|
6041
|
-
code:
|
|
6235
|
+
code: INSTALL_FAILED,
|
|
6042
6236
|
message: `npm could not install ${name}${code === void 0 ? "" : ` (${code})`}${output}`,
|
|
6043
|
-
hint: `fix what npm reports, then run it again, or install it yourself: ${installCommandLine(ctx.install)}
|
|
6044
|
-
retryable: false
|
|
6237
|
+
hint: `fix what npm reports, then run it again, or install it yourself: ${installCommandLine(ctx.install)}`
|
|
6045
6238
|
});
|
|
6046
6239
|
return new CliError({
|
|
6047
|
-
code:
|
|
6240
|
+
code: NPM_FAILED,
|
|
6048
6241
|
message: `npm ${call} failed with exit code ${answer.exitCode}${output}`,
|
|
6049
|
-
hint: "fix what npm reports, then run it again"
|
|
6050
|
-
retryable: false
|
|
6242
|
+
hint: "fix what npm reports, then run it again"
|
|
6051
6243
|
});
|
|
6052
6244
|
}
|
|
6053
6245
|
function noLatest(ctx, message) {
|
|
6054
6246
|
return new CliError({
|
|
6055
|
-
code:
|
|
6247
|
+
code: NO_LATEST,
|
|
6056
6248
|
message,
|
|
6057
|
-
hint: `check that ${ctx.install.package} is published on ${ctx.install.registry}
|
|
6058
|
-
retryable: false
|
|
6249
|
+
hint: `check that ${ctx.install.package} is published on ${ctx.install.registry}`
|
|
6059
6250
|
});
|
|
6060
6251
|
}
|
|
6061
6252
|
/**
|
|
@@ -6072,10 +6263,9 @@ async function runNpm(call, args, ctx, signal = ctx.signal) {
|
|
|
6072
6263
|
], ctx, signal).catch((error) => {
|
|
6073
6264
|
if (signal?.aborted === true) throw signal.reason;
|
|
6074
6265
|
throw new CliError({
|
|
6075
|
-
code:
|
|
6266
|
+
code: NPM_FAILED,
|
|
6076
6267
|
message: `npm could not be started: ${messageOf(error)}`,
|
|
6077
|
-
hint: "install Node with npm, or put npm on PATH"
|
|
6078
|
-
retryable: false
|
|
6268
|
+
hint: "install Node with npm, or put npm on PATH"
|
|
6079
6269
|
}, { cause: error });
|
|
6080
6270
|
});
|
|
6081
6271
|
if (answer.exitCode !== 0) throw failureOf(call, answer, ctx);
|
|
@@ -6126,16 +6316,16 @@ async function latestVersion(ctx) {
|
|
|
6126
6316
|
}
|
|
6127
6317
|
//#endregion
|
|
6128
6318
|
//#region ../agent-cli/dist/global-install.js
|
|
6319
|
+
const NOT_GLOBAL_INSTALL = "NOT_GLOBAL_INSTALL";
|
|
6129
6320
|
/** Where npm puts global packages under its global prefix. */
|
|
6130
6321
|
function globalModulesDir(prefix) {
|
|
6131
6322
|
return process.platform === "win32" ? join(prefix, "node_modules") : join(prefix, "lib", "node_modules");
|
|
6132
6323
|
}
|
|
6133
6324
|
function notGlobal(ctx, message) {
|
|
6134
6325
|
return new CliError({
|
|
6135
|
-
code:
|
|
6326
|
+
code: NOT_GLOBAL_INSTALL,
|
|
6136
6327
|
message,
|
|
6137
|
-
hint: `install it with npm, so \`${ctx.cliName} update\` can replace it: ${installCommandLine(ctx.install)}
|
|
6138
|
-
retryable: false
|
|
6328
|
+
hint: `install it with npm, so \`${ctx.cliName} update\` can replace it: ${installCommandLine(ctx.install)}`
|
|
6139
6329
|
});
|
|
6140
6330
|
}
|
|
6141
6331
|
async function realpathOrUndefined(path) {
|
|
@@ -6166,122 +6356,943 @@ async function globalInstallOf(bin, ctx) {
|
|
|
6166
6356
|
};
|
|
6167
6357
|
}
|
|
6168
6358
|
//#endregion
|
|
6169
|
-
//#region ../agent-cli/dist/
|
|
6170
|
-
|
|
6171
|
-
const
|
|
6172
|
-
function
|
|
6173
|
-
|
|
6359
|
+
//#region ../agent-cli/dist/confirm.js
|
|
6360
|
+
const CONFIRMATION_REQUIRED = "CONFIRMATION_REQUIRED";
|
|
6361
|
+
const CONFIRMATION_MISMATCH = "CONFIRMATION_MISMATCH";
|
|
6362
|
+
function checkConfirmation({ invocation, commandLine, given }, expected) {
|
|
6363
|
+
if (given === expected) return;
|
|
6364
|
+
const hint = `to confirm, run \`${commandLineWith(invocation, CONFIRM_FLAG.flag, expected)}\``;
|
|
6365
|
+
if (given === void 0) throw new UsageError({
|
|
6366
|
+
code: CONFIRMATION_REQUIRED,
|
|
6367
|
+
message: `\`${commandLine}\` is destructive and needs ${CONFIRM_FLAG.flag}`,
|
|
6368
|
+
hint
|
|
6369
|
+
});
|
|
6370
|
+
throw new UsageError({
|
|
6371
|
+
code: CONFIRMATION_MISMATCH,
|
|
6372
|
+
message: `${CONFIRM_FLAG.flag} ${JSON.stringify(given)} does not match the target of \`${commandLine}\``,
|
|
6373
|
+
hint
|
|
6374
|
+
});
|
|
6174
6375
|
}
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6376
|
+
//#endregion
|
|
6377
|
+
//#region ../agent-cli/dist/cost.js
|
|
6378
|
+
const NOT_CONFIRMED = "NOT_CONFIRMED";
|
|
6379
|
+
/** Refuses a run whose Plan states a cost the caller has not approved with `--yes`. */
|
|
6380
|
+
function checkCost({ invocation, commandLine, yes }, cost) {
|
|
6381
|
+
if (cost === void 0 || yes) return;
|
|
6382
|
+
throw new CliError({
|
|
6383
|
+
code: NOT_CONFIRMED,
|
|
6384
|
+
message: `\`${commandLine}\` needs ${YES_FLAG.flag}: ${cost}`,
|
|
6385
|
+
hint: `to approve the cost, run \`${commandLineWith(invocation, YES_FLAG.flag)}\``
|
|
6386
|
+
});
|
|
6181
6387
|
}
|
|
6182
|
-
|
|
6183
|
-
|
|
6388
|
+
//#endregion
|
|
6389
|
+
//#region ../agent-cli/dist/agent.js
|
|
6390
|
+
const AGENT_VARIABLES = [
|
|
6391
|
+
"CLAUDECODE",
|
|
6392
|
+
"CODEX_CI",
|
|
6393
|
+
"CODEX_SANDBOX",
|
|
6394
|
+
"GEMINI_CLI",
|
|
6395
|
+
"CURSOR_AGENT",
|
|
6396
|
+
"CI"
|
|
6397
|
+
];
|
|
6398
|
+
/** Whether a Coding agent, not a person, is running the Agent CLI. */
|
|
6399
|
+
function isAgent(env) {
|
|
6400
|
+
return AGENT_VARIABLES.some((name) => env[name] !== void 0);
|
|
6184
6401
|
}
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6402
|
+
//#endregion
|
|
6403
|
+
//#region ../agent-cli/dist/errno.js
|
|
6404
|
+
const PERMISSION_DENIED = "PERMISSION_DENIED";
|
|
6405
|
+
const DISK_FULL = "DISK_FULL";
|
|
6406
|
+
const NOT_FOUND = "NOT_FOUND";
|
|
6407
|
+
const ALREADY_EXISTS = "ALREADY_EXISTS";
|
|
6408
|
+
function permissionHint({ path, access, callerLine, env }) {
|
|
6409
|
+
if (!isAgent(env)) return `check the permissions of ${path} and its folder`;
|
|
6410
|
+
return `your sandbox may block it: ask your user to run \`! ${callerLine}\`, or ${access === "read" ? `to allow reading ${path} in the sandbox` : `to allow ${path} in the sandbox's write list`}`;
|
|
6411
|
+
}
|
|
6412
|
+
/** The error a file system failure on `path` stands for; any other error comes back unchanged. */
|
|
6413
|
+
function classifyErrno(error, context) {
|
|
6414
|
+
const { path } = context;
|
|
6415
|
+
switch (errnoOf(error)) {
|
|
6416
|
+
case "EACCES":
|
|
6417
|
+
case "EPERM": return new CliError({
|
|
6418
|
+
code: PERMISSION_DENIED,
|
|
6419
|
+
message: `permission denied: ${path}`,
|
|
6420
|
+
hint: permissionHint(context)
|
|
6421
|
+
}, { cause: error });
|
|
6422
|
+
case "ENOSPC": return new CliError({
|
|
6423
|
+
code: DISK_FULL,
|
|
6424
|
+
message: `no space left on the disk holding ${path}`,
|
|
6425
|
+
hint: "free space on that disk, then run the same command again"
|
|
6426
|
+
}, { cause: error });
|
|
6427
|
+
case "ENOENT": return new CliError({
|
|
6428
|
+
code: NOT_FOUND,
|
|
6429
|
+
message: `not found: ${path}`,
|
|
6430
|
+
hint: `check that ${path} and its folder exist`
|
|
6431
|
+
}, { cause: error });
|
|
6432
|
+
case "EEXIST": return new CliError({
|
|
6433
|
+
code: ALREADY_EXISTS,
|
|
6434
|
+
message: `already exists: ${path}`,
|
|
6435
|
+
hint: `pass another path, or remove ${path}`
|
|
6436
|
+
}, { cause: error });
|
|
6437
|
+
default: return error;
|
|
6196
6438
|
}
|
|
6197
|
-
const version = skillVersionIn(skill);
|
|
6198
|
-
if (version === void 0 || !isVersion(version) || !isVersion(cliVersion)) return {
|
|
6199
|
-
path,
|
|
6200
|
-
version,
|
|
6201
|
-
state: "unversioned"
|
|
6202
|
-
};
|
|
6203
|
-
return {
|
|
6204
|
-
path,
|
|
6205
|
-
version,
|
|
6206
|
-
state: standingOf(version, cliVersion)
|
|
6207
|
-
};
|
|
6208
6439
|
}
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
if (copy !== void 0 && real !== void 0 && !seen.has(real)) {
|
|
6218
|
-
seen.add(real);
|
|
6219
|
-
copies.push(copy);
|
|
6440
|
+
//#endregion
|
|
6441
|
+
//#region ../agent-cli/dist/clock.js
|
|
6442
|
+
const realClock = {
|
|
6443
|
+
now: () => Date.now(),
|
|
6444
|
+
sleep: (ms, signal) => new Promise((resolve, reject) => {
|
|
6445
|
+
if (signal?.aborted === true) {
|
|
6446
|
+
reject(signal.reason);
|
|
6447
|
+
return;
|
|
6220
6448
|
}
|
|
6449
|
+
const onAbort = () => {
|
|
6450
|
+
clearTimeout(timer);
|
|
6451
|
+
reject(signal?.reason);
|
|
6452
|
+
};
|
|
6453
|
+
const timer = setTimeout(() => {
|
|
6454
|
+
signal?.removeEventListener("abort", onAbort);
|
|
6455
|
+
resolve();
|
|
6456
|
+
}, ms);
|
|
6457
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
6458
|
+
})
|
|
6459
|
+
};
|
|
6460
|
+
/** Runs `then` once `ms` have passed on `clock`; aborting `cancel` drops it. */
|
|
6461
|
+
function after(clock, ms, cancel, then) {
|
|
6462
|
+
clock.sleep(ms, cancel).then(then, (error) => {
|
|
6463
|
+
if (!cancel.aborted) throw error;
|
|
6464
|
+
});
|
|
6465
|
+
}
|
|
6466
|
+
async function poll(clock, check, intervalMs, signal) {
|
|
6467
|
+
for (;;) {
|
|
6468
|
+
signal.throwIfAborted();
|
|
6469
|
+
const value = await check();
|
|
6470
|
+
if (value !== void 0) return value;
|
|
6471
|
+
await clock.sleep(intervalMs, signal);
|
|
6221
6472
|
}
|
|
6222
|
-
return copies;
|
|
6223
6473
|
}
|
|
6224
6474
|
//#endregion
|
|
6225
|
-
//#region ../agent-cli/dist/
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6475
|
+
//#region ../agent-cli/dist/interrupts.js
|
|
6476
|
+
const INTERRUPTED = "INTERRUPTED";
|
|
6477
|
+
const DEADLINE_EXCEEDED = "DEADLINE_EXCEEDED";
|
|
6478
|
+
/** How long an interrupted Command may take to settle before the run ends without it. */
|
|
6479
|
+
const GRACE_MS = 3e3;
|
|
6480
|
+
const GRACE_OVER = Symbol("grace over");
|
|
6481
|
+
function interruptedError() {
|
|
6482
|
+
return new CliError({
|
|
6483
|
+
code: INTERRUPTED,
|
|
6484
|
+
message: "interrupted before it finished",
|
|
6485
|
+
hint: "run the command again"
|
|
6486
|
+
});
|
|
6231
6487
|
}
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
const minimum = engineMinimum(range);
|
|
6240
|
-
if (minimum === void 0) return {
|
|
6241
|
-
state: "problem",
|
|
6242
|
-
message: `${cli.name} declares engines.node "${range}", which doctor cannot read: only >=X.Y.Z is supported`
|
|
6243
|
-
};
|
|
6244
|
-
if (meetsMinimum(found, minimum)) return ok(`Node ${found} meets ${range}`);
|
|
6245
|
-
const major = minimum[0];
|
|
6246
|
-
return {
|
|
6247
|
-
state: "problem",
|
|
6248
|
-
message: `${cli.name} runs on Node ${found}, older than the ${range} it needs; install Node ${minimum.join(".")} or newer and make it the default`,
|
|
6249
|
-
fix: `nvm install ${major} && nvm alias default ${major}`
|
|
6250
|
-
};
|
|
6251
|
-
}
|
|
6252
|
-
};
|
|
6488
|
+
const WAIT_HINT = "run it again later, when the service it waits on may answer faster";
|
|
6489
|
+
function deadlineError(commandLine, ms, hint) {
|
|
6490
|
+
return new CliError({
|
|
6491
|
+
code: DEADLINE_EXCEEDED,
|
|
6492
|
+
message: `${commandLine} ran past its ${ms} ms deadline`,
|
|
6493
|
+
hint
|
|
6494
|
+
});
|
|
6253
6495
|
}
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6496
|
+
/** One Command run's cancellation: its signal, its deadlines and the steps it must finish. */
|
|
6497
|
+
var RunControl = class {
|
|
6498
|
+
signal;
|
|
6499
|
+
#controller = new AbortController();
|
|
6500
|
+
#commandLine;
|
|
6501
|
+
#outer;
|
|
6502
|
+
#onOuterAbort = () => this.#controller.abort(interruptedError());
|
|
6503
|
+
/** Each running must-finish step, tracked until it settles, with its name. */
|
|
6504
|
+
#steps = /* @__PURE__ */ new Map();
|
|
6505
|
+
#progress;
|
|
6506
|
+
#clock;
|
|
6507
|
+
#disposed = new AbortController();
|
|
6508
|
+
#deadlineHit;
|
|
6509
|
+
#graceCancel = new AbortController();
|
|
6510
|
+
#endGrace = () => {};
|
|
6511
|
+
#graceOver = new Promise((resolve) => {
|
|
6512
|
+
this.#endGrace = resolve;
|
|
6513
|
+
});
|
|
6514
|
+
constructor({ commandLine, outer, clock, progress, runDeadline }) {
|
|
6515
|
+
this.#commandLine = commandLine;
|
|
6516
|
+
this.#outer = outer;
|
|
6517
|
+
this.#clock = clock;
|
|
6518
|
+
this.#progress = progress;
|
|
6519
|
+
this.signal = this.#controller.signal;
|
|
6520
|
+
this.signal.addEventListener("abort", () => this.#onStop(), { once: true });
|
|
6521
|
+
if (outer?.aborted === true) this.#onOuterAbort();
|
|
6522
|
+
else outer?.addEventListener("abort", this.#onOuterAbort, { once: true });
|
|
6523
|
+
if (runDeadline !== void 0) {
|
|
6524
|
+
const { ms, hint } = runDeadline;
|
|
6525
|
+
after(clock, ms, this.#disposed.signal, () => this.#controller.abort(deadlineError(commandLine, ms, hint)));
|
|
6270
6526
|
}
|
|
6271
|
-
}
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6527
|
+
}
|
|
6528
|
+
deadline(ms) {
|
|
6529
|
+
const controller = new AbortController();
|
|
6530
|
+
after(this.#clock, ms, this.#disposed.signal, () => {
|
|
6531
|
+
this.#deadlineHit ??= deadlineError(this.#commandLine, ms, WAIT_HINT);
|
|
6532
|
+
controller.abort(this.#deadlineHit);
|
|
6533
|
+
});
|
|
6534
|
+
return AbortSignal.any([this.signal, controller.signal]);
|
|
6535
|
+
}
|
|
6536
|
+
async runToEnd(name, work) {
|
|
6537
|
+
this.#graceCancel.abort();
|
|
6538
|
+
if (this.signal.aborted) this.#finishing(name);
|
|
6539
|
+
const step = work();
|
|
6540
|
+
const settled = step.then(() => {}, () => {});
|
|
6541
|
+
this.#steps.set(settled, name);
|
|
6542
|
+
try {
|
|
6543
|
+
return await step;
|
|
6544
|
+
} finally {
|
|
6545
|
+
this.#steps.delete(settled);
|
|
6546
|
+
this.#startGrace();
|
|
6547
|
+
}
|
|
6548
|
+
}
|
|
6549
|
+
/** Waits for the Command, its must-finish steps, and no longer than the grace once interrupted. */
|
|
6550
|
+
async settle(work) {
|
|
6551
|
+
try {
|
|
6552
|
+
const value = await Promise.race([work, this.#graceOver]);
|
|
6553
|
+
if (this.signal.aborted || value === GRACE_OVER) throw this.signal.reason;
|
|
6554
|
+
return value;
|
|
6555
|
+
} finally {
|
|
6556
|
+
await this.#stepsDone();
|
|
6557
|
+
this.#dispose();
|
|
6558
|
+
}
|
|
6559
|
+
}
|
|
6560
|
+
/**
|
|
6561
|
+
* The error a run ends with: an interrupt or a missed deadline outranks what the Command threw,
|
|
6562
|
+
* unless the Command threw its own `INTERRUPTED`, saying what it finished before it stopped.
|
|
6563
|
+
*/
|
|
6564
|
+
errorAfter(error) {
|
|
6565
|
+
if (this.signal.aborted) return error instanceof CliError && error.code === "INTERRUPTED" ? error : this.signal.reason;
|
|
6566
|
+
if (this.#deadlineHit !== void 0 && !(error instanceof CliError)) return this.#deadlineHit;
|
|
6567
|
+
return error;
|
|
6568
|
+
}
|
|
6569
|
+
#onStop() {
|
|
6570
|
+
for (const name of this.#steps.values()) this.#finishing(name);
|
|
6571
|
+
this.#startGrace();
|
|
6572
|
+
}
|
|
6573
|
+
#finishing(name) {
|
|
6574
|
+
this.#progress(`finishing ${name}`);
|
|
6575
|
+
}
|
|
6576
|
+
#startGrace() {
|
|
6577
|
+
if (this.signal.aborted && this.#steps.size === 0) {
|
|
6578
|
+
this.#graceCancel.abort();
|
|
6579
|
+
this.#graceCancel = new AbortController();
|
|
6580
|
+
after(this.#clock, GRACE_MS, this.#graceCancel.signal, () => this.#endGrace(GRACE_OVER));
|
|
6581
|
+
}
|
|
6582
|
+
}
|
|
6583
|
+
async #stepsDone() {
|
|
6584
|
+
while (this.#steps.size > 0) await Promise.all(this.#steps.keys());
|
|
6585
|
+
}
|
|
6586
|
+
#dispose() {
|
|
6587
|
+
this.#graceCancel.abort();
|
|
6588
|
+
this.#disposed.abort();
|
|
6589
|
+
this.#outer?.removeEventListener("abort", this.#onOuterAbort);
|
|
6590
|
+
}
|
|
6591
|
+
};
|
|
6592
|
+
//#endregion
|
|
6593
|
+
//#region ../agent-cli/dist/outputs.js
|
|
6594
|
+
const OUTPUT_EXISTS = "OUTPUT_EXISTS";
|
|
6595
|
+
/** Refuses a run that would overwrite existing outputs unless the caller passed `--force`. */
|
|
6596
|
+
async function checkOutputs({ invocation, commandLine, force, files }, outputs) {
|
|
6597
|
+
if (outputs === void 0 || force) return;
|
|
6598
|
+
const found = await Promise.all(outputs.map((path) => files.exists(path)));
|
|
6599
|
+
const existing = outputs.filter((_path, index) => found[index]);
|
|
6600
|
+
if (existing.length === 0) return;
|
|
6601
|
+
const them = existing.length === 1 ? "it" : "them";
|
|
6602
|
+
throw new CliError({
|
|
6603
|
+
code: OUTPUT_EXISTS,
|
|
6604
|
+
message: `\`${commandLine}\` would overwrite ${existing.join(", ")}`,
|
|
6605
|
+
hint: `to replace ${them}, run \`${commandLineWith(invocation, FORCE_FLAG.flag)}\``
|
|
6606
|
+
});
|
|
6607
|
+
}
|
|
6608
|
+
//#endregion
|
|
6609
|
+
//#region ../agent-cli/dist/project.js
|
|
6610
|
+
const PROJECT_INVALID = "PROJECT_INVALID";
|
|
6611
|
+
function invalid(path, problem, options) {
|
|
6612
|
+
return new CliError({
|
|
6613
|
+
code: PROJECT_INVALID,
|
|
6614
|
+
message: `the Project file ${path} is invalid: ${problem}`,
|
|
6615
|
+
hint: `fix ${path}, then run the command again`
|
|
6616
|
+
}, options);
|
|
6617
|
+
}
|
|
6618
|
+
function readText(path) {
|
|
6619
|
+
try {
|
|
6620
|
+
return readFileSync(path, "utf8");
|
|
6621
|
+
} catch (error) {
|
|
6622
|
+
if (isMissingFile(error)) return void 0;
|
|
6623
|
+
throw error;
|
|
6624
|
+
}
|
|
6625
|
+
}
|
|
6626
|
+
function parsed(path, text, schema) {
|
|
6627
|
+
let json;
|
|
6628
|
+
try {
|
|
6629
|
+
json = JSON.parse(text);
|
|
6630
|
+
} catch (error) {
|
|
6631
|
+
throw invalid(path, messageOf(error), { cause: error });
|
|
6632
|
+
}
|
|
6633
|
+
const result = schema.safeParse(json);
|
|
6634
|
+
if (!result.success) throw invalid(path, prettifyError(result.error));
|
|
6635
|
+
return result.data;
|
|
6636
|
+
}
|
|
6637
|
+
function projectFrom({ file, schema }, folder) {
|
|
6638
|
+
const path = join(folder, file);
|
|
6639
|
+
const text = readText(path);
|
|
6640
|
+
if (text !== void 0) return {
|
|
6641
|
+
root: folder,
|
|
6642
|
+
settings: parsed(path, text, schema)
|
|
6643
|
+
};
|
|
6644
|
+
const parent = dirname(folder);
|
|
6645
|
+
return parent === folder ? void 0 : projectFrom({
|
|
6646
|
+
file,
|
|
6647
|
+
schema
|
|
6648
|
+
}, parent);
|
|
6649
|
+
}
|
|
6650
|
+
/** The nearest Project file at or above `cwd`, parsed by its schema; undefined when there is none. */
|
|
6651
|
+
function projectOf(projectFile, cwd) {
|
|
6652
|
+
return projectFrom(projectFile, resolve(cwd));
|
|
6653
|
+
}
|
|
6654
|
+
//#endregion
|
|
6655
|
+
//#region ../agent-cli/dist/tools.js
|
|
6656
|
+
const TOOL_MISSING = "TOOL_MISSING";
|
|
6657
|
+
const WINDOWS_EXTENSIONS = ".COM;.EXE;.BAT;.CMD";
|
|
6658
|
+
const NOT_EXECUTABLE = /* @__PURE__ */ new Set([
|
|
6659
|
+
"ENOENT",
|
|
6660
|
+
"ENOTDIR",
|
|
6661
|
+
"EACCES"
|
|
6662
|
+
]);
|
|
6663
|
+
function pathOf(env) {
|
|
6664
|
+
return env[Object.keys(env).find((name) => name.toUpperCase() === "PATH") ?? "PATH"] ?? "";
|
|
6665
|
+
}
|
|
6666
|
+
function extensionsOf(env) {
|
|
6667
|
+
return process.platform === "win32" ? (env.PATHEXT ?? WINDOWS_EXTENSIONS).split(";") : [""];
|
|
6668
|
+
}
|
|
6669
|
+
async function isExecutable(file) {
|
|
6670
|
+
try {
|
|
6671
|
+
await access(file, constants$1.X_OK);
|
|
6672
|
+
return true;
|
|
6673
|
+
} catch (error) {
|
|
6674
|
+
if (NOT_EXECUTABLE.has(errnoOf(error) ?? "")) return false;
|
|
6675
|
+
throw error;
|
|
6676
|
+
}
|
|
6677
|
+
}
|
|
6678
|
+
/** Where `name` is found on `PATH` from `env`, or undefined. */
|
|
6679
|
+
async function findTool(name, env) {
|
|
6680
|
+
const candidates = pathOf(env).split(delimiter).filter((folder) => folder !== "").flatMap((folder) => extensionsOf(env).map((extension) => join(folder, `${name}${extension}`)));
|
|
6681
|
+
for (const file of candidates) if (await isExecutable(file)) return file;
|
|
6682
|
+
}
|
|
6683
|
+
/** Fails with `TOOL_MISSING`, naming every missing tool at once, unless all are on `PATH`. */
|
|
6684
|
+
async function checkTools(tools, env) {
|
|
6685
|
+
const found = await Promise.all(tools.map((tool) => findTool(tool.name, env)));
|
|
6686
|
+
const missing = tools.filter((_tool, index) => found[index] === void 0);
|
|
6687
|
+
if (missing.length === 0) return;
|
|
6688
|
+
const names = missing.map(({ name }) => name).join(", ");
|
|
6689
|
+
throw new CliError({
|
|
6690
|
+
code: TOOL_MISSING,
|
|
6691
|
+
message: `${missing.length === 1 ? "a tool it runs is" : "tools it runs are"} not on PATH: ${names}`,
|
|
6692
|
+
hint: `install ${missing.length === 1 ? "it" : "them"}, then run the same command again: ${missing.map(({ install }) => install).join("; ")}`
|
|
6693
|
+
});
|
|
6694
|
+
}
|
|
6695
|
+
function toolsIn(node) {
|
|
6696
|
+
return isCommand(node) ? [...node.tools ?? []] : Object.values(node).flatMap(toolsIn);
|
|
6697
|
+
}
|
|
6698
|
+
/** One `doctor` row per distinct tool the Commands declare, with its install command as the fix. */
|
|
6699
|
+
function toolRows(commands) {
|
|
6700
|
+
return [...new Map(toolsIn(commands).map((tool) => [tool.name, tool])).values()].map(({ name, install }) => ({
|
|
6701
|
+
name,
|
|
6702
|
+
run: async (ctx) => {
|
|
6703
|
+
const file = await findTool(name, ctx.env);
|
|
6704
|
+
return file === void 0 ? {
|
|
6705
|
+
state: "problem",
|
|
6706
|
+
message: `${name} is not on PATH`,
|
|
6707
|
+
fix: install
|
|
6708
|
+
} : {
|
|
6709
|
+
state: "ok",
|
|
6710
|
+
message: `found at ${file}`
|
|
6711
|
+
};
|
|
6712
|
+
}
|
|
6713
|
+
}));
|
|
6714
|
+
}
|
|
6715
|
+
//#endregion
|
|
6716
|
+
//#region ../agent-cli/dist/spawn.js
|
|
6717
|
+
const TOOL_FAILED = "TOOL_FAILED";
|
|
6718
|
+
const STDERR_TAIL_LINES = 20;
|
|
6719
|
+
const SIGNAL_EXIT_BASE = 128;
|
|
6720
|
+
const realSpawn = (command, args, { cwd, env, signal }) => new Promise((resolve, reject) => {
|
|
6721
|
+
signal.throwIfAborted();
|
|
6722
|
+
const child = spawn(command, args, {
|
|
6723
|
+
cwd,
|
|
6724
|
+
env,
|
|
6725
|
+
stdio: [
|
|
6726
|
+
"ignore",
|
|
6727
|
+
"pipe",
|
|
6728
|
+
"pipe"
|
|
6729
|
+
]
|
|
6730
|
+
});
|
|
6731
|
+
const stdout = [];
|
|
6732
|
+
const stderr = [];
|
|
6733
|
+
child.stdout.on("data", (chunk) => stdout.push(chunk));
|
|
6734
|
+
child.stderr.on("data", (chunk) => stderr.push(chunk));
|
|
6735
|
+
const kill = () => {
|
|
6736
|
+
child.kill();
|
|
6737
|
+
};
|
|
6738
|
+
signal.addEventListener("abort", kill, { once: true });
|
|
6739
|
+
child.on("error", (error) => {
|
|
6740
|
+
signal.removeEventListener("abort", kill);
|
|
6741
|
+
reject(error);
|
|
6742
|
+
});
|
|
6743
|
+
child.on("close", (code, killedBy) => {
|
|
6744
|
+
signal.removeEventListener("abort", kill);
|
|
6745
|
+
if (signal.aborted) {
|
|
6746
|
+
reject(signal.reason);
|
|
6747
|
+
return;
|
|
6748
|
+
}
|
|
6749
|
+
resolve({
|
|
6750
|
+
stdout: Buffer.concat(stdout).toString(),
|
|
6751
|
+
stderr: Buffer.concat(stderr).toString(),
|
|
6752
|
+
exitCode: code ?? SIGNAL_EXIT_BASE + (killedBy === null ? 0 : constants.signals[killedBy])
|
|
6753
|
+
});
|
|
6754
|
+
});
|
|
6755
|
+
});
|
|
6756
|
+
function failedError(command, { exitCode, stderr }) {
|
|
6757
|
+
const tail = lastLines(stderr, STDERR_TAIL_LINES);
|
|
6758
|
+
return new CliError({
|
|
6759
|
+
code: TOOL_FAILED,
|
|
6760
|
+
message: tail === "" ? `${command} exited with ${exitCode} and wrote nothing to stderr` : `${command} exited with ${exitCode}; its stderr ends:\n${tail}`,
|
|
6761
|
+
hint: `the output of ${command} above says why it failed`
|
|
6762
|
+
});
|
|
6763
|
+
}
|
|
6764
|
+
function missingError(command, cause) {
|
|
6765
|
+
return new CliError({
|
|
6766
|
+
code: TOOL_MISSING,
|
|
6767
|
+
message: `${command} could not be started: it is not on PATH`,
|
|
6768
|
+
hint: `install ${command}, then run the same command again`
|
|
6769
|
+
}, { cause });
|
|
6770
|
+
}
|
|
6771
|
+
/** `ctx.spawn`: `spawn` bound to the run, its start failures classified by errno. */
|
|
6772
|
+
function contextSpawn(run, defaults, callerLine) {
|
|
6773
|
+
return async (command, args = [], options = {}) => {
|
|
6774
|
+
let result;
|
|
6775
|
+
try {
|
|
6776
|
+
result = await run(command, args, {
|
|
6777
|
+
cwd: options.cwd ?? defaults.cwd,
|
|
6778
|
+
env: options.env ?? defaults.env,
|
|
6779
|
+
signal: defaults.signal
|
|
6780
|
+
});
|
|
6781
|
+
} catch (error) {
|
|
6782
|
+
if (isMissingFile(error)) throw missingError(command, error);
|
|
6783
|
+
throw classifyErrno(error, {
|
|
6784
|
+
path: command,
|
|
6785
|
+
access: "read",
|
|
6786
|
+
callerLine,
|
|
6787
|
+
env: defaults.env
|
|
6788
|
+
});
|
|
6789
|
+
}
|
|
6790
|
+
if (options.check === true && result.exitCode !== 0) throw failedError(command, result);
|
|
6791
|
+
return result;
|
|
6792
|
+
};
|
|
6793
|
+
}
|
|
6794
|
+
//#endregion
|
|
6795
|
+
//#region ../agent-cli/dist/exit-classes.js
|
|
6796
|
+
const SIGNAL_EXIT_CODES = {
|
|
6797
|
+
SIGINT: 130,
|
|
6798
|
+
SIGTERM: 143
|
|
6799
|
+
};
|
|
6800
|
+
const EXIT_CODES = {
|
|
6801
|
+
caller: 1,
|
|
6802
|
+
operator: 2,
|
|
6803
|
+
source: 3,
|
|
6804
|
+
wait: 75,
|
|
6805
|
+
bug: 70
|
|
6806
|
+
};
|
|
6807
|
+
/** The codes the Runtime and its built-in Commands raise, each with the class that must act on it. */
|
|
6808
|
+
function runtimeCodes() {
|
|
6809
|
+
return {
|
|
6810
|
+
[INVALID_INPUT]: "caller",
|
|
6811
|
+
[UNKNOWN_OPTION]: "caller",
|
|
6812
|
+
[UNKNOWN_COMMAND]: "caller",
|
|
6813
|
+
[UNKNOWN_FIELD]: "caller",
|
|
6814
|
+
[CONFIRMATION_REQUIRED]: "caller",
|
|
6815
|
+
[CONFIRMATION_MISMATCH]: "caller",
|
|
6816
|
+
[NOT_CONFIRMED]: "operator",
|
|
6817
|
+
[OUTPUT_EXISTS]: "caller",
|
|
6818
|
+
[INTERRUPTED]: "interrupted",
|
|
6819
|
+
[DEADLINE_EXCEEDED]: "wait",
|
|
6820
|
+
[INTERNAL_CODE]: "bug",
|
|
6821
|
+
[PERMISSION_DENIED]: "operator",
|
|
6822
|
+
[DISK_FULL]: "operator",
|
|
6823
|
+
[NOT_FOUND]: "caller",
|
|
6824
|
+
[ALREADY_EXISTS]: "caller",
|
|
6825
|
+
[TOOL_FAILED]: "operator",
|
|
6826
|
+
[TOOL_MISSING]: "operator",
|
|
6827
|
+
[PROJECT_INVALID]: "operator",
|
|
6828
|
+
[DOCTOR_PROBLEMS]: "operator",
|
|
6829
|
+
[NOT_GLOBAL_INSTALL]: "operator",
|
|
6830
|
+
[REGISTRY_UNREACHABLE]: "operator",
|
|
6831
|
+
[REGISTRY_AUTH]: "operator",
|
|
6832
|
+
[INSTALL_FAILED]: "operator",
|
|
6833
|
+
[NPM_FAILED]: "operator",
|
|
6834
|
+
[NO_LATEST]: "source"
|
|
6835
|
+
};
|
|
6836
|
+
}
|
|
6837
|
+
/** The codes of `errors` that the Runtime already declares, which a CLI cannot redeclare. */
|
|
6838
|
+
function runtimeCodesIn(errors) {
|
|
6839
|
+
return Object.keys(errors).filter((code) => Object.hasOwn(runtimeCodes(), code));
|
|
6840
|
+
}
|
|
6841
|
+
function exitClassOfOne(error, errors) {
|
|
6842
|
+
if (!(error instanceof CliError)) return "bug";
|
|
6843
|
+
if (error instanceof UsageError) return "caller";
|
|
6844
|
+
return runtimeCodes()[error.code] ?? errors[error.code]?.class ?? "bug";
|
|
6845
|
+
}
|
|
6846
|
+
function isBug(error, errors) {
|
|
6847
|
+
return exitClassOfOne(error, errors) === "bug";
|
|
6848
|
+
}
|
|
6849
|
+
const ACT_FIRST = [
|
|
6850
|
+
"caller",
|
|
6851
|
+
"operator",
|
|
6852
|
+
"source",
|
|
6853
|
+
"wait",
|
|
6854
|
+
"interrupted"
|
|
6855
|
+
];
|
|
6856
|
+
function exitClassOf(error, errors) {
|
|
6857
|
+
const classes = errorsOf(error).map((each) => exitClassOfOne(each, errors));
|
|
6858
|
+
if (classes.includes("bug")) return "bug";
|
|
6859
|
+
return ACT_FIRST.find((exitClass) => classes.includes(exitClass)) ?? "bug";
|
|
6860
|
+
}
|
|
6861
|
+
/**
|
|
6862
|
+
* The classes other than bug and interrupt that a run of `cli` can end in: those of the Runtime's
|
|
6863
|
+
* codes it can reach, and those of its own table.
|
|
6864
|
+
*/
|
|
6865
|
+
function reachableExitClasses(cli) {
|
|
6866
|
+
const runtime = [
|
|
6867
|
+
"caller",
|
|
6868
|
+
"operator",
|
|
6869
|
+
"wait",
|
|
6870
|
+
...cli.commands !== void 0 && cli.install !== void 0 ? ["source"] : []
|
|
6871
|
+
];
|
|
6872
|
+
const own = Object.values(cli.errors ?? {}).map((declaration) => declaration.class);
|
|
6873
|
+
return /* @__PURE__ */ new Set([...runtime, ...own]);
|
|
6874
|
+
}
|
|
6875
|
+
/** The signal named by an interrupt's abort reason; any other reason counts as Ctrl-C. */
|
|
6876
|
+
function stopSignalOf(reason) {
|
|
6877
|
+
return reason === "SIGTERM" ? "SIGTERM" : "SIGINT";
|
|
6878
|
+
}
|
|
6879
|
+
/**
|
|
6880
|
+
* The exit code of a run that failed with `error`, given the CLI's error table; `stop` is the
|
|
6881
|
+
* signal that interrupted it, if any.
|
|
6882
|
+
*/
|
|
6883
|
+
function exitCodeOf(error, errors, stop) {
|
|
6884
|
+
const exitClass = exitClassOf(error, errors);
|
|
6885
|
+
return exitClass === "interrupted" ? SIGNAL_EXIT_CODES[stopSignalOf(stop?.reason)] : EXIT_CODES[exitClass];
|
|
6886
|
+
}
|
|
6887
|
+
//#endregion
|
|
6888
|
+
//#region ../agent-cli/dist/help.js
|
|
6889
|
+
function table(rows) {
|
|
6890
|
+
const width = Math.max(...rows.map(([left]) => left.length));
|
|
6891
|
+
return rows.map(([left, right]) => right === "" ? ` ${left}` : ` ${left.padEnd(width)} ${right}`);
|
|
6892
|
+
}
|
|
6893
|
+
function section(title, rows, style) {
|
|
6894
|
+
return rows.length === 0 ? [] : [
|
|
6895
|
+
"",
|
|
6896
|
+
style.bold(`${title}:`),
|
|
6897
|
+
...table(rows)
|
|
6898
|
+
];
|
|
6899
|
+
}
|
|
6900
|
+
function summaryOf(node) {
|
|
6901
|
+
return node.kind === "command" ? node.description : `group: ${Object.keys(node.commands).join(", ")}`;
|
|
6902
|
+
}
|
|
6903
|
+
function commandRows({ commands }) {
|
|
6904
|
+
return Object.entries(commands).map(([key, node]) => [key, summaryOf(node)]);
|
|
6905
|
+
}
|
|
6906
|
+
function lines(...parts) {
|
|
6907
|
+
return `${parts.join("\n")}\n`;
|
|
6908
|
+
}
|
|
6909
|
+
function listingLines(heading, group, style) {
|
|
6910
|
+
return [
|
|
6911
|
+
style.bold(heading),
|
|
6912
|
+
...section("Commands", commandRows(group), style),
|
|
6913
|
+
"",
|
|
6914
|
+
`Run \`${group.commandLine} <command> --help\` for its examples and input.`
|
|
6915
|
+
];
|
|
6916
|
+
}
|
|
6917
|
+
const EXIT_MEANINGS = {
|
|
6918
|
+
caller: "the caller fixes its command",
|
|
6919
|
+
operator: "the operator acts on their machine",
|
|
6920
|
+
source: "someone at the source acts",
|
|
6921
|
+
wait: "nobody acts: wait, then run it again"
|
|
6922
|
+
};
|
|
6923
|
+
function exitCodeRows(cli) {
|
|
6924
|
+
return [
|
|
6925
|
+
["0", "done"],
|
|
6926
|
+
...[...[...reachableExitClasses(cli)].map((exitClass) => [EXIT_CODES[exitClass], EXIT_MEANINGS[exitClass]]), [EXIT_CODES.bug, `a bug in ${cli.name}`]].sort(([a], [b]) => a - b).map(([code, meaning]) => [String(code), meaning]),
|
|
6927
|
+
[Object.values(SIGNAL_EXIT_CODES).join(", "), "interrupted"]
|
|
6928
|
+
];
|
|
6929
|
+
}
|
|
6930
|
+
function firstExample(node) {
|
|
6931
|
+
if (node.kind === "command") return node.examples.slice(0, 1);
|
|
6932
|
+
return Object.values(node.commands).flatMap(firstExample).slice(0, 1);
|
|
6933
|
+
}
|
|
6934
|
+
function rootExamples(root) {
|
|
6935
|
+
if (root.kind === "command") return [...root.examples];
|
|
6936
|
+
const { doctor, ...others } = root.commands;
|
|
6937
|
+
return [...Object.values(others), ...doctor === void 0 ? [] : [doctor]].flatMap(firstExample);
|
|
6938
|
+
}
|
|
6939
|
+
function examplesSection(examples, style) {
|
|
6940
|
+
return section("Examples", examples.map(({ command, note }) => [command, note]), style);
|
|
6941
|
+
}
|
|
6942
|
+
/** The CLI's own help: a listing or its single Command's help, ending with exit codes and examples. */
|
|
6943
|
+
function cliHelp(cli, root, style) {
|
|
6944
|
+
return lines(...root.kind === "command" ? commandLines(root, style, { examples: false }) : listingLines(`${root.commandLine} ${cli.version}`, root, style), ...section("Exit codes", exitCodeRows(cli), style), ...examplesSection(rootExamples(root), style));
|
|
6945
|
+
}
|
|
6946
|
+
function groupHelp(group, style) {
|
|
6947
|
+
return lines(...listingLines(group.commandLine, group, style));
|
|
6948
|
+
}
|
|
6949
|
+
const EFFECT_NOTES = {
|
|
6950
|
+
read: "changes nothing",
|
|
6951
|
+
write: "changes something; show the Plan with --dry-run",
|
|
6952
|
+
destructive: "changes something hard to undo; show the Plan with --dry-run, run with --confirm",
|
|
6953
|
+
serve: "changes nothing; prints its data at once, then runs until Ctrl-C, which exits 0"
|
|
6954
|
+
};
|
|
6955
|
+
function choicesOf(field) {
|
|
6956
|
+
return field.choices === void 0 ? [] : [`one of: ${field.choices.join(", ")}`];
|
|
6957
|
+
}
|
|
6958
|
+
function defaultsOf(field) {
|
|
6959
|
+
if (field.defaultValue === void 0) return [];
|
|
6960
|
+
if (field.type !== "boolean") return [`default: ${JSON.stringify(field.defaultValue)}`];
|
|
6961
|
+
return field.defaultValue === true ? ["on by default; this flag turns it off"] : [];
|
|
6962
|
+
}
|
|
6963
|
+
function fieldRow(field, notes) {
|
|
6964
|
+
const all = [...field.required ? ["required"] : [], ...notes];
|
|
6965
|
+
const suffix = all.length === 0 ? "" : `(${all.join("; ")})`;
|
|
6966
|
+
return [field.usage, [field.description ?? "", suffix].filter((part) => part !== "").join(" ")];
|
|
6967
|
+
}
|
|
6968
|
+
function argRow(field) {
|
|
6969
|
+
return fieldRow(field, [...choicesOf(field), ...defaultsOf(field)]);
|
|
6970
|
+
}
|
|
6971
|
+
function optionRow(field) {
|
|
6972
|
+
return fieldRow(field, defaultsOf(field));
|
|
6973
|
+
}
|
|
6974
|
+
function flagRow({ usage, description }) {
|
|
6975
|
+
return [usage, description];
|
|
6976
|
+
}
|
|
6977
|
+
function commandLines(spec, style, { examples }) {
|
|
6978
|
+
return [
|
|
6979
|
+
style.bold(spec.commandLine),
|
|
6980
|
+
spec.description,
|
|
6981
|
+
...examples ? examplesSection(spec.examples, style) : [],
|
|
6982
|
+
...section("Arguments", spec.args.map(argRow), style),
|
|
6983
|
+
...section("Options", spec.options.map(optionRow), style),
|
|
6984
|
+
"",
|
|
6985
|
+
`${style.bold("Effect:")} ${spec.effect} (${EFFECT_NOTES[spec.effect]})`,
|
|
6986
|
+
...section("Standard flags", spec.standardFlags.map(flagRow), style)
|
|
6987
|
+
];
|
|
6988
|
+
}
|
|
6989
|
+
function commandHelp(spec, style) {
|
|
6990
|
+
return lines(...commandLines(spec, style, { examples: true }));
|
|
6991
|
+
}
|
|
6992
|
+
//#endregion
|
|
6993
|
+
//#region ../agent-cli/dist/help-json.js
|
|
6994
|
+
function inputSchema(schema) {
|
|
6995
|
+
return toJSONSchema(schema, {
|
|
6996
|
+
io: "input",
|
|
6997
|
+
unrepresentable: "any"
|
|
6998
|
+
});
|
|
6999
|
+
}
|
|
7000
|
+
function optionsSchema(options) {
|
|
7001
|
+
return inputSchema(object(Object.fromEntries(options.map(({ name, schema }) => [name, schema]))));
|
|
7002
|
+
}
|
|
7003
|
+
function commandData(spec) {
|
|
7004
|
+
return {
|
|
7005
|
+
name: spec.commandLine,
|
|
7006
|
+
description: spec.description,
|
|
7007
|
+
effect: spec.effect,
|
|
7008
|
+
examples: spec.examples,
|
|
7009
|
+
args: inputSchema(spec.command.args ?? object({})),
|
|
7010
|
+
options: optionsSchema(spec.options),
|
|
7011
|
+
standardFlags: spec.standardFlags.map(({ usage, description, schema }) => ({
|
|
7012
|
+
usage,
|
|
7013
|
+
description,
|
|
7014
|
+
schema: inputSchema(schema)
|
|
7015
|
+
})),
|
|
7016
|
+
output: spec.output === void 0 ? null : toJSONSchema(spec.output, { unrepresentable: "any" })
|
|
7017
|
+
};
|
|
7018
|
+
}
|
|
7019
|
+
function nodeData(node) {
|
|
7020
|
+
return node.kind === "command" ? commandData(node) : groupData(node);
|
|
7021
|
+
}
|
|
7022
|
+
function groupData(group) {
|
|
7023
|
+
return {
|
|
7024
|
+
name: group.commandLine,
|
|
7025
|
+
commands: Object.values(group.commands).map(nodeData)
|
|
7026
|
+
};
|
|
7027
|
+
}
|
|
7028
|
+
function printed$1(data) {
|
|
7029
|
+
return `${JSON.stringify(data)}\n`;
|
|
7030
|
+
}
|
|
7031
|
+
function errorsData(errors) {
|
|
7032
|
+
return Object.fromEntries(Object.entries(errors).map(([code, declaration]) => [code, {
|
|
7033
|
+
class: declaration.class,
|
|
7034
|
+
details: declaration.details === void 0 ? null : toJSONSchema(declaration.details, { unrepresentable: "any" })
|
|
7035
|
+
}]));
|
|
7036
|
+
}
|
|
7037
|
+
function cliHelpJson({ version, errors }, root) {
|
|
7038
|
+
return printed$1({
|
|
7039
|
+
name: root.commandLine,
|
|
7040
|
+
version,
|
|
7041
|
+
...nodeData(root),
|
|
7042
|
+
errors: errorsData(errors ?? {})
|
|
7043
|
+
});
|
|
7044
|
+
}
|
|
7045
|
+
function groupHelpJson(group) {
|
|
7046
|
+
return printed$1(groupData(group));
|
|
7047
|
+
}
|
|
7048
|
+
function commandHelpJson(spec) {
|
|
7049
|
+
return printed$1(commandData(spec));
|
|
7050
|
+
}
|
|
7051
|
+
//#endregion
|
|
7052
|
+
//#region ../agent-cli/dist/output.js
|
|
7053
|
+
const SUCCESS_EXIT_CODE = 0;
|
|
7054
|
+
function withTrailingNewline(text) {
|
|
7055
|
+
return text === "" || text.endsWith("\n") ? text : `${text}\n`;
|
|
7056
|
+
}
|
|
7057
|
+
function printed(value, render, { json, invocation, style, fields }) {
|
|
7058
|
+
if (!(value instanceof Page)) return json ? `${JSON.stringify(value)}\n` : withTrailingNewline(render(style));
|
|
7059
|
+
const page = printedPage(value, invocation);
|
|
7060
|
+
if (fields === void 0) return json ? `${JSON.stringify(page)}\n` : `${withTrailingNewline(render(style))}${pageFooter(page)}`;
|
|
7061
|
+
const rows = projected(page.items, fields);
|
|
7062
|
+
return json ? `${JSON.stringify({
|
|
7063
|
+
...page,
|
|
7064
|
+
items: rows
|
|
7065
|
+
})}\n` : `${renderRows(rows, fields)}${pageFooter(page)}`;
|
|
7066
|
+
}
|
|
7067
|
+
function errorText(error, format) {
|
|
7068
|
+
const text = formatRuntimeError(error, {
|
|
7069
|
+
...format,
|
|
7070
|
+
isBug: (each) => isBug(each, format.errors)
|
|
7071
|
+
});
|
|
7072
|
+
const { usageHelp, json } = format;
|
|
7073
|
+
return usageHelp !== void 0 && !json && error instanceof UsageError ? `${text}\n${usageHelp}` : text;
|
|
7074
|
+
}
|
|
7075
|
+
function stdoutOf({ value, render }, format, spill) {
|
|
7076
|
+
const text = printed(value, render, format);
|
|
7077
|
+
return value instanceof Page ? text : spill(text, format.json);
|
|
7078
|
+
}
|
|
7079
|
+
/** What a serve Command prints the moment it starts. */
|
|
7080
|
+
function startedOutput(outcome, format, spill) {
|
|
7081
|
+
return stdoutOf(outcome, {
|
|
7082
|
+
...format,
|
|
7083
|
+
fields: void 0
|
|
7084
|
+
}, spill);
|
|
7085
|
+
}
|
|
7086
|
+
/** A serve Command stopped after it started: stopping it is how it is meant to end. */
|
|
7087
|
+
const STOPPED_RESULT = {
|
|
7088
|
+
stdout: "",
|
|
7089
|
+
stderr: "",
|
|
7090
|
+
exitCode: SUCCESS_EXIT_CODE
|
|
7091
|
+
};
|
|
7092
|
+
function errorResult(error, format) {
|
|
7093
|
+
return {
|
|
7094
|
+
stdout: "",
|
|
7095
|
+
stderr: errorText(error, format),
|
|
7096
|
+
exitCode: exitCodeOf(error, format.errors, format.stop)
|
|
7097
|
+
};
|
|
7098
|
+
}
|
|
7099
|
+
async function commandResult(settled, format, spill) {
|
|
7100
|
+
if (settled.ok) try {
|
|
7101
|
+
return {
|
|
7102
|
+
stdout: await stdoutOf(settled.outcome, format, spill),
|
|
7103
|
+
stderr: "",
|
|
7104
|
+
exitCode: SUCCESS_EXIT_CODE
|
|
7105
|
+
};
|
|
7106
|
+
} catch (spillError) {
|
|
7107
|
+
return errorResult(spillError, format);
|
|
7108
|
+
}
|
|
7109
|
+
const { error, delivered } = settled;
|
|
7110
|
+
const result = errorResult(error, format);
|
|
7111
|
+
if (delivered === void 0) return result;
|
|
7112
|
+
try {
|
|
7113
|
+
return {
|
|
7114
|
+
...result,
|
|
7115
|
+
stdout: await stdoutOf(delivered, format, spill)
|
|
7116
|
+
};
|
|
7117
|
+
} catch (spillError) {
|
|
7118
|
+
const both = new AggregateError([...errorsOf(error), spillError]);
|
|
7119
|
+
return {
|
|
7120
|
+
...result,
|
|
7121
|
+
stderr: errorText(both, format)
|
|
7122
|
+
};
|
|
7123
|
+
}
|
|
7124
|
+
}
|
|
7125
|
+
function textHelp(node, root, cli, style) {
|
|
7126
|
+
if (node === root) return cliHelp(cli, node, style);
|
|
7127
|
+
return node.kind === "command" ? commandHelp(node, style) : groupHelp(node, style);
|
|
7128
|
+
}
|
|
7129
|
+
function helpOf(node, root, cli, style, json) {
|
|
7130
|
+
if (!json) return textHelp(node, root, cli, style);
|
|
7131
|
+
if (node === root) return cliHelpJson(cli, node);
|
|
7132
|
+
return node.kind === "command" ? commandHelpJson(node) : groupHelpJson(node);
|
|
7133
|
+
}
|
|
7134
|
+
function helpResult(node, root, cli, { style, json }) {
|
|
7135
|
+
return {
|
|
7136
|
+
stdout: helpOf(node, root, cli, style, json),
|
|
7137
|
+
stderr: "",
|
|
7138
|
+
exitCode: SUCCESS_EXIT_CODE
|
|
7139
|
+
};
|
|
7140
|
+
}
|
|
7141
|
+
/** The first line of `--version`: the version, and the commit and time of a stamped build. */
|
|
7142
|
+
function versionLine({ version, build }) {
|
|
7143
|
+
return build === void 0 ? version : `${version} (${build.sha}${build.dirty ? "+dirty" : ""}) built ${build.builtAt}`;
|
|
7144
|
+
}
|
|
7145
|
+
function versionResult(cli, packageRoot) {
|
|
7146
|
+
return {
|
|
7147
|
+
stdout: `${(cli.build === void 0 ? [versionLine(cli)] : [versionLine(cli), `changelog ${join(packageRoot, "CHANGELOG.md")}`]).join("\n")}\n`,
|
|
7148
|
+
stderr: "",
|
|
7149
|
+
exitCode: SUCCESS_EXIT_CODE
|
|
7150
|
+
};
|
|
7151
|
+
}
|
|
7152
|
+
//#endregion
|
|
7153
|
+
//#region ../agent-cli/dist/skills.js
|
|
7154
|
+
/** Where the skills CLI (`npx skills add`) puts a skill, under a project and under home. */
|
|
7155
|
+
const SKILL_DIRS = [[".claude", "skills"], [".agents", "skills"]];
|
|
7156
|
+
function skillUpdateCommand(cliName) {
|
|
7157
|
+
return `npx -y skills update ${cliName}`;
|
|
7158
|
+
}
|
|
7159
|
+
const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---/;
|
|
7160
|
+
const METADATA_VERSION = /^metadata:[ \t]*\r?\n(?:[ \t]+.*\r?\n)*?[ \t]+version:[ \t]*["']?([^"'\s]+)["']?[ \t]*$/m;
|
|
7161
|
+
/** The version a SKILL.md's frontmatter `metadata.version` states. */
|
|
7162
|
+
function skillVersionIn(skill) {
|
|
7163
|
+
const frontmatter = FRONTMATTER.exec(skill)?.[1];
|
|
7164
|
+
return frontmatter === void 0 ? void 0 : METADATA_VERSION.exec(`${frontmatter}\n`)?.[1];
|
|
7165
|
+
}
|
|
7166
|
+
function homeOf(env) {
|
|
7167
|
+
return env.HOME ?? env.USERPROFILE ?? homedir();
|
|
7168
|
+
}
|
|
7169
|
+
async function copyAt(path, cliVersion) {
|
|
7170
|
+
let skill;
|
|
7171
|
+
try {
|
|
7172
|
+
skill = await readFile(join(path, "SKILL.md"), "utf8");
|
|
7173
|
+
} catch (error) {
|
|
7174
|
+
if (isMissingFile(error)) return;
|
|
7175
|
+
return {
|
|
7176
|
+
path,
|
|
7177
|
+
version: void 0,
|
|
7178
|
+
state: "unreadable"
|
|
7179
|
+
};
|
|
7180
|
+
}
|
|
7181
|
+
const version = skillVersionIn(skill);
|
|
7182
|
+
if (version === void 0 || !isVersion(version) || !isVersion(cliVersion)) return {
|
|
7183
|
+
path,
|
|
7184
|
+
version,
|
|
7185
|
+
state: "unversioned"
|
|
7186
|
+
};
|
|
7187
|
+
return {
|
|
7188
|
+
path,
|
|
7189
|
+
version,
|
|
7190
|
+
state: standingOf(version, cliVersion)
|
|
7191
|
+
};
|
|
7192
|
+
}
|
|
7193
|
+
/** Every installed copy of the skill named after the CLI, in the project first, then under home. */
|
|
7194
|
+
async function skillCopies(skillName, cliVersion, cwd, env) {
|
|
7195
|
+
const paths = [cwd, homeOf(env)].flatMap((root) => SKILL_DIRS.map((dir) => join(root, ...dir, skillName)));
|
|
7196
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7197
|
+
const copies = [];
|
|
7198
|
+
for (const path of paths) {
|
|
7199
|
+
const copy = await copyAt(path, cliVersion);
|
|
7200
|
+
const real = copy === void 0 ? void 0 : await realpath(path);
|
|
7201
|
+
if (copy !== void 0 && real !== void 0 && !seen.has(real)) {
|
|
7202
|
+
seen.add(real);
|
|
7203
|
+
copies.push(copy);
|
|
7204
|
+
}
|
|
7205
|
+
}
|
|
7206
|
+
return copies;
|
|
7207
|
+
}
|
|
7208
|
+
//#endregion
|
|
7209
|
+
//#region ../agent-cli/dist/doctor-rows.js
|
|
7210
|
+
function ok(message) {
|
|
7211
|
+
return {
|
|
7212
|
+
state: "ok",
|
|
7213
|
+
message
|
|
7214
|
+
};
|
|
7215
|
+
}
|
|
7216
|
+
function buildRow(cli) {
|
|
7217
|
+
return {
|
|
7218
|
+
name: "build",
|
|
7219
|
+
run: () => ok(versionLine(cli))
|
|
7220
|
+
};
|
|
7221
|
+
}
|
|
7222
|
+
function nodeRow(cli) {
|
|
7223
|
+
return {
|
|
7224
|
+
name: "node",
|
|
7225
|
+
run: () => {
|
|
7226
|
+
const found = process.versions.node;
|
|
7227
|
+
const range = cli.engines?.node;
|
|
7228
|
+
if (range === void 0) return ok(`Node ${found}; ${cli.name} declares no engines.node to check it against`);
|
|
7229
|
+
const minimum = engineMinimum(range);
|
|
7230
|
+
if (minimum === void 0) return {
|
|
7231
|
+
state: "problem",
|
|
7232
|
+
message: `${cli.name} declares engines.node "${range}", which doctor cannot read: only >=X.Y.Z is supported`
|
|
7233
|
+
};
|
|
7234
|
+
if (meetsMinimum(found, minimum)) return ok(`Node ${found} meets ${range}`);
|
|
7235
|
+
const major = minimum[0];
|
|
7236
|
+
return {
|
|
7237
|
+
state: "problem",
|
|
7238
|
+
message: `${cli.name} runs on Node ${found}, older than the ${range} it needs; install Node ${minimum.join(".")} or newer and make it the default`,
|
|
7239
|
+
fix: `nvm install ${major} && nvm alias default ${major}`
|
|
7240
|
+
};
|
|
7241
|
+
}
|
|
7242
|
+
};
|
|
7243
|
+
}
|
|
7244
|
+
function projectRow(projectFile) {
|
|
7245
|
+
const { file } = projectFile;
|
|
7246
|
+
return {
|
|
7247
|
+
name: "project",
|
|
7248
|
+
run: (ctx) => {
|
|
7249
|
+
let project;
|
|
7250
|
+
try {
|
|
7251
|
+
project = projectOf(projectFile, ctx.cwd);
|
|
7252
|
+
} catch (error) {
|
|
7253
|
+
if (error instanceof CliError && error.code === "PROJECT_INVALID") return {
|
|
7254
|
+
state: "problem",
|
|
7255
|
+
message: error.message
|
|
7256
|
+
};
|
|
7257
|
+
throw error;
|
|
7258
|
+
}
|
|
7259
|
+
return ok(project === void 0 ? `none found: no ${file} at or above ${ctx.cwd}` : join(project.root, file));
|
|
7260
|
+
}
|
|
7261
|
+
};
|
|
7262
|
+
}
|
|
7263
|
+
function installRow(cli, bin) {
|
|
7264
|
+
return {
|
|
7265
|
+
name: "install",
|
|
7266
|
+
advisory: true,
|
|
7267
|
+
run: async (ctx) => {
|
|
7268
|
+
const { install } = cli;
|
|
7269
|
+
if (install === void 0) return ok(`${cli.name} declares no install, so it has no \`update\``);
|
|
7270
|
+
try {
|
|
7271
|
+
return ok(`a global npm install under ${(await globalInstallOf(bin, npmContext(cli, install, ctx))).prefix}`);
|
|
7272
|
+
} catch (error) {
|
|
7273
|
+
if (error instanceof CliError && error.code === "NOT_GLOBAL_INSTALL") return {
|
|
7274
|
+
state: "problem",
|
|
7275
|
+
message: error.message,
|
|
7276
|
+
fix: installCommandLine(install)
|
|
7277
|
+
};
|
|
7278
|
+
throw error;
|
|
7279
|
+
}
|
|
7280
|
+
}
|
|
7281
|
+
};
|
|
7282
|
+
}
|
|
7283
|
+
function registryRow(cli) {
|
|
7284
|
+
return {
|
|
7285
|
+
name: "registry",
|
|
7286
|
+
advisory: true,
|
|
7287
|
+
run: async (ctx) => {
|
|
7288
|
+
const { install } = cli;
|
|
7289
|
+
if (install === void 0) return ok(`${cli.name} declares no registry to compare this build with`);
|
|
7290
|
+
const latest = await latestVersion(npmContext(cli, install, ctx));
|
|
7291
|
+
const standing = standingOf(cli.version, latest);
|
|
7292
|
+
const head = `${install.registry} has ${latest} as latest: this build`;
|
|
7293
|
+
if (standing === "behind") return {
|
|
7294
|
+
state: "problem",
|
|
7295
|
+
message: `${head} (${cli.version}) is older`,
|
|
6285
7296
|
fix: `${cli.name} update`
|
|
6286
7297
|
};
|
|
6287
7298
|
return ok(`${head} is ${standing === "current" ? "current" : `newer (${cli.version})`}`);
|
|
@@ -6318,10 +7329,14 @@ function skillRow(cli) {
|
|
|
6318
7329
|
}
|
|
6319
7330
|
};
|
|
6320
7331
|
}
|
|
6321
|
-
/**
|
|
6322
|
-
function
|
|
7332
|
+
/** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
|
|
7333
|
+
function doctorChecks(cli, bin) {
|
|
6323
7334
|
return [
|
|
7335
|
+
buildRow(cli),
|
|
6324
7336
|
nodeRow(cli),
|
|
7337
|
+
...cli.project === void 0 ? [] : [projectRow(cli.project)],
|
|
7338
|
+
...cli.doctor ?? [],
|
|
7339
|
+
...toolRows(cli.commands),
|
|
6325
7340
|
installRow(cli, bin),
|
|
6326
7341
|
registryRow(cli),
|
|
6327
7342
|
skillRow(cli)
|
|
@@ -6329,7 +7344,8 @@ function fixedRows(cli, bin) {
|
|
|
6329
7344
|
}
|
|
6330
7345
|
//#endregion
|
|
6331
7346
|
//#region ../agent-cli/dist/doctor.js
|
|
6332
|
-
const
|
|
7347
|
+
const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
|
|
7348
|
+
const DEFAULT_DEADLINE_MS = 1e4;
|
|
6333
7349
|
const MS_PER_SECOND = 1e3;
|
|
6334
7350
|
const MIN_LABEL_WIDTH = 8;
|
|
6335
7351
|
const reportSchema = object({
|
|
@@ -6341,19 +7357,10 @@ const reportSchema = object({
|
|
|
6341
7357
|
})),
|
|
6342
7358
|
next: array(string())
|
|
6343
7359
|
});
|
|
6344
|
-
function
|
|
6345
|
-
return new Promise((_resolve, reject) => {
|
|
6346
|
-
if (signal.aborted) {
|
|
6347
|
-
reject(signal.reason);
|
|
6348
|
-
return;
|
|
6349
|
-
}
|
|
6350
|
-
signal.addEventListener("abort", () => reject(signal.reason), { once: true });
|
|
6351
|
-
});
|
|
6352
|
-
}
|
|
6353
|
-
function problemOf(check, error, { signal, deadline }) {
|
|
7360
|
+
function problemOf(check, error, { signal, deadline, ms }) {
|
|
6354
7361
|
if (!signal.aborted && deadline.aborted && error === deadline.reason) return {
|
|
6355
7362
|
state: "problem",
|
|
6356
|
-
message: `${check.name} did not answer within ${
|
|
7363
|
+
message: `${check.name} did not answer within ${ms / MS_PER_SECOND} s`
|
|
6357
7364
|
};
|
|
6358
7365
|
if (error instanceof CliError) return {
|
|
6359
7366
|
state: "problem",
|
|
@@ -6364,23 +7371,28 @@ function problemOf(check, error, { signal, deadline }) {
|
|
|
6364
7371
|
message: `the ${check.name} row hit a bug: ${messageOf(error)}`
|
|
6365
7372
|
};
|
|
6366
7373
|
}
|
|
7374
|
+
function withSignal(ctx, signal) {
|
|
7375
|
+
return Object.create(ctx, { signal: { value: signal } });
|
|
7376
|
+
}
|
|
6367
7377
|
async function rowOf(check, ctx) {
|
|
6368
|
-
const
|
|
7378
|
+
const ms = check.deadlineMs ?? DEFAULT_DEADLINE_MS;
|
|
7379
|
+
const signal = ctx.deadline(ms);
|
|
6369
7380
|
let finding;
|
|
6370
7381
|
try {
|
|
6371
|
-
finding = await Promise.race([Promise.resolve().then(() => check.run(
|
|
6372
|
-
...ctx,
|
|
6373
|
-
signal
|
|
6374
|
-
})), untilAborted(signal)]);
|
|
7382
|
+
finding = await Promise.race([Promise.resolve().then(() => check.run(withSignal(ctx, signal))), untilAborted(signal)]);
|
|
6375
7383
|
} catch (error) {
|
|
6376
7384
|
finding = problemOf(check, error, {
|
|
6377
7385
|
signal: ctx.signal,
|
|
6378
|
-
deadline: signal
|
|
7386
|
+
deadline: signal,
|
|
7387
|
+
ms
|
|
6379
7388
|
});
|
|
6380
7389
|
}
|
|
6381
7390
|
return {
|
|
6382
|
-
|
|
6383
|
-
|
|
7391
|
+
row: {
|
|
7392
|
+
check: check.name,
|
|
7393
|
+
...finding
|
|
7394
|
+
},
|
|
7395
|
+
advisory: check.advisory === true
|
|
6384
7396
|
};
|
|
6385
7397
|
}
|
|
6386
7398
|
function nextOf(rows) {
|
|
@@ -6394,18 +7406,16 @@ function render({ rows, next }, style) {
|
|
|
6394
7406
|
return `${check.padEnd(width)}${label}${" ".repeat(stateWidth - state.length)}${message}`;
|
|
6395
7407
|
}), ...next.map((fix) => `${"next".padEnd(width)}${fix}`)].join("\n");
|
|
6396
7408
|
}
|
|
6397
|
-
function failure(cliName, report) {
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
code: "DOCTOR_PROBLEMS",
|
|
7409
|
+
function failure(cliName, problems, report) {
|
|
7410
|
+
return new CliError({
|
|
7411
|
+
code: DOCTOR_PROBLEMS,
|
|
6401
7412
|
message: `${cliName} doctor found ${problems.length === 1 ? "a problem" : `${problems.length} problems`}: ${problems.join(", ")}`,
|
|
6402
|
-
hint: report.next.length === 0 ? "each problem row says what is wrong" : "run the commands under next, then run doctor again"
|
|
6403
|
-
|
|
6404
|
-
}, report);
|
|
7413
|
+
hint: report.next.length === 0 ? "each problem row says what is wrong" : "run the commands under next, then run doctor again"
|
|
7414
|
+
});
|
|
6405
7415
|
}
|
|
6406
|
-
/** The built-in `doctor`: the fixed rows
|
|
7416
|
+
/** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
|
|
6407
7417
|
function doctorCommand(cli, bin) {
|
|
6408
|
-
return defineCommand({
|
|
7418
|
+
return defineCommand$1({
|
|
6409
7419
|
name: "doctor",
|
|
6410
7420
|
description: "check the setup and say what fixes each problem",
|
|
6411
7421
|
examples: [{
|
|
@@ -6418,120 +7428,24 @@ function doctorCommand(cli, bin) {
|
|
|
6418
7428
|
effect: "read",
|
|
6419
7429
|
output: reportSchema,
|
|
6420
7430
|
run: async (_input, ctx) => {
|
|
6421
|
-
const
|
|
6422
|
-
|
|
7431
|
+
const checked = await Promise.all(doctorChecks(cli, bin).map((check) => rowOf(check, ctx)));
|
|
7432
|
+
ctx.signal.throwIfAborted();
|
|
7433
|
+
const rows = checked.map(({ row }) => row);
|
|
6423
7434
|
const report = {
|
|
6424
7435
|
rows,
|
|
6425
7436
|
next: nextOf(rows)
|
|
6426
7437
|
};
|
|
6427
|
-
|
|
7438
|
+
const problems = checked.filter(({ row, advisory }) => row.state === "problem" && !advisory).map(({ row }) => row.check);
|
|
7439
|
+
if (problems.length > 0) {
|
|
7440
|
+
ctx.deliver(report);
|
|
7441
|
+
throw failure(cli.name, problems, report);
|
|
7442
|
+
}
|
|
6428
7443
|
return report;
|
|
6429
7444
|
},
|
|
6430
7445
|
render
|
|
6431
7446
|
});
|
|
6432
7447
|
}
|
|
6433
7448
|
//#endregion
|
|
6434
|
-
//#region ../agent-cli/dist/interrupts.js
|
|
6435
|
-
/** How long an interrupted Command may take to settle before the run ends without it. */
|
|
6436
|
-
const GRACE_MS = 3e3;
|
|
6437
|
-
const GRACE_OVER = Symbol("grace over");
|
|
6438
|
-
const INTERRUPTED = "INTERRUPTED";
|
|
6439
|
-
function interruptedError() {
|
|
6440
|
-
return new CliError({
|
|
6441
|
-
code: INTERRUPTED,
|
|
6442
|
-
message: "interrupted before it finished",
|
|
6443
|
-
hint: "run the command again",
|
|
6444
|
-
retryable: true
|
|
6445
|
-
});
|
|
6446
|
-
}
|
|
6447
|
-
function deadlineError(commandLine, ms) {
|
|
6448
|
-
return new CliError({
|
|
6449
|
-
code: "DEADLINE_EXCEEDED",
|
|
6450
|
-
message: `${commandLine} ran past its ${ms} ms deadline`,
|
|
6451
|
-
hint: "run it again later, when the service it waits on may answer faster",
|
|
6452
|
-
retryable: true
|
|
6453
|
-
});
|
|
6454
|
-
}
|
|
6455
|
-
/** One Command run's cancellation: its signal, its deadlines and the steps it must finish. */
|
|
6456
|
-
var RunControl = class {
|
|
6457
|
-
signal;
|
|
6458
|
-
#controller = new AbortController();
|
|
6459
|
-
#commandLine;
|
|
6460
|
-
#outer;
|
|
6461
|
-
#onOuterAbort = () => this.#controller.abort(interruptedError());
|
|
6462
|
-
#steps = /* @__PURE__ */ new Set();
|
|
6463
|
-
#deadlineTimers = /* @__PURE__ */ new Set();
|
|
6464
|
-
#deadlineHit;
|
|
6465
|
-
#graceTimer;
|
|
6466
|
-
#endGrace = () => {};
|
|
6467
|
-
#graceOver = new Promise((resolve) => {
|
|
6468
|
-
this.#endGrace = resolve;
|
|
6469
|
-
});
|
|
6470
|
-
constructor(commandLine, outer) {
|
|
6471
|
-
this.#commandLine = commandLine;
|
|
6472
|
-
this.#outer = outer;
|
|
6473
|
-
this.signal = this.#controller.signal;
|
|
6474
|
-
this.signal.addEventListener("abort", () => this.#startGrace(), { once: true });
|
|
6475
|
-
if (outer?.aborted === true) this.#onOuterAbort();
|
|
6476
|
-
else outer?.addEventListener("abort", this.#onOuterAbort, { once: true });
|
|
6477
|
-
}
|
|
6478
|
-
deadline(ms) {
|
|
6479
|
-
const controller = new AbortController();
|
|
6480
|
-
const timer = setTimeout(() => {
|
|
6481
|
-
this.#deadlineHit ??= deadlineError(this.#commandLine, ms);
|
|
6482
|
-
controller.abort(this.#deadlineHit);
|
|
6483
|
-
}, ms);
|
|
6484
|
-
this.#deadlineTimers.add(timer);
|
|
6485
|
-
return AbortSignal.any([this.signal, controller.signal]);
|
|
6486
|
-
}
|
|
6487
|
-
async runToEnd(work) {
|
|
6488
|
-
clearTimeout(this.#graceTimer);
|
|
6489
|
-
const step = work();
|
|
6490
|
-
const settled = step.then(() => {}, () => {});
|
|
6491
|
-
this.#steps.add(settled);
|
|
6492
|
-
try {
|
|
6493
|
-
return await step;
|
|
6494
|
-
} finally {
|
|
6495
|
-
this.#steps.delete(settled);
|
|
6496
|
-
this.#startGrace();
|
|
6497
|
-
}
|
|
6498
|
-
}
|
|
6499
|
-
/** Waits for the Command, its must-finish steps, and no longer than the grace once interrupted. */
|
|
6500
|
-
async settle(work) {
|
|
6501
|
-
try {
|
|
6502
|
-
const value = await Promise.race([work, this.#graceOver]);
|
|
6503
|
-
if (this.signal.aborted || value === GRACE_OVER) throw this.signal.reason;
|
|
6504
|
-
return value;
|
|
6505
|
-
} finally {
|
|
6506
|
-
await this.#stepsDone();
|
|
6507
|
-
this.#dispose();
|
|
6508
|
-
}
|
|
6509
|
-
}
|
|
6510
|
-
/**
|
|
6511
|
-
* The error a run ends with: an interrupt or a missed deadline outranks what the Command threw,
|
|
6512
|
-
* unless the Command threw its own `INTERRUPTED`, saying what it finished before it stopped.
|
|
6513
|
-
*/
|
|
6514
|
-
errorAfter(error) {
|
|
6515
|
-
if (this.signal.aborted) return error instanceof CliError && error.code === "INTERRUPTED" ? error : this.signal.reason;
|
|
6516
|
-
if (this.#deadlineHit !== void 0 && !(error instanceof CliError)) return this.#deadlineHit;
|
|
6517
|
-
return error;
|
|
6518
|
-
}
|
|
6519
|
-
#startGrace() {
|
|
6520
|
-
if (this.signal.aborted && this.#steps.size === 0) {
|
|
6521
|
-
clearTimeout(this.#graceTimer);
|
|
6522
|
-
this.#graceTimer = setTimeout(() => this.#endGrace(GRACE_OVER), GRACE_MS);
|
|
6523
|
-
}
|
|
6524
|
-
}
|
|
6525
|
-
async #stepsDone() {
|
|
6526
|
-
while (this.#steps.size > 0) await Promise.all(this.#steps);
|
|
6527
|
-
}
|
|
6528
|
-
#dispose() {
|
|
6529
|
-
clearTimeout(this.#graceTimer);
|
|
6530
|
-
for (const timer of this.#deadlineTimers) clearTimeout(timer);
|
|
6531
|
-
this.#outer?.removeEventListener("abort", this.#onOuterAbort);
|
|
6532
|
-
}
|
|
6533
|
-
};
|
|
6534
|
-
//#endregion
|
|
6535
7449
|
//#region ../agent-cli/dist/upgrade-notes.js
|
|
6536
7450
|
const RELEASE_HEADING = /^## v?(\S+)/;
|
|
6537
7451
|
function releasesIn(changelog) {
|
|
@@ -6595,17 +7509,16 @@ function renderUpdate(cli, install, update) {
|
|
|
6595
7509
|
...update.next.map((command) => `next: ${command}, so the ${cli.name} skill describes ${installed.version}`)
|
|
6596
7510
|
].join("\n");
|
|
6597
7511
|
}
|
|
6598
|
-
function interruptedAfterInstall(plan
|
|
6599
|
-
return new
|
|
7512
|
+
function interruptedAfterInstall(plan) {
|
|
7513
|
+
return new CliError({
|
|
6600
7514
|
code: INTERRUPTED,
|
|
6601
7515
|
message: `interrupted, but ${plan.package}@${plan.latest} had already been installed with the npm under ${plan.prefix}, replacing ${plan.from}`,
|
|
6602
|
-
hint: "nothing to run again: run the commands under next"
|
|
6603
|
-
|
|
6604
|
-
}, update);
|
|
7516
|
+
hint: "nothing to run again: run the commands under next"
|
|
7517
|
+
});
|
|
6605
7518
|
}
|
|
6606
7519
|
/** The built-in `update`, for a CLI installed globally with npm. */
|
|
6607
7520
|
function updateCommand(cli, install, bin) {
|
|
6608
|
-
return defineCommand({
|
|
7521
|
+
return defineCommand$1({
|
|
6609
7522
|
name: "update",
|
|
6610
7523
|
description: "install the latest version of this CLI from its registry",
|
|
6611
7524
|
examples: [{
|
|
@@ -6639,7 +7552,7 @@ function updateCommand(cli, install, bin) {
|
|
|
6639
7552
|
};
|
|
6640
7553
|
ctx.signal.throwIfAborted();
|
|
6641
7554
|
ctx.progress(`installing ${plan.package}@${latest} with the npm under ${prefix}…`);
|
|
6642
|
-
await ctx.runToEnd(() => installGlobally(latest, npmContext(cli, install, ctx)));
|
|
7555
|
+
await ctx.runToEnd(`installing ${plan.package}@${latest}`, () => installGlobally(latest, npmContext(cli, install, ctx)));
|
|
6643
7556
|
const update = {
|
|
6644
7557
|
from,
|
|
6645
7558
|
latest,
|
|
@@ -6650,7 +7563,10 @@ function updateCommand(cli, install, bin) {
|
|
|
6650
7563
|
upgrades: await upgradeNotes(plan.packageDir, from, latest),
|
|
6651
7564
|
next: [skillUpdateCommand(cli.name)]
|
|
6652
7565
|
};
|
|
6653
|
-
if (ctx.signal.aborted)
|
|
7566
|
+
if (ctx.signal.aborted) {
|
|
7567
|
+
ctx.deliver(update);
|
|
7568
|
+
throw interruptedAfterInstall(plan);
|
|
7569
|
+
}
|
|
6654
7570
|
return update;
|
|
6655
7571
|
},
|
|
6656
7572
|
render: (update) => renderUpdate(cli, install, update),
|
|
@@ -6666,263 +7582,255 @@ function builtInCommands(cli, bin) {
|
|
|
6666
7582
|
...cli.install === void 0 ? {} : { update: updateCommand(cli, cli.install, bin) }
|
|
6667
7583
|
};
|
|
6668
7584
|
}
|
|
6669
|
-
|
|
7585
|
+
//#endregion
|
|
7586
|
+
//#region ../agent-cli/dist/agent-cli.js
|
|
7587
|
+
function checkOwnCodes(cli) {
|
|
7588
|
+
const redeclared = runtimeCodesIn(cli.errors ?? {});
|
|
7589
|
+
if (redeclared.length > 0) throw new Error(`${cli.name} declares ${redeclared.join(", ")}, an error code the Runtime already declares`);
|
|
7590
|
+
}
|
|
7591
|
+
function defineCli$1(cli) {
|
|
7592
|
+
checkOwnCodes(cli);
|
|
6670
7593
|
if (cli.commands === void 0) return cli;
|
|
6671
7594
|
const { commands } = cli;
|
|
6672
7595
|
const taken = Object.keys(builtInCommands(cli, void 0)).filter((name) => commands[name] !== void 0);
|
|
6673
7596
|
if (taken.length > 0) throw new Error(`${cli.name} defines ${taken.join(", ")}, a built-in Command it cannot replace`);
|
|
6674
|
-
return cli;
|
|
6675
|
-
}
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
description: command.description,
|
|
6685
|
-
effect: command.effect,
|
|
6686
|
-
examples: command.examples,
|
|
6687
|
-
args: argFields(command.args),
|
|
6688
|
-
options: optionFields(command.options),
|
|
6689
|
-
standardFlags: standardFlagsFor(command.effect, list),
|
|
6690
|
-
list,
|
|
6691
|
-
output: list?.output ?? command.output
|
|
6692
|
-
};
|
|
6693
|
-
}
|
|
6694
|
-
function groupSpec(commandLine, commands) {
|
|
6695
|
-
return {
|
|
6696
|
-
kind: "group",
|
|
6697
|
-
commandLine,
|
|
6698
|
-
commands: Object.fromEntries(Object.entries(commands).map(([key, node]) => [key, specOf(`${commandLine} ${key}`, node)]))
|
|
6699
|
-
};
|
|
6700
|
-
}
|
|
6701
|
-
function specOf(commandLine, node) {
|
|
6702
|
-
return isCommand(node) ? commandSpec(commandLine, node) : groupSpec(commandLine, node);
|
|
6703
|
-
}
|
|
6704
|
-
//#endregion
|
|
6705
|
-
//#region ../agent-cli/dist/confirm.js
|
|
6706
|
-
function checkConfirmation({ invocation, commandLine, given }, expected) {
|
|
6707
|
-
if (given === expected) return;
|
|
6708
|
-
const hint = `to confirm, run \`${commandLineWith(invocation, CONFIRM_FLAG.flag, expected)}\``;
|
|
6709
|
-
if (given === void 0) throw new UsageError({
|
|
6710
|
-
code: "CONFIRMATION_REQUIRED",
|
|
6711
|
-
message: `\`${commandLine}\` is destructive and needs ${CONFIRM_FLAG.flag}`,
|
|
6712
|
-
hint
|
|
6713
|
-
});
|
|
6714
|
-
throw new UsageError({
|
|
6715
|
-
code: "CONFIRMATION_MISMATCH",
|
|
6716
|
-
message: `${CONFIRM_FLAG.flag} ${JSON.stringify(given)} does not match the target of \`${commandLine}\``,
|
|
6717
|
-
hint
|
|
6718
|
-
});
|
|
6719
|
-
}
|
|
6720
|
-
//#endregion
|
|
6721
|
-
//#region ../agent-cli/dist/execute.js
|
|
6722
|
-
function outcomeOf(value, render) {
|
|
6723
|
-
return {
|
|
6724
|
-
value,
|
|
6725
|
-
render: (style) => render(value, style)
|
|
6726
|
-
};
|
|
6727
|
-
}
|
|
6728
|
-
/** How the Command prints data it fails with, which is the data its `run` or `apply` returns. */
|
|
6729
|
-
function renderOf(command) {
|
|
6730
|
-
return (data, style) => command.render(data, style);
|
|
6731
|
-
}
|
|
6732
|
-
async function execute(command, input, ctx, { dryRun, confirm, page, invocation, commandLine }) {
|
|
6733
|
-
if (command.rows !== void 0) return outcomeOf(await command.run({
|
|
6734
|
-
...input,
|
|
6735
|
-
...page
|
|
6736
|
-
}, ctx), (data, style) => command.render(data, style));
|
|
6737
|
-
if (command.effect === "read") return outcomeOf(await command.run(input, ctx), (data, style) => command.render(data, style));
|
|
6738
|
-
const plan = await command.plan(input, ctx);
|
|
6739
|
-
if (dryRun) return outcomeOf(plan, (value, style) => command.renderPlan(value, style));
|
|
6740
|
-
if (command.effect === "destructive") checkConfirmation({
|
|
6741
|
-
invocation,
|
|
6742
|
-
commandLine,
|
|
6743
|
-
given: confirm
|
|
6744
|
-
}, command.confirm(plan));
|
|
6745
|
-
return outcomeOf(await command.apply(plan, ctx), (data, style) => command.render(data, style));
|
|
6746
|
-
}
|
|
6747
|
-
//#endregion
|
|
6748
|
-
//#region ../agent-cli/dist/help.js
|
|
6749
|
-
function table(rows) {
|
|
6750
|
-
const width = Math.max(...rows.map(([left]) => left.length));
|
|
6751
|
-
return rows.map(([left, right]) => right === "" ? ` ${left}` : ` ${left.padEnd(width)} ${right}`);
|
|
6752
|
-
}
|
|
6753
|
-
function section(title, rows, style) {
|
|
6754
|
-
return rows.length === 0 ? [] : [
|
|
6755
|
-
"",
|
|
6756
|
-
style.bold(`${title}:`),
|
|
6757
|
-
...table(rows)
|
|
6758
|
-
];
|
|
6759
|
-
}
|
|
6760
|
-
function summaryOf(node) {
|
|
6761
|
-
return node.kind === "command" ? node.description : `group: ${Object.keys(node.commands).join(", ")}`;
|
|
6762
|
-
}
|
|
6763
|
-
function commandRows({ commands }) {
|
|
6764
|
-
return Object.entries(commands).map(([key, node]) => [key, summaryOf(node)]);
|
|
6765
|
-
}
|
|
6766
|
-
function lines(...parts) {
|
|
6767
|
-
return `${parts.join("\n")}\n`;
|
|
6768
|
-
}
|
|
6769
|
-
function listing(heading, group, style) {
|
|
6770
|
-
return lines(style.bold(heading), ...section("Commands", commandRows(group), style), "", `Run \`${group.commandLine} <command> --help\` for its examples and input.`);
|
|
6771
|
-
}
|
|
6772
|
-
function cliHelp(version, root, style) {
|
|
6773
|
-
return listing(`${root.commandLine} ${version}`, root, style);
|
|
6774
|
-
}
|
|
6775
|
-
function groupHelp(group, style) {
|
|
6776
|
-
return listing(group.commandLine, group, style);
|
|
6777
|
-
}
|
|
6778
|
-
const EFFECT_NOTES = {
|
|
6779
|
-
read: "changes nothing",
|
|
6780
|
-
write: "changes something; show the Plan with --dry-run",
|
|
6781
|
-
destructive: "changes something hard to undo; show the Plan with --dry-run, run with --confirm"
|
|
6782
|
-
};
|
|
6783
|
-
function choicesOf(field) {
|
|
6784
|
-
return field.choices === void 0 ? [] : [`one of: ${field.choices.join(", ")}`];
|
|
6785
|
-
}
|
|
6786
|
-
function defaultsOf(field) {
|
|
6787
|
-
if (field.defaultValue === void 0) return [];
|
|
6788
|
-
if (field.type !== "boolean") return [`default: ${JSON.stringify(field.defaultValue)}`];
|
|
6789
|
-
return field.defaultValue === true ? ["on by default; this flag turns it off"] : [];
|
|
6790
|
-
}
|
|
6791
|
-
function fieldRow(field, notes) {
|
|
6792
|
-
const all = [...field.required ? ["required"] : [], ...notes];
|
|
6793
|
-
const suffix = all.length === 0 ? "" : `(${all.join("; ")})`;
|
|
6794
|
-
return [field.usage, [field.description ?? "", suffix].filter((part) => part !== "").join(" ")];
|
|
6795
|
-
}
|
|
6796
|
-
function argRow(field) {
|
|
6797
|
-
return fieldRow(field, [...choicesOf(field), ...defaultsOf(field)]);
|
|
6798
|
-
}
|
|
6799
|
-
function optionRow(field) {
|
|
6800
|
-
return fieldRow(field, defaultsOf(field));
|
|
6801
|
-
}
|
|
6802
|
-
function flagRow({ usage, description }) {
|
|
6803
|
-
return [usage, description];
|
|
6804
|
-
}
|
|
6805
|
-
function commandHelp(spec, style) {
|
|
6806
|
-
return lines(style.bold(spec.commandLine), spec.description, ...section("Examples", spec.examples.map(({ command, note }) => [command, note]), style), ...section("Arguments", spec.args.map(argRow), style), ...section("Options", spec.options.map(optionRow), style), "", `${style.bold("Effect:")} ${spec.effect} (${EFFECT_NOTES[spec.effect]})`, ...section("Standard flags", spec.standardFlags.map(flagRow), style));
|
|
6807
|
-
}
|
|
6808
|
-
//#endregion
|
|
6809
|
-
//#region ../agent-cli/dist/help-json.js
|
|
6810
|
-
function inputSchema(schema) {
|
|
6811
|
-
return toJSONSchema(schema, {
|
|
6812
|
-
io: "input",
|
|
6813
|
-
unrepresentable: "any"
|
|
6814
|
-
});
|
|
6815
|
-
}
|
|
6816
|
-
function optionsSchema(options) {
|
|
6817
|
-
return inputSchema(object(Object.fromEntries(options.map(({ name, schema }) => [name, schema]))));
|
|
6818
|
-
}
|
|
6819
|
-
function commandData(spec) {
|
|
6820
|
-
return {
|
|
6821
|
-
name: spec.commandLine,
|
|
6822
|
-
description: spec.description,
|
|
6823
|
-
effect: spec.effect,
|
|
6824
|
-
examples: spec.examples,
|
|
6825
|
-
args: inputSchema(spec.command.args ?? object({})),
|
|
6826
|
-
options: optionsSchema(spec.options),
|
|
6827
|
-
standardFlags: spec.standardFlags.map(({ usage, description, schema }) => ({
|
|
6828
|
-
usage,
|
|
6829
|
-
description,
|
|
6830
|
-
schema: inputSchema(schema)
|
|
6831
|
-
})),
|
|
6832
|
-
output: spec.output === void 0 ? null : toJSONSchema(spec.output, { unrepresentable: "any" })
|
|
7597
|
+
return cli;
|
|
7598
|
+
}
|
|
7599
|
+
/**
|
|
7600
|
+
* Declares the CLI's ports and its Project file's settings once; the `defineCommand` and
|
|
7601
|
+
* `defineCli` it returns type `ctx.ports` and `ctx.project`.
|
|
7602
|
+
*/
|
|
7603
|
+
function agentCli() {
|
|
7604
|
+
return {
|
|
7605
|
+
defineCommand: defineCommandFor(),
|
|
7606
|
+
defineCli: defineCli$1
|
|
6833
7607
|
};
|
|
6834
7608
|
}
|
|
6835
|
-
|
|
6836
|
-
|
|
7609
|
+
//#endregion
|
|
7610
|
+
//#region ../agent-cli/dist/error-table.js
|
|
7611
|
+
/** Keeps each code's literal class and `details` schema, so `cliError` can type its throw sites. */
|
|
7612
|
+
function defineErrors(table) {
|
|
7613
|
+
return table;
|
|
6837
7614
|
}
|
|
6838
|
-
|
|
7615
|
+
/** A `CliError` for a code of `table`, whose `details` must match the code's schema. */
|
|
7616
|
+
function cliError(_table, code, init, options) {
|
|
7617
|
+
return new CliError({
|
|
7618
|
+
...init,
|
|
7619
|
+
code
|
|
7620
|
+
}, options);
|
|
7621
|
+
}
|
|
7622
|
+
//#endregion
|
|
7623
|
+
//#region ../agent-cli/dist/command-spec.js
|
|
7624
|
+
function declaredOf(command) {
|
|
7625
|
+
if (!hasPlan(command)) return {
|
|
7626
|
+
outputs: false,
|
|
7627
|
+
force: void 0,
|
|
7628
|
+
cost: false
|
|
7629
|
+
};
|
|
6839
7630
|
return {
|
|
6840
|
-
|
|
6841
|
-
|
|
7631
|
+
outputs: command.outputs !== void 0,
|
|
7632
|
+
force: command.force,
|
|
7633
|
+
cost: command.cost !== void 0
|
|
6842
7634
|
};
|
|
6843
7635
|
}
|
|
6844
|
-
function
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
7636
|
+
function commandSpec(commandLine, command) {
|
|
7637
|
+
const list = command.rows === void 0 ? void 0 : listSpec(command.rows);
|
|
7638
|
+
return {
|
|
7639
|
+
kind: "command",
|
|
7640
|
+
commandLine,
|
|
7641
|
+
command,
|
|
7642
|
+
description: command.description,
|
|
7643
|
+
effect: command.effect,
|
|
7644
|
+
examples: command.examples,
|
|
7645
|
+
args: argFields(command.args),
|
|
7646
|
+
options: optionFields(command.options),
|
|
7647
|
+
standardFlags: standardFlagsFor(command.effect, declaredOf(command), list),
|
|
7648
|
+
list,
|
|
7649
|
+
output: list?.output ?? command.output
|
|
7650
|
+
};
|
|
6853
7651
|
}
|
|
6854
|
-
function
|
|
6855
|
-
return
|
|
7652
|
+
function groupSpec(commandLine, commands) {
|
|
7653
|
+
return {
|
|
7654
|
+
kind: "group",
|
|
7655
|
+
commandLine,
|
|
7656
|
+
commands: Object.fromEntries(Object.entries(commands).map(([key, node]) => [key, specOf(`${commandLine} ${key}`, node)]))
|
|
7657
|
+
};
|
|
6856
7658
|
}
|
|
6857
|
-
function
|
|
6858
|
-
return
|
|
7659
|
+
function specOf(commandLine, node) {
|
|
7660
|
+
return isCommand(node) ? commandSpec(commandLine, node) : groupSpec(commandLine, node);
|
|
6859
7661
|
}
|
|
6860
7662
|
//#endregion
|
|
6861
|
-
//#region ../agent-cli/dist/
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
7663
|
+
//#region ../agent-cli/dist/execute.js
|
|
7664
|
+
function outcomeOf(value, render) {
|
|
7665
|
+
return {
|
|
7666
|
+
value,
|
|
7667
|
+
render: (style) => render(value, style)
|
|
7668
|
+
};
|
|
6867
7669
|
}
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
if (fields === void 0) return json ? `${JSON.stringify(page)}\n` : `${withTrailingNewline(render(style))}${pageFooter(page)}`;
|
|
6872
|
-
const rows = projected(page.items, fields);
|
|
6873
|
-
return json ? `${JSON.stringify({
|
|
6874
|
-
...page,
|
|
6875
|
-
items: rows
|
|
6876
|
-
})}\n` : `${renderRows(rows, fields)}${pageFooter(page)}`;
|
|
7670
|
+
/** Delivered data as the Command prints it, which is the data its `run` or `apply` returns. */
|
|
7671
|
+
function deliveredOutcome(command, data) {
|
|
7672
|
+
return outcomeOf(data, command.render);
|
|
6877
7673
|
}
|
|
6878
|
-
function
|
|
7674
|
+
function dryRunOutcome(command, plan) {
|
|
7675
|
+
const renderPlan = (style) => command.renderPlan(plan, style);
|
|
7676
|
+
if (command.outputs === void 0 && command.cost === void 0) return {
|
|
7677
|
+
value: plan,
|
|
7678
|
+
render: renderPlan
|
|
7679
|
+
};
|
|
7680
|
+
const outputs = command.outputs?.(plan);
|
|
7681
|
+
const cost = command.cost?.(plan);
|
|
6879
7682
|
return {
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
|
|
7683
|
+
value: {
|
|
7684
|
+
plan,
|
|
7685
|
+
...outputs === void 0 ? {} : { outputs },
|
|
7686
|
+
...command.cost === void 0 ? {} : { cost: cost ?? null }
|
|
7687
|
+
},
|
|
7688
|
+
render: (style) => [
|
|
7689
|
+
renderPlan(style),
|
|
7690
|
+
...outputs === void 0 ? [] : ["outputs:", ...outputs.map((path) => ` ${path}`)],
|
|
7691
|
+
...cost === void 0 ? [] : [`cost: ${cost}`]
|
|
7692
|
+
].join("\n")
|
|
6883
7693
|
};
|
|
6884
7694
|
}
|
|
6885
|
-
function
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
|
|
7695
|
+
async function execute(command, input, ctx, { dryRun, confirm, yes, page, invocation, commandLine, started }) {
|
|
7696
|
+
await checkTools(command.tools ?? [], ctx.env);
|
|
7697
|
+
if (command.rows !== void 0) return outcomeOf(await command.run({
|
|
7698
|
+
...input,
|
|
7699
|
+
...page
|
|
7700
|
+
}, ctx), (data, style) => command.render(data, style));
|
|
7701
|
+
if (command.effect === "read") return outcomeOf(await command.run(input, ctx), (data, style) => command.render(data, style));
|
|
7702
|
+
if (command.effect === "serve") {
|
|
7703
|
+
await started(outcomeOf(await command.start(input, ctx), (value, style) => command.render(value, style)));
|
|
7704
|
+
return untilAborted(ctx.signal);
|
|
6893
7705
|
}
|
|
6894
|
-
const
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
};
|
|
7706
|
+
const plan = await command.plan(input, ctx);
|
|
7707
|
+
if (dryRun) return dryRunOutcome(command, plan);
|
|
7708
|
+
await checkOutputs({
|
|
7709
|
+
invocation,
|
|
7710
|
+
commandLine,
|
|
7711
|
+
force: ctx.force,
|
|
7712
|
+
files: ctx.files
|
|
7713
|
+
}, command.outputs?.(plan));
|
|
7714
|
+
checkCost({
|
|
7715
|
+
invocation,
|
|
7716
|
+
commandLine,
|
|
7717
|
+
yes
|
|
7718
|
+
}, command.cost?.(plan));
|
|
7719
|
+
if (command.effect === "destructive") checkConfirmation({
|
|
7720
|
+
invocation,
|
|
7721
|
+
commandLine,
|
|
7722
|
+
given: confirm
|
|
7723
|
+
}, command.confirm(plan));
|
|
7724
|
+
return outcomeOf(await command.apply(plan, ctx), (data, style) => command.render(data, style));
|
|
6902
7725
|
}
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
7726
|
+
//#endregion
|
|
7727
|
+
//#region ../agent-cli/dist/files.js
|
|
7728
|
+
const TEMP_FILE = /^\..+\.agent-cli-(\d+)\.tmp$/;
|
|
7729
|
+
function tempPathOf(path) {
|
|
7730
|
+
return join(dirname(path), `.${basename(path)}.agent-cli-${process.pid}.tmp`);
|
|
7731
|
+
}
|
|
7732
|
+
function isAlive(pid) {
|
|
7733
|
+
try {
|
|
7734
|
+
process.kill(pid, 0);
|
|
7735
|
+
return true;
|
|
7736
|
+
} catch (error) {
|
|
7737
|
+
return errnoOf(error) === "EPERM";
|
|
6907
7738
|
}
|
|
6908
|
-
if (node.kind === "command") return commandHelp(node, style);
|
|
6909
|
-
return node === root ? cliHelp(cli.version, node, style) : groupHelp(node, style);
|
|
6910
7739
|
}
|
|
6911
|
-
function
|
|
7740
|
+
async function sweep(folder) {
|
|
7741
|
+
const dead = (await readdir(folder)).filter((name) => {
|
|
7742
|
+
const pid = TEMP_FILE.exec(name)?.[1];
|
|
7743
|
+
return pid !== void 0 && !isAlive(Number(pid));
|
|
7744
|
+
});
|
|
7745
|
+
await Promise.all(dead.map((name) => rm(join(folder, name), { force: true })));
|
|
7746
|
+
}
|
|
7747
|
+
/** Real files for one run: the first write to each folder sweeps the temp files of dead writers. */
|
|
7748
|
+
function realFiles() {
|
|
7749
|
+
const swept = /* @__PURE__ */ new Set();
|
|
6912
7750
|
return {
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
7751
|
+
exists: async (path) => {
|
|
7752
|
+
try {
|
|
7753
|
+
await access(path);
|
|
7754
|
+
return true;
|
|
7755
|
+
} catch (error) {
|
|
7756
|
+
if (isMissingFile(error)) return false;
|
|
7757
|
+
throw error;
|
|
7758
|
+
}
|
|
7759
|
+
},
|
|
7760
|
+
write: async (path, data) => {
|
|
7761
|
+
const folder = dirname(path);
|
|
7762
|
+
await mkdir(folder, { recursive: true });
|
|
7763
|
+
if (!swept.has(folder)) {
|
|
7764
|
+
await sweep(folder);
|
|
7765
|
+
swept.add(folder);
|
|
7766
|
+
}
|
|
7767
|
+
const temp = tempPathOf(path);
|
|
7768
|
+
try {
|
|
7769
|
+
await writeFile(temp, data);
|
|
7770
|
+
await rename(temp, path);
|
|
7771
|
+
} catch (error) {
|
|
7772
|
+
await rm(temp, { force: true });
|
|
7773
|
+
throw error;
|
|
7774
|
+
}
|
|
7775
|
+
},
|
|
7776
|
+
read: (path) => readFile(path),
|
|
7777
|
+
list: (folder) => readdir(folder),
|
|
7778
|
+
remove: (path) => rm(path, {
|
|
7779
|
+
recursive: true,
|
|
7780
|
+
force: true
|
|
7781
|
+
}),
|
|
7782
|
+
mkdir: async (path, options) => {
|
|
7783
|
+
if (options?.exclusive !== true) {
|
|
7784
|
+
await mkdir(path, { recursive: true });
|
|
7785
|
+
return;
|
|
7786
|
+
}
|
|
7787
|
+
await mkdir(dirname(path), { recursive: true });
|
|
7788
|
+
await mkdir(path);
|
|
7789
|
+
}
|
|
6916
7790
|
};
|
|
6917
7791
|
}
|
|
6918
|
-
|
|
7792
|
+
/**
|
|
7793
|
+
* `files` resolving paths against `cwd`, its failures classified by errno; `list` drops the
|
|
7794
|
+
* Runtime's temp files and sorts.
|
|
7795
|
+
*/
|
|
7796
|
+
function classifiedFiles(files, { cwd, env, callerLine }) {
|
|
7797
|
+
async function at(access, path, work) {
|
|
7798
|
+
const target = resolve(cwd, path);
|
|
7799
|
+
try {
|
|
7800
|
+
return await work(target);
|
|
7801
|
+
} catch (error) {
|
|
7802
|
+
throw classifyErrno(error, {
|
|
7803
|
+
path: target,
|
|
7804
|
+
access,
|
|
7805
|
+
callerLine,
|
|
7806
|
+
env
|
|
7807
|
+
});
|
|
7808
|
+
}
|
|
7809
|
+
}
|
|
6919
7810
|
return {
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
7811
|
+
exists: (path) => at("read", path, (target) => files.exists(target)),
|
|
7812
|
+
write: (path, data) => at("write", path, (target) => files.write(target, data)),
|
|
7813
|
+
read: (path) => at("read", path, (target) => files.read(target)),
|
|
7814
|
+
list: (folder) => at("read", folder, async (target) => (await files.list(target)).filter((name) => !TEMP_FILE.test(name)).sort()),
|
|
7815
|
+
remove: (path) => at("write", path, (target) => files.remove(target)),
|
|
7816
|
+
mkdir: (path, options) => at("write", path, (target) => files.mkdir(target, options))
|
|
6923
7817
|
};
|
|
6924
7818
|
}
|
|
6925
7819
|
//#endregion
|
|
7820
|
+
//#region ../agent-cli/dist/package-root.js
|
|
7821
|
+
/**
|
|
7822
|
+
* The nearest folder holding a `package.json`, searched upward from the bin or, run without one,
|
|
7823
|
+
* from `cwd`; the search's start when none holds one. The bin is resolved through links first,
|
|
7824
|
+
* since npm's global bin is a link to it.
|
|
7825
|
+
*/
|
|
7826
|
+
function packageRootOf(bin, cwd) {
|
|
7827
|
+
const start = bin === void 0 ? resolve(cwd) : dirname(realpathSync(bin));
|
|
7828
|
+
for (let dir = start;; dir = dirname(dir)) {
|
|
7829
|
+
if (existsSync(join(dir, "package.json"))) return dir;
|
|
7830
|
+
if (dirname(dir) === dir) return start;
|
|
7831
|
+
}
|
|
7832
|
+
}
|
|
7833
|
+
//#endregion
|
|
6926
7834
|
//#region ../agent-cli/dist/suggest.js
|
|
6927
7835
|
const MAX_DISTANCE = 3;
|
|
6928
7836
|
const MIN_SIMILARITY = .4;
|
|
@@ -7047,40 +7955,6 @@ function tokenize(words, known) {
|
|
|
7047
7955
|
};
|
|
7048
7956
|
}
|
|
7049
7957
|
//#endregion
|
|
7050
|
-
//#region ../agent-cli/dist/usage.js
|
|
7051
|
-
function unknownError({ code, problem, commandLine, corrections, listed }) {
|
|
7052
|
-
return new UsageError({
|
|
7053
|
-
code,
|
|
7054
|
-
message: `${problem} for \`${commandLine}\``,
|
|
7055
|
-
hint: corrections.length === 0 ? `run \`${commandLine} --help\` to see the ${listed}` : `did you mean ${corrections.map((correction) => `\`${correction}\``).join(" or ")}?`
|
|
7056
|
-
});
|
|
7057
|
-
}
|
|
7058
|
-
function unknownOptionError(commandLine, invocation, flag, suggestions) {
|
|
7059
|
-
return unknownError({
|
|
7060
|
-
code: "UNKNOWN_OPTION",
|
|
7061
|
-
problem: `unknown option '${flag}'`,
|
|
7062
|
-
commandLine,
|
|
7063
|
-
corrections: suggestions.map((name) => commandLineRenaming(invocation, /* @__PURE__ */ new Map([[flag, name]]))),
|
|
7064
|
-
listed: "options"
|
|
7065
|
-
});
|
|
7066
|
-
}
|
|
7067
|
-
function unknownCommandError(commandLine, name, suggestions) {
|
|
7068
|
-
return unknownError({
|
|
7069
|
-
code: "UNKNOWN_COMMAND",
|
|
7070
|
-
problem: `unknown command '${name}'`,
|
|
7071
|
-
commandLine,
|
|
7072
|
-
corrections: suggestions.map((suggestion) => `${commandLine} ${suggestion}`),
|
|
7073
|
-
listed: "commands"
|
|
7074
|
-
});
|
|
7075
|
-
}
|
|
7076
|
-
function invalidInputError(commandLine, problem) {
|
|
7077
|
-
return new UsageError({
|
|
7078
|
-
code: "INVALID_INPUT",
|
|
7079
|
-
message: problem,
|
|
7080
|
-
hint: `run \`${commandLine} --help\` to see the expected input`
|
|
7081
|
-
});
|
|
7082
|
-
}
|
|
7083
|
-
//#endregion
|
|
7084
7958
|
//#region ../agent-cli/dist/parse-input.js
|
|
7085
7959
|
const NO_INPUT = object({});
|
|
7086
7960
|
function knownFlags(spec) {
|
|
@@ -7112,10 +7986,14 @@ function optionValue(field, raw) {
|
|
|
7112
7986
|
return field.type === "boolean" && raw === true && field.label === `--no-${field.name}` ? false : raw;
|
|
7113
7987
|
}
|
|
7114
7988
|
function converted(field, raw) {
|
|
7989
|
+
if (Array.isArray(raw)) return raw.map((element) => converted(field, element));
|
|
7115
7990
|
if (field.type !== "number" || typeof raw !== "string" || raw.trim() === "") return raw;
|
|
7116
7991
|
const number = Number(raw);
|
|
7117
7992
|
return Number.isNaN(number) ? raw : number;
|
|
7118
7993
|
}
|
|
7994
|
+
function variadicValue(field, values) {
|
|
7995
|
+
return values.length === 0 && !field.required ? void 0 : values;
|
|
7996
|
+
}
|
|
7119
7997
|
function parse(schema, values) {
|
|
7120
7998
|
const input = Object.fromEntries([...values].filter(([, raw]) => raw !== void 0).map(([field, raw]) => [field.key, converted(field, raw)]));
|
|
7121
7999
|
return schema.safeParse(input);
|
|
@@ -7127,9 +8005,15 @@ function issueLines(result, values, howToPass, reported) {
|
|
|
7127
8005
|
if (field === void 0) return [` ${issue.message}`];
|
|
7128
8006
|
if (reported.includes(field)) return [];
|
|
7129
8007
|
const raw = values.get(field);
|
|
7130
|
-
|
|
8008
|
+
if (raw === void 0) return [` ${field.label}: required, ${howToPass(field)}`];
|
|
8009
|
+
return Array.isArray(raw) ? [operandsIssueLine(field, raw, issue, [...values.keys()].indexOf(field) + 1)] : [` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`];
|
|
7131
8010
|
});
|
|
7132
8011
|
}
|
|
8012
|
+
function operandsIssueLine(field, raw, issue, first) {
|
|
8013
|
+
const [, element] = issue.path;
|
|
8014
|
+
if (typeof element === "number") return ` ${field.label} ${JSON.stringify(raw[element])} (argument ${first + element}): ${issue.message}`;
|
|
8015
|
+
return raw.length === 0 ? ` ${field.label}: ${issue.message}, pass them as arguments from ${first}` : ` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`;
|
|
8016
|
+
}
|
|
7133
8017
|
function unknownLine({ flag, suggestion }) {
|
|
7134
8018
|
return ` unknown option '${flag}'${suggestion === void 0 ? "" : ` (did you mean ${suggestion}?)`}`;
|
|
7135
8019
|
}
|
|
@@ -7137,7 +8021,7 @@ function invalidInput(commandLine, invocation, unknown, otherLines) {
|
|
|
7137
8021
|
const renames = new Map(unknown.flatMap(({ flag, suggestion }) => suggestion === void 0 ? [] : [[flag, suggestion]]));
|
|
7138
8022
|
const correctable = otherLines.length === 0 && renames.size === unknown.length;
|
|
7139
8023
|
return new UsageError({
|
|
7140
|
-
code:
|
|
8024
|
+
code: INVALID_INPUT,
|
|
7141
8025
|
message: [
|
|
7142
8026
|
`invalid input for \`${commandLine}\``,
|
|
7143
8027
|
...unknown.map(unknownLine),
|
|
@@ -7153,7 +8037,8 @@ function parseInput(spec, words, invocation) {
|
|
|
7153
8037
|
const { operands, unknownOptions, values } = tokenize(words, known);
|
|
7154
8038
|
if (values.get(CONFIRM_FLAG.flag) === true) throw invalidInputError(spec.commandLine, `option '${CONFIRM_FLAG.usage}' argument missing`);
|
|
7155
8039
|
const missing = [...optionFields, ...pageFields].filter((field) => field.type !== "boolean" && values.get(field.label) === true);
|
|
7156
|
-
const argValues = new Map(argFields.map((field, index) => [field, operands[index]?.value]));
|
|
8040
|
+
const argValues = new Map(argFields.map((field, index) => [field, field.variadic ? variadicValue(field, operands.slice(index).filter((operand) => !operand.afterUnknownOption).map((operand) => operand.value)) : operands[index]?.value]));
|
|
8041
|
+
const extraOperands = argFields.some((field) => field.variadic) ? [] : operands.slice(argFields.length);
|
|
7157
8042
|
const valuesOf = (fields) => new Map(fields.map((field) => [field, missing.includes(field) ? void 0 : optionValue(field, values.get(field.label))]));
|
|
7158
8043
|
const optionValues = valuesOf(optionFields);
|
|
7159
8044
|
const pageValues = valuesOf(pageFields);
|
|
@@ -7163,7 +8048,7 @@ function parseInput(spec, words, invocation) {
|
|
|
7163
8048
|
const unknown = unknownOptionsOf(unknownOptions, candidateFlags(known));
|
|
7164
8049
|
const otherLines = [
|
|
7165
8050
|
...missing.map((field) => ` ${field.label}: missing value, pass ${field.usage}`),
|
|
7166
|
-
...
|
|
8051
|
+
...extraOperands.filter((operand) => !operand.afterUnknownOption).map((operand) => ` unexpected argument ${JSON.stringify(operand.value)}`),
|
|
7167
8052
|
...issueLines(args, argValues, (field) => `pass it as argument ${argFields.indexOf(field) + 1}`, []),
|
|
7168
8053
|
...issueLines(options, optionValues, (field) => `pass ${field.usage}`, missing),
|
|
7169
8054
|
...issueLines(page, pageValues, (field) => `pass ${field.usage}`, missing)
|
|
@@ -7190,6 +8075,8 @@ function parseCommand({ spec, words, json }, invocation) {
|
|
|
7190
8075
|
json,
|
|
7191
8076
|
dryRun: values.get(DRY_RUN_FLAG.flag) === true,
|
|
7192
8077
|
confirm: typeof confirm === "string" ? confirm : void 0,
|
|
8078
|
+
yes: values.get(YES_FLAG.flag) === true,
|
|
8079
|
+
force: values.get(FORCE_FLAG.flag) === true,
|
|
7193
8080
|
page,
|
|
7194
8081
|
fields: spec.list === void 0 ? void 0 : selectedFields(values, spec.list.rowFields, spec.commandLine)
|
|
7195
8082
|
}
|
|
@@ -7244,6 +8131,7 @@ function walk(node, words, json, invocation) {
|
|
|
7244
8131
|
return {
|
|
7245
8132
|
kind: "usage error",
|
|
7246
8133
|
error: unknownOptionError(node.commandLine, invocation, first, suggestions),
|
|
8134
|
+
node,
|
|
7247
8135
|
json
|
|
7248
8136
|
};
|
|
7249
8137
|
}
|
|
@@ -7254,6 +8142,7 @@ function unknownCommand(group, name, json) {
|
|
|
7254
8142
|
return {
|
|
7255
8143
|
kind: "usage error",
|
|
7256
8144
|
error: unknownCommandError(group.commandLine, name, suggestions),
|
|
8145
|
+
node: group,
|
|
7257
8146
|
json
|
|
7258
8147
|
};
|
|
7259
8148
|
}
|
|
@@ -7269,19 +8158,102 @@ function route(root, invocation) {
|
|
|
7269
8158
|
return walk(root, argv.filter((word, index) => !(index < options.length && word === JSON_FLAG.flag)), json, invocation);
|
|
7270
8159
|
}
|
|
7271
8160
|
//#endregion
|
|
8161
|
+
//#region ../agent-cli/dist/secrets.js
|
|
8162
|
+
function dotenvPath(cliName, env) {
|
|
8163
|
+
const config = env.XDG_CONFIG_HOME || join(env.HOME || homedir(), ".config");
|
|
8164
|
+
return join(config, cliName, ".env");
|
|
8165
|
+
}
|
|
8166
|
+
function readDotenv(path, env, callerLine) {
|
|
8167
|
+
let text;
|
|
8168
|
+
try {
|
|
8169
|
+
text = readFileSync(path, "utf8");
|
|
8170
|
+
} catch (error) {
|
|
8171
|
+
if (isMissingFile(error)) return {};
|
|
8172
|
+
throw classifyErrno(error, {
|
|
8173
|
+
path,
|
|
8174
|
+
access: "read",
|
|
8175
|
+
callerLine,
|
|
8176
|
+
env
|
|
8177
|
+
});
|
|
8178
|
+
}
|
|
8179
|
+
return parseEnv(text);
|
|
8180
|
+
}
|
|
8181
|
+
/** Looks `name` up in the env, then in `$XDG_CONFIG_HOME/<cli>/.env`; an empty value counts as unset. */
|
|
8182
|
+
function secretOf({ cliName, env, callerLine }, name) {
|
|
8183
|
+
const fromEnv = env[name];
|
|
8184
|
+
if (fromEnv) return {
|
|
8185
|
+
value: fromEnv,
|
|
8186
|
+
origin: { kind: "env" }
|
|
8187
|
+
};
|
|
8188
|
+
const path = dotenvPath(cliName, env);
|
|
8189
|
+
const fromFile = readDotenv(path, env, callerLine)[name];
|
|
8190
|
+
return fromFile ? {
|
|
8191
|
+
value: fromFile,
|
|
8192
|
+
origin: {
|
|
8193
|
+
kind: "file",
|
|
8194
|
+
path
|
|
8195
|
+
}
|
|
8196
|
+
} : void 0;
|
|
8197
|
+
}
|
|
8198
|
+
//#endregion
|
|
8199
|
+
//#region ../agent-cli/dist/spill.js
|
|
8200
|
+
const STDOUT_BUDGET_CHARS = 3e4;
|
|
8201
|
+
const SPILL_RETENTION_MS = 6048e5;
|
|
8202
|
+
const PREVIEW_CHARS = 2e3;
|
|
8203
|
+
const SPILL_FILE = /^\d{4}-\d\d-\d\dT\d\d-\d\d-\d\d\.\d{3}Z-.+\.(json|txt)$/;
|
|
8204
|
+
function spillName(now, commandName, json) {
|
|
8205
|
+
return `${new Date(now).toISOString().replaceAll(":", "-")}-${commandName}.${json ? "json" : "txt"}`;
|
|
8206
|
+
}
|
|
8207
|
+
async function pruneOne(path, cutoff) {
|
|
8208
|
+
try {
|
|
8209
|
+
if ((await stat(path)).mtimeMs < cutoff) await rm(path, { force: true });
|
|
8210
|
+
} catch (error) {
|
|
8211
|
+
if (!isMissingFile(error)) throw error;
|
|
8212
|
+
}
|
|
8213
|
+
}
|
|
8214
|
+
async function pruneOld(folder, cutoff) {
|
|
8215
|
+
const names = (await readdir(folder)).filter((name) => SPILL_FILE.test(name));
|
|
8216
|
+
await Promise.all(names.map((name) => pruneOne(join(folder, name), cutoff)));
|
|
8217
|
+
}
|
|
8218
|
+
async function prepare(folder, cutoff, target) {
|
|
8219
|
+
try {
|
|
8220
|
+
await mkdir(folder, { recursive: true });
|
|
8221
|
+
await pruneOld(folder, cutoff);
|
|
8222
|
+
} catch (error) {
|
|
8223
|
+
throw classifyErrno(error, {
|
|
8224
|
+
path: folder,
|
|
8225
|
+
access: "write",
|
|
8226
|
+
callerLine: target.callerLine,
|
|
8227
|
+
env: target.env
|
|
8228
|
+
});
|
|
8229
|
+
}
|
|
8230
|
+
}
|
|
8231
|
+
function tempRoot(env) {
|
|
8232
|
+
const { TMPDIR } = env;
|
|
8233
|
+
return TMPDIR === void 0 || TMPDIR === "" ? tmpdir() : TMPDIR;
|
|
8234
|
+
}
|
|
8235
|
+
function spillTo(target) {
|
|
8236
|
+
return async (printed, json) => {
|
|
8237
|
+
if (printed.length <= STDOUT_BUDGET_CHARS) return printed;
|
|
8238
|
+
const now = target.clock.now();
|
|
8239
|
+
const folder = join(tempRoot(target.env), target.cliName);
|
|
8240
|
+
await prepare(folder, now - SPILL_RETENTION_MS, target);
|
|
8241
|
+
const file = join(folder, spillName(now, target.commandName, json));
|
|
8242
|
+
await target.files.write(file, printed);
|
|
8243
|
+
const bytes = Buffer.byteLength(printed);
|
|
8244
|
+
const preview = printed.slice(0, PREVIEW_CHARS);
|
|
8245
|
+
return json ? `${JSON.stringify({
|
|
8246
|
+
file,
|
|
8247
|
+
bytes,
|
|
8248
|
+
preview
|
|
8249
|
+
})}\n` : `file: ${file}\nbytes: ${bytes}\npreview:\n${preview}\n`;
|
|
8250
|
+
};
|
|
8251
|
+
}
|
|
8252
|
+
//#endregion
|
|
7272
8253
|
//#region ../agent-cli/dist/style.js
|
|
7273
|
-
const AGENT_VARIABLES = [
|
|
7274
|
-
"CLAUDECODE",
|
|
7275
|
-
"CODEX_CI",
|
|
7276
|
-
"CODEX_SANDBOX",
|
|
7277
|
-
"GEMINI_CLI",
|
|
7278
|
-
"CURSOR_AGENT",
|
|
7279
|
-
"CI"
|
|
7280
|
-
];
|
|
7281
8254
|
function colourEnabled(env, stdoutIsTTY) {
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
return stdoutIsTTY && !noColor && !agent;
|
|
8255
|
+
if (env.NO_COLOR !== void 0 && env.NO_COLOR !== "") return false;
|
|
8256
|
+
return env.FORCE_COLOR !== void 0 && env.FORCE_COLOR !== "" && env.FORCE_COLOR !== "0" || stdoutIsTTY && !isAgent(env);
|
|
7285
8257
|
}
|
|
7286
8258
|
function sgr(open, close) {
|
|
7287
8259
|
return (text) => `\u001b[${open}m${text}\u001b[${close}m`;
|
|
@@ -7308,7 +8280,7 @@ function styleFor(env, stdoutIsTTY) {
|
|
|
7308
8280
|
}
|
|
7309
8281
|
//#endregion
|
|
7310
8282
|
//#region ../agent-cli/dist/run-cli.js
|
|
7311
|
-
async function runCommand(routed, { base, signal, format: baseFormat }) {
|
|
8283
|
+
async function runCommand(routed, { base, writeStdout, signal, format: baseFormat, ports, clock, files, spawn, projectFile }) {
|
|
7312
8284
|
const { command, commandLine } = routed.spec;
|
|
7313
8285
|
const format = {
|
|
7314
8286
|
...baseFormat,
|
|
@@ -7316,19 +8288,70 @@ async function runCommand(routed, { base, signal, format: baseFormat }) {
|
|
|
7316
8288
|
};
|
|
7317
8289
|
const { invocation } = format;
|
|
7318
8290
|
let parsed;
|
|
8291
|
+
let project;
|
|
7319
8292
|
try {
|
|
7320
8293
|
parsed = parseCommand(routed, invocation);
|
|
8294
|
+
project = projectFile === void 0 ? void 0 : projectOf(projectFile, base.cwd);
|
|
7321
8295
|
} catch (error) {
|
|
7322
8296
|
return errorResult(error, format);
|
|
7323
8297
|
}
|
|
7324
8298
|
const { input, flags } = parsed;
|
|
7325
|
-
const control = new RunControl(
|
|
8299
|
+
const control = new RunControl({
|
|
8300
|
+
commandLine,
|
|
8301
|
+
outer: signal,
|
|
8302
|
+
clock,
|
|
8303
|
+
progress: base.progress,
|
|
8304
|
+
runDeadline: command.deadline === void 0 ? void 0 : {
|
|
8305
|
+
ms: command.deadline.ms,
|
|
8306
|
+
hint: command.deadline.resume(input)
|
|
8307
|
+
}
|
|
8308
|
+
});
|
|
8309
|
+
let delivered;
|
|
8310
|
+
const callerLine = commandLineOf(invocation);
|
|
8311
|
+
const classified = classifiedFiles(files, {
|
|
8312
|
+
cwd: base.cwd,
|
|
8313
|
+
env: base.env,
|
|
8314
|
+
callerLine
|
|
8315
|
+
});
|
|
8316
|
+
const spill = spillTo({
|
|
8317
|
+
cliName: format.cliName,
|
|
8318
|
+
commandName: command.name,
|
|
8319
|
+
env: base.env,
|
|
8320
|
+
clock,
|
|
8321
|
+
files: classified,
|
|
8322
|
+
callerLine
|
|
8323
|
+
});
|
|
8324
|
+
const portsBase = {
|
|
8325
|
+
cwd: base.cwd,
|
|
8326
|
+
env: base.env,
|
|
8327
|
+
packageRoot: base.packageRoot,
|
|
8328
|
+
secret: base.secret,
|
|
8329
|
+
signal: control.signal,
|
|
8330
|
+
clock,
|
|
8331
|
+
files: classified,
|
|
8332
|
+
spawn: contextSpawn(spawn, {
|
|
8333
|
+
cwd: base.cwd,
|
|
8334
|
+
env: base.env,
|
|
8335
|
+
signal: control.signal
|
|
8336
|
+
}, callerLine)
|
|
8337
|
+
};
|
|
8338
|
+
const builtPorts = once(() => ports(portsBase));
|
|
7326
8339
|
const ctx = {
|
|
7327
8340
|
...base,
|
|
7328
|
-
|
|
8341
|
+
...portsBase,
|
|
7329
8342
|
deadline: (ms) => control.deadline(ms),
|
|
7330
|
-
runToEnd: (work) => control.runToEnd(work)
|
|
8343
|
+
runToEnd: (name, work) => control.runToEnd(name, work),
|
|
8344
|
+
get ports() {
|
|
8345
|
+
return builtPorts();
|
|
8346
|
+
},
|
|
8347
|
+
project,
|
|
8348
|
+
force: flags.force,
|
|
8349
|
+
poll: (check, { intervalMs }) => poll(clock, check, intervalMs, control.signal),
|
|
8350
|
+
deliver: (data) => {
|
|
8351
|
+
delivered = deliveredOutcome(command, data);
|
|
8352
|
+
}
|
|
7331
8353
|
};
|
|
8354
|
+
let served = false;
|
|
7332
8355
|
let settled;
|
|
7333
8356
|
try {
|
|
7334
8357
|
settled = {
|
|
@@ -7336,24 +8359,53 @@ async function runCommand(routed, { base, signal, format: baseFormat }) {
|
|
|
7336
8359
|
outcome: await control.settle(execute(command, input, ctx, {
|
|
7337
8360
|
dryRun: flags.dryRun,
|
|
7338
8361
|
confirm: flags.confirm,
|
|
8362
|
+
yes: flags.yes,
|
|
7339
8363
|
page: flags.page,
|
|
7340
8364
|
invocation,
|
|
7341
|
-
commandLine
|
|
8365
|
+
commandLine,
|
|
8366
|
+
started: async (outcome) => {
|
|
8367
|
+
writeStdout(await startedOutput(outcome, format, spill));
|
|
8368
|
+
served = true;
|
|
8369
|
+
}
|
|
7342
8370
|
}))
|
|
7343
8371
|
};
|
|
7344
8372
|
} catch (error) {
|
|
8373
|
+
if (served && control.signal.aborted) return STOPPED_RESULT;
|
|
7345
8374
|
settled = {
|
|
7346
8375
|
ok: false,
|
|
7347
8376
|
error: control.errorAfter(error),
|
|
7348
|
-
|
|
8377
|
+
delivered
|
|
7349
8378
|
};
|
|
7350
8379
|
}
|
|
7351
8380
|
return commandResult(settled, {
|
|
7352
8381
|
...format,
|
|
7353
8382
|
fields: flags.fields
|
|
7354
|
-
});
|
|
8383
|
+
}, spill);
|
|
8384
|
+
}
|
|
8385
|
+
/** `build` runs on the first call; later calls give its value or throw its error again. */
|
|
8386
|
+
function once(build) {
|
|
8387
|
+
let outcome;
|
|
8388
|
+
return () => {
|
|
8389
|
+
if (outcome === void 0) try {
|
|
8390
|
+
outcome = {
|
|
8391
|
+
ok: true,
|
|
8392
|
+
value: build()
|
|
8393
|
+
};
|
|
8394
|
+
} catch (error) {
|
|
8395
|
+
outcome = {
|
|
8396
|
+
ok: false,
|
|
8397
|
+
error
|
|
8398
|
+
};
|
|
8399
|
+
}
|
|
8400
|
+
if (outcome.ok) return outcome.value;
|
|
8401
|
+
throw outcome.error;
|
|
8402
|
+
};
|
|
7355
8403
|
}
|
|
7356
|
-
|
|
8404
|
+
function portsOf(cli, replacement) {
|
|
8405
|
+
if (replacement !== void 0) return () => replacement;
|
|
8406
|
+
return cli.ports ?? (() => ({}));
|
|
8407
|
+
}
|
|
8408
|
+
async function runWithProgress(cli, argv, options, write) {
|
|
7357
8409
|
const format = {
|
|
7358
8410
|
cliName: cli.name,
|
|
7359
8411
|
env: options.env,
|
|
@@ -7362,40 +8414,55 @@ async function runWithProgress(cli, argv, options, writeProgress) {
|
|
|
7362
8414
|
cliName: cli.name,
|
|
7363
8415
|
argv
|
|
7364
8416
|
},
|
|
7365
|
-
json: false
|
|
8417
|
+
json: false,
|
|
8418
|
+
errors: cli.errors ?? {},
|
|
8419
|
+
stop: options.signal
|
|
7366
8420
|
};
|
|
8421
|
+
const builtIns = cli.commands === void 0 ? {} : builtInCommands(cli, options.bin);
|
|
7367
8422
|
const root = cli.commands === void 0 ? commandSpec(cli.name, cli.command) : groupSpec(cli.name, {
|
|
7368
8423
|
...cli.commands,
|
|
7369
|
-
...
|
|
8424
|
+
...builtIns
|
|
7370
8425
|
});
|
|
7371
8426
|
const routed = route(root, format.invocation);
|
|
8427
|
+
const misused = (node) => isAgent(options.env) ? {
|
|
8428
|
+
...format,
|
|
8429
|
+
usageHelp: textHelp(node, root, cli, format.style)
|
|
8430
|
+
} : format;
|
|
7372
8431
|
switch (routed.kind) {
|
|
7373
|
-
case "version": return versionResult(cli);
|
|
8432
|
+
case "version": return versionResult(cli, packageRootOf(options.bin, options.cwd));
|
|
7374
8433
|
case "help": return helpResult(routed.node, root, cli, {
|
|
7375
8434
|
...format,
|
|
7376
8435
|
json: routed.json
|
|
7377
8436
|
});
|
|
7378
8437
|
case "usage error": return errorResult(routed.error, {
|
|
7379
|
-
...
|
|
8438
|
+
...misused(routed.node),
|
|
7380
8439
|
json: routed.json
|
|
7381
8440
|
});
|
|
7382
8441
|
case "command": return runCommand(routed, {
|
|
7383
8442
|
base: {
|
|
7384
8443
|
cwd: options.cwd,
|
|
7385
8444
|
env: options.env,
|
|
7386
|
-
|
|
8445
|
+
packageRoot: packageRootOf(options.bin, options.cwd),
|
|
8446
|
+
progress: (message) => write.stderr(`${message}\n`),
|
|
8447
|
+
secret: (name) => secretOf({
|
|
8448
|
+
cliName: cli.name,
|
|
8449
|
+
env: options.env,
|
|
8450
|
+
callerLine: commandLineOf(format.invocation)
|
|
8451
|
+
}, name)
|
|
7387
8452
|
},
|
|
8453
|
+
writeStdout: (text) => write.stdout(text),
|
|
7388
8454
|
signal: options.signal,
|
|
7389
|
-
format
|
|
8455
|
+
format: misused(routed.spec),
|
|
8456
|
+
ports: portsOf(cli, options.ports),
|
|
8457
|
+
clock: options.clock ?? realClock,
|
|
8458
|
+
files: options.files ?? realFiles(),
|
|
8459
|
+
spawn: options.spawn ?? realSpawn,
|
|
8460
|
+
projectFile: Object.values(builtIns).includes(routed.spec.command) ? void 0 : cli.project
|
|
7390
8461
|
});
|
|
7391
8462
|
}
|
|
7392
8463
|
}
|
|
7393
8464
|
//#endregion
|
|
7394
8465
|
//#region ../agent-cli/dist/run-process.js
|
|
7395
|
-
const SIGNAL_EXIT_CODES = {
|
|
7396
|
-
SIGINT: 130,
|
|
7397
|
-
SIGTERM: 143
|
|
7398
|
-
};
|
|
7399
8466
|
function written(stream, text) {
|
|
7400
8467
|
return new Promise((resolve) => stream.write(text, () => resolve()));
|
|
7401
8468
|
}
|
|
@@ -7404,7 +8471,7 @@ async function runProcess(cli) {
|
|
|
7404
8471
|
const onSignal = (signal) => {
|
|
7405
8472
|
if (stop.signal.aborted) process.exit(SIGNAL_EXIT_CODES[signal]);
|
|
7406
8473
|
process.stderr.write("\nstopping… (Ctrl-C again to quit now)\n");
|
|
7407
|
-
stop.abort();
|
|
8474
|
+
stop.abort(signal);
|
|
7408
8475
|
};
|
|
7409
8476
|
process.on("SIGINT", onSignal);
|
|
7410
8477
|
process.on("SIGTERM", onSignal);
|
|
@@ -7415,7 +8482,10 @@ async function runProcess(cli) {
|
|
|
7415
8482
|
stdoutIsTTY: process.stdout.isTTY === true,
|
|
7416
8483
|
signal: stop.signal,
|
|
7417
8484
|
bin: process.argv[1]
|
|
7418
|
-
},
|
|
8485
|
+
}, {
|
|
8486
|
+
stdout: (text) => process.stdout.write(text),
|
|
8487
|
+
stderr: (text) => process.stderr.write(text)
|
|
8488
|
+
});
|
|
7419
8489
|
await written(process.stdout, result.stdout);
|
|
7420
8490
|
await written(process.stderr, result.stderr);
|
|
7421
8491
|
process.exitCode = result.exitCode;
|
|
@@ -7428,11 +8498,13 @@ async function runProcess(cli) {
|
|
|
7428
8498
|
//#endregion
|
|
7429
8499
|
//#region src/build.ts
|
|
7430
8500
|
const build = {
|
|
7431
|
-
"sha": "
|
|
7432
|
-
"dirty": false
|
|
8501
|
+
"sha": "a7760d0",
|
|
8502
|
+
"dirty": false,
|
|
8503
|
+
"builtAt": "2026-10-19T10:55:24.637Z"
|
|
7433
8504
|
};
|
|
7434
8505
|
//#endregion
|
|
7435
8506
|
//#region src/steps.ts
|
|
8507
|
+
const stepErrors = defineErrors({ STEP_FAILED: { class: "operator" } });
|
|
7436
8508
|
const INSTALL = [{
|
|
7437
8509
|
command: "pnpm",
|
|
7438
8510
|
args: ["install"]
|
|
@@ -7501,11 +8573,9 @@ function tail(output) {
|
|
|
7501
8573
|
return output.trimEnd().split(/\r?\n/).slice(-20).join("\n");
|
|
7502
8574
|
}
|
|
7503
8575
|
function stepFailed(problem, left, cwd, cause) {
|
|
7504
|
-
return
|
|
7505
|
-
code: "STEP_FAILED",
|
|
8576
|
+
return cliError(stepErrors, "STEP_FAILED", {
|
|
7506
8577
|
message: problem,
|
|
7507
|
-
hint: `fix the problem, then run in ${cwd}: ${left.map(stepLine).join(" && ")}
|
|
7508
|
-
retryable: false
|
|
8578
|
+
hint: `fix the problem, then run in ${cwd}: ${left.map(stepLine).join(" && ")}`
|
|
7509
8579
|
}, { cause });
|
|
7510
8580
|
}
|
|
7511
8581
|
/** Runs each step in `cwd` in order, capturing its output so only the Runtime writes to stdout. */
|
|
@@ -7559,9 +8629,10 @@ async function writeTemplate(root, files, values) {
|
|
|
7559
8629
|
}
|
|
7560
8630
|
//#endregion
|
|
7561
8631
|
//#region src/version.ts
|
|
7562
|
-
const version = "0.
|
|
8632
|
+
const version = "0.4.0";
|
|
7563
8633
|
//#endregion
|
|
7564
8634
|
//#region src/create.ts
|
|
8635
|
+
const { defineCommand } = agentCli();
|
|
7565
8636
|
const PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?([a-z0-9][a-z0-9._-]*)$/;
|
|
7566
8637
|
function errorCode(error) {
|
|
7567
8638
|
return error instanceof Error && "code" in error ? error.code : void 0;
|
|
@@ -7582,64 +8653,69 @@ async function ensureFree(path) {
|
|
|
7582
8653
|
hint: "run `create-agent-cli <name>` with a name whose directory is free, or empty it first"
|
|
7583
8654
|
});
|
|
7584
8655
|
}
|
|
8656
|
+
const create = defineCommand({
|
|
8657
|
+
name: "create",
|
|
8658
|
+
description: "Create a new Agent CLI project in ./<name>",
|
|
8659
|
+
examples: [{
|
|
8660
|
+
command: "create-agent-cli weather --description \"Weather forecasts\"",
|
|
8661
|
+
note: "create ./weather, install dependencies and make the first commit"
|
|
8662
|
+
}],
|
|
8663
|
+
effect: "write",
|
|
8664
|
+
args: object({ name: string().regex(PACKAGE_NAME, "must be a lowercase npm package name, such as weather or @me/weather").describe("package name; its unscoped part names the bin and the directory") }),
|
|
8665
|
+
options: object({
|
|
8666
|
+
description: string().default("An Agent CLI.").describe("one line saying what the CLI does"),
|
|
8667
|
+
install: boolean().default(true).describe("run pnpm install"),
|
|
8668
|
+
git: boolean().default(true).describe("create a git repository with an initial commit")
|
|
8669
|
+
}),
|
|
8670
|
+
plan: async ({ name, description, install, git }, ctx) => {
|
|
8671
|
+
const binName = PACKAGE_NAME.exec(name)?.[1] ?? name;
|
|
8672
|
+
const path = resolve(ctx.cwd, binName);
|
|
8673
|
+
await ensureFree(path);
|
|
8674
|
+
const values = {
|
|
8675
|
+
packageName: name,
|
|
8676
|
+
binName,
|
|
8677
|
+
description,
|
|
8678
|
+
debugVariable: debugVariable(binName),
|
|
8679
|
+
runtimeVersion: version
|
|
8680
|
+
};
|
|
8681
|
+
return {
|
|
8682
|
+
path,
|
|
8683
|
+
values,
|
|
8684
|
+
files: await templateFiles(values),
|
|
8685
|
+
steps: stepsFor({
|
|
8686
|
+
install,
|
|
8687
|
+
git
|
|
8688
|
+
}),
|
|
8689
|
+
install
|
|
8690
|
+
};
|
|
8691
|
+
},
|
|
8692
|
+
apply: async (plan, ctx) => {
|
|
8693
|
+
await mkdir(plan.path, { recursive: true });
|
|
8694
|
+
await writeTemplate(plan.path, plan.files, plan.values);
|
|
8695
|
+
await runSteps(plan.steps, plan.path, ctx);
|
|
8696
|
+
return {
|
|
8697
|
+
path: plan.path,
|
|
8698
|
+
next: `cd ${plan.values.binName} && pnpm ${plan.install ? "test" : "install"}`
|
|
8699
|
+
};
|
|
8700
|
+
},
|
|
8701
|
+
render: ({ path, next }) => `Created ${path}\nnext: ${next}`,
|
|
8702
|
+
renderPlan: (plan) => [
|
|
8703
|
+
`Would create ${plan.path}:`,
|
|
8704
|
+
...plan.files.map((file) => ` create ${file.target}`),
|
|
8705
|
+
...plan.steps.map((step) => ` run ${stepLine(step)}`)
|
|
8706
|
+
].join("\n")
|
|
8707
|
+
});
|
|
8708
|
+
//#endregion
|
|
8709
|
+
//#region src/cli.ts
|
|
8710
|
+
const { defineCli } = agentCli();
|
|
7585
8711
|
//#endregion
|
|
7586
8712
|
//#region src/bin.ts
|
|
7587
8713
|
await runProcess(defineCli({
|
|
7588
8714
|
name: "create-agent-cli",
|
|
7589
8715
|
version,
|
|
7590
8716
|
build,
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
description: "Create a new Agent CLI project in ./<name>",
|
|
7594
|
-
examples: [{
|
|
7595
|
-
command: "create-agent-cli weather --description \"Weather forecasts\"",
|
|
7596
|
-
note: "create ./weather, install dependencies and make the first commit"
|
|
7597
|
-
}],
|
|
7598
|
-
effect: "write",
|
|
7599
|
-
args: object({ name: string().regex(PACKAGE_NAME, "must be a lowercase npm package name, such as weather or @me/weather").describe("package name; its unscoped part names the bin and the directory") }),
|
|
7600
|
-
options: object({
|
|
7601
|
-
description: string().default("An Agent CLI.").describe("one line saying what the CLI does"),
|
|
7602
|
-
install: boolean().default(true).describe("run pnpm install"),
|
|
7603
|
-
git: boolean().default(true).describe("create a git repository with an initial commit")
|
|
7604
|
-
}),
|
|
7605
|
-
plan: async ({ name, description, install, git }, ctx) => {
|
|
7606
|
-
const binName = PACKAGE_NAME.exec(name)?.[1] ?? name;
|
|
7607
|
-
const path = resolve(ctx.cwd, binName);
|
|
7608
|
-
await ensureFree(path);
|
|
7609
|
-
const values = {
|
|
7610
|
-
packageName: name,
|
|
7611
|
-
binName,
|
|
7612
|
-
description,
|
|
7613
|
-
debugVariable: debugVariable(binName),
|
|
7614
|
-
runtimeVersion: version
|
|
7615
|
-
};
|
|
7616
|
-
return {
|
|
7617
|
-
path,
|
|
7618
|
-
values,
|
|
7619
|
-
files: await templateFiles(values),
|
|
7620
|
-
steps: stepsFor({
|
|
7621
|
-
install,
|
|
7622
|
-
git
|
|
7623
|
-
}),
|
|
7624
|
-
install
|
|
7625
|
-
};
|
|
7626
|
-
},
|
|
7627
|
-
apply: async (plan, ctx) => {
|
|
7628
|
-
await mkdir(plan.path, { recursive: true });
|
|
7629
|
-
await writeTemplate(plan.path, plan.files, plan.values);
|
|
7630
|
-
await runSteps(plan.steps, plan.path, ctx);
|
|
7631
|
-
return {
|
|
7632
|
-
path: plan.path,
|
|
7633
|
-
next: `cd ${plan.values.binName} && pnpm ${plan.install ? "test" : "install"}`
|
|
7634
|
-
};
|
|
7635
|
-
},
|
|
7636
|
-
render: ({ path, next }) => `Created ${path}\nnext: ${next}`,
|
|
7637
|
-
renderPlan: (plan) => [
|
|
7638
|
-
`Would create ${plan.path}:`,
|
|
7639
|
-
...plan.files.map((file) => ` create ${file.target}`),
|
|
7640
|
-
...plan.steps.map((step) => ` run ${stepLine(step)}`)
|
|
7641
|
-
].join("\n")
|
|
7642
|
-
})
|
|
8717
|
+
errors: stepErrors,
|
|
8718
|
+
command: create
|
|
7643
8719
|
}));
|
|
7644
8720
|
//#endregion
|
|
7645
8721
|
export {};
|