@duyquangnvx/create-agent-cli 0.16.0 → 0.18.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 +76 -0
- package/README.md +3 -3
- package/agents-section.md +5 -0
- package/dist/bin.js +2301 -1209
- package/package.json +4 -3
- package/partials/global/skillCheck.md +1 -1
- package/template/AGENTS.md +4 -7
- package/template/package.json +1 -1
- package/template/scripts/release.ts +1 -1
- package/template/skills/{{binName}}/SKILL.md +3 -3
- package/template/src/cli.ts +14 -26
- package/template/test/cli.test.ts +27 -15
- package/template/tsdown.config.ts +1 -1
- package/template/src/build.ts +0 -6
package/dist/bin.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { parseArgs, parseEnv } from "node:util";
|
|
3
3
|
import { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
4
|
import { constants, existsSync, readFileSync, realpathSync } from "node:fs";
|
|
5
|
-
import { access, chmod, link, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
6
5
|
import { constants as constants$1, homedir, tmpdir } from "node:os";
|
|
6
|
+
import { access, chmod, link, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
7
7
|
import { spawn } from "node:child_process";
|
|
8
8
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
@@ -139,7 +139,7 @@ const allowsEval = /* @__PURE__*/ cached(() => {
|
|
|
139
139
|
return false;
|
|
140
140
|
}
|
|
141
141
|
});
|
|
142
|
-
function isPlainObject(o) {
|
|
142
|
+
function isPlainObject$1(o) {
|
|
143
143
|
if (isObject(o) === false) return false;
|
|
144
144
|
const ctor = o.constructor;
|
|
145
145
|
if (ctor === void 0) return true;
|
|
@@ -150,7 +150,7 @@ function isPlainObject(o) {
|
|
|
150
150
|
return true;
|
|
151
151
|
}
|
|
152
152
|
function shallowClone(o) {
|
|
153
|
-
if (isPlainObject(o)) return { ...o };
|
|
153
|
+
if (isPlainObject$1(o)) return { ...o };
|
|
154
154
|
if (Array.isArray(o)) return [...o];
|
|
155
155
|
if (o instanceof Map) return new Map(o);
|
|
156
156
|
if (o instanceof Set) return new Set(o);
|
|
@@ -238,7 +238,7 @@ function omit(schema, mask) {
|
|
|
238
238
|
}));
|
|
239
239
|
}
|
|
240
240
|
function extend(schema, shape) {
|
|
241
|
-
if (!isPlainObject(shape)) throw new Error("Invalid input to extend: expected a plain object");
|
|
241
|
+
if (!isPlainObject$1(shape)) throw new Error("Invalid input to extend: expected a plain object");
|
|
242
242
|
const checks = schema._zod.def.checks;
|
|
243
243
|
if (checks && checks.length > 0) {
|
|
244
244
|
const existingShape = sourceShape(schema);
|
|
@@ -253,7 +253,7 @@ function extended(schema, shape) {
|
|
|
253
253
|
return newShape;
|
|
254
254
|
}
|
|
255
255
|
function safeExtend(schema, shape) {
|
|
256
|
-
if (!isPlainObject(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
|
|
256
|
+
if (!isPlainObject$1(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
|
|
257
257
|
return clone(schema, mergeDefs(schema._zod.def, { shape: extended(schema, shape) }));
|
|
258
258
|
}
|
|
259
259
|
function merge(a, b) {
|
|
@@ -2338,7 +2338,7 @@ function mergeValues(a, b) {
|
|
|
2338
2338
|
valid: true,
|
|
2339
2339
|
data: a
|
|
2340
2340
|
};
|
|
2341
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
2341
|
+
if (isPlainObject$1(a) && isPlainObject$1(b)) {
|
|
2342
2342
|
const bKeys = Object.keys(b);
|
|
2343
2343
|
const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
|
|
2344
2344
|
const newObj = {
|
|
@@ -2431,7 +2431,7 @@ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => {
|
|
|
2431
2431
|
memo?.attach(inst);
|
|
2432
2432
|
inst._zod.parse = (payload, ctx) => {
|
|
2433
2433
|
const input = payload.value;
|
|
2434
|
-
if (!isPlainObject(input)) {
|
|
2434
|
+
if (!isPlainObject$1(input)) {
|
|
2435
2435
|
payload.issues.push({
|
|
2436
2436
|
expected: "record",
|
|
2437
2437
|
code: "invalid_type",
|
|
@@ -4863,7 +4863,7 @@ const parse$1 = /* @__PURE__ */ _parse(ZodRealError);
|
|
|
4863
4863
|
const parseAsync = /* @__PURE__ */ _parseAsync(ZodRealError);
|
|
4864
4864
|
const safeParse = /* @__PURE__ */ _safeParse(ZodRealError);
|
|
4865
4865
|
const safeParseAsync = /* @__PURE__ */ _safeParseAsync(ZodRealError);
|
|
4866
|
-
const encode = /* @__PURE__ */ _encode(ZodRealError);
|
|
4866
|
+
const encode$1 = /* @__PURE__ */ _encode(ZodRealError);
|
|
4867
4867
|
const decode = /* @__PURE__ */ _decode(ZodRealError);
|
|
4868
4868
|
const encodeAsync = /* @__PURE__ */ _encodeAsync(ZodRealError);
|
|
4869
4869
|
const decodeAsync = /* @__PURE__ */ _decodeAsync(ZodRealError);
|
|
@@ -5015,7 +5015,7 @@ const ZodType = /*@__PURE__*/ $constructor("ZodType", (inst, def) => {
|
|
|
5015
5015
|
return validateAsync$1(this, data, params);
|
|
5016
5016
|
},
|
|
5017
5017
|
encode: function _encode(data, params) {
|
|
5018
|
-
return encode(this, data, params, { callee: _encode });
|
|
5018
|
+
return encode$1(this, data, params, { callee: _encode });
|
|
5019
5019
|
},
|
|
5020
5020
|
decode: function _decode(data, params) {
|
|
5021
5021
|
return decode(this, data, params, { callee: _decode });
|
|
@@ -5774,21 +5774,196 @@ async function poll(clock, check, intervalMs, signal) {
|
|
|
5774
5774
|
}
|
|
5775
5775
|
}
|
|
5776
5776
|
//#endregion
|
|
5777
|
+
//#region ../agent-cli/dist/command-line/tokenize.js
|
|
5778
|
+
const NEGATIVE_NUMBER = /^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/;
|
|
5779
|
+
function isOptionLike(word) {
|
|
5780
|
+
return word !== void 0 && word.length > 1 && word[0] === "-" && !NEGATIVE_NUMBER.test(word);
|
|
5781
|
+
}
|
|
5782
|
+
function parseArgsOptions(known) {
|
|
5783
|
+
return Object.fromEntries(known.map(({ flag, takes }) => [flag.slice(2), { type: takes === "value" ? "string" : "boolean" }]));
|
|
5784
|
+
}
|
|
5785
|
+
function flagItem(token, { flag, takes }, words) {
|
|
5786
|
+
if (takes !== "optional value" || token.inlineValue === true) return {
|
|
5787
|
+
kind: "flag",
|
|
5788
|
+
flag,
|
|
5789
|
+
value: token.value ?? true
|
|
5790
|
+
};
|
|
5791
|
+
const took = token.index + 1;
|
|
5792
|
+
const next = words[took];
|
|
5793
|
+
return next === void 0 || isOptionLike(next) ? {
|
|
5794
|
+
kind: "flag",
|
|
5795
|
+
flag,
|
|
5796
|
+
value: true
|
|
5797
|
+
} : {
|
|
5798
|
+
kind: "flag",
|
|
5799
|
+
flag,
|
|
5800
|
+
value: next,
|
|
5801
|
+
took
|
|
5802
|
+
};
|
|
5803
|
+
}
|
|
5804
|
+
function itemOf(token, words, byFlag) {
|
|
5805
|
+
const word = words[token.index] ?? "";
|
|
5806
|
+
if (token.kind === "option-terminator") return { kind: "end" };
|
|
5807
|
+
if (token.kind === "positional" || NEGATIVE_NUMBER.test(word)) return {
|
|
5808
|
+
kind: "operand",
|
|
5809
|
+
value: word
|
|
5810
|
+
};
|
|
5811
|
+
const flag = byFlag.get(token.rawName);
|
|
5812
|
+
return flag === void 0 || flag.takes === "nothing" && token.inlineValue === true ? {
|
|
5813
|
+
kind: "unknown option",
|
|
5814
|
+
word
|
|
5815
|
+
} : flagItem(token, flag, words);
|
|
5816
|
+
}
|
|
5817
|
+
/** Splits a Command's words into operands, unknown options and the values of known flags. */
|
|
5818
|
+
function tokenize(words, known) {
|
|
5819
|
+
const byFlag = new Map(known.map((flag) => [flag.flag, flag]));
|
|
5820
|
+
const { tokens } = parseArgs({
|
|
5821
|
+
args: [...words],
|
|
5822
|
+
options: parseArgsOptions(known),
|
|
5823
|
+
strict: false,
|
|
5824
|
+
allowPositionals: true,
|
|
5825
|
+
tokens: true
|
|
5826
|
+
});
|
|
5827
|
+
const operands = [];
|
|
5828
|
+
const unknownOptions = [];
|
|
5829
|
+
const occurrences = /* @__PURE__ */ new Map();
|
|
5830
|
+
const done = /* @__PURE__ */ new Set();
|
|
5831
|
+
let literal = false;
|
|
5832
|
+
let afterUnknownOption = false;
|
|
5833
|
+
for (const token of tokens) {
|
|
5834
|
+
if (done.has(token.index)) continue;
|
|
5835
|
+
done.add(token.index);
|
|
5836
|
+
const item = itemOf(token, words, byFlag);
|
|
5837
|
+
if (item.kind === "end") literal = true;
|
|
5838
|
+
else if (item.kind === "operand") {
|
|
5839
|
+
operands.push({
|
|
5840
|
+
value: item.value,
|
|
5841
|
+
afterUnknownOption: !literal && afterUnknownOption
|
|
5842
|
+
});
|
|
5843
|
+
afterUnknownOption = false;
|
|
5844
|
+
} else if (item.kind === "unknown option") {
|
|
5845
|
+
unknownOptions.push(item.word);
|
|
5846
|
+
afterUnknownOption = true;
|
|
5847
|
+
} else {
|
|
5848
|
+
occurrences.set(item.flag, [...occurrences.get(item.flag) ?? [], item.value]);
|
|
5849
|
+
if (item.took !== void 0) done.add(item.took);
|
|
5850
|
+
}
|
|
5851
|
+
}
|
|
5852
|
+
return {
|
|
5853
|
+
operands,
|
|
5854
|
+
unknownOptions,
|
|
5855
|
+
values: new Map([...occurrences].map(([flag, all]) => [flag, all[all.length - 1] ?? true])),
|
|
5856
|
+
occurrences
|
|
5857
|
+
};
|
|
5858
|
+
}
|
|
5859
|
+
const SHELL_SAFE = /^[\w@%+=:,./-]+$/;
|
|
5860
|
+
function quoted$1(token) {
|
|
5861
|
+
return SHELL_SAFE.test(token) ? token : `'${token.replaceAll("'", `'\\''`)}'`;
|
|
5862
|
+
}
|
|
5863
|
+
function pasteable(runAs, tokens, stdinArg) {
|
|
5864
|
+
const line = [runAs, ...tokens.map(quoted$1)].join(" ");
|
|
5865
|
+
return stdinArg === void 0 ? line : `${line} < <${stdinArg} file>`;
|
|
5866
|
+
}
|
|
5867
|
+
function split(argv) {
|
|
5868
|
+
const end = argv.indexOf("--");
|
|
5869
|
+
return end === -1 ? {
|
|
5870
|
+
options: [...argv],
|
|
5871
|
+
operands: []
|
|
5872
|
+
} : {
|
|
5873
|
+
options: argv.slice(0, end),
|
|
5874
|
+
operands: argv.slice(end)
|
|
5875
|
+
};
|
|
5876
|
+
}
|
|
5877
|
+
function tookValue(takes, next) {
|
|
5878
|
+
return takes === "value" || takes === "optional value" && next !== void 0 && !isOptionLike(next);
|
|
5879
|
+
}
|
|
5880
|
+
function without(flag, takes, tokens) {
|
|
5881
|
+
const kept = [];
|
|
5882
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
5883
|
+
const token = tokens[index] ?? "";
|
|
5884
|
+
if (token === flag) {
|
|
5885
|
+
if (tookValue(takes, tokens[index + 1])) index += 1;
|
|
5886
|
+
} else if (!token.startsWith(`${flag}=`)) kept.push(token);
|
|
5887
|
+
}
|
|
5888
|
+
return kept;
|
|
5889
|
+
}
|
|
5890
|
+
/**
|
|
5891
|
+
* The caller's words after the CLI's name, with each flag in `remove` dropped along with its value
|
|
5892
|
+
* and the words in `add` placed before any `--`.
|
|
5893
|
+
*/
|
|
5894
|
+
function changedArgv({ argv, flags }, { add = [], remove = [] } = {}) {
|
|
5895
|
+
const { options, operands } = split(argv);
|
|
5896
|
+
const takes = new Map(flags.map((known) => [known.flag, known.takes]));
|
|
5897
|
+
return [
|
|
5898
|
+
...remove.reduce((tokens, flag) => without(flag, takes.get(flag) ?? "nothing", tokens), options),
|
|
5899
|
+
...add,
|
|
5900
|
+
...operands
|
|
5901
|
+
];
|
|
5902
|
+
}
|
|
5903
|
+
/** The caller's command line as typed, ready to paste, changed as `changedArgv` does, the stdin arg's file redirected in. */
|
|
5904
|
+
function commandLineOf(invocation, change) {
|
|
5905
|
+
return pasteable(invocation.runAs, changedArgv(invocation, change), invocation.stdinArg);
|
|
5906
|
+
}
|
|
5907
|
+
function renamed(token, renames) {
|
|
5908
|
+
const [flag = token, ...value] = token.split("=");
|
|
5909
|
+
const name = renames.get(flag);
|
|
5910
|
+
if (name === void 0) return token;
|
|
5911
|
+
return value.length === 0 ? name : `${name}=${value.join("=")}`;
|
|
5912
|
+
}
|
|
5913
|
+
/** The caller's command line, ready to paste, with each flag in `renames` typed as its new name. */
|
|
5914
|
+
function commandLineRenaming({ runAs, argv, stdinArg }, renames) {
|
|
5915
|
+
const { options, operands } = split(argv);
|
|
5916
|
+
return pasteable(runAs, [...options.map((token) => renamed(token, renames)), ...operands], stdinArg);
|
|
5917
|
+
}
|
|
5918
|
+
//#endregion
|
|
5919
|
+
//#region ../agent-cli/dist/next-step.js
|
|
5920
|
+
function wholeLine(line) {
|
|
5921
|
+
return {
|
|
5922
|
+
kind: "line",
|
|
5923
|
+
line
|
|
5924
|
+
};
|
|
5925
|
+
}
|
|
5926
|
+
function isWords(step) {
|
|
5927
|
+
return Array.isArray(step);
|
|
5928
|
+
}
|
|
5929
|
+
/** The words after the Run-as, or `undefined` for a line given whole. */
|
|
5930
|
+
function wordsOf(step) {
|
|
5931
|
+
if (isWords(step)) return step;
|
|
5932
|
+
return step.kind === "rerun" ? step.words : void 0;
|
|
5933
|
+
}
|
|
5934
|
+
/** The Next step as one shell-quoted line starting with the Run-as, or the whole line as given. */
|
|
5935
|
+
function lineOf(step, runAs) {
|
|
5936
|
+
if (isWords(step)) return pasteable(runAs, step);
|
|
5937
|
+
return step.kind === "rerun" ? pasteable(runAs, step.words, step.stdinArg) : step.line;
|
|
5938
|
+
}
|
|
5939
|
+
//#endregion
|
|
5777
5940
|
//#region ../agent-cli/dist/errors.js
|
|
5778
5941
|
var CliError = class extends Error {
|
|
5779
5942
|
code;
|
|
5780
5943
|
hint;
|
|
5781
5944
|
details;
|
|
5782
5945
|
retryAt;
|
|
5783
|
-
|
|
5946
|
+
next;
|
|
5947
|
+
constructor({ code, message, hint, details, retryAt, next = [] }, options) {
|
|
5784
5948
|
super(message, options);
|
|
5785
5949
|
this.name = "CliError";
|
|
5786
5950
|
this.code = code;
|
|
5787
5951
|
this.hint = hint;
|
|
5788
5952
|
this.details = details;
|
|
5789
5953
|
this.retryAt = retryAt;
|
|
5954
|
+
this.next = next;
|
|
5790
5955
|
}
|
|
5791
5956
|
};
|
|
5957
|
+
var RuntimeError = class extends CliError {
|
|
5958
|
+
constructor({ next, ...fields }, options) {
|
|
5959
|
+
super(fields, options);
|
|
5960
|
+
this.next = next;
|
|
5961
|
+
}
|
|
5962
|
+
};
|
|
5963
|
+
/** A `CliError` whose Next steps may hold a line given whole, which only the Runtime builds. */
|
|
5964
|
+
function runtimeError(fields, options) {
|
|
5965
|
+
return new RuntimeError(fields, options);
|
|
5966
|
+
}
|
|
5792
5967
|
/** The caller called the Agent CLI wrong; the same call can't succeed. */
|
|
5793
5968
|
var UsageError = class extends CliError {
|
|
5794
5969
|
constructor(fields) {
|
|
@@ -5834,21 +6009,28 @@ function bugHint(format) {
|
|
|
5834
6009
|
return bugs === void 0 ? rerun : `${rerun}, then report it at ${bugs}`;
|
|
5835
6010
|
}
|
|
5836
6011
|
function fieldsOf$1(error, format) {
|
|
5837
|
-
if (error instanceof CliError) {
|
|
5838
|
-
const { code, message, hint, details, retryAt } = error;
|
|
5839
|
-
return {
|
|
5840
|
-
code,
|
|
5841
|
-
message,
|
|
5842
|
-
hint: format.isBug(error) ? bugHint(format) : hint,
|
|
5843
|
-
details,
|
|
5844
|
-
retryAt
|
|
5845
|
-
};
|
|
5846
|
-
}
|
|
5847
|
-
return {
|
|
6012
|
+
if (!(error instanceof CliError)) return {
|
|
5848
6013
|
code: INTERNAL,
|
|
5849
6014
|
message: messageOf(error),
|
|
5850
6015
|
hint: bugHint(format)
|
|
5851
6016
|
};
|
|
6017
|
+
const { code, message, hint, details, retryAt, next } = error;
|
|
6018
|
+
if (format.isBug(error)) return {
|
|
6019
|
+
code,
|
|
6020
|
+
message,
|
|
6021
|
+
hint: bugHint(format),
|
|
6022
|
+
details,
|
|
6023
|
+
retryAt
|
|
6024
|
+
};
|
|
6025
|
+
const lines = next.map((step) => lineOf(step, format.runAs));
|
|
6026
|
+
return {
|
|
6027
|
+
code,
|
|
6028
|
+
message,
|
|
6029
|
+
hint,
|
|
6030
|
+
details,
|
|
6031
|
+
retryAt,
|
|
6032
|
+
...lines.length === 0 ? {} : { next: lines }
|
|
6033
|
+
};
|
|
5852
6034
|
}
|
|
5853
6035
|
function causesOf(error) {
|
|
5854
6036
|
return error instanceof Error && error.cause !== void 0 ? [error.cause, ...causesOf(error.cause)] : [];
|
|
@@ -5884,7 +6066,8 @@ function errorLines(error, format) {
|
|
|
5884
6066
|
const { style } = format;
|
|
5885
6067
|
const label = style.red(format.isBug(error) ? "internal error:" : "error:");
|
|
5886
6068
|
const between = blocks.map((block) => `${block}\n`).join("");
|
|
5887
|
-
|
|
6069
|
+
const runs = (fields.next ?? []).map((line) => `${style.cyan("run:")} ${line}\n`).join("");
|
|
6070
|
+
return `${label} ${fields.message}\n${between}${style.cyan("hint:")} ${fields.hint}\n${runs}`;
|
|
5888
6071
|
}
|
|
5889
6072
|
function formatRuntimeError(error, format) {
|
|
5890
6073
|
const errors = errorsOf(error);
|
|
@@ -5898,7 +6081,7 @@ function formatRuntimeError(error, format) {
|
|
|
5898
6081
|
return errors.map((each) => errorLines(each, format)).join("");
|
|
5899
6082
|
}
|
|
5900
6083
|
//#endregion
|
|
5901
|
-
//#region ../agent-cli/dist/stdin.js
|
|
6084
|
+
//#region ../agent-cli/dist/context/stdin.js
|
|
5902
6085
|
const STDIN_META = "stdin";
|
|
5903
6086
|
function isStdinSchema(schema) {
|
|
5904
6087
|
return globalRegistry$1.get(schema)?.[STDIN_META] === true;
|
|
@@ -5972,7 +6155,7 @@ function readStdin(source, signal, idle) {
|
|
|
5972
6155
|
});
|
|
5973
6156
|
}
|
|
5974
6157
|
//#endregion
|
|
5975
|
-
//#region ../agent-cli/dist/input.js
|
|
6158
|
+
//#region ../agent-cli/dist/command-line/input.js
|
|
5976
6159
|
function isWrapper(schema) {
|
|
5977
6160
|
return schema instanceof ZodOptional || schema instanceof ZodNullable || schema instanceof ZodDefault || schema instanceof ZodPrefault;
|
|
5978
6161
|
}
|
|
@@ -6074,190 +6257,52 @@ function checkNoBooleanArrayOption(name, options) {
|
|
|
6074
6257
|
if (booleans.length > 0) throw new Error(`Command '${name}' declares boolean array option ${keysOf(booleans)}; a switch cannot repeat, use a boolean`);
|
|
6075
6258
|
}
|
|
6076
6259
|
//#endregion
|
|
6077
|
-
//#region ../agent-cli/dist/
|
|
6078
|
-
const
|
|
6079
|
-
|
|
6080
|
-
|
|
6260
|
+
//#region ../agent-cli/dist/command-line/usage.js
|
|
6261
|
+
const INVALID_INPUT = "INVALID_INPUT";
|
|
6262
|
+
const UNKNOWN_OPTION = "UNKNOWN_OPTION";
|
|
6263
|
+
const UNKNOWN_COMMAND = "UNKNOWN_COMMAND";
|
|
6264
|
+
function unknownError({ code, problem, commandLine, corrections, listed }) {
|
|
6265
|
+
return new UsageError({
|
|
6266
|
+
code,
|
|
6267
|
+
message: `${problem} for \`${commandLine}\``,
|
|
6268
|
+
hint: corrections.length === 0 ? `run \`${commandLine} --help\` to see the ${listed}` : `did you mean ${corrections.map((correction) => `\`${correction}\``).join(" or ")}?`
|
|
6269
|
+
});
|
|
6081
6270
|
}
|
|
6082
|
-
function
|
|
6083
|
-
return
|
|
6271
|
+
function unknownOptionError(commandLine, invocation, flag, suggestions) {
|
|
6272
|
+
return unknownError({
|
|
6273
|
+
code: UNKNOWN_OPTION,
|
|
6274
|
+
problem: `unknown option '${flag}'`,
|
|
6275
|
+
commandLine,
|
|
6276
|
+
corrections: suggestions.map((name) => commandLineRenaming(invocation, /* @__PURE__ */ new Map([[flag, name]]))),
|
|
6277
|
+
listed: "options"
|
|
6278
|
+
});
|
|
6084
6279
|
}
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
};
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
value: true
|
|
6097
|
-
} : {
|
|
6098
|
-
kind: "flag",
|
|
6099
|
-
flag,
|
|
6100
|
-
value: next,
|
|
6101
|
-
took
|
|
6102
|
-
};
|
|
6280
|
+
/** Text opening with `-` was read as an option, where the Command could have read it from stdin. */
|
|
6281
|
+
function stdinTextError(commandLine, invocation, word) {
|
|
6282
|
+
const withStdin = commandLineOf(invocation, {
|
|
6283
|
+
remove: [word],
|
|
6284
|
+
add: ["-"]
|
|
6285
|
+
});
|
|
6286
|
+
return new UsageError({
|
|
6287
|
+
code: UNKNOWN_OPTION,
|
|
6288
|
+
message: `unknown option '${word}' for \`${commandLine}\``,
|
|
6289
|
+
hint: `to pass text opening with \`-\`, pass \`-\` and send the text on stdin through a heredoc: \`${withStdin} <<'EOF'\`, then the text, then \`EOF\``
|
|
6290
|
+
});
|
|
6103
6291
|
}
|
|
6104
|
-
function
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
return flag === void 0 || flag.takes === "nothing" && token.inlineValue === true ? {
|
|
6113
|
-
kind: "unknown option",
|
|
6114
|
-
word
|
|
6115
|
-
} : flagItem(token, flag, words);
|
|
6292
|
+
function unknownCommandError(commandLine, name, suggestions) {
|
|
6293
|
+
return unknownError({
|
|
6294
|
+
code: UNKNOWN_COMMAND,
|
|
6295
|
+
problem: `unknown command '${name}'`,
|
|
6296
|
+
commandLine,
|
|
6297
|
+
corrections: suggestions.map((suggestion) => `${commandLine} ${suggestion}`),
|
|
6298
|
+
listed: "commands"
|
|
6299
|
+
});
|
|
6116
6300
|
}
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
options: parseArgsOptions(known),
|
|
6123
|
-
strict: false,
|
|
6124
|
-
allowPositionals: true,
|
|
6125
|
-
tokens: true
|
|
6126
|
-
});
|
|
6127
|
-
const operands = [];
|
|
6128
|
-
const unknownOptions = [];
|
|
6129
|
-
const occurrences = /* @__PURE__ */ new Map();
|
|
6130
|
-
const done = /* @__PURE__ */ new Set();
|
|
6131
|
-
let literal = false;
|
|
6132
|
-
let afterUnknownOption = false;
|
|
6133
|
-
for (const token of tokens) {
|
|
6134
|
-
if (done.has(token.index)) continue;
|
|
6135
|
-
done.add(token.index);
|
|
6136
|
-
const item = itemOf(token, words, byFlag);
|
|
6137
|
-
if (item.kind === "end") literal = true;
|
|
6138
|
-
else if (item.kind === "operand") {
|
|
6139
|
-
operands.push({
|
|
6140
|
-
value: item.value,
|
|
6141
|
-
afterUnknownOption: !literal && afterUnknownOption
|
|
6142
|
-
});
|
|
6143
|
-
afterUnknownOption = false;
|
|
6144
|
-
} else if (item.kind === "unknown option") {
|
|
6145
|
-
unknownOptions.push(item.word);
|
|
6146
|
-
afterUnknownOption = true;
|
|
6147
|
-
} else {
|
|
6148
|
-
occurrences.set(item.flag, [...occurrences.get(item.flag) ?? [], item.value]);
|
|
6149
|
-
if (item.took !== void 0) done.add(item.took);
|
|
6150
|
-
}
|
|
6151
|
-
}
|
|
6152
|
-
return {
|
|
6153
|
-
operands,
|
|
6154
|
-
unknownOptions,
|
|
6155
|
-
values: new Map([...occurrences].map(([flag, all]) => [flag, all[all.length - 1] ?? true])),
|
|
6156
|
-
occurrences
|
|
6157
|
-
};
|
|
6158
|
-
}
|
|
6159
|
-
const SHELL_SAFE = /^[\w@%+=:,./-]+$/;
|
|
6160
|
-
function quoted$1(token) {
|
|
6161
|
-
return SHELL_SAFE.test(token) ? token : `'${token.replaceAll("'", `'\\''`)}'`;
|
|
6162
|
-
}
|
|
6163
|
-
function pasteable(runAs, tokens, stdinArg) {
|
|
6164
|
-
const line = [runAs, ...tokens.map(quoted$1)].join(" ");
|
|
6165
|
-
return stdinArg === void 0 ? line : `${line} < <${stdinArg} file>`;
|
|
6166
|
-
}
|
|
6167
|
-
function split(argv) {
|
|
6168
|
-
const end = argv.indexOf("--");
|
|
6169
|
-
return end === -1 ? {
|
|
6170
|
-
options: [...argv],
|
|
6171
|
-
operands: []
|
|
6172
|
-
} : {
|
|
6173
|
-
options: argv.slice(0, end),
|
|
6174
|
-
operands: argv.slice(end)
|
|
6175
|
-
};
|
|
6176
|
-
}
|
|
6177
|
-
function tookValue(takes, next) {
|
|
6178
|
-
return takes === "value" || takes === "optional value" && next !== void 0 && !isOptionLike(next);
|
|
6179
|
-
}
|
|
6180
|
-
function without(flag, takes, tokens) {
|
|
6181
|
-
const kept = [];
|
|
6182
|
-
for (let index = 0; index < tokens.length; index += 1) {
|
|
6183
|
-
const token = tokens[index] ?? "";
|
|
6184
|
-
if (token === flag) {
|
|
6185
|
-
if (tookValue(takes, tokens[index + 1])) index += 1;
|
|
6186
|
-
} else if (!token.startsWith(`${flag}=`)) kept.push(token);
|
|
6187
|
-
}
|
|
6188
|
-
return kept;
|
|
6189
|
-
}
|
|
6190
|
-
/**
|
|
6191
|
-
* The caller's command line as typed, ready to paste, with each flag in `remove` dropped along with
|
|
6192
|
-
* its value, the words in `add` placed before any `--`, and the stdin arg's file redirected in.
|
|
6193
|
-
*/
|
|
6194
|
-
function commandLineOf({ runAs, argv, flags, stdinArg }, { add = [], remove = [] } = {}) {
|
|
6195
|
-
const { options, operands } = split(argv);
|
|
6196
|
-
const takes = new Map(flags.map((known) => [known.flag, known.takes]));
|
|
6197
|
-
return pasteable(runAs, [
|
|
6198
|
-
...remove.reduce((tokens, flag) => without(flag, takes.get(flag) ?? "nothing", tokens), options),
|
|
6199
|
-
...add,
|
|
6200
|
-
...operands
|
|
6201
|
-
], stdinArg);
|
|
6202
|
-
}
|
|
6203
|
-
function renamed(token, renames) {
|
|
6204
|
-
const [flag = token, ...value] = token.split("=");
|
|
6205
|
-
const name = renames.get(flag);
|
|
6206
|
-
if (name === void 0) return token;
|
|
6207
|
-
return value.length === 0 ? name : `${name}=${value.join("=")}`;
|
|
6208
|
-
}
|
|
6209
|
-
/** The caller's command line, ready to paste, with each flag in `renames` typed as its new name. */
|
|
6210
|
-
function commandLineRenaming({ runAs, argv, stdinArg }, renames) {
|
|
6211
|
-
const { options, operands } = split(argv);
|
|
6212
|
-
return pasteable(runAs, [...options.map((token) => renamed(token, renames)), ...operands], stdinArg);
|
|
6213
|
-
}
|
|
6214
|
-
//#endregion
|
|
6215
|
-
//#region ../agent-cli/dist/usage.js
|
|
6216
|
-
const INVALID_INPUT = "INVALID_INPUT";
|
|
6217
|
-
const UNKNOWN_OPTION = "UNKNOWN_OPTION";
|
|
6218
|
-
const UNKNOWN_COMMAND = "UNKNOWN_COMMAND";
|
|
6219
|
-
function unknownError({ code, problem, commandLine, corrections, listed }) {
|
|
6220
|
-
return new UsageError({
|
|
6221
|
-
code,
|
|
6222
|
-
message: `${problem} for \`${commandLine}\``,
|
|
6223
|
-
hint: corrections.length === 0 ? `run \`${commandLine} --help\` to see the ${listed}` : `did you mean ${corrections.map((correction) => `\`${correction}\``).join(" or ")}?`
|
|
6224
|
-
});
|
|
6225
|
-
}
|
|
6226
|
-
function unknownOptionError(commandLine, invocation, flag, suggestions) {
|
|
6227
|
-
return unknownError({
|
|
6228
|
-
code: UNKNOWN_OPTION,
|
|
6229
|
-
problem: `unknown option '${flag}'`,
|
|
6230
|
-
commandLine,
|
|
6231
|
-
corrections: suggestions.map((name) => commandLineRenaming(invocation, /* @__PURE__ */ new Map([[flag, name]]))),
|
|
6232
|
-
listed: "options"
|
|
6233
|
-
});
|
|
6234
|
-
}
|
|
6235
|
-
/** Text opening with `-` was read as an option, where the Command could have read it from stdin. */
|
|
6236
|
-
function stdinTextError(commandLine, invocation, word) {
|
|
6237
|
-
const withStdin = commandLineOf(invocation, {
|
|
6238
|
-
remove: [word],
|
|
6239
|
-
add: ["-"]
|
|
6240
|
-
});
|
|
6241
|
-
return new UsageError({
|
|
6242
|
-
code: UNKNOWN_OPTION,
|
|
6243
|
-
message: `unknown option '${word}' for \`${commandLine}\``,
|
|
6244
|
-
hint: `to pass text opening with \`-\`, pass \`-\` and send the text on stdin through a heredoc: \`${withStdin} <<'EOF'\`, then the text, then \`EOF\``
|
|
6245
|
-
});
|
|
6246
|
-
}
|
|
6247
|
-
function unknownCommandError(commandLine, name, suggestions) {
|
|
6248
|
-
return unknownError({
|
|
6249
|
-
code: UNKNOWN_COMMAND,
|
|
6250
|
-
problem: `unknown command '${name}'`,
|
|
6251
|
-
commandLine,
|
|
6252
|
-
corrections: suggestions.map((suggestion) => `${commandLine} ${suggestion}`),
|
|
6253
|
-
listed: "commands"
|
|
6254
|
-
});
|
|
6255
|
-
}
|
|
6256
|
-
function invalidInputError(commandLine, problem) {
|
|
6257
|
-
return new UsageError({
|
|
6258
|
-
code: INVALID_INPUT,
|
|
6259
|
-
message: problem,
|
|
6260
|
-
hint: `run \`${commandLine} --help\` to see the expected input`
|
|
6301
|
+
function invalidInputError(commandLine, problem) {
|
|
6302
|
+
return new UsageError({
|
|
6303
|
+
code: INVALID_INPUT,
|
|
6304
|
+
message: problem,
|
|
6305
|
+
hint: `run \`${commandLine} --help\` to see the expected input`
|
|
6261
6306
|
});
|
|
6262
6307
|
}
|
|
6263
6308
|
//#endregion
|
|
@@ -6365,16 +6410,19 @@ function cursorWords(cursor) {
|
|
|
6365
6410
|
function printedPage(page, invocation) {
|
|
6366
6411
|
return page.nextCursor === void 0 ? { items: page.items } : {
|
|
6367
6412
|
items: page.items,
|
|
6368
|
-
next:
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6413
|
+
next: lineOf({
|
|
6414
|
+
kind: "rerun",
|
|
6415
|
+
words: changedArgv(invocation, {
|
|
6416
|
+
remove: [PAGE_FLAGS.cursor.flag],
|
|
6417
|
+
add: cursorWords(page.nextCursor)
|
|
6418
|
+
}),
|
|
6419
|
+
stdinArg: invocation.stdinArg
|
|
6420
|
+
}, invocation.runAs)
|
|
6372
6421
|
};
|
|
6373
6422
|
}
|
|
6374
|
-
/** The
|
|
6375
|
-
function pageFooter({ items, next }) {
|
|
6376
|
-
|
|
6377
|
-
return `${items.length} shown; ${more}\n`;
|
|
6423
|
+
/** The lines that end a rendered page, so the caller always knows whether and how to get more. */
|
|
6424
|
+
function pageFooter({ items, next }, style) {
|
|
6425
|
+
return next === void 0 ? `${items.length} shown; no more pages\n` : `${items.length} shown; run the Next step for the next page\n${style.cyan("run:")} ${next}\n`;
|
|
6378
6426
|
}
|
|
6379
6427
|
//#endregion
|
|
6380
6428
|
//#region ../agent-cli/dist/planned.js
|
|
@@ -6383,7 +6431,7 @@ function hasPlan(command) {
|
|
|
6383
6431
|
return command.effect === "write" || command.effect === "destructive";
|
|
6384
6432
|
}
|
|
6385
6433
|
//#endregion
|
|
6386
|
-
//#region ../agent-cli/dist/flags.js
|
|
6434
|
+
//#region ../agent-cli/dist/command-line/flags.js
|
|
6387
6435
|
const HELP_FLAG = "--help";
|
|
6388
6436
|
const VERSION_FLAG = "--version";
|
|
6389
6437
|
const ROUTING_FLAGS = [
|
|
@@ -6391,7 +6439,7 @@ const ROUTING_FLAGS = [
|
|
|
6391
6439
|
"-h",
|
|
6392
6440
|
VERSION_FLAG
|
|
6393
6441
|
];
|
|
6394
|
-
function nameOf(flag) {
|
|
6442
|
+
function nameOf$1(flag) {
|
|
6395
6443
|
return flag.replace(/^--?/, "");
|
|
6396
6444
|
}
|
|
6397
6445
|
function standardFlag(flag, { placeholder, ...rest }) {
|
|
@@ -6429,6 +6477,7 @@ const FORCE_FLAG = standardFlag("--force", {
|
|
|
6429
6477
|
});
|
|
6430
6478
|
const EFFECT_FLAGS = {
|
|
6431
6479
|
read: [JSON_FLAG],
|
|
6480
|
+
act: [JSON_FLAG],
|
|
6432
6481
|
write: [JSON_FLAG, DRY_RUN_FLAG],
|
|
6433
6482
|
destructive: [
|
|
6434
6483
|
JSON_FLAG,
|
|
@@ -6443,7 +6492,7 @@ const RESERVED = new Map([
|
|
|
6443
6492
|
YES_FLAG.flag,
|
|
6444
6493
|
FORCE_FLAG.flag,
|
|
6445
6494
|
...LIST_FLAGS
|
|
6446
|
-
].map((flag) => [nameOf(flag), flag]));
|
|
6495
|
+
].map((flag) => [nameOf$1(flag), flag]));
|
|
6447
6496
|
/** The Standard flags of a Command with this Effect and declarations, and of a List Command. */
|
|
6448
6497
|
function standardFlagsFor(effect, { outputs, force, cost }, list) {
|
|
6449
6498
|
const forceFlag = force === void 0 ? FORCE_FLAG : {
|
|
@@ -6458,7 +6507,7 @@ function standardFlagsFor(effect, { outputs, force, cost }, list) {
|
|
|
6458
6507
|
];
|
|
6459
6508
|
}
|
|
6460
6509
|
/** Throws when the Command declares an arg or option under a Standard flag's name. */
|
|
6461
|
-
function checkNoStandardFlags(command) {
|
|
6510
|
+
function checkNoStandardFlags(command, label) {
|
|
6462
6511
|
const lines = [...argFields(command.args).map(({ key }) => ({
|
|
6463
6512
|
kind: "arg",
|
|
6464
6513
|
key
|
|
@@ -6469,40 +6518,46 @@ function checkNoStandardFlags(command) {
|
|
|
6469
6518
|
const flag = RESERVED.get(kebab(key));
|
|
6470
6519
|
return flag === void 0 ? [] : [` ${kind} '${key}' is the Standard flag ${flag}`];
|
|
6471
6520
|
});
|
|
6472
|
-
if (lines.length > 0) throw new Error([`Command '${
|
|
6521
|
+
if (lines.length > 0) throw new Error([`Command '${label}' declares Standard flags the Runtime adds; rename them:`, ...lines].join("\n"));
|
|
6473
6522
|
}
|
|
6474
6523
|
/** Throws when `force` is declared on a Command with no Plan, or says nothing. */
|
|
6475
|
-
function checkForce(command) {
|
|
6524
|
+
function checkForce(command, label) {
|
|
6476
6525
|
const force = "force" in command ? command.force : void 0;
|
|
6477
6526
|
if (force === void 0) return;
|
|
6478
|
-
if (!hasPlan(command)) throw new Error(`Command '${
|
|
6479
|
-
if (force.trim() === "") throw new Error(`Command '${
|
|
6527
|
+
if (!hasPlan(command)) throw new Error(`Command '${label}' declares force, which only a write or destructive Command may`);
|
|
6528
|
+
if (force.trim() === "") throw new Error(`Command '${label}' declares an empty force; say what ${FORCE_FLAG.flag} replaces`);
|
|
6480
6529
|
}
|
|
6481
6530
|
//#endregion
|
|
6482
|
-
//#region ../agent-cli/dist/define.js
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6531
|
+
//#region ../agent-cli/dist/define-command.js
|
|
6532
|
+
/** Throws when the Command's declaration breaks a rule its type cannot express; `label` names it. */
|
|
6533
|
+
function checkCommand(command, label, table) {
|
|
6534
|
+
checkNoStandardFlags(command, label);
|
|
6535
|
+
checkForce(command, label);
|
|
6536
|
+
checkArrayArgLast(label, command.args);
|
|
6537
|
+
checkStdinFields(label, command.args, command.options);
|
|
6538
|
+
checkNoBooleanArrayOption(label, command.options);
|
|
6539
|
+
checkErrors(command, label, table);
|
|
6540
|
+
}
|
|
6541
|
+
function checkErrors(command, label, table) {
|
|
6542
|
+
const unknown = (command.errors ?? []).filter((code) => !Object.hasOwn(table, code));
|
|
6543
|
+
if (unknown.length > 0) throw new Error(`${label} declares ${unknown.join(", ")} in errors, a code the Error table lacks`);
|
|
6490
6544
|
}
|
|
6491
6545
|
function defineCommandFor() {
|
|
6492
|
-
return
|
|
6546
|
+
return declared;
|
|
6493
6547
|
}
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
return typeof node.effect === "string";
|
|
6548
|
+
function declared(command) {
|
|
6549
|
+
return command;
|
|
6497
6550
|
}
|
|
6551
|
+
const defineCommand$1 = defineCommandFor();
|
|
6498
6552
|
//#endregion
|
|
6499
|
-
//#region ../agent-cli/dist/project.js
|
|
6553
|
+
//#region ../agent-cli/dist/context/project.js
|
|
6500
6554
|
const PROJECT_INVALID = "PROJECT_INVALID";
|
|
6501
|
-
function invalid(path, problem,
|
|
6555
|
+
function invalid(path, problem, rerun, options) {
|
|
6502
6556
|
return new CliError({
|
|
6503
6557
|
code: PROJECT_INVALID,
|
|
6504
6558
|
message: `the Project file ${path} is invalid: ${problem}`,
|
|
6505
|
-
hint: `fix ${path}, then run
|
|
6559
|
+
hint: `fix ${path}, then run the Next step`,
|
|
6560
|
+
next: [rerun]
|
|
6506
6561
|
}, options);
|
|
6507
6562
|
}
|
|
6508
6563
|
function readText(path, fileError) {
|
|
@@ -6516,15 +6571,15 @@ function readText(path, fileError) {
|
|
|
6516
6571
|
});
|
|
6517
6572
|
}
|
|
6518
6573
|
}
|
|
6519
|
-
function parsed(path, text, schema,
|
|
6574
|
+
function parsed(path, text, schema, rerun) {
|
|
6520
6575
|
let json;
|
|
6521
6576
|
try {
|
|
6522
6577
|
json = JSON.parse(text);
|
|
6523
6578
|
} catch (error) {
|
|
6524
|
-
throw invalid(path, messageOf(error),
|
|
6579
|
+
throw invalid(path, messageOf(error), rerun, { cause: error });
|
|
6525
6580
|
}
|
|
6526
6581
|
const result = schema.safeParse(json);
|
|
6527
|
-
if (!result.success) throw invalid(path, prettifyError(result.error),
|
|
6582
|
+
if (!result.success) throw invalid(path, prettifyError(result.error), rerun);
|
|
6528
6583
|
return result.data;
|
|
6529
6584
|
}
|
|
6530
6585
|
function projectFrom(projectFile, folder, scope) {
|
|
@@ -6532,7 +6587,7 @@ function projectFrom(projectFile, folder, scope) {
|
|
|
6532
6587
|
const text = readText(path, scope.fileError);
|
|
6533
6588
|
if (text !== void 0) return {
|
|
6534
6589
|
root: folder,
|
|
6535
|
-
settings: parsed(path, text, projectFile.schema, scope.
|
|
6590
|
+
settings: parsed(path, text, projectFile.schema, scope.rerun)
|
|
6536
6591
|
};
|
|
6537
6592
|
const parent = dirname(folder);
|
|
6538
6593
|
return parent === folder ? void 0 : projectFrom(projectFile, parent, scope);
|
|
@@ -6542,7 +6597,110 @@ function projectOf(projectFile, cwd, scope) {
|
|
|
6542
6597
|
return projectFrom(projectFile, resolve(cwd), scope);
|
|
6543
6598
|
}
|
|
6544
6599
|
//#endregion
|
|
6545
|
-
//#region ../agent-cli/dist/
|
|
6600
|
+
//#region ../agent-cli/dist/define.js
|
|
6601
|
+
function isCommand(node) {
|
|
6602
|
+
return typeof node.effect === "string";
|
|
6603
|
+
}
|
|
6604
|
+
//#endregion
|
|
6605
|
+
//#region ../agent-cli/dist/context/declared.js
|
|
6606
|
+
/**
|
|
6607
|
+
* What the CLI declares itself (`own`) and every Command under `commands` declares, each name once,
|
|
6608
|
+
* for a `doctor` row: a Command requires only its own, but `doctor` checks them all.
|
|
6609
|
+
*/
|
|
6610
|
+
function declaredIn(own, commands, needsOf) {
|
|
6611
|
+
const walk = (node) => isCommand(node) ? [...needsOf(node) ?? []] : Object.values(node).flatMap(walk);
|
|
6612
|
+
return [...new Map([...own, ...walk(commands)].map((need) => [need.name, need])).values()];
|
|
6613
|
+
}
|
|
6614
|
+
//#endregion
|
|
6615
|
+
//#region ../agent-cli/dist/context/secrets.js
|
|
6616
|
+
const SECRET_MISSING = "SECRET_MISSING";
|
|
6617
|
+
/** `$XDG_CONFIG_HOME/<cli>/.env`, with `~/.config` when the variable is unset or empty. */
|
|
6618
|
+
function envFileOf(cliName, env) {
|
|
6619
|
+
const config = env.XDG_CONFIG_HOME || join(env.HOME || homedir(), ".config");
|
|
6620
|
+
return join(config, cliName, ".env");
|
|
6621
|
+
}
|
|
6622
|
+
function readDotenv(path, fileError) {
|
|
6623
|
+
let text;
|
|
6624
|
+
try {
|
|
6625
|
+
text = readFileSync(path, "utf8");
|
|
6626
|
+
} catch (error) {
|
|
6627
|
+
if (isMissingFile(error)) return {};
|
|
6628
|
+
throw fileError(error, {
|
|
6629
|
+
path,
|
|
6630
|
+
access: "read"
|
|
6631
|
+
});
|
|
6632
|
+
}
|
|
6633
|
+
return parseEnv(text);
|
|
6634
|
+
}
|
|
6635
|
+
/** Looks `name` up in the env, then in `envFile`; an empty value counts as unset. */
|
|
6636
|
+
function secretOf({ envFile, env, fileError }, name) {
|
|
6637
|
+
const fromEnv = env[name];
|
|
6638
|
+
if (fromEnv) return {
|
|
6639
|
+
value: fromEnv,
|
|
6640
|
+
origin: { kind: "env" }
|
|
6641
|
+
};
|
|
6642
|
+
const fromFile = readDotenv(envFile, fileError)[name];
|
|
6643
|
+
return fromFile ? {
|
|
6644
|
+
value: fromFile,
|
|
6645
|
+
origin: {
|
|
6646
|
+
kind: "file",
|
|
6647
|
+
path: envFile
|
|
6648
|
+
}
|
|
6649
|
+
} : void 0;
|
|
6650
|
+
}
|
|
6651
|
+
function missingIn(scope, secrets) {
|
|
6652
|
+
return secrets.filter(({ name }) => secretOf(scope, name) === void 0);
|
|
6653
|
+
}
|
|
6654
|
+
function getItFrom({ get }) {
|
|
6655
|
+
return `(get it from ${get})`;
|
|
6656
|
+
}
|
|
6657
|
+
function whereToGet(secrets) {
|
|
6658
|
+
return secrets.map((secret) => `${secret.name} ${getItFrom(secret)}`).join(", ");
|
|
6659
|
+
}
|
|
6660
|
+
/** Fails with `SECRET_MISSING`, naming every missing Secret at once, unless all are set. */
|
|
6661
|
+
function checkSecrets(secrets, scope, rerun) {
|
|
6662
|
+
const missing = missingIn(scope, secrets);
|
|
6663
|
+
if (missing.length === 0) return;
|
|
6664
|
+
const names = missing.map(({ name }) => name).join(", ");
|
|
6665
|
+
throw new CliError({
|
|
6666
|
+
code: SECRET_MISSING,
|
|
6667
|
+
message: `${missing.length === 1 ? "a Secret it needs is" : "Secrets it needs are"} not set: ${names}`,
|
|
6668
|
+
hint: `set ${whereToGet(missing)} in the environment or in ${scope.envFile}, then run the Next step`,
|
|
6669
|
+
next: [rerun]
|
|
6670
|
+
});
|
|
6671
|
+
}
|
|
6672
|
+
function originOf({ origin }) {
|
|
6673
|
+
return origin.kind === "env" ? "the environment" : origin.path;
|
|
6674
|
+
}
|
|
6675
|
+
/** The `doctor` row over every distinct Secret the CLI and its Commands declare; none without any. */
|
|
6676
|
+
function secretRows(secrets, commands) {
|
|
6677
|
+
const declared = declaredIn(secrets, commands, (command) => command.secrets);
|
|
6678
|
+
if (declared.length === 0) return [];
|
|
6679
|
+
return [{
|
|
6680
|
+
name: "secrets",
|
|
6681
|
+
run: ({ env, envFile, fileError }) => {
|
|
6682
|
+
const read = declared.map((declaration) => ({
|
|
6683
|
+
declaration,
|
|
6684
|
+
secret: secretOf({
|
|
6685
|
+
env,
|
|
6686
|
+
envFile,
|
|
6687
|
+
fileError
|
|
6688
|
+
}, declaration.name)
|
|
6689
|
+
}));
|
|
6690
|
+
const missing = read.filter(({ secret }) => secret === void 0);
|
|
6691
|
+
if (missing.length > 0) return {
|
|
6692
|
+
state: "problem",
|
|
6693
|
+
message: `${missing.map(({ declaration }) => `${declaration.name} is not set ${getItFrom(declaration)}`).join(", ")}; add ${missing.length === 1 ? "it" : "them"} to ${envFile} or the environment`
|
|
6694
|
+
};
|
|
6695
|
+
return {
|
|
6696
|
+
state: "ok",
|
|
6697
|
+
message: read.flatMap(({ declaration, secret }) => secret === void 0 ? [] : [`${declaration.name} from ${originOf(secret)}`]).join(", ")
|
|
6698
|
+
};
|
|
6699
|
+
}
|
|
6700
|
+
}];
|
|
6701
|
+
}
|
|
6702
|
+
//#endregion
|
|
6703
|
+
//#region ../agent-cli/dist/context/tools.js
|
|
6546
6704
|
const TOOL_MISSING = "TOOL_MISSING";
|
|
6547
6705
|
const WINDOWS_EXTENSIONS = ".COM;.EXE;.BAT;.CMD";
|
|
6548
6706
|
function pathOf(env) {
|
|
@@ -6572,23 +6730,21 @@ async function findTool(name, env) {
|
|
|
6572
6730
|
for (const file of candidates) if (await isExecutable(file)) return file;
|
|
6573
6731
|
}
|
|
6574
6732
|
/** Fails with `TOOL_MISSING`, naming every missing tool at once, unless all are on `PATH`. */
|
|
6575
|
-
async function checkTools(tools, env,
|
|
6733
|
+
async function checkTools(tools, env, rerun) {
|
|
6576
6734
|
const found = await Promise.all(tools.map((tool) => findTool(tool.name, env)));
|
|
6577
6735
|
const missing = tools.filter((_tool, index) => found[index] === void 0);
|
|
6578
6736
|
if (missing.length === 0) return;
|
|
6579
6737
|
const names = missing.map(({ name }) => name).join(", ");
|
|
6580
|
-
throw
|
|
6738
|
+
throw runtimeError({
|
|
6581
6739
|
code: TOOL_MISSING,
|
|
6582
6740
|
message: `${missing.length === 1 ? "a tool it runs is" : "tools it runs are"} not on PATH: ${names}`,
|
|
6583
|
-
hint:
|
|
6741
|
+
hint: "run the Next steps in order: each install, then the command again",
|
|
6742
|
+
next: [...missing.map(({ install }) => wholeLine(install)), rerun]
|
|
6584
6743
|
});
|
|
6585
6744
|
}
|
|
6586
|
-
function toolsIn(node) {
|
|
6587
|
-
return isCommand(node) ? [...node.tools ?? []] : Object.values(node).flatMap(toolsIn);
|
|
6588
|
-
}
|
|
6589
6745
|
/** One `doctor` row per distinct tool the CLI and its Commands declare, with its install command as the fix. */
|
|
6590
6746
|
function toolRows(tools, commands) {
|
|
6591
|
-
return
|
|
6747
|
+
return declaredIn(tools, commands, (command) => command.tools).map(({ name, install }) => ({
|
|
6592
6748
|
name,
|
|
6593
6749
|
run: async (ctx) => {
|
|
6594
6750
|
const file = await findTool(name, ctx.env);
|
|
@@ -6605,72 +6761,18 @@ function toolRows(tools, commands) {
|
|
|
6605
6761
|
}
|
|
6606
6762
|
//#endregion
|
|
6607
6763
|
//#region ../agent-cli/dist/version.js
|
|
6608
|
-
/** The
|
|
6609
|
-
function
|
|
6610
|
-
return
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
const MANAGERS = [
|
|
6615
|
-
"pnpm",
|
|
6616
|
-
"npm",
|
|
6617
|
-
"yarn",
|
|
6618
|
-
"bun"
|
|
6619
|
-
];
|
|
6620
|
-
const LOCKFILES = [
|
|
6621
|
-
["pnpm-lock.yaml", "pnpm"],
|
|
6622
|
-
["package-lock.json", "npm"],
|
|
6623
|
-
["yarn.lock", "yarn"],
|
|
6624
|
-
["bun.lock", "bun"],
|
|
6625
|
-
["bun.lockb", "bun"]
|
|
6626
|
-
];
|
|
6627
|
-
const manifestSchema$1 = object({
|
|
6628
|
-
packageManager: string().optional(),
|
|
6629
|
-
dependencies: record(string(), unknown()).optional(),
|
|
6630
|
-
devDependencies: record(string(), unknown()).optional()
|
|
6631
|
-
});
|
|
6632
|
-
/** `dir` and every folder above it, nearest first. */
|
|
6633
|
-
function ancestorsOf(dir) {
|
|
6634
|
-
const parent = dirname(dir);
|
|
6635
|
-
return parent === dir ? [dir] : [dir, ...ancestorsOf(parent)];
|
|
6636
|
-
}
|
|
6637
|
-
async function exists(path) {
|
|
6638
|
-
return await orMissing(stat(path)) !== void 0;
|
|
6639
|
-
}
|
|
6640
|
-
/** Whether `path` lies strictly inside `dir`. */
|
|
6641
|
-
function isInside(dir, path) {
|
|
6642
|
-
const inner = relative(dir, path);
|
|
6643
|
-
return inner !== "" && !inner.startsWith("..") && !isAbsolute(inner);
|
|
6644
|
-
}
|
|
6645
|
-
async function manifestIn(dir) {
|
|
6646
|
-
let text;
|
|
6647
|
-
try {
|
|
6648
|
-
text = await readFile(join(dir, "package.json"), "utf8");
|
|
6649
|
-
} catch (error) {
|
|
6650
|
-
if (isMissingFile(error)) return void 0;
|
|
6651
|
-
throw error;
|
|
6652
|
-
}
|
|
6653
|
-
let manifest;
|
|
6654
|
-
try {
|
|
6655
|
-
manifest = JSON.parse(text);
|
|
6656
|
-
} catch {
|
|
6657
|
-
return;
|
|
6658
|
-
}
|
|
6659
|
-
return manifestSchema$1.safeParse(manifest).data;
|
|
6660
|
-
}
|
|
6661
|
-
async function declaredManager(dir) {
|
|
6662
|
-
const name = (await manifestIn(dir))?.packageManager?.split("@")[0];
|
|
6663
|
-
return MANAGERS.find((manager) => manager === name);
|
|
6664
|
-
}
|
|
6665
|
-
async function lockfileRootOf(cwd) {
|
|
6666
|
-
for (const dir of ancestorsOf(cwd)) for (const [file, kind] of LOCKFILES) if (await exists(join(dir, file))) return {
|
|
6667
|
-
dir,
|
|
6668
|
-
manager: await declaredManager(dir) ?? kind
|
|
6764
|
+
/** The bundler's stamp, absent when the CLI runs unbundled. Read per call, so a test can define it. */
|
|
6765
|
+
function buildStamp() {
|
|
6766
|
+
return {
|
|
6767
|
+
"sha": "e9645e3",
|
|
6768
|
+
"dirty": false,
|
|
6769
|
+
"builtAt": "2026-10-28T08:17:12.000Z"
|
|
6669
6770
|
};
|
|
6670
6771
|
}
|
|
6671
|
-
/** The
|
|
6672
|
-
|
|
6673
|
-
|
|
6772
|
+
/** The first line of `--version`: the version, and the commit and time of a stamped build. */
|
|
6773
|
+
function versionLine({ version }) {
|
|
6774
|
+
const build = buildStamp();
|
|
6775
|
+
return build === void 0 ? version : `${version} (${build.sha}${build.dirty ? "+dirty" : ""}) built ${build.builtAt}`;
|
|
6674
6776
|
}
|
|
6675
6777
|
//#endregion
|
|
6676
6778
|
//#region ../agent-cli/dist/tail.js
|
|
@@ -6679,7 +6781,7 @@ function lastLines(output, count) {
|
|
|
6679
6781
|
return output.trim().split("\n").slice(-count).join("\n");
|
|
6680
6782
|
}
|
|
6681
6783
|
//#endregion
|
|
6682
|
-
//#region ../agent-cli/dist/spawn.js
|
|
6784
|
+
//#region ../agent-cli/dist/context/spawn.js
|
|
6683
6785
|
const TOOL_FAILED = "TOOL_FAILED";
|
|
6684
6786
|
const STDERR_TAIL_LINES$1 = 20;
|
|
6685
6787
|
const SIGNAL_EXIT_BASE = 128;
|
|
@@ -6904,15 +7006,16 @@ function failedError(command, { exitCode, stderr }) {
|
|
|
6904
7006
|
hint: `the output of ${command} above says why it failed`
|
|
6905
7007
|
});
|
|
6906
7008
|
}
|
|
6907
|
-
function missingError(command,
|
|
7009
|
+
function missingError(command, rerun, cause) {
|
|
6908
7010
|
return new CliError({
|
|
6909
7011
|
code: TOOL_MISSING,
|
|
6910
7012
|
message: `${command} could not be started: it is not on PATH`,
|
|
6911
|
-
hint: `install ${command}, then run
|
|
7013
|
+
hint: `install ${command}, then run the Next step`,
|
|
7014
|
+
next: [rerun]
|
|
6912
7015
|
}, { cause });
|
|
6913
7016
|
}
|
|
6914
|
-
function startError(command, error, { fileError,
|
|
6915
|
-
if (isMissingFile(error)) return missingError(command,
|
|
7017
|
+
function startError(command, error, { fileError, rerun }) {
|
|
7018
|
+
if (isMissingFile(error)) return missingError(command, rerun, error);
|
|
6916
7019
|
return fileError(error, {
|
|
6917
7020
|
path: command,
|
|
6918
7021
|
access: "read"
|
|
@@ -7049,7 +7152,7 @@ const NO_LATEST = "NO_LATEST";
|
|
|
7049
7152
|
function npmContext(cli, registry, ctx, node, cwd) {
|
|
7050
7153
|
return {
|
|
7051
7154
|
cliName: cli.name,
|
|
7052
|
-
|
|
7155
|
+
rerun: ctx.rerun(),
|
|
7053
7156
|
registry,
|
|
7054
7157
|
cwd,
|
|
7055
7158
|
env: ctx.env,
|
|
@@ -7058,6 +7161,7 @@ function npmContext(cli, registry, ctx, node, cwd) {
|
|
|
7058
7161
|
};
|
|
7059
7162
|
}
|
|
7060
7163
|
const STDERR_TAIL_LINES = 10;
|
|
7164
|
+
const RUN_AGAIN = "run it again";
|
|
7061
7165
|
const RM_RETRIES = 3;
|
|
7062
7166
|
const NETWORK_CODES = /* @__PURE__ */ new Set([
|
|
7063
7167
|
"ENOTFOUND",
|
|
@@ -7121,27 +7225,31 @@ function failureOf(call, answer, ctx) {
|
|
|
7121
7225
|
const { label: registry, package: name, loginHint, unreachableHint } = ctx.registry;
|
|
7122
7226
|
const code = NPM_CODE.exec(answer.stderr)?.[1];
|
|
7123
7227
|
const output = tail$1(answer.stderr);
|
|
7124
|
-
const
|
|
7228
|
+
const next = [ctx.rerun];
|
|
7125
7229
|
if (code !== void 0 && NETWORK_CODES.has(code)) return new CliError({
|
|
7126
7230
|
code: REGISTRY_UNREACHABLE,
|
|
7127
7231
|
message: `npm could not reach ${registry} (${code})${output}`,
|
|
7128
|
-
hint: `${unreachableHint}, then ${
|
|
7232
|
+
hint: `${unreachableHint}, then ${RUN_AGAIN}`,
|
|
7233
|
+
next
|
|
7129
7234
|
});
|
|
7130
7235
|
if (code !== void 0 && AUTH_CODES.has(code)) return new CliError({
|
|
7131
7236
|
code: REGISTRY_AUTH,
|
|
7132
7237
|
message: `${registry} refused npm's credentials (${code})${output}`,
|
|
7133
|
-
hint: `${loginHint}, then ${
|
|
7238
|
+
hint: `${loginHint}, then ${RUN_AGAIN}`,
|
|
7239
|
+
next
|
|
7134
7240
|
});
|
|
7135
7241
|
if (call === "view" && code === "E404") return noLatest(ctx, `npm found no ${name}@latest on ${registry}: no version of it is published there`);
|
|
7136
|
-
if (call === "install") return
|
|
7242
|
+
if (call === "install") return runtimeError({
|
|
7137
7243
|
code: INSTALL_FAILED,
|
|
7138
7244
|
message: `npm could not install ${name}${code === void 0 ? "" : ` (${code})`}${output}`,
|
|
7139
|
-
hint: `fix what npm reports, then ${
|
|
7245
|
+
hint: `fix what npm reports, then ${RUN_AGAIN} with the first Next step, or install it yourself with the second`,
|
|
7246
|
+
next: [...next, wholeLine(installCommandLine(ctx.registry))]
|
|
7140
7247
|
});
|
|
7141
7248
|
return new CliError({
|
|
7142
7249
|
code: NPM_FAILED,
|
|
7143
7250
|
message: `npm ${call} failed with exit code ${answer.exitCode}${output}`,
|
|
7144
|
-
hint: `fix what npm reports, then ${
|
|
7251
|
+
hint: `fix what npm reports, then ${RUN_AGAIN}`,
|
|
7252
|
+
next
|
|
7145
7253
|
});
|
|
7146
7254
|
}
|
|
7147
7255
|
function noLatest(ctx, message) {
|
|
@@ -7217,10 +7325,73 @@ async function latestVersion(ctx) {
|
|
|
7217
7325
|
return version;
|
|
7218
7326
|
}
|
|
7219
7327
|
//#endregion
|
|
7220
|
-
//#region ../agent-cli/dist/built-ins/
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
7328
|
+
//#region ../agent-cli/dist/built-ins/project-root.js
|
|
7329
|
+
const MANAGERS = [
|
|
7330
|
+
"pnpm",
|
|
7331
|
+
"npm",
|
|
7332
|
+
"yarn",
|
|
7333
|
+
"bun"
|
|
7334
|
+
];
|
|
7335
|
+
const LOCKFILES = [
|
|
7336
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
7337
|
+
["package-lock.json", "npm"],
|
|
7338
|
+
["yarn.lock", "yarn"],
|
|
7339
|
+
["bun.lock", "bun"],
|
|
7340
|
+
["bun.lockb", "bun"]
|
|
7341
|
+
];
|
|
7342
|
+
const manifestSchema$1 = object({
|
|
7343
|
+
packageManager: string().optional(),
|
|
7344
|
+
dependencies: record(string(), unknown()).optional(),
|
|
7345
|
+
devDependencies: record(string(), unknown()).optional()
|
|
7346
|
+
});
|
|
7347
|
+
/** `dir` and every folder above it, nearest first. */
|
|
7348
|
+
function ancestorsOf(dir) {
|
|
7349
|
+
const parent = dirname(dir);
|
|
7350
|
+
return parent === dir ? [dir] : [dir, ...ancestorsOf(parent)];
|
|
7351
|
+
}
|
|
7352
|
+
async function exists(path) {
|
|
7353
|
+
return await orMissing(stat(path)) !== void 0;
|
|
7354
|
+
}
|
|
7355
|
+
/** Whether `path` lies strictly inside `dir`. */
|
|
7356
|
+
function isInside(dir, path) {
|
|
7357
|
+
const inner = relative(dir, path);
|
|
7358
|
+
return inner !== "" && !inner.startsWith("..") && !isAbsolute(inner);
|
|
7359
|
+
}
|
|
7360
|
+
async function manifestIn(dir) {
|
|
7361
|
+
let text;
|
|
7362
|
+
try {
|
|
7363
|
+
text = await readFile(join(dir, "package.json"), "utf8");
|
|
7364
|
+
} catch (error) {
|
|
7365
|
+
if (isMissingFile(error)) return void 0;
|
|
7366
|
+
throw error;
|
|
7367
|
+
}
|
|
7368
|
+
let manifest;
|
|
7369
|
+
try {
|
|
7370
|
+
manifest = JSON.parse(text);
|
|
7371
|
+
} catch {
|
|
7372
|
+
return;
|
|
7373
|
+
}
|
|
7374
|
+
return manifestSchema$1.safeParse(manifest).data;
|
|
7375
|
+
}
|
|
7376
|
+
async function declaredManager(dir) {
|
|
7377
|
+
const name = (await manifestIn(dir))?.packageManager?.split("@")[0];
|
|
7378
|
+
return MANAGERS.find((manager) => manager === name);
|
|
7379
|
+
}
|
|
7380
|
+
async function lockfileRootOf(cwd) {
|
|
7381
|
+
for (const dir of ancestorsOf(cwd)) for (const [file, kind] of LOCKFILES) if (await exists(join(dir, file))) return {
|
|
7382
|
+
dir,
|
|
7383
|
+
manager: await declaredManager(dir) ?? kind
|
|
7384
|
+
};
|
|
7385
|
+
}
|
|
7386
|
+
/** The package manager's project root: the folder of the nearest lockfile, or `cwd` without one. */
|
|
7387
|
+
async function projectRootOf(cwd) {
|
|
7388
|
+
return (await lockfileRootOf(cwd))?.dir ?? cwd;
|
|
7389
|
+
}
|
|
7390
|
+
//#endregion
|
|
7391
|
+
//#region ../agent-cli/dist/built-ins/install/run-as.js
|
|
7392
|
+
/** The Run-as: the bare name, or `npx -q --no-install <bin>` for a Dependency install (ADR 0011). */
|
|
7393
|
+
function runAsOf({ name, install }) {
|
|
7394
|
+
return install?.mode === "dependency" ? `npx -q --no-install ${name}` : name;
|
|
7224
7395
|
}
|
|
7225
7396
|
//#endregion
|
|
7226
7397
|
//#region ../agent-cli/dist/built-ins/install/dependency.js
|
|
@@ -7444,13 +7615,18 @@ async function skillCopies(cliName, version, { cwd, env }) {
|
|
|
7444
7615
|
}
|
|
7445
7616
|
return copies;
|
|
7446
7617
|
}
|
|
7447
|
-
|
|
7448
|
-
|
|
7618
|
+
const has = (copies, wanted) => copies.some(({ state }) => state === wanted);
|
|
7619
|
+
function fixFor(cliName, copies, from) {
|
|
7449
7620
|
const update = `npx -y skills update ${cliName}`;
|
|
7450
|
-
const add =
|
|
7621
|
+
const add = from !== void 0 && "source" in from ? `npx -y skills add ${from.source} --skill ${cliName} -g` : void 0;
|
|
7451
7622
|
if (copies.length === 0) return add;
|
|
7452
|
-
if (has("unversioned") && add !== void 0) return has("behind") ? `${update} && ${add}` : add;
|
|
7453
|
-
|
|
7623
|
+
if (has(copies, "unversioned") && add !== void 0) return has(copies, "behind") ? `${update} && ${add}` : add;
|
|
7624
|
+
if (from !== void 0 && "page" in from) return has(copies, "behind") ? update : void 0;
|
|
7625
|
+
return has(copies, "behind") || has(copies, "unversioned") ? update : void 0;
|
|
7626
|
+
}
|
|
7627
|
+
function pageNote(copies, from) {
|
|
7628
|
+
if (from === void 0 || !("page" in from)) return;
|
|
7629
|
+
return copies.length === 0 || has(copies, "unversioned") ? `copy your install line from ${from.page}` : void 0;
|
|
7454
7630
|
}
|
|
7455
7631
|
const SKILL_STATE_NOTES = {
|
|
7456
7632
|
current: "the same as this build",
|
|
@@ -7462,12 +7638,13 @@ const SKILL_STATE_NOTES = {
|
|
|
7462
7638
|
function describeCopy({ path, version, state }) {
|
|
7463
7639
|
return `${path}${version === void 0 ? "" : ` ${version}`} (${SKILL_STATE_NOTES[state]})`;
|
|
7464
7640
|
}
|
|
7465
|
-
/** A skill
|
|
7466
|
-
function hubSkill(cli,
|
|
7467
|
-
const
|
|
7468
|
-
const
|
|
7469
|
-
const
|
|
7470
|
-
const
|
|
7641
|
+
/** A skill on a Skill Hub, which `from` says how to install; with neither, no line adds it. */
|
|
7642
|
+
function hubSkill(cli, from) {
|
|
7643
|
+
const findingOf = (copies) => {
|
|
7644
|
+
const fix = fixFor(cli.name, copies, from);
|
|
7645
|
+
const note = pageNote(copies, from);
|
|
7646
|
+
const found = copies.length === 0 ? `no copy of the ${cli.name} skill is installed` : copies.map(describeCopy).join("; ");
|
|
7647
|
+
const message = note === void 0 ? found : `${found}; ${note}`;
|
|
7471
7648
|
return fix === void 0 ? {
|
|
7472
7649
|
state: "ok",
|
|
7473
7650
|
message
|
|
@@ -7483,10 +7660,16 @@ function hubSkill(cli, source) {
|
|
|
7483
7660
|
rows: [{
|
|
7484
7661
|
name: "skill",
|
|
7485
7662
|
advisory: true,
|
|
7486
|
-
run: (ctx) =>
|
|
7663
|
+
run: async (ctx) => findingOf(await skillCopies(cli.name, cli.version, ctx))
|
|
7487
7664
|
}],
|
|
7488
7665
|
notice: async () => {},
|
|
7489
|
-
|
|
7666
|
+
nextAt: async (version, ctx) => {
|
|
7667
|
+
const copies = await skillCopies(cli.name, version, ctx);
|
|
7668
|
+
const note = pageNote(copies, from);
|
|
7669
|
+
if (note !== void 0) ctx.notice(note);
|
|
7670
|
+
const fix = fixFor(cli.name, copies, from);
|
|
7671
|
+
return fix === void 0 ? [] : [fix];
|
|
7672
|
+
}
|
|
7490
7673
|
};
|
|
7491
7674
|
}
|
|
7492
7675
|
//#endregion
|
|
@@ -7497,10 +7680,10 @@ function markersOf(name) {
|
|
|
7497
7680
|
end: `<!-- END:${name} -->`
|
|
7498
7681
|
};
|
|
7499
7682
|
}
|
|
7500
|
-
/** `text` with the CLI's
|
|
7501
|
-
function
|
|
7683
|
+
/** `text` with the CLI's Agents section between its markers, appended when they are missing; nothing else changes. */
|
|
7684
|
+
function withSection({ name, text: section }, text) {
|
|
7502
7685
|
const { begin, end } = markersOf(name);
|
|
7503
|
-
const whole = `${begin}\n${
|
|
7686
|
+
const whole = `${begin}\n${section}\n${end}`;
|
|
7504
7687
|
const start = text.indexOf(begin);
|
|
7505
7688
|
const stop = start === -1 ? -1 : text.indexOf(end, start);
|
|
7506
7689
|
if (stop !== -1) return `${text.slice(0, start)}${whole}${text.slice(stop + end.length)}`;
|
|
@@ -7515,7 +7698,7 @@ async function agentsMdAt(agents, root) {
|
|
|
7515
7698
|
agents,
|
|
7516
7699
|
change: "create"
|
|
7517
7700
|
};
|
|
7518
|
-
if (
|
|
7701
|
+
if (withSection(agents, existing) === existing) return {
|
|
7519
7702
|
path,
|
|
7520
7703
|
agents,
|
|
7521
7704
|
change: null
|
|
@@ -7543,15 +7726,15 @@ function agentsRow(agents, install) {
|
|
|
7543
7726
|
const fix = `${install.runAs} skill install`;
|
|
7544
7727
|
if (change === "rewrite") return {
|
|
7545
7728
|
state: "problem",
|
|
7546
|
-
message: `${path} holds a ${name}
|
|
7729
|
+
message: `${path} holds a ${name} Agents section other than the one ${fix} writes`,
|
|
7547
7730
|
fix
|
|
7548
7731
|
};
|
|
7549
7732
|
if (change !== null) return {
|
|
7550
7733
|
state: "problem",
|
|
7551
|
-
message: `${path} holds no ${name}
|
|
7734
|
+
message: `${path} holds no ${name} Agents section, so sessions in this repo do not know ${name}`,
|
|
7552
7735
|
fix
|
|
7553
7736
|
};
|
|
7554
|
-
const holds = `${path} holds the ${name}
|
|
7737
|
+
const holds = `${path} holds the ${name} Agents section`;
|
|
7555
7738
|
const [edit] = await handEditsAt(root);
|
|
7556
7739
|
return edit === void 0 ? {
|
|
7557
7740
|
state: "ok",
|
|
@@ -7564,7 +7747,7 @@ function agentsRow(agents, install) {
|
|
|
7564
7747
|
};
|
|
7565
7748
|
}
|
|
7566
7749
|
//#endregion
|
|
7567
|
-
//#region ../agent-cli/dist/agent.js
|
|
7750
|
+
//#region ../agent-cli/dist/context/agent.js
|
|
7568
7751
|
const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
|
|
7569
7752
|
const isSet = (name) => (env) => (env[name] ?? "") !== "";
|
|
7570
7753
|
const equals = (name, value) => (env) => env[name] === value;
|
|
@@ -7598,16 +7781,22 @@ function isAgent(env) {
|
|
|
7598
7781
|
return MARKERS.some((marker) => marker(env));
|
|
7599
7782
|
}
|
|
7600
7783
|
//#endregion
|
|
7601
|
-
//#region ../agent-cli/dist/errno.js
|
|
7784
|
+
//#region ../agent-cli/dist/context/errno.js
|
|
7602
7785
|
const PERMISSION_DENIED = "PERMISSION_DENIED";
|
|
7603
7786
|
const DISK_FULL = "DISK_FULL";
|
|
7604
7787
|
const NOT_FOUND = "NOT_FOUND";
|
|
7605
7788
|
const ALREADY_EXISTS = "ALREADY_EXISTS";
|
|
7606
7789
|
const NOT_A_FILE = "NOT_A_FILE";
|
|
7607
|
-
function
|
|
7608
|
-
if (platform === "win32") return
|
|
7609
|
-
|
|
7610
|
-
|
|
7790
|
+
function permissionAdvice({ path, access, rerun, env, platform }) {
|
|
7791
|
+
if (platform === "win32") return {
|
|
7792
|
+
hint: `a program may hold ${path} open: close it, then run the Next step`,
|
|
7793
|
+
next: [rerun]
|
|
7794
|
+
};
|
|
7795
|
+
if (!isAgent(env)) return { hint: `check the permissions of ${path} and its folder` };
|
|
7796
|
+
return {
|
|
7797
|
+
hint: `your sandbox may block it: ask your user to type ! then the Next step, or ${access === "read" ? `to allow reading ${path} in the sandbox` : `to allow ${path} in the sandbox's write list`}`,
|
|
7798
|
+
next: [rerun]
|
|
7799
|
+
};
|
|
7611
7800
|
}
|
|
7612
7801
|
function fileErrorOf(scope) {
|
|
7613
7802
|
return (error, at) => classifyErrno(error, {
|
|
@@ -7624,13 +7813,14 @@ function classifyErrno(error, context) {
|
|
|
7624
7813
|
case "EBUSY": return new CliError({
|
|
7625
7814
|
code: PERMISSION_DENIED,
|
|
7626
7815
|
message: `permission denied: ${path}`,
|
|
7627
|
-
|
|
7816
|
+
...permissionAdvice(context)
|
|
7628
7817
|
}, { cause: error });
|
|
7629
7818
|
case "ENOSPC":
|
|
7630
7819
|
case "EDQUOT": return new CliError({
|
|
7631
7820
|
code: DISK_FULL,
|
|
7632
7821
|
message: `no space left on the disk holding ${path}`,
|
|
7633
|
-
hint:
|
|
7822
|
+
hint: "free space on that disk, then run the Next step",
|
|
7823
|
+
next: [context.rerun]
|
|
7634
7824
|
}, { cause: error });
|
|
7635
7825
|
case "ENOENT":
|
|
7636
7826
|
case "ENOTDIR":
|
|
@@ -7653,7 +7843,7 @@ function classifyErrno(error, context) {
|
|
|
7653
7843
|
}
|
|
7654
7844
|
}
|
|
7655
7845
|
//#endregion
|
|
7656
|
-
//#region ../agent-cli/dist/files.js
|
|
7846
|
+
//#region ../agent-cli/dist/context/files.js
|
|
7657
7847
|
const TEMP_FILE = /^\..+\.agent-cli-(\d+)\.tmp$/;
|
|
7658
7848
|
/** Where the Runtime writes `path` before moving it into place; a dead writer's is swept. */
|
|
7659
7849
|
function tempPathOf(path) {
|
|
@@ -7826,10 +8016,10 @@ function classifiedFiles(files, { cwd, fileError }) {
|
|
|
7826
8016
|
};
|
|
7827
8017
|
}
|
|
7828
8018
|
//#endregion
|
|
7829
|
-
//#region ../agent-cli/dist/outputs.js
|
|
8019
|
+
//#region ../agent-cli/dist/context/outputs.js
|
|
7830
8020
|
const OUTPUT_EXISTS = "OUTPUT_EXISTS";
|
|
7831
8021
|
/** Refuses a run that would overwrite existing outputs unless the caller passed `--force`. */
|
|
7832
|
-
async function checkOutputs({
|
|
8022
|
+
async function checkOutputs({ rerun, commandLine, force, files }, outputs) {
|
|
7833
8023
|
if (outputs === void 0 || force) return;
|
|
7834
8024
|
const found = await Promise.all(outputs.map((path) => files.exists(path)));
|
|
7835
8025
|
const existing = outputs.filter((_path, index) => found[index]);
|
|
@@ -7838,13 +8028,14 @@ async function checkOutputs({ invocation, commandLine, force, files }, outputs)
|
|
|
7838
8028
|
throw new CliError({
|
|
7839
8029
|
code: OUTPUT_EXISTS,
|
|
7840
8030
|
message: `\`${commandLine}\` would overwrite ${existing.join(", ")}`,
|
|
7841
|
-
hint: `to replace ${them}, run
|
|
8031
|
+
hint: `to replace ${them}, run the Next step`,
|
|
8032
|
+
next: [rerun({ add: [FORCE_FLAG.flag] })]
|
|
7842
8033
|
});
|
|
7843
8034
|
}
|
|
7844
8035
|
/** Guards the writes to declared outputs of `files`, whose paths resolve against `cwd`. */
|
|
7845
8036
|
function outputsGuard(files, cwd) {
|
|
7846
8037
|
const unwritten = /* @__PURE__ */ new Set();
|
|
7847
|
-
let
|
|
8038
|
+
let forceStep = [];
|
|
7848
8039
|
const exclusiveWrite = async (path, data, options) => {
|
|
7849
8040
|
const target = resolve(cwd, path);
|
|
7850
8041
|
unwritten.delete(target);
|
|
@@ -7859,7 +8050,8 @@ function outputsGuard(files, cwd) {
|
|
|
7859
8050
|
throw new CliError({
|
|
7860
8051
|
code: ALREADY_EXISTS,
|
|
7861
8052
|
message: error.message,
|
|
7862
|
-
hint:
|
|
8053
|
+
hint: "to replace it, run the Next step",
|
|
8054
|
+
next: [forceStep]
|
|
7863
8055
|
}, { cause: error });
|
|
7864
8056
|
}
|
|
7865
8057
|
};
|
|
@@ -7868,8 +8060,8 @@ function outputsGuard(files, cwd) {
|
|
|
7868
8060
|
...files,
|
|
7869
8061
|
write: (path, data, options) => unwritten.has(resolve(cwd, path)) ? exclusiveWrite(path, data, options) : files.write(path, data, options)
|
|
7870
8062
|
},
|
|
7871
|
-
guard: (outputs,
|
|
7872
|
-
|
|
8063
|
+
guard: (outputs, step) => {
|
|
8064
|
+
forceStep = step;
|
|
7873
8065
|
for (const path of outputs) unwritten.add(resolve(cwd, path));
|
|
7874
8066
|
}
|
|
7875
8067
|
};
|
|
@@ -7952,10 +8144,10 @@ async function planOf(cli, folder, agents, cwd, packageRoot) {
|
|
|
7952
8144
|
handEdits: agents === void 0 ? [] : await handEditsAt(root)
|
|
7953
8145
|
};
|
|
7954
8146
|
}
|
|
7955
|
-
const
|
|
8147
|
+
const SECTION_VERBS = {
|
|
7956
8148
|
create: "create",
|
|
7957
|
-
add: "add the
|
|
7958
|
-
rewrite: "rewrite the
|
|
8149
|
+
add: "add the Agents section to",
|
|
8150
|
+
rewrite: "rewrite the Agents section in"
|
|
7959
8151
|
};
|
|
7960
8152
|
function renderPlan(cli, plan) {
|
|
7961
8153
|
const files = [
|
|
@@ -7967,7 +8159,7 @@ function renderPlan(cli, plan) {
|
|
|
7967
8159
|
return [
|
|
7968
8160
|
files.length === 0 ? `the ${cli.name} skill at ${plan.copy} already matches the package` : `would copy the ${cli.name} skill to ${plan.copy}:`,
|
|
7969
8161
|
...files,
|
|
7970
|
-
...agentsMd === null ? [] : [agentsMd.change === null ? `${agentsMd.path} already holds the ${cli.name}
|
|
8162
|
+
...agentsMd === null ? [] : [agentsMd.change === null ? `${agentsMd.path} already holds the ${cli.name} Agents section` : `would ${SECTION_VERBS[agentsMd.change]} ${agentsMd.path}:\n${agentsMd.agents.text}`],
|
|
7971
8163
|
...plan.handEdits.map((edit) => `by hand: ${edit}`)
|
|
7972
8164
|
].join("\n");
|
|
7973
8165
|
}
|
|
@@ -7975,7 +8167,7 @@ function renderInstalled(cli, data) {
|
|
|
7975
8167
|
const { written, removed, agentsMd } = data;
|
|
7976
8168
|
return [
|
|
7977
8169
|
written.length + removed.length === 0 ? `the ${cli.name} skill at ${data.copy} already matches the package` : `copied the ${cli.name} skill to ${data.copy}: wrote ${written.length} files, removed ${removed.length}`,
|
|
7978
|
-
...agentsMd === null ? [] : [agentsMd.changed ? `wrote the ${cli.name}
|
|
8170
|
+
...agentsMd === null ? [] : [agentsMd.changed ? `wrote the ${cli.name} Agents section in ${agentsMd.path}` : `${agentsMd.path} already holds the ${cli.name} Agents section`],
|
|
7979
8171
|
...data.handEdits.map((edit) => `by hand: ${edit}`)
|
|
7980
8172
|
].join("\n");
|
|
7981
8173
|
}
|
|
@@ -7983,21 +8175,20 @@ function editedRemovals(plan, ctx) {
|
|
|
7983
8175
|
const them = plan.remove.length === 1 ? "it" : "them";
|
|
7984
8176
|
return new CliError({
|
|
7985
8177
|
code: OUTPUT_EXISTS,
|
|
7986
|
-
message:
|
|
7987
|
-
hint: `to remove ${them}, run
|
|
8178
|
+
message: `skill install would remove ${plan.remove.map((file) => join(plan.copy, file)).join(", ")}`,
|
|
8179
|
+
hint: `to remove ${them}, run the Next step`,
|
|
8180
|
+
next: [ctx.rerun({ add: [FORCE_FLAG.flag] })]
|
|
7988
8181
|
});
|
|
7989
8182
|
}
|
|
7990
8183
|
/** The built-in `skill install`, for a CLI whose skill ships in its package. */
|
|
7991
|
-
function skillInstallCommand(cli, folder,
|
|
7992
|
-
const { runAs } = install;
|
|
8184
|
+
function skillInstallCommand(cli, folder, agents) {
|
|
7993
8185
|
return defineCommand$1({
|
|
7994
|
-
|
|
7995
|
-
description: agents === void 0 ? "copy this CLI's skill into the project" : "copy this CLI's skill into the project and write its AGENTS.md block",
|
|
8186
|
+
description: agents === void 0 ? "copy this CLI's skill into the project" : "copy this CLI's skill into the project and write its Agents section",
|
|
7996
8187
|
examples: [{
|
|
7997
|
-
command: `${
|
|
8188
|
+
command: `${cli.name} skill install`,
|
|
7998
8189
|
note: "install the skill this version ships"
|
|
7999
8190
|
}, {
|
|
8000
|
-
command: `${
|
|
8191
|
+
command: `${cli.name} skill install --dry-run`,
|
|
8001
8192
|
note: "show what it would change"
|
|
8002
8193
|
}],
|
|
8003
8194
|
effect: "write",
|
|
@@ -8012,7 +8203,7 @@ function skillInstallCommand(cli, folder, install, agents) {
|
|
|
8012
8203
|
const { agentsMd } = plan;
|
|
8013
8204
|
if (agentsMd !== null && agentsMd.change !== null) {
|
|
8014
8205
|
const existing = await orMissing(readFile(agentsMd.path, "utf8")) ?? "";
|
|
8015
|
-
await ctx.files.write(agentsMd.path,
|
|
8206
|
+
await ctx.files.write(agentsMd.path, withSection(agentsMd.agents, existing));
|
|
8016
8207
|
}
|
|
8017
8208
|
return {
|
|
8018
8209
|
copy: plan.copy,
|
|
@@ -8103,45 +8294,53 @@ function packagedSkill(cli, { packaged: folder, agents: text }, install) {
|
|
|
8103
8294
|
};
|
|
8104
8295
|
return {
|
|
8105
8296
|
kind: "packaged",
|
|
8106
|
-
builtIns: { skill: { install: skillInstallCommand(cli, folder,
|
|
8297
|
+
builtIns: { skill: { install: skillInstallCommand(cli, folder, agents) } },
|
|
8107
8298
|
rows: [{
|
|
8108
8299
|
name: "skill",
|
|
8109
8300
|
advisory: true,
|
|
8110
8301
|
run: (ctx) => findingOf(cli, folder, install, ctx)
|
|
8111
8302
|
}, ...agents === void 0 ? [] : [agentsRow(agents, install)]],
|
|
8112
8303
|
notice: (launch, ctx) => notice(cli, folder, install, launch, ctx),
|
|
8113
|
-
|
|
8304
|
+
nextAt: async (_version, ctx) => {
|
|
8305
|
+
const { fix } = await findingOf(cli, folder, install, ctx);
|
|
8306
|
+
return fix === void 0 ? [] : [fix];
|
|
8307
|
+
}
|
|
8114
8308
|
};
|
|
8115
8309
|
}
|
|
8116
8310
|
//#endregion
|
|
8117
8311
|
//#region ../agent-cli/dist/built-ins/skill/skill.js
|
|
8118
8312
|
/** A Packaged skill, or else a Skill Hub's, also for a CLI that declares no `skill`. */
|
|
8119
|
-
function skillOf(cli, install) {
|
|
8313
|
+
function skillOf$1(cli, install) {
|
|
8120
8314
|
const { skill } = cli;
|
|
8121
|
-
return skill !== void 0 && "packaged" in skill ? packagedSkill(cli, skill, install) : hubSkill(cli, skill
|
|
8315
|
+
return skill !== void 0 && "packaged" in skill ? packagedSkill(cli, skill, install) : hubSkill(cli, skill);
|
|
8122
8316
|
}
|
|
8123
8317
|
//#endregion
|
|
8124
|
-
//#region ../agent-cli/dist/interrupts.js
|
|
8318
|
+
//#region ../agent-cli/dist/context/interrupts.js
|
|
8125
8319
|
const INTERRUPTED = "INTERRUPTED";
|
|
8126
8320
|
const DEADLINE_EXCEEDED = "DEADLINE_EXCEEDED";
|
|
8127
8321
|
/** How long an interrupted Command may take to settle before the run ends without it. */
|
|
8128
8322
|
const GRACE_MS = 3e3;
|
|
8129
8323
|
const GRACE_OVER = Symbol("grace over");
|
|
8130
|
-
function interruptedError(
|
|
8324
|
+
function interruptedError(rerun) {
|
|
8131
8325
|
return new CliError({
|
|
8132
8326
|
code: INTERRUPTED,
|
|
8133
8327
|
message: "interrupted before it finished",
|
|
8134
|
-
hint:
|
|
8328
|
+
hint: "to finish it, run the Next step, unless it was stopped on purpose; if a tool timeout stopped it, give it longer",
|
|
8329
|
+
next: [rerun]
|
|
8135
8330
|
});
|
|
8136
8331
|
}
|
|
8137
|
-
|
|
8138
|
-
|
|
8332
|
+
const BOUND_WORDS = {
|
|
8333
|
+
deadline: "deadline",
|
|
8334
|
+
ignoreStop: "timeout"
|
|
8335
|
+
};
|
|
8336
|
+
function waitHint(bound) {
|
|
8337
|
+
return bound === "ignoreStop" ? "the call may have been billed: ask your user before running the Next step" : "run the Next step later, when the service it waits on may answer faster";
|
|
8139
8338
|
}
|
|
8140
|
-
function deadlineError(commandLine, ms,
|
|
8339
|
+
function deadlineError(commandLine, ms, advice, bound = "deadline") {
|
|
8141
8340
|
return new CliError({
|
|
8142
8341
|
code: DEADLINE_EXCEEDED,
|
|
8143
|
-
message: `${commandLine} ran past its ${ms} ms ${bound}`,
|
|
8144
|
-
|
|
8342
|
+
message: `${commandLine} ran past its ${ms} ms ${BOUND_WORDS[bound]}`,
|
|
8343
|
+
...advice
|
|
8145
8344
|
});
|
|
8146
8345
|
}
|
|
8147
8346
|
/** One Command run's cancellation: its signal, its deadlines and the steps it must finish. */
|
|
@@ -8149,24 +8348,24 @@ var RunControl = class {
|
|
|
8149
8348
|
signal;
|
|
8150
8349
|
#controller = new AbortController();
|
|
8151
8350
|
#commandLine;
|
|
8152
|
-
#
|
|
8351
|
+
#rerun;
|
|
8153
8352
|
#outer;
|
|
8154
|
-
#onOuterAbort = () => this.#controller.abort(interruptedError(this.#
|
|
8353
|
+
#onOuterAbort = () => this.#controller.abort(interruptedError(this.#rerun));
|
|
8155
8354
|
/** Each running must-finish step, tracked until it settles, with its name. */
|
|
8156
8355
|
#steps = /* @__PURE__ */ new Map();
|
|
8157
8356
|
#progress;
|
|
8158
8357
|
#clock;
|
|
8159
8358
|
#disposed = new AbortController();
|
|
8160
|
-
/** The reasons this run's deadlines
|
|
8359
|
+
/** The reasons this run's deadlines aborted with, to tell them in a Command's error. */
|
|
8161
8360
|
#abortReasons = /* @__PURE__ */ new WeakSet();
|
|
8162
8361
|
#graceCancel = new AbortController();
|
|
8163
8362
|
#endGrace = () => {};
|
|
8164
8363
|
#graceOver = new Promise((resolve) => {
|
|
8165
8364
|
this.#endGrace = resolve;
|
|
8166
8365
|
});
|
|
8167
|
-
constructor({ commandLine,
|
|
8366
|
+
constructor({ commandLine, rerun, outer, clock, progress, runDeadline }) {
|
|
8168
8367
|
this.#commandLine = commandLine;
|
|
8169
|
-
this.#
|
|
8368
|
+
this.#rerun = rerun;
|
|
8170
8369
|
this.#outer = outer;
|
|
8171
8370
|
this.#clock = clock;
|
|
8172
8371
|
this.#progress = progress;
|
|
@@ -8175,20 +8374,21 @@ var RunControl = class {
|
|
|
8175
8374
|
if (outer?.aborted === true) this.#onOuterAbort();
|
|
8176
8375
|
else outer?.addEventListener("abort", this.#onOuterAbort, { once: true });
|
|
8177
8376
|
if (runDeadline !== void 0) {
|
|
8178
|
-
const { ms,
|
|
8179
|
-
after(clock, ms, this.#disposed.signal, () => this.#controller.abort(deadlineError(commandLine, ms,
|
|
8377
|
+
const { ms, advice } = runDeadline;
|
|
8378
|
+
after(clock, ms, this.#disposed.signal, () => this.#controller.abort(deadlineError(commandLine, ms, advice())));
|
|
8180
8379
|
}
|
|
8181
8380
|
}
|
|
8182
|
-
deadline(ms) {
|
|
8183
|
-
return AbortSignal.any([this.signal, this.#abortsAfter(ms, "deadline")]);
|
|
8184
|
-
}
|
|
8185
|
-
timeout(ms) {
|
|
8186
|
-
return this.#abortsAfter(ms, "timeout");
|
|
8381
|
+
deadline(ms, options = {}) {
|
|
8382
|
+
return options.ignoreStop === true ? this.#abortsAfter(ms, "ignoreStop") : AbortSignal.any([this.signal, this.#abortsAfter(ms, "deadline")]);
|
|
8187
8383
|
}
|
|
8188
8384
|
#abortsAfter(ms, bound) {
|
|
8189
8385
|
const controller = new AbortController();
|
|
8190
8386
|
after(this.#clock, ms, this.#disposed.signal, () => {
|
|
8191
|
-
const
|
|
8387
|
+
const advice = {
|
|
8388
|
+
hint: waitHint(bound),
|
|
8389
|
+
next: [this.#rerun]
|
|
8390
|
+
};
|
|
8391
|
+
const reason = deadlineError(this.#commandLine, ms, advice, bound);
|
|
8192
8392
|
this.#abortReasons.add(reason);
|
|
8193
8393
|
controller.abort(reason);
|
|
8194
8394
|
});
|
|
@@ -8221,8 +8421,8 @@ var RunControl = class {
|
|
|
8221
8421
|
/**
|
|
8222
8422
|
* The error a run ends with: an interrupt or the run deadline outranks what the Command threw,
|
|
8223
8423
|
* unless the Command threw its own `INTERRUPTED`, saying what it finished before it stopped.
|
|
8224
|
-
* Otherwise each leaf that is not a `CliError` and whose cause chain holds a deadline's
|
|
8225
|
-
*
|
|
8424
|
+
* Otherwise each leaf that is not a `CliError` and whose cause chain holds a deadline's abort is
|
|
8425
|
+
* reported as that abort, so a declared error keeps its own code.
|
|
8226
8426
|
*/
|
|
8227
8427
|
errorAfter(error) {
|
|
8228
8428
|
if (this.signal.aborted) return error instanceof CliError && error.code === "INTERRUPTED" ? error : this.signal.reason;
|
|
@@ -8265,10 +8465,11 @@ function globalModulesDir(prefix) {
|
|
|
8265
8465
|
return process.platform === "win32" ? join(prefix, "node_modules") : join(prefix, "lib", "node_modules");
|
|
8266
8466
|
}
|
|
8267
8467
|
function notGlobal(ctx, message) {
|
|
8268
|
-
return
|
|
8468
|
+
return runtimeError({
|
|
8269
8469
|
code: NOT_GLOBAL_INSTALL,
|
|
8270
8470
|
message,
|
|
8271
|
-
hint:
|
|
8471
|
+
hint: "install it with npm by running the Next step, so its update Command can replace it",
|
|
8472
|
+
next: [wholeLine(installCommandLine(ctx.registry))]
|
|
8272
8473
|
});
|
|
8273
8474
|
}
|
|
8274
8475
|
/**
|
|
@@ -8403,10 +8604,6 @@ function renderUpdate(cli, install, update) {
|
|
|
8403
8604
|
...next
|
|
8404
8605
|
]).join("\n");
|
|
8405
8606
|
}
|
|
8406
|
-
async function skillNext(skill, latest, ctx) {
|
|
8407
|
-
const { fix } = await skill.findingAt(latest, ctx);
|
|
8408
|
-
return fix === void 0 ? [] : [fix];
|
|
8409
|
-
}
|
|
8410
8607
|
function interruptedAfterInstall(plan) {
|
|
8411
8608
|
return new CliError({
|
|
8412
8609
|
code: INTERRUPTED,
|
|
@@ -8417,7 +8614,6 @@ function interruptedAfterInstall(plan) {
|
|
|
8417
8614
|
/** The built-in `update`, for a CLI installed globally with npm. */
|
|
8418
8615
|
function updateCommand(cli, install, skill, { bin, node }) {
|
|
8419
8616
|
return defineCommand$1({
|
|
8420
|
-
name: "update",
|
|
8421
8617
|
description: "install the latest version of this CLI from its registry",
|
|
8422
8618
|
examples: [{
|
|
8423
8619
|
command: `${cli.name} update`,
|
|
@@ -8446,7 +8642,7 @@ function updateCommand(cli, install, skill, { bin, node }) {
|
|
|
8446
8642
|
latest,
|
|
8447
8643
|
installed: null,
|
|
8448
8644
|
upgrades: [],
|
|
8449
|
-
next: await
|
|
8645
|
+
next: await skill.nextAt(latest, ctx)
|
|
8450
8646
|
};
|
|
8451
8647
|
ctx.signal.throwIfAborted();
|
|
8452
8648
|
ctx.progress(`installing ${plan.package}@${latest} with the npm under ${prefix}…`);
|
|
@@ -8459,7 +8655,7 @@ function updateCommand(cli, install, skill, { bin, node }) {
|
|
|
8459
8655
|
prefix
|
|
8460
8656
|
},
|
|
8461
8657
|
upgrades: await upgradesOf(plan.packageDir, from, latest),
|
|
8462
|
-
next: await
|
|
8658
|
+
next: await skill.nextAt(latest, ctx)
|
|
8463
8659
|
};
|
|
8464
8660
|
if (ctx.signal.aborted) {
|
|
8465
8661
|
ctx.deliver(update);
|
|
@@ -8504,7 +8700,7 @@ function checkOf(cli, install, { bin, node }) {
|
|
|
8504
8700
|
function globalInstall(cli, install) {
|
|
8505
8701
|
const adapter = {
|
|
8506
8702
|
runAs: runAsOf(cli),
|
|
8507
|
-
builtIns: (launch) => ({ update: updateCommand(cli, install, skillOf(cli, adapter), launch) }),
|
|
8703
|
+
builtIns: (launch) => ({ update: updateCommand(cli, install, skillOf$1(cli, adapter), launch) }),
|
|
8508
8704
|
exitClasses: ["source"],
|
|
8509
8705
|
check: (launch) => checkOf(cli, install, launch)
|
|
8510
8706
|
};
|
|
@@ -8590,7 +8786,7 @@ function readProject(projectFile, ctx) {
|
|
|
8590
8786
|
ok: true,
|
|
8591
8787
|
project: projectOf(projectFile, ctx.cwd, {
|
|
8592
8788
|
fileError: ctx.fileError,
|
|
8593
|
-
|
|
8789
|
+
rerun: ctx.rerun()
|
|
8594
8790
|
})
|
|
8595
8791
|
};
|
|
8596
8792
|
} catch (error) {
|
|
@@ -8653,14 +8849,12 @@ function doctorChecks(cli, launch, read) {
|
|
|
8653
8849
|
...cli.project === void 0 ? [] : [projectRow(cli.project, read)],
|
|
8654
8850
|
...cli.doctor ?? [],
|
|
8655
8851
|
...toolRows(cli.tools ?? [], cli.commands),
|
|
8852
|
+
...secretRows(cli.secrets ?? [], cli.commands),
|
|
8656
8853
|
installRow(check),
|
|
8657
8854
|
registryRow(cli, check),
|
|
8658
|
-
...skillOf(cli, install).rows
|
|
8855
|
+
...skillOf$1(cli, install).rows
|
|
8659
8856
|
];
|
|
8660
8857
|
}
|
|
8661
|
-
//#endregion
|
|
8662
|
-
//#region ../agent-cli/dist/built-ins/doctor.js
|
|
8663
|
-
const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
|
|
8664
8858
|
const DEFAULT_DEADLINE_MS = 1e4;
|
|
8665
8859
|
const MS_PER_SECOND = 1e3;
|
|
8666
8860
|
const MIN_LABEL_WIDTH = 8;
|
|
@@ -8731,24 +8925,33 @@ function render({ rows, next }, style) {
|
|
|
8731
8925
|
return `${check.padEnd(width)}${label}${" ".repeat(stateWidth - state.length)}${message}`;
|
|
8732
8926
|
}), ...next.map((fix) => `${"next".padEnd(width)}${fix}`)].join("\n");
|
|
8733
8927
|
}
|
|
8734
|
-
function failure(cliName,
|
|
8735
|
-
const errors = problems.map(({ check, message, fix, code }) =>
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8928
|
+
function failure(cliName, rerun, problems) {
|
|
8929
|
+
const errors = problems.map(({ check, message, fix, code }) => {
|
|
8930
|
+
const head = {
|
|
8931
|
+
code: code ?? "DOCTOR_PROBLEMS",
|
|
8932
|
+
message: `${cliName} doctor found a problem in ${check}: ${message}`
|
|
8933
|
+
};
|
|
8934
|
+
return runtimeError(fix === void 0 ? {
|
|
8935
|
+
...head,
|
|
8936
|
+
hint: "the row says what is wrong",
|
|
8937
|
+
next: []
|
|
8938
|
+
} : {
|
|
8939
|
+
...head,
|
|
8940
|
+
hint: "run the Next steps in order",
|
|
8941
|
+
next: [wholeLine(fix), rerun]
|
|
8942
|
+
});
|
|
8943
|
+
});
|
|
8740
8944
|
return new AggregateError(errors);
|
|
8741
8945
|
}
|
|
8742
8946
|
/** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
|
|
8743
8947
|
function doctorCommand(cli, launch) {
|
|
8744
8948
|
return defineCommand$1({
|
|
8745
|
-
name: "doctor",
|
|
8746
8949
|
description: "check the setup and say what fixes each problem",
|
|
8747
8950
|
examples: [{
|
|
8748
|
-
command: `${
|
|
8951
|
+
command: `${cli.name} doctor`,
|
|
8749
8952
|
note: "check the setup and list the commands that fix it"
|
|
8750
8953
|
}, {
|
|
8751
|
-
command: `${
|
|
8954
|
+
command: `${cli.name} doctor --json`,
|
|
8752
8955
|
note: "get the rows and fixes as data"
|
|
8753
8956
|
}],
|
|
8754
8957
|
effect: "read",
|
|
@@ -8768,7 +8971,7 @@ function doctorCommand(cli, launch) {
|
|
|
8768
8971
|
const problems = checked.filter(({ row, advisory }) => row.state === "problem" && !advisory).map(({ row }) => row);
|
|
8769
8972
|
if (problems.length > 0) {
|
|
8770
8973
|
ctx.deliver(report);
|
|
8771
|
-
throw failure(cli.name, ctx.
|
|
8974
|
+
throw failure(cli.name, ctx.rerun(), problems);
|
|
8772
8975
|
}
|
|
8773
8976
|
return report;
|
|
8774
8977
|
},
|
|
@@ -8786,53 +8989,104 @@ function builtInCommands(cli, launch) {
|
|
|
8786
8989
|
return {
|
|
8787
8990
|
doctor: doctorCommand(cli, launch),
|
|
8788
8991
|
...install.builtIns(launch),
|
|
8789
|
-
...skillOf(cli, install).builtIns
|
|
8992
|
+
...skillOf$1(cli, install).builtIns
|
|
8790
8993
|
};
|
|
8791
8994
|
}
|
|
8792
8995
|
//#endregion
|
|
8793
|
-
//#region ../agent-cli/dist/
|
|
8794
|
-
|
|
8795
|
-
|
|
8796
|
-
|
|
8797
|
-
if (given === expected) return;
|
|
8798
|
-
const hint = `to confirm, run \`${commandLineOf(invocation, {
|
|
8799
|
-
remove: [CONFIRM_FLAG.flag],
|
|
8800
|
-
add: [CONFIRM_FLAG.flag, expected]
|
|
8801
|
-
})}\``;
|
|
8802
|
-
if (given === void 0) throw new UsageError({
|
|
8803
|
-
code: CONFIRMATION_REQUIRED,
|
|
8804
|
-
message: `\`${commandLine}\` is destructive and needs ${CONFIRM_FLAG.flag}`,
|
|
8805
|
-
hint
|
|
8806
|
-
});
|
|
8807
|
-
throw new UsageError({
|
|
8808
|
-
code: CONFIRMATION_MISMATCH,
|
|
8809
|
-
message: `${CONFIRM_FLAG.flag} ${JSON.stringify(given)} does not match the target of \`${commandLine}\``,
|
|
8810
|
-
hint
|
|
8811
|
-
});
|
|
8996
|
+
//#region ../agent-cli/dist/command-spec.js
|
|
8997
|
+
/** The group's Commands and groups that help and suggestions may name: hidden Commands left out. */
|
|
8998
|
+
function visibleCommands({ commands }) {
|
|
8999
|
+
return Object.fromEntries(Object.entries(commands).filter(([, node]) => node.kind === "group" || !node.hidden));
|
|
8812
9000
|
}
|
|
8813
|
-
|
|
8814
|
-
|
|
8815
|
-
|
|
8816
|
-
|
|
8817
|
-
function
|
|
8818
|
-
if (
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
9001
|
+
/** The words that label a Command in errors and spill files: its path, or the CLI's name for a single-Command CLI. */
|
|
9002
|
+
function commandLabel(path, cliName) {
|
|
9003
|
+
return path.length === 0 ? [cliName] : path;
|
|
9004
|
+
}
|
|
9005
|
+
function declaredOf(command) {
|
|
9006
|
+
if (!hasPlan(command)) return {
|
|
9007
|
+
outputs: false,
|
|
9008
|
+
force: void 0,
|
|
9009
|
+
cost: false
|
|
9010
|
+
};
|
|
9011
|
+
return {
|
|
9012
|
+
outputs: command.outputs !== void 0,
|
|
9013
|
+
force: command.force,
|
|
9014
|
+
cost: command.cost !== void 0
|
|
9015
|
+
};
|
|
9016
|
+
}
|
|
9017
|
+
function withRunAs(example, { name, runAs }) {
|
|
9018
|
+
const { command } = example;
|
|
9019
|
+
return command === name || command.startsWith(`${name} `) ? {
|
|
9020
|
+
...example,
|
|
9021
|
+
command: `${runAs}${command.slice(name.length)}`
|
|
9022
|
+
} : example;
|
|
9023
|
+
}
|
|
9024
|
+
function commandSpec(commandLine, command, { path, builtIn, names }) {
|
|
9025
|
+
const list = command.rows === void 0 ? void 0 : listSpec(command.rows);
|
|
9026
|
+
return {
|
|
9027
|
+
kind: "command",
|
|
9028
|
+
commandLine,
|
|
9029
|
+
path,
|
|
9030
|
+
command,
|
|
9031
|
+
builtIn,
|
|
9032
|
+
description: command.description,
|
|
9033
|
+
help: command.help,
|
|
9034
|
+
hidden: command.hidden === true,
|
|
9035
|
+
operator: command.operator === true,
|
|
9036
|
+
effect: command.effect,
|
|
9037
|
+
examples: command.examples.map((example) => withRunAs(example, names)),
|
|
9038
|
+
args: argFields(command.args),
|
|
9039
|
+
options: optionFields(command.options),
|
|
9040
|
+
standardFlags: standardFlagsFor(command.effect, declaredOf(command), list),
|
|
9041
|
+
list,
|
|
9042
|
+
output: list?.output ?? command.output
|
|
9043
|
+
};
|
|
9044
|
+
}
|
|
9045
|
+
function group(commandLine, commands) {
|
|
9046
|
+
return {
|
|
9047
|
+
kind: "group",
|
|
9048
|
+
commandLine,
|
|
9049
|
+
commands
|
|
9050
|
+
};
|
|
9051
|
+
}
|
|
9052
|
+
/** The root group of a multi-Command CLI: the author's Commands, then the Built-in Commands. */
|
|
9053
|
+
function groupSpec(names, commands, builtIns) {
|
|
9054
|
+
const { runAs } = names;
|
|
9055
|
+
return group(runAs, {
|
|
9056
|
+
...specsOf(runAs, commands, {
|
|
9057
|
+
path: [],
|
|
9058
|
+
builtIn: false,
|
|
9059
|
+
names
|
|
9060
|
+
}),
|
|
9061
|
+
...specsOf(runAs, builtIns, {
|
|
9062
|
+
path: [],
|
|
9063
|
+
builtIn: true,
|
|
9064
|
+
names
|
|
9065
|
+
})
|
|
8823
9066
|
});
|
|
8824
9067
|
}
|
|
9068
|
+
function specsOf(commandLine, commands, { path, builtIn, names }) {
|
|
9069
|
+
return Object.fromEntries(Object.entries(commands).map(([key, node]) => [key, specOf(`${commandLine} ${key}`, node, {
|
|
9070
|
+
path: [...path, key],
|
|
9071
|
+
builtIn,
|
|
9072
|
+
names
|
|
9073
|
+
})]));
|
|
9074
|
+
}
|
|
9075
|
+
function specOf(commandLine, node, place) {
|
|
9076
|
+
return isCommand(node) ? commandSpec(commandLine, node, place) : group(commandLine, specsOf(commandLine, node, place));
|
|
9077
|
+
}
|
|
8825
9078
|
//#endregion
|
|
8826
|
-
//#region ../agent-cli/dist/
|
|
8827
|
-
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
|
|
8835
|
-
|
|
9079
|
+
//#region ../agent-cli/dist/error-table.js
|
|
9080
|
+
/** The Error table a CLI declares, empty when it declares none. */
|
|
9081
|
+
function errorTableOf({ errors }) {
|
|
9082
|
+
return errors ?? {};
|
|
9083
|
+
}
|
|
9084
|
+
/** The `CliError` for a code of `Table`, as `cliError` and `ctx.fail` build it. */
|
|
9085
|
+
function cliErrorOf(code, init, options) {
|
|
9086
|
+
return new CliError({
|
|
9087
|
+
...init,
|
|
9088
|
+
code
|
|
9089
|
+
}, options);
|
|
8836
9090
|
}
|
|
8837
9091
|
//#endregion
|
|
8838
9092
|
//#region ../agent-cli/dist/exit-classes.js
|
|
@@ -8848,43 +9102,48 @@ const EXIT_CODES = {
|
|
|
8848
9102
|
bug: 70
|
|
8849
9103
|
};
|
|
8850
9104
|
const RUNTIME_EXIT_CLASSES = {
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
8872
|
-
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
|
|
9105
|
+
INVALID_INPUT: "caller",
|
|
9106
|
+
UNKNOWN_OPTION: "caller",
|
|
9107
|
+
UNKNOWN_COMMAND: "caller",
|
|
9108
|
+
UNKNOWN_FIELD: "caller",
|
|
9109
|
+
CONFIRMATION_REQUIRED: "caller",
|
|
9110
|
+
CONFIRMATION_MISMATCH: "caller",
|
|
9111
|
+
NOT_CONFIRMED: "operator",
|
|
9112
|
+
NEEDS_OPERATOR: "operator",
|
|
9113
|
+
OUTPUT_EXISTS: "caller",
|
|
9114
|
+
STDIN_STALLED: "caller",
|
|
9115
|
+
INTERRUPTED: "interrupted",
|
|
9116
|
+
DEADLINE_EXCEEDED: "wait",
|
|
9117
|
+
INTERNAL: "bug",
|
|
9118
|
+
PERMISSION_DENIED: "operator",
|
|
9119
|
+
DISK_FULL: "operator",
|
|
9120
|
+
NOT_FOUND: "caller",
|
|
9121
|
+
ALREADY_EXISTS: "caller",
|
|
9122
|
+
NOT_A_FILE: "caller",
|
|
9123
|
+
TOOL_FAILED: "operator",
|
|
9124
|
+
TOOL_MISSING: "operator",
|
|
9125
|
+
SECRET_MISSING: "operator",
|
|
9126
|
+
PROJECT_INVALID: "operator",
|
|
9127
|
+
DOCTOR_PROBLEMS: "operator",
|
|
9128
|
+
NOT_GLOBAL_INSTALL: "operator",
|
|
9129
|
+
REGISTRY_UNREACHABLE: "operator",
|
|
9130
|
+
REGISTRY_AUTH: "operator",
|
|
9131
|
+
INSTALL_FAILED: "operator",
|
|
9132
|
+
NPM_FAILED: "operator",
|
|
9133
|
+
NO_LATEST: "source"
|
|
8879
9134
|
};
|
|
9135
|
+
function isRuntimeCode(code) {
|
|
9136
|
+
return Object.hasOwn(RUNTIME_EXIT_CLASSES, code);
|
|
9137
|
+
}
|
|
8880
9138
|
/** The codes of `errors` that the Runtime already declares, which a CLI cannot redeclare. */
|
|
8881
9139
|
function runtimeCodesIn(errors) {
|
|
8882
|
-
return Object.keys(errors).filter(
|
|
9140
|
+
return Object.keys(errors).filter(isRuntimeCode);
|
|
8883
9141
|
}
|
|
8884
9142
|
function exitClassOfOne(error, errors) {
|
|
8885
9143
|
if (!(error instanceof CliError)) return "bug";
|
|
8886
9144
|
if (error instanceof UsageError) return "caller";
|
|
8887
|
-
|
|
9145
|
+
if (isRuntimeCode(error.code)) return RUNTIME_EXIT_CLASSES[error.code];
|
|
9146
|
+
return errors[error.code]?.class ?? "bug";
|
|
8888
9147
|
}
|
|
8889
9148
|
function isBug(error, errors) {
|
|
8890
9149
|
return exitClassOfOne(error, errors) === "bug";
|
|
@@ -8912,7 +9171,7 @@ function reachableExitClasses(cli) {
|
|
|
8912
9171
|
"wait",
|
|
8913
9172
|
...cli.commands === void 0 ? [] : installOf(cli).exitClasses
|
|
8914
9173
|
];
|
|
8915
|
-
const own = Object.values(cli
|
|
9174
|
+
const own = Object.values(errorTableOf(cli)).map((declaration) => declaration.class);
|
|
8916
9175
|
return /* @__PURE__ */ new Set([...runtime, ...own]);
|
|
8917
9176
|
}
|
|
8918
9177
|
/** The signal named by an interrupt's abort reason; any other reason counts as Ctrl-C. */
|
|
@@ -8929,17 +9188,31 @@ function exitCodeOf(error, errors, stop) {
|
|
|
8929
9188
|
}
|
|
8930
9189
|
//#endregion
|
|
8931
9190
|
//#region ../agent-cli/dist/agent-cli.js
|
|
8932
|
-
function checkOwnCodes(
|
|
8933
|
-
const redeclared = runtimeCodesIn(
|
|
8934
|
-
if (redeclared.length > 0) throw new Error(
|
|
9191
|
+
function checkOwnCodes(errors) {
|
|
9192
|
+
const redeclared = runtimeCodesIn(errors);
|
|
9193
|
+
if (redeclared.length > 0) throw new Error(`The Error table declares ${redeclared.join(", ")}, an error code the Runtime already declares`);
|
|
8935
9194
|
}
|
|
8936
|
-
function
|
|
8937
|
-
|
|
9195
|
+
function checkTree(commands, path, table) {
|
|
9196
|
+
for (const [key, node] of Object.entries(commands)) {
|
|
9197
|
+
const at = [...path, key];
|
|
9198
|
+
if (isCommand(node)) checkCommand(node, at.join(" "), table);
|
|
9199
|
+
else checkTree(node, at, table);
|
|
9200
|
+
}
|
|
9201
|
+
}
|
|
9202
|
+
function checkSkillPage({ name, skill }) {
|
|
9203
|
+
if (skill === void 0 || !("page" in skill)) return;
|
|
9204
|
+
if (!URL.canParse(skill.page) || new URL(skill.page).protocol !== "https:") throw new Error(`${name} declares skill.page ${skill.page}, which is not an https URL`);
|
|
9205
|
+
}
|
|
9206
|
+
function checkCli(cli) {
|
|
9207
|
+
const table = errorTableOf(cli);
|
|
9208
|
+
checkSkillPage(cli);
|
|
8938
9209
|
if (cli.commands === void 0) {
|
|
8939
|
-
|
|
9210
|
+
checkCommand(cli.command, commandLabel([], cli.name).join(" "), table);
|
|
9211
|
+
if (skillOf$1(cli, installOf(cli)).kind === "packaged") throw new Error(`${cli.name} declares a Packaged skill, which only a CLI with several Commands can install`);
|
|
8940
9212
|
return cli;
|
|
8941
9213
|
}
|
|
8942
9214
|
const { commands } = cli;
|
|
9215
|
+
checkTree(commands, [], table);
|
|
8943
9216
|
const taken = Object.keys(builtInCommands(cli, {
|
|
8944
9217
|
bin: void 0,
|
|
8945
9218
|
node: void 0
|
|
@@ -8947,107 +9220,541 @@ function defineCli$1(cli) {
|
|
|
8947
9220
|
if (taken.length > 0) throw new Error(`${cli.name} defines ${taken.join(", ")}, a built-in Command it cannot replace`);
|
|
8948
9221
|
return cli;
|
|
8949
9222
|
}
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
|
|
8953
|
-
|
|
8954
|
-
function agentCli() {
|
|
8955
|
-
return {
|
|
8956
|
-
defineCommand: defineCommandFor(),
|
|
8957
|
-
defineCli: defineCli$1
|
|
8958
|
-
};
|
|
8959
|
-
}
|
|
8960
|
-
//#endregion
|
|
8961
|
-
//#region ../agent-cli/dist/error-table.js
|
|
8962
|
-
/**
|
|
8963
|
-
* Keeps each code's literal class and `details` schema, so `cliError` can type its throw sites;
|
|
8964
|
-
* `print` must name a string key of the code's `details`.
|
|
8965
|
-
*/
|
|
8966
|
-
function defineErrors(table) {
|
|
8967
|
-
return table;
|
|
8968
|
-
}
|
|
8969
|
-
/**
|
|
8970
|
-
* A `CliError` for a code of `table`, whose `details` must match the code's schema. The `hint`
|
|
8971
|
-
* names the next command to run and says whether running it again can help; `retryAt` (ISO 8601)
|
|
8972
|
-
* is allowed only on a wait-class code.
|
|
8973
|
-
*/
|
|
8974
|
-
function cliError(_table, code, init, options) {
|
|
8975
|
-
return new CliError({
|
|
8976
|
-
...init,
|
|
8977
|
-
code
|
|
8978
|
-
}, options);
|
|
8979
|
-
}
|
|
8980
|
-
//#endregion
|
|
8981
|
-
//#region ../agent-cli/dist/command-spec.js
|
|
8982
|
-
/** The group's Commands and groups that help and suggestions may name: hidden Commands left out. */
|
|
8983
|
-
function visibleCommands({ commands }) {
|
|
8984
|
-
return Object.fromEntries(Object.entries(commands).filter(([, node]) => node.kind === "group" || !node.hidden));
|
|
9223
|
+
function nameOf({ name, bin }) {
|
|
9224
|
+
const bins = typeof bin === "object" ? Object.keys(bin) : [];
|
|
9225
|
+
const [only] = bins;
|
|
9226
|
+
return bins.length === 1 && only !== void 0 ? only : name.replace(/^@[^/]+\//, "");
|
|
8985
9227
|
}
|
|
8986
|
-
function
|
|
8987
|
-
if (
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
cost: false
|
|
9228
|
+
function installFrom(name, manifest, install) {
|
|
9229
|
+
if (install === "dependency") return {
|
|
9230
|
+
mode: "dependency",
|
|
9231
|
+
package: manifest.name
|
|
8991
9232
|
};
|
|
8992
|
-
return {
|
|
8993
|
-
|
|
8994
|
-
|
|
8995
|
-
|
|
9233
|
+
if (install !== "global") return {
|
|
9234
|
+
mode: "dependency",
|
|
9235
|
+
package: manifest.name,
|
|
9236
|
+
lockstep: install.lockstep
|
|
8996
9237
|
};
|
|
8997
|
-
|
|
8998
|
-
|
|
8999
|
-
path: [],
|
|
9000
|
-
builtIn: false
|
|
9001
|
-
};
|
|
9002
|
-
function commandSpec(commandLine, command, { path, builtIn } = SINGLE_COMMAND) {
|
|
9003
|
-
const list = command.rows === void 0 ? void 0 : listSpec(command.rows);
|
|
9238
|
+
const registry = manifest.publishConfig?.registry;
|
|
9239
|
+
if (registry === void 0) throw new Error(`${name} declares a Global install, which needs publishConfig.registry in its package.json`);
|
|
9004
9240
|
return {
|
|
9005
|
-
|
|
9006
|
-
|
|
9007
|
-
|
|
9008
|
-
command,
|
|
9009
|
-
builtIn,
|
|
9010
|
-
description: command.description,
|
|
9011
|
-
help: command.help,
|
|
9012
|
-
hidden: command.hidden === true,
|
|
9013
|
-
operator: command.operator === true,
|
|
9014
|
-
effect: command.effect,
|
|
9015
|
-
examples: command.examples,
|
|
9016
|
-
args: argFields(command.args),
|
|
9017
|
-
options: optionFields(command.options),
|
|
9018
|
-
standardFlags: standardFlagsFor(command.effect, declaredOf(command), list),
|
|
9019
|
-
list,
|
|
9020
|
-
output: list?.output ?? command.output
|
|
9241
|
+
mode: "global",
|
|
9242
|
+
package: manifest.name,
|
|
9243
|
+
registry
|
|
9021
9244
|
};
|
|
9022
9245
|
}
|
|
9023
|
-
function
|
|
9246
|
+
function resolved(cli) {
|
|
9247
|
+
const { manifest, ...declared } = cli;
|
|
9248
|
+
const name = nameOf(manifest);
|
|
9249
|
+
const about = {
|
|
9250
|
+
name,
|
|
9251
|
+
version: manifest.version,
|
|
9252
|
+
description: manifest.description
|
|
9253
|
+
};
|
|
9254
|
+
if (declared.commands === void 0) return {
|
|
9255
|
+
...declared,
|
|
9256
|
+
...about
|
|
9257
|
+
};
|
|
9258
|
+
const { install, ...rest } = declared;
|
|
9024
9259
|
return {
|
|
9025
|
-
|
|
9026
|
-
|
|
9027
|
-
|
|
9260
|
+
...rest,
|
|
9261
|
+
...about,
|
|
9262
|
+
...manifest.engines === void 0 ? {} : { engines: manifest.engines },
|
|
9263
|
+
...install === void 0 ? {} : { install: installFrom(name, manifest, install) }
|
|
9028
9264
|
};
|
|
9029
9265
|
}
|
|
9030
|
-
/**
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9266
|
+
/**
|
|
9267
|
+
* Takes the CLI's ports factory, Project file and Error table once; the `defineCommand`,
|
|
9268
|
+
* `defineCli` and `cliError` it returns are typed by them.
|
|
9269
|
+
*/
|
|
9270
|
+
function agentCli(values = {}) {
|
|
9271
|
+
checkOwnCodes(errorTableOf(values));
|
|
9272
|
+
return {
|
|
9273
|
+
defineCommand: defineCommandFor(),
|
|
9274
|
+
defineCli: (cli) => checkCli({
|
|
9275
|
+
...resolved(cli),
|
|
9276
|
+
...values
|
|
9036
9277
|
}),
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
|
|
9044
|
-
|
|
9045
|
-
|
|
9046
|
-
|
|
9047
|
-
|
|
9048
|
-
}
|
|
9049
|
-
|
|
9050
|
-
|
|
9278
|
+
cliError: cliErrorOf
|
|
9279
|
+
};
|
|
9280
|
+
}
|
|
9281
|
+
//#endregion
|
|
9282
|
+
//#region ../agent-cli/dist/context/side-task.js
|
|
9283
|
+
/** How long a run waits for its Side task once its output is written. */
|
|
9284
|
+
const SIDE_TASK_WAIT_MS = 1e3;
|
|
9285
|
+
const noSideTask = async () => {};
|
|
9286
|
+
function waitOver() {
|
|
9287
|
+
return new DOMException(`the side task ran past its ${SIDE_TASK_WAIT_MS} ms wait`, "TimeoutError");
|
|
9288
|
+
}
|
|
9289
|
+
function startSideTask(sideTask, runWith, { clock, failed }) {
|
|
9290
|
+
if (sideTask === void 0) return noSideTask;
|
|
9291
|
+
const controller = new AbortController();
|
|
9292
|
+
const { signal } = controller;
|
|
9293
|
+
const running = (async () => sideTask(runWith(signal)))().catch((error) => {
|
|
9294
|
+
if (!(signal.aborted && error === signal.reason)) failed(error);
|
|
9295
|
+
});
|
|
9296
|
+
return async () => {
|
|
9297
|
+
const waited = new AbortController();
|
|
9298
|
+
const capped = new Promise((resolve) => after(clock, SIDE_TASK_WAIT_MS, waited.signal, () => {
|
|
9299
|
+
const over = waitOver();
|
|
9300
|
+
failed(over);
|
|
9301
|
+
controller.abort(over);
|
|
9302
|
+
resolve();
|
|
9303
|
+
}));
|
|
9304
|
+
await Promise.race([running, capped]);
|
|
9305
|
+
waited.abort();
|
|
9306
|
+
};
|
|
9307
|
+
}
|
|
9308
|
+
//#endregion
|
|
9309
|
+
//#region ../agent-cli/dist/command-line/suggest.js
|
|
9310
|
+
const MAX_DISTANCE = 3;
|
|
9311
|
+
const MIN_SIMILARITY = .4;
|
|
9312
|
+
function distance(a, b) {
|
|
9313
|
+
const width = b.length + 1;
|
|
9314
|
+
const d = Array.from({ length: (a.length + 1) * width }, (_, k) => {
|
|
9315
|
+
const i = Math.floor(k / width);
|
|
9316
|
+
const j = k % width;
|
|
9317
|
+
return i === 0 || j === 0 ? i + j : 0;
|
|
9318
|
+
});
|
|
9319
|
+
const at = (i, j) => d[i * width + j] ?? 0;
|
|
9320
|
+
for (let i = 1; i <= a.length; i++) for (let j = 1; j <= b.length; j++) {
|
|
9321
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
9322
|
+
const edit = Math.min(at(i - 1, j) + 1, at(i, j - 1) + 1, at(i - 1, j - 1) + cost);
|
|
9323
|
+
const transposed = i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1];
|
|
9324
|
+
d[i * width + j] = transposed ? Math.min(edit, at(i - 2, j - 2) + 1) : edit;
|
|
9325
|
+
}
|
|
9326
|
+
return at(a.length, b.length);
|
|
9327
|
+
}
|
|
9328
|
+
function isClose(word, candidate) {
|
|
9329
|
+
const length = Math.max(word.length, candidate.length);
|
|
9330
|
+
const edits = distance(word, candidate);
|
|
9331
|
+
return candidate.length > 1 && edits < MAX_DISTANCE && (length - edits) / length > MIN_SIMILARITY;
|
|
9332
|
+
}
|
|
9333
|
+
/** The names closest to `word`, sorted, several when they tie, or none when nothing is close. */
|
|
9334
|
+
function closestNames(word, names) {
|
|
9335
|
+
const close = [...new Set(names)].filter((candidate) => isClose(word, candidate));
|
|
9336
|
+
const best = Math.min(...close.map((candidate) => distance(word, candidate)));
|
|
9337
|
+
return close.filter((candidate) => distance(word, candidate) === best).sort((a, b) => a.localeCompare(b));
|
|
9338
|
+
}
|
|
9339
|
+
/** The long flags closest to `flag`, sorted, or none for a short flag or when nothing is close. */
|
|
9340
|
+
function closestFlags(flag, flags) {
|
|
9341
|
+
if (!flag.startsWith("--")) return [];
|
|
9342
|
+
const names = flags.map((candidate) => candidate.slice(2));
|
|
9343
|
+
return closestNames(flag.slice(2), names).map((name) => `--${name}`);
|
|
9344
|
+
}
|
|
9345
|
+
/** The one long flag closest to `flag`, or none when nothing is close or several tie. */
|
|
9346
|
+
function closestFlag(flag, flags) {
|
|
9347
|
+
const closest = closestFlags(flag, flags);
|
|
9348
|
+
return closest.length === 1 ? closest[0] : void 0;
|
|
9349
|
+
}
|
|
9350
|
+
//#endregion
|
|
9351
|
+
//#region ../agent-cli/dist/command-line/parse-input.js
|
|
9352
|
+
const NO_INPUT = object({});
|
|
9353
|
+
const WHITESPACE = /\s/;
|
|
9354
|
+
function knownFlags(spec) {
|
|
9355
|
+
return [...spec.options.map((field) => ({
|
|
9356
|
+
flag: field.label,
|
|
9357
|
+
takes: field.type === "boolean" ? "nothing" : "optional value"
|
|
9358
|
+
})), ...spec.standardFlags.map(({ flag, takes }) => ({
|
|
9359
|
+
flag,
|
|
9360
|
+
takes
|
|
9361
|
+
}))];
|
|
9362
|
+
}
|
|
9363
|
+
function candidateFlags(known) {
|
|
9364
|
+
return [
|
|
9365
|
+
...known.map(({ flag }) => flag),
|
|
9366
|
+
VERSION_FLAG,
|
|
9367
|
+
HELP_FLAG
|
|
9368
|
+
];
|
|
9369
|
+
}
|
|
9370
|
+
function unknownOptionsOf(words, candidates) {
|
|
9371
|
+
return words.map((word) => {
|
|
9372
|
+
const flag = word.split("=")[0] ?? word;
|
|
9373
|
+
return {
|
|
9374
|
+
flag,
|
|
9375
|
+
suggestion: closestFlag(flag, candidates)
|
|
9376
|
+
};
|
|
9377
|
+
});
|
|
9378
|
+
}
|
|
9379
|
+
function optionValue(field, all) {
|
|
9380
|
+
if (field.variadic) return variadicValue(field, (all ?? []).filter((value) => value !== true));
|
|
9381
|
+
const raw = all?.[all.length - 1];
|
|
9382
|
+
return field.type === "boolean" && raw === true && field.label === `--no-${field.name}` ? false : raw;
|
|
9383
|
+
}
|
|
9384
|
+
function converted(field, raw) {
|
|
9385
|
+
if (Array.isArray(raw)) return raw.map((element) => converted(field, element));
|
|
9386
|
+
if (field.type !== "number" || typeof raw !== "string" || raw.trim() === "") return raw;
|
|
9387
|
+
const number = Number(raw);
|
|
9388
|
+
return Number.isNaN(number) ? raw : number;
|
|
9389
|
+
}
|
|
9390
|
+
function variadicValue(field, values) {
|
|
9391
|
+
return values.length === 0 && !field.required ? void 0 : values;
|
|
9392
|
+
}
|
|
9393
|
+
function parse(schema, values) {
|
|
9394
|
+
const input = Object.fromEntries([...values].filter(([, raw]) => raw !== void 0).map(([field, raw]) => [field.key, converted(field, raw)]));
|
|
9395
|
+
return schema.safeParse(input);
|
|
9396
|
+
}
|
|
9397
|
+
function issueLines(result, values, { howToPass, arrayIssueLine, reported = [], fromStdin }) {
|
|
9398
|
+
if (result.success) return [];
|
|
9399
|
+
return result.error.issues.flatMap((issue) => {
|
|
9400
|
+
const field = [...values.keys()].find((candidate) => candidate.key === issue.path[0]);
|
|
9401
|
+
if (field === void 0) return [` ${issue.message}`];
|
|
9402
|
+
if (reported.includes(field)) return [];
|
|
9403
|
+
const raw = values.get(field);
|
|
9404
|
+
if (raw === void 0) return [` ${field.label}: required, ${howToPass(field)}`];
|
|
9405
|
+
if (field === fromStdin) return [` ${field.label} from stdin: ${issue.message}`];
|
|
9406
|
+
return Array.isArray(raw) ? [arrayIssueLine(field, raw, issue)] : [` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`];
|
|
9407
|
+
});
|
|
9408
|
+
}
|
|
9409
|
+
function flagValuesIssueLine(field, raw, issue) {
|
|
9410
|
+
const [, element] = issue.path;
|
|
9411
|
+
if (typeof element === "number") return ` ${field.label} ${JSON.stringify(raw[element])}: ${issue.message}`;
|
|
9412
|
+
return raw.length === 0 ? ` ${field.label}: ${issue.message}, pass ${field.usage}` : ` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`;
|
|
9413
|
+
}
|
|
9414
|
+
function operandsIssueLine(field, raw, issue, first) {
|
|
9415
|
+
const [, element] = issue.path;
|
|
9416
|
+
if (typeof element === "number") return ` ${field.label} ${JSON.stringify(raw[element])} (argument ${first + element}): ${issue.message}`;
|
|
9417
|
+
return raw.length === 0 ? ` ${field.label}: ${issue.message}, pass them as arguments from ${first}` : ` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`;
|
|
9418
|
+
}
|
|
9419
|
+
function unknownLine({ flag, suggestion }) {
|
|
9420
|
+
return ` unknown option '${flag}'${suggestion === void 0 ? "" : ` (did you mean ${suggestion}?)`}`;
|
|
9421
|
+
}
|
|
9422
|
+
function invalidInput(commandLine, invocation, unknown, otherLines) {
|
|
9423
|
+
const renames = new Map(unknown.flatMap(({ flag, suggestion }) => suggestion === void 0 ? [] : [[flag, suggestion]]));
|
|
9424
|
+
const correctable = otherLines.length === 0 && renames.size === unknown.length;
|
|
9425
|
+
return new UsageError({
|
|
9426
|
+
code: INVALID_INPUT,
|
|
9427
|
+
message: [
|
|
9428
|
+
`invalid input for \`${commandLine}\``,
|
|
9429
|
+
...unknown.map(unknownLine),
|
|
9430
|
+
...otherLines
|
|
9431
|
+
].join("\n"),
|
|
9432
|
+
hint: correctable ? `did you mean \`${commandLineRenaming(invocation, renames)}\`?` : `run \`${commandLine} --help\` to see the expected input`
|
|
9433
|
+
});
|
|
9434
|
+
}
|
|
9435
|
+
function stdinFieldOf(spec, operands) {
|
|
9436
|
+
const index = spec.args.findIndex((field) => field.stdin);
|
|
9437
|
+
return operands[index]?.value === "-" ? spec.args[index] : void 0;
|
|
9438
|
+
}
|
|
9439
|
+
/** The name of the routed Command's arg given `-`, which takes its text from stdin. */
|
|
9440
|
+
function stdinArgOf({ spec, words }) {
|
|
9441
|
+
return stdinFieldOf(spec, tokenize(words, knownFlags(spec)).operands)?.name;
|
|
9442
|
+
}
|
|
9443
|
+
async function stdinTextOf(spec, operands, read) {
|
|
9444
|
+
const field = stdinFieldOf(spec, operands);
|
|
9445
|
+
return field === void 0 ? void 0 : {
|
|
9446
|
+
field,
|
|
9447
|
+
text: await read(field)
|
|
9448
|
+
};
|
|
9449
|
+
}
|
|
9450
|
+
async function parseInput(spec, words, invocation, readStdin) {
|
|
9451
|
+
const { command, args: argFields, options: optionFields } = spec;
|
|
9452
|
+
const pageFields = spec.list?.pageFields ?? [];
|
|
9453
|
+
const known = knownFlags(spec);
|
|
9454
|
+
const { operands, unknownOptions, values, occurrences } = tokenize(words, known);
|
|
9455
|
+
const stdin = await stdinTextOf(spec, operands, readStdin);
|
|
9456
|
+
if (values.get(CONFIRM_FLAG.flag) === true) throw invalidInputError(spec.commandLine, `option '${CONFIRM_FLAG.usage}' argument missing`);
|
|
9457
|
+
const missing = [...optionFields, ...pageFields].filter((field) => field.type !== "boolean" && (field.variadic ? occurrences.get(field.label)?.includes(true) : values.get(field.label) === true));
|
|
9458
|
+
const argValue = (field, index) => {
|
|
9459
|
+
if (field === stdin?.field) return stdin.text;
|
|
9460
|
+
if (!field.variadic) return operands[index]?.value;
|
|
9461
|
+
return variadicValue(field, operands.slice(index).filter((operand) => !operand.afterUnknownOption).map((operand) => operand.value));
|
|
9462
|
+
};
|
|
9463
|
+
const argValues = new Map(argFields.map((field, index) => [field, argValue(field, index)]));
|
|
9464
|
+
const extraOperands = argFields.some((field) => field.variadic) ? [] : operands.slice(argFields.length);
|
|
9465
|
+
const valuesOf = (fields) => new Map(fields.map((field) => [field, missing.includes(field) ? void 0 : optionValue(field, occurrences.get(field.label))]));
|
|
9466
|
+
const flagWording = {
|
|
9467
|
+
howToPass: (field) => `pass ${field.usage}`,
|
|
9468
|
+
arrayIssueLine: flagValuesIssueLine,
|
|
9469
|
+
reported: missing
|
|
9470
|
+
};
|
|
9471
|
+
const optionValues = valuesOf(optionFields);
|
|
9472
|
+
const pageValues = valuesOf(pageFields);
|
|
9473
|
+
const args = parse(command.args ?? NO_INPUT, argValues);
|
|
9474
|
+
const options = parse(command.options ?? NO_INPUT, optionValues);
|
|
9475
|
+
const page = parse(PAGE_INPUT, pageValues);
|
|
9476
|
+
const unknown = unknownOptionsOf(unknownOptions, candidateFlags(known));
|
|
9477
|
+
const otherLines = [
|
|
9478
|
+
...missing.map((field) => ` ${field.label}: missing value, pass ${field.usage}`),
|
|
9479
|
+
...extraOperands.filter((operand) => !operand.afterUnknownOption).map((operand) => ` unexpected argument ${JSON.stringify(operand.value)}`),
|
|
9480
|
+
...issueLines(args, argValues, {
|
|
9481
|
+
howToPass: (field) => `pass it as argument ${argFields.indexOf(field) + 1}`,
|
|
9482
|
+
arrayIssueLine: (field, raw, issue) => operandsIssueLine(field, raw, issue, argFields.indexOf(field) + 1),
|
|
9483
|
+
fromStdin: stdin?.field
|
|
9484
|
+
}),
|
|
9485
|
+
...issueLines(options, optionValues, flagWording),
|
|
9486
|
+
...issueLines(page, pageValues, flagWording)
|
|
9487
|
+
];
|
|
9488
|
+
if (unknown.length === 0 && otherLines.length === 0 && args.success && options.success && page.success) return {
|
|
9489
|
+
input: {
|
|
9490
|
+
...args.data,
|
|
9491
|
+
...options.data
|
|
9492
|
+
},
|
|
9493
|
+
page: page.data,
|
|
9494
|
+
values
|
|
9495
|
+
};
|
|
9496
|
+
const [onlyWord] = unknownOptions;
|
|
9497
|
+
if (onlyWord !== void 0 && unknownOptions.length === 1 && WHITESPACE.test(onlyWord) && argFields.some((field) => field.stdin && argValues.get(field) === void 0)) throw stdinTextError(spec.commandLine, invocation, onlyWord);
|
|
9498
|
+
const [only] = unknown;
|
|
9499
|
+
if (only !== void 0 && unknown.length === 1 && otherLines.length === 0) throw unknownOptionError(spec.commandLine, invocation, only.flag, only.suggestion === void 0 ? [] : [only.suggestion]);
|
|
9500
|
+
throw invalidInput(spec.commandLine, invocation, unknown, otherLines);
|
|
9501
|
+
}
|
|
9502
|
+
/**
|
|
9503
|
+
* The validated input and Standard flag values of the routed Command, or one usage error; the arg
|
|
9504
|
+
* given `-` takes its text from `readStdin`.
|
|
9505
|
+
*/
|
|
9506
|
+
async function parseCommand({ spec, words, json }, invocation, readStdin) {
|
|
9507
|
+
const { input, page, values } = await parseInput(spec, words, invocation, readStdin);
|
|
9508
|
+
const confirm = values.get(CONFIRM_FLAG.flag);
|
|
9509
|
+
return {
|
|
9510
|
+
input,
|
|
9511
|
+
flags: {
|
|
9512
|
+
json,
|
|
9513
|
+
dryRun: values.get(DRY_RUN_FLAG.flag) === true,
|
|
9514
|
+
confirm: typeof confirm === "string" ? confirm : void 0,
|
|
9515
|
+
yes: values.get(YES_FLAG.flag) === true,
|
|
9516
|
+
force: values.get(FORCE_FLAG.flag) === true,
|
|
9517
|
+
page,
|
|
9518
|
+
fields: spec.list === void 0 ? void 0 : selectedFields(values, spec.list.rowFields, spec.commandLine)
|
|
9519
|
+
}
|
|
9520
|
+
};
|
|
9521
|
+
}
|
|
9522
|
+
//#endregion
|
|
9523
|
+
//#region ../agent-cli/dist/command-line/route.js
|
|
9524
|
+
const GROUP_FLAGS = [
|
|
9525
|
+
HELP_FLAG,
|
|
9526
|
+
VERSION_FLAG,
|
|
9527
|
+
JSON_FLAG.flag
|
|
9528
|
+
];
|
|
9529
|
+
function beforeEnd(words) {
|
|
9530
|
+
const end = words.indexOf("--");
|
|
9531
|
+
return end === -1 ? words : words.slice(0, end);
|
|
9532
|
+
}
|
|
9533
|
+
function wantsHelp(words) {
|
|
9534
|
+
return beforeEnd(words).some((word) => word === "--help" || word === "-h");
|
|
9535
|
+
}
|
|
9536
|
+
function childOf(group, name) {
|
|
9537
|
+
return Object.hasOwn(group.commands, name) ? group.commands[name] : void 0;
|
|
9538
|
+
}
|
|
9539
|
+
function isFlagLike(word) {
|
|
9540
|
+
return word.length > 1 && word[0] === "-";
|
|
9541
|
+
}
|
|
9542
|
+
function walk(node, words, json, invocation) {
|
|
9543
|
+
const help = {
|
|
9544
|
+
kind: "help",
|
|
9545
|
+
node,
|
|
9546
|
+
json
|
|
9547
|
+
};
|
|
9548
|
+
if (node.kind === "command") return wantsHelp(words) ? help : {
|
|
9549
|
+
kind: "command",
|
|
9550
|
+
spec: node,
|
|
9551
|
+
words,
|
|
9552
|
+
json
|
|
9553
|
+
};
|
|
9554
|
+
const [first, ...rest] = words;
|
|
9555
|
+
if (first === void 0) return help;
|
|
9556
|
+
const child = childOf(node, first);
|
|
9557
|
+
if (child !== void 0) return walk(child, rest, json, invocation);
|
|
9558
|
+
if (first === "--") {
|
|
9559
|
+
const [name, ...after] = rest;
|
|
9560
|
+
if (name === void 0) return help;
|
|
9561
|
+
const named = childOf(node, name);
|
|
9562
|
+
if (named !== void 0) return walk(named, ["--", ...after], json, invocation);
|
|
9563
|
+
return unknownCommand(node, name, json);
|
|
9564
|
+
}
|
|
9565
|
+
if (wantsHelp(words)) return help;
|
|
9566
|
+
if (isFlagLike(first)) {
|
|
9567
|
+
const suggestions = closestFlags(first, GROUP_FLAGS);
|
|
9568
|
+
return {
|
|
9569
|
+
kind: "usage error",
|
|
9570
|
+
error: unknownOptionError(node.commandLine, invocation, first, suggestions),
|
|
9571
|
+
node,
|
|
9572
|
+
json
|
|
9573
|
+
};
|
|
9574
|
+
}
|
|
9575
|
+
return unknownCommand(node, first, json);
|
|
9576
|
+
}
|
|
9577
|
+
function unknownCommand(group, name, json) {
|
|
9578
|
+
const suggestions = closestNames(name, Object.keys(visibleCommands(group)));
|
|
9579
|
+
return {
|
|
9580
|
+
kind: "usage error",
|
|
9581
|
+
error: unknownCommandError(group.commandLine, name, suggestions),
|
|
9582
|
+
node: group,
|
|
9583
|
+
json
|
|
9584
|
+
};
|
|
9585
|
+
}
|
|
9586
|
+
/** Walks the caller's command line through the Commands to the one it names, or to a stop. */
|
|
9587
|
+
function route(root, invocation) {
|
|
9588
|
+
const { argv } = invocation;
|
|
9589
|
+
const options = beforeEnd(argv);
|
|
9590
|
+
const json = options.includes(JSON_FLAG.flag);
|
|
9591
|
+
if (options.includes("--version")) return {
|
|
9592
|
+
kind: "version",
|
|
9593
|
+
json
|
|
9594
|
+
};
|
|
9595
|
+
return walk(root, argv.filter((word, index) => !(index < options.length && word === JSON_FLAG.flag)), json, invocation);
|
|
9596
|
+
}
|
|
9597
|
+
//#endregion
|
|
9598
|
+
//#region ../agent-cli/dist/command-line/route-line.js
|
|
9599
|
+
/** Routes `argv`, the line's words after the Run-as, to a Command of `root`. */
|
|
9600
|
+
function routeLine(root, runAs, argv) {
|
|
9601
|
+
if (!argv.ok) return {
|
|
9602
|
+
ok: false,
|
|
9603
|
+
reason: `it does not tokenize: ${argv.reason}`
|
|
9604
|
+
};
|
|
9605
|
+
const invocation = {
|
|
9606
|
+
runAs,
|
|
9607
|
+
argv: argv.words,
|
|
9608
|
+
flags: []
|
|
9609
|
+
};
|
|
9610
|
+
const routed = route(root, invocation);
|
|
9611
|
+
switch (routed.kind) {
|
|
9612
|
+
case "usage error": return {
|
|
9613
|
+
ok: false,
|
|
9614
|
+
reason: routed.error.message
|
|
9615
|
+
};
|
|
9616
|
+
case "help":
|
|
9617
|
+
case "version": return {
|
|
9618
|
+
ok: false,
|
|
9619
|
+
reason: "it names no Command"
|
|
9620
|
+
};
|
|
9621
|
+
case "command": return {
|
|
9622
|
+
ok: true,
|
|
9623
|
+
routed,
|
|
9624
|
+
invocation
|
|
9625
|
+
};
|
|
9626
|
+
}
|
|
9627
|
+
}
|
|
9628
|
+
//#endregion
|
|
9629
|
+
//#region ../agent-cli/dist/command-line/shell-words.js
|
|
9630
|
+
const BLANK = /\s/;
|
|
9631
|
+
const SHELL_SYNTAX = /* @__PURE__ */ new Set([
|
|
9632
|
+
"|",
|
|
9633
|
+
"&",
|
|
9634
|
+
";",
|
|
9635
|
+
">",
|
|
9636
|
+
"(",
|
|
9637
|
+
")",
|
|
9638
|
+
"$",
|
|
9639
|
+
"`"
|
|
9640
|
+
]);
|
|
9641
|
+
const STDIN_REDIRECT = "<";
|
|
9642
|
+
const DOUBLE_QUOTE_ESCAPES = /* @__PURE__ */ new Set([
|
|
9643
|
+
"$",
|
|
9644
|
+
"`",
|
|
9645
|
+
"\"",
|
|
9646
|
+
"\\"
|
|
9647
|
+
]);
|
|
9648
|
+
function quotedFrom(line, start, quote) {
|
|
9649
|
+
let word = "";
|
|
9650
|
+
for (let index = start; index < line.length; index += 1) {
|
|
9651
|
+
const char = line[index] ?? "";
|
|
9652
|
+
if (char === quote) return {
|
|
9653
|
+
word,
|
|
9654
|
+
end: index + 1
|
|
9655
|
+
};
|
|
9656
|
+
const next = line[index + 1];
|
|
9657
|
+
if (quote === "\"" && char === "\\" && next !== void 0 && DOUBLE_QUOTE_ESCAPES.has(next)) {
|
|
9658
|
+
word += next;
|
|
9659
|
+
index += 1;
|
|
9660
|
+
} else word += char;
|
|
9661
|
+
}
|
|
9662
|
+
}
|
|
9663
|
+
function skipBlanks(line, start) {
|
|
9664
|
+
let index = start;
|
|
9665
|
+
while (BLANK.test(line[index] ?? "")) index += 1;
|
|
9666
|
+
return index;
|
|
9667
|
+
}
|
|
9668
|
+
function isBoundary(char) {
|
|
9669
|
+
return BLANK.test(char) || char === STDIN_REDIRECT || SHELL_SYNTAX.has(char);
|
|
9670
|
+
}
|
|
9671
|
+
function wordFrom(line, start) {
|
|
9672
|
+
let word = "";
|
|
9673
|
+
let index = start;
|
|
9674
|
+
while (index < line.length && !isBoundary(line[index] ?? "")) {
|
|
9675
|
+
const char = line[index] ?? "";
|
|
9676
|
+
if (char === "'" || char === "\"") {
|
|
9677
|
+
const quoted = quotedFrom(line, index + 1, char);
|
|
9678
|
+
if (quoted === void 0) return { reason: `its ${char} is never closed` };
|
|
9679
|
+
word += quoted.word;
|
|
9680
|
+
index = quoted.end;
|
|
9681
|
+
} else if (char === "\\") {
|
|
9682
|
+
word += line[index + 1] ?? "";
|
|
9683
|
+
index += 2;
|
|
9684
|
+
} else {
|
|
9685
|
+
word += char;
|
|
9686
|
+
index += 1;
|
|
9687
|
+
}
|
|
9688
|
+
}
|
|
9689
|
+
return {
|
|
9690
|
+
word,
|
|
9691
|
+
end: index
|
|
9692
|
+
};
|
|
9693
|
+
}
|
|
9694
|
+
/**
|
|
9695
|
+
* The words a POSIX shell would pass for `line`, without the file of a `< file` redirect; a reason
|
|
9696
|
+
* instead when a quote is left open or the line uses other shell syntax.
|
|
9697
|
+
*/
|
|
9698
|
+
function shellWords(line) {
|
|
9699
|
+
const words = [];
|
|
9700
|
+
let index = skipBlanks(line, 0);
|
|
9701
|
+
while (index < line.length) {
|
|
9702
|
+
const redirect = line[index] === STDIN_REDIRECT;
|
|
9703
|
+
if (redirect) index = skipBlanks(line, index + 1);
|
|
9704
|
+
const char = line[index];
|
|
9705
|
+
if (char === void 0 || char === STDIN_REDIRECT) return {
|
|
9706
|
+
ok: false,
|
|
9707
|
+
reason: "its `<` names no file"
|
|
9708
|
+
};
|
|
9709
|
+
if (SHELL_SYNTAX.has(char)) return {
|
|
9710
|
+
ok: false,
|
|
9711
|
+
reason: `it uses the shell's \`${char}\``
|
|
9712
|
+
};
|
|
9713
|
+
const scanned = wordFrom(line, index);
|
|
9714
|
+
if ("reason" in scanned) return {
|
|
9715
|
+
ok: false,
|
|
9716
|
+
reason: scanned.reason
|
|
9717
|
+
};
|
|
9718
|
+
if (!redirect) words.push(scanned.word);
|
|
9719
|
+
index = skipBlanks(line, scanned.end);
|
|
9720
|
+
}
|
|
9721
|
+
return {
|
|
9722
|
+
ok: true,
|
|
9723
|
+
words
|
|
9724
|
+
};
|
|
9725
|
+
}
|
|
9726
|
+
//#endregion
|
|
9727
|
+
//#region ../agent-cli/dist/check-next-steps.js
|
|
9728
|
+
function argvOf(words, runAs) {
|
|
9729
|
+
const line = shellWords(lineOf(words, runAs));
|
|
9730
|
+
const lead = shellWords(runAs);
|
|
9731
|
+
if (!lead.ok) return lead;
|
|
9732
|
+
if (!line.ok) return line;
|
|
9733
|
+
return {
|
|
9734
|
+
ok: true,
|
|
9735
|
+
words: line.words.slice(lead.words.length)
|
|
9736
|
+
};
|
|
9737
|
+
}
|
|
9738
|
+
/**
|
|
9739
|
+
* Why `step` would not run a Command of `root`, or `undefined` when it would. A line given whole is
|
|
9740
|
+
* not checked, since it may run another program.
|
|
9741
|
+
*/
|
|
9742
|
+
function nextStepProblem(root, runAs, step) {
|
|
9743
|
+
const words = wordsOf(step);
|
|
9744
|
+
if (words === void 0) return void 0;
|
|
9745
|
+
const line = routeLine(root, runAs, argvOf(words, runAs));
|
|
9746
|
+
if (!line.ok) return line.reason;
|
|
9747
|
+
const { routed } = line;
|
|
9748
|
+
const { unknownOptions } = tokenize(routed.words, knownFlags(routed.spec));
|
|
9749
|
+
return unknownOptions.length === 0 ? void 0 : `unknown option ${unknownOptions.join(", ")}`;
|
|
9750
|
+
}
|
|
9751
|
+
/** `error`, or a bug naming each of its Next steps that would not run. */
|
|
9752
|
+
function checkedNextSteps(error, check, runAs) {
|
|
9753
|
+
const problems = errorsOf(error).flatMap((leaf) => leaf instanceof CliError ? leaf.next.flatMap((step) => {
|
|
9754
|
+
const problem = check(step);
|
|
9755
|
+
return problem === void 0 ? [] : [`\`${lineOf(step, runAs)}\`, a Next step of ${leaf.code}: ${problem}`];
|
|
9756
|
+
}) : []);
|
|
9757
|
+
return problems.length === 0 ? error : new Error(`a Next step would not run: ${problems.join("; ")}`, { cause: error });
|
|
9051
9758
|
}
|
|
9052
9759
|
//#endregion
|
|
9053
9760
|
//#region ../agent-cli/dist/help.js
|
|
@@ -9115,6 +9822,7 @@ function groupHelp(group, style) {
|
|
|
9115
9822
|
}
|
|
9116
9823
|
const EFFECT_NOTES = {
|
|
9117
9824
|
read: "changes nothing",
|
|
9825
|
+
act: "changes the state of a running program, not files or services; may act again each time it runs",
|
|
9118
9826
|
write: "changes something; show the Plan with --dry-run",
|
|
9119
9827
|
destructive: "changes something hard to undo; show the Plan with --dry-run, run with --confirm",
|
|
9120
9828
|
serve: "changes nothing; prints its data at once, then runs until Ctrl-C, which exits 0"
|
|
@@ -9170,7 +9878,7 @@ function inputSchema(schema) {
|
|
|
9170
9878
|
function optionsSchema(options) {
|
|
9171
9879
|
return inputSchema(object(Object.fromEntries(options.map(({ name, schema }) => [name, schema]))));
|
|
9172
9880
|
}
|
|
9173
|
-
function commandData(spec) {
|
|
9881
|
+
function commandData(spec, table) {
|
|
9174
9882
|
return {
|
|
9175
9883
|
name: spec.commandLine,
|
|
9176
9884
|
description: spec.description,
|
|
@@ -9178,6 +9886,11 @@ function commandData(spec) {
|
|
|
9178
9886
|
effect: spec.effect,
|
|
9179
9887
|
operator: spec.operator,
|
|
9180
9888
|
examples: spec.examples,
|
|
9889
|
+
secrets: spec.command.secrets ?? [],
|
|
9890
|
+
errors: (spec.command.errors ?? []).map((code) => ({
|
|
9891
|
+
code,
|
|
9892
|
+
class: table[code]?.class
|
|
9893
|
+
})),
|
|
9181
9894
|
args: inputSchema(spec.command.args ?? object({})),
|
|
9182
9895
|
options: optionsSchema(spec.options),
|
|
9183
9896
|
standardFlags: spec.standardFlags.map(({ usage, description, schema }) => ({
|
|
@@ -9188,13 +9901,13 @@ function commandData(spec) {
|
|
|
9188
9901
|
output: spec.output === void 0 ? null : toJSONSchema(spec.output, { unrepresentable: "any" })
|
|
9189
9902
|
};
|
|
9190
9903
|
}
|
|
9191
|
-
function nodeData(node) {
|
|
9192
|
-
return node.kind === "command" ? commandData(node) : groupData(node);
|
|
9904
|
+
function nodeData(node, table) {
|
|
9905
|
+
return node.kind === "command" ? commandData(node, table) : groupData(node, table);
|
|
9193
9906
|
}
|
|
9194
|
-
function groupData(group) {
|
|
9907
|
+
function groupData(group, table) {
|
|
9195
9908
|
return {
|
|
9196
9909
|
name: group.commandLine,
|
|
9197
|
-
commands: Object.values(visibleCommands(group)).map(nodeData)
|
|
9910
|
+
commands: Object.values(visibleCommands(group)).map((node) => nodeData(node, table))
|
|
9198
9911
|
};
|
|
9199
9912
|
}
|
|
9200
9913
|
function printed$1(data) {
|
|
@@ -9206,21 +9919,31 @@ function errorsData(errors) {
|
|
|
9206
9919
|
details: declaration.details === void 0 ? null : toJSONSchema(declaration.details, { unrepresentable: "any" })
|
|
9207
9920
|
}]));
|
|
9208
9921
|
}
|
|
9209
|
-
function
|
|
9210
|
-
return
|
|
9922
|
+
function publishedTable(table, root) {
|
|
9923
|
+
if (root.kind !== "command") return table;
|
|
9924
|
+
const declared = new Set(root.command.errors ?? []);
|
|
9925
|
+
return Object.fromEntries(Object.entries(table).filter(([code]) => declared.has(code)));
|
|
9926
|
+
}
|
|
9927
|
+
function cliHelpJson(cli, root) {
|
|
9928
|
+
const { name, version, description } = cli;
|
|
9929
|
+
const header = {
|
|
9211
9930
|
name,
|
|
9212
9931
|
version,
|
|
9213
|
-
description
|
|
9214
|
-
|
|
9932
|
+
description
|
|
9933
|
+
};
|
|
9934
|
+
const table = errorTableOf(cli);
|
|
9935
|
+
return printed$1({
|
|
9936
|
+
...header,
|
|
9937
|
+
...nodeData(root, table),
|
|
9215
9938
|
name,
|
|
9216
|
-
errors: errorsData(
|
|
9939
|
+
errors: errorsData(publishedTable(table, root))
|
|
9217
9940
|
});
|
|
9218
9941
|
}
|
|
9219
|
-
function groupHelpJson(group) {
|
|
9220
|
-
return printed$1(groupData(group));
|
|
9942
|
+
function groupHelpJson(group, table) {
|
|
9943
|
+
return printed$1(groupData(group, table));
|
|
9221
9944
|
}
|
|
9222
|
-
function commandHelpJson(spec) {
|
|
9223
|
-
return printed$1(commandData(spec));
|
|
9945
|
+
function commandHelpJson(spec, table) {
|
|
9946
|
+
return printed$1(commandData(spec, table));
|
|
9224
9947
|
}
|
|
9225
9948
|
//#endregion
|
|
9226
9949
|
//#region ../agent-cli/dist/output.js
|
|
@@ -9229,14 +9952,14 @@ function withTrailingNewline(text) {
|
|
|
9229
9952
|
return text === "" || text.endsWith("\n") ? text : `${text}\n`;
|
|
9230
9953
|
}
|
|
9231
9954
|
function printed(value, render, { json, invocation, style, fields }) {
|
|
9232
|
-
if (!(value instanceof Page)) return json ? `${JSON.stringify(value)}\n` : withTrailingNewline(render(style));
|
|
9955
|
+
if (!(value instanceof Page)) return json ? `${JSON.stringify(value ?? null)}\n` : withTrailingNewline(render(style));
|
|
9233
9956
|
const page = printedPage(value, invocation);
|
|
9234
|
-
if (fields === void 0) return json ? `${JSON.stringify(page)}\n` : `${withTrailingNewline(render(style))}${pageFooter(page)}`;
|
|
9957
|
+
if (fields === void 0) return json ? `${JSON.stringify(page)}\n` : `${withTrailingNewline(render(style))}${pageFooter(page, style)}`;
|
|
9235
9958
|
const rows = projected(page.items, fields);
|
|
9236
9959
|
return json ? `${JSON.stringify({
|
|
9237
9960
|
...page,
|
|
9238
9961
|
items: rows
|
|
9239
|
-
})}\n` : `${renderRows(rows, fields)}${pageFooter(page)}`;
|
|
9962
|
+
})}\n` : `${renderRows(rows, fields)}${pageFooter(page, style)}`;
|
|
9240
9963
|
}
|
|
9241
9964
|
/** A progress message as stderr carries it: one JSON object per line under `--json` (ADR 0006). */
|
|
9242
9965
|
function progressLine(message, json) {
|
|
@@ -9252,6 +9975,7 @@ function stderrLine(key, text, json) {
|
|
|
9252
9975
|
function errorText(error, format) {
|
|
9253
9976
|
const text = formatRuntimeError(error, {
|
|
9254
9977
|
...format,
|
|
9978
|
+
runAs: format.invocation.runAs,
|
|
9255
9979
|
isBug: (each) => isBug(each, format.errors)
|
|
9256
9980
|
});
|
|
9257
9981
|
const { usageHelp, json } = format;
|
|
@@ -9275,10 +9999,11 @@ const STOPPED_RESULT = {
|
|
|
9275
9999
|
exitCode: SUCCESS_EXIT_CODE
|
|
9276
10000
|
};
|
|
9277
10001
|
function errorResult(error, format) {
|
|
10002
|
+
const checked = format.checkNextStep === void 0 ? error : checkedNextSteps(error, format.checkNextStep, format.invocation.runAs);
|
|
9278
10003
|
return {
|
|
9279
10004
|
stdout: "",
|
|
9280
|
-
stderr: errorText(
|
|
9281
|
-
exitCode: exitCodeOf(
|
|
10005
|
+
stderr: errorText(checked, format),
|
|
10006
|
+
exitCode: exitCodeOf(checked, format.errors, format.stop)
|
|
9282
10007
|
};
|
|
9283
10008
|
}
|
|
9284
10009
|
async function commandResult(settled, format, spill) {
|
|
@@ -9292,12 +10017,18 @@ async function commandResult(settled, format, spill) {
|
|
|
9292
10017
|
return errorResult(spillError, format);
|
|
9293
10018
|
}
|
|
9294
10019
|
const { error, delivered } = settled;
|
|
10020
|
+
if (delivered === void 0) return errorResult(error, format);
|
|
10021
|
+
let outcome;
|
|
10022
|
+
try {
|
|
10023
|
+
outcome = delivered();
|
|
10024
|
+
} catch (rejected) {
|
|
10025
|
+
return errorResult(new AggregateError([...errorsOf(error), rejected]), format);
|
|
10026
|
+
}
|
|
9295
10027
|
const result = errorResult(error, format);
|
|
9296
|
-
if (delivered === void 0) return result;
|
|
9297
10028
|
try {
|
|
9298
10029
|
return {
|
|
9299
10030
|
...result,
|
|
9300
|
-
stdout: await stdoutOf(
|
|
10031
|
+
stdout: await stdoutOf(outcome, format, spill)
|
|
9301
10032
|
};
|
|
9302
10033
|
} catch (spillError) {
|
|
9303
10034
|
const both = new AggregateError([...errorsOf(error), spillError]);
|
|
@@ -9314,7 +10045,8 @@ function textHelp(node, root, cli, style) {
|
|
|
9314
10045
|
function helpOf(node, root, cli, style, json) {
|
|
9315
10046
|
if (!json) return textHelp(node, root, cli, style);
|
|
9316
10047
|
if (node === root) return cliHelpJson(cli, node);
|
|
9317
|
-
|
|
10048
|
+
const table = errorTableOf(cli);
|
|
10049
|
+
return node.kind === "command" ? commandHelpJson(node, table) : groupHelpJson(node, table);
|
|
9318
10050
|
}
|
|
9319
10051
|
function helpResult(node, root, cli, { style, json }) {
|
|
9320
10052
|
return {
|
|
@@ -9325,7 +10057,7 @@ function helpResult(node, root, cli, { style, json }) {
|
|
|
9325
10057
|
}
|
|
9326
10058
|
function versionResult(cli, packageRoot) {
|
|
9327
10059
|
return {
|
|
9328
|
-
stdout: `${(
|
|
10060
|
+
stdout: `${(buildStamp() === void 0 ? [versionLine(cli)] : [versionLine(cli), `changelog ${join(packageRoot, "CHANGELOG.md")}`]).join("\n")}\n`,
|
|
9329
10061
|
stderr: "",
|
|
9330
10062
|
exitCode: SUCCESS_EXIT_CODE
|
|
9331
10063
|
};
|
|
@@ -9345,509 +10077,795 @@ function packageRootOf(bin, cwd) {
|
|
|
9345
10077
|
}
|
|
9346
10078
|
}
|
|
9347
10079
|
//#endregion
|
|
9348
|
-
//#region ../agent-cli/dist/
|
|
9349
|
-
|
|
9350
|
-
|
|
9351
|
-
|
|
9352
|
-
|
|
9353
|
-
|
|
9354
|
-
const i = Math.floor(k / width);
|
|
9355
|
-
const j = k % width;
|
|
9356
|
-
return i === 0 || j === 0 ? i + j : 0;
|
|
9357
|
-
});
|
|
9358
|
-
const at = (i, j) => d[i * width + j] ?? 0;
|
|
9359
|
-
for (let i = 1; i <= a.length; i++) for (let j = 1; j <= b.length; j++) {
|
|
9360
|
-
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
9361
|
-
const edit = Math.min(at(i - 1, j) + 1, at(i, j - 1) + 1, at(i - 1, j - 1) + cost);
|
|
9362
|
-
const transposed = i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1];
|
|
9363
|
-
d[i * width + j] = transposed ? Math.min(edit, at(i - 2, j - 2) + 1) : edit;
|
|
9364
|
-
}
|
|
9365
|
-
return at(a.length, b.length);
|
|
9366
|
-
}
|
|
9367
|
-
function isClose(word, candidate) {
|
|
9368
|
-
const length = Math.max(word.length, candidate.length);
|
|
9369
|
-
const edits = distance(word, candidate);
|
|
9370
|
-
return candidate.length > 1 && edits < MAX_DISTANCE && (length - edits) / length > MIN_SIMILARITY;
|
|
9371
|
-
}
|
|
9372
|
-
/** The names closest to `word`, sorted, several when they tie, or none when nothing is close. */
|
|
9373
|
-
function closestNames(word, names) {
|
|
9374
|
-
const close = [...new Set(names)].filter((candidate) => isClose(word, candidate));
|
|
9375
|
-
const best = Math.min(...close.map((candidate) => distance(word, candidate)));
|
|
9376
|
-
return close.filter((candidate) => distance(word, candidate) === best).sort((a, b) => a.localeCompare(b));
|
|
9377
|
-
}
|
|
9378
|
-
/** The long flags closest to `flag`, sorted, or none for a short flag or when nothing is close. */
|
|
9379
|
-
function closestFlags(flag, flags) {
|
|
9380
|
-
if (!flag.startsWith("--")) return [];
|
|
9381
|
-
const names = flags.map((candidate) => candidate.slice(2));
|
|
9382
|
-
return closestNames(flag.slice(2), names).map((name) => `--${name}`);
|
|
9383
|
-
}
|
|
9384
|
-
/** The one long flag closest to `flag`, or none when nothing is close or several tie. */
|
|
9385
|
-
function closestFlag(flag, flags) {
|
|
9386
|
-
const closest = closestFlags(flag, flags);
|
|
9387
|
-
return closest.length === 1 ? closest[0] : void 0;
|
|
9388
|
-
}
|
|
9389
|
-
//#endregion
|
|
9390
|
-
//#region ../agent-cli/dist/route.js
|
|
9391
|
-
const GROUP_FLAGS = [
|
|
9392
|
-
HELP_FLAG,
|
|
9393
|
-
VERSION_FLAG,
|
|
9394
|
-
JSON_FLAG.flag
|
|
9395
|
-
];
|
|
9396
|
-
function beforeEnd(words) {
|
|
9397
|
-
const end = words.indexOf("--");
|
|
9398
|
-
return end === -1 ? words : words.slice(0, end);
|
|
9399
|
-
}
|
|
9400
|
-
function wantsHelp(words) {
|
|
9401
|
-
return beforeEnd(words).some((word) => word === "--help" || word === "-h");
|
|
9402
|
-
}
|
|
9403
|
-
function childOf(group, name) {
|
|
9404
|
-
return Object.hasOwn(group.commands, name) ? group.commands[name] : void 0;
|
|
9405
|
-
}
|
|
9406
|
-
function isFlagLike(word) {
|
|
9407
|
-
return word.length > 1 && word[0] === "-";
|
|
9408
|
-
}
|
|
9409
|
-
function walk(node, words, json, invocation) {
|
|
9410
|
-
const help = {
|
|
9411
|
-
kind: "help",
|
|
9412
|
-
node,
|
|
9413
|
-
json
|
|
9414
|
-
};
|
|
9415
|
-
if (node.kind === "command") return wantsHelp(words) ? help : {
|
|
9416
|
-
kind: "command",
|
|
9417
|
-
spec: node,
|
|
9418
|
-
words,
|
|
9419
|
-
json
|
|
9420
|
-
};
|
|
9421
|
-
const [first, ...rest] = words;
|
|
9422
|
-
if (first === void 0) return help;
|
|
9423
|
-
const child = childOf(node, first);
|
|
9424
|
-
if (child !== void 0) return walk(child, rest, json, invocation);
|
|
9425
|
-
if (first === "--") {
|
|
9426
|
-
const [name, ...after] = rest;
|
|
9427
|
-
if (name === void 0) return help;
|
|
9428
|
-
const named = childOf(node, name);
|
|
9429
|
-
if (named !== void 0) return walk(named, ["--", ...after], json, invocation);
|
|
9430
|
-
return unknownCommand(node, name, json);
|
|
9431
|
-
}
|
|
9432
|
-
if (wantsHelp(words)) return help;
|
|
9433
|
-
if (isFlagLike(first)) {
|
|
9434
|
-
const suggestions = closestFlags(first, GROUP_FLAGS);
|
|
9435
|
-
return {
|
|
9436
|
-
kind: "usage error",
|
|
9437
|
-
error: unknownOptionError(node.commandLine, invocation, first, suggestions),
|
|
9438
|
-
node,
|
|
9439
|
-
json
|
|
9440
|
-
};
|
|
9441
|
-
}
|
|
9442
|
-
return unknownCommand(node, first, json);
|
|
9443
|
-
}
|
|
9444
|
-
function unknownCommand(group, name, json) {
|
|
9445
|
-
const suggestions = closestNames(name, Object.keys(visibleCommands(group)));
|
|
9446
|
-
return {
|
|
9447
|
-
kind: "usage error",
|
|
9448
|
-
error: unknownCommandError(group.commandLine, name, suggestions),
|
|
9449
|
-
node: group,
|
|
9450
|
-
json
|
|
10080
|
+
//#region ../agent-cli/dist/root-spec.js
|
|
10081
|
+
/** The CLI's Commands as routing and help see them, the Built-in Commands included. */
|
|
10082
|
+
function rootSpec(cli, launch) {
|
|
10083
|
+
const names = {
|
|
10084
|
+
name: cli.name,
|
|
10085
|
+
runAs: runAsOf(cli)
|
|
9451
10086
|
};
|
|
10087
|
+
return cli.commands === void 0 ? {
|
|
10088
|
+
...commandSpec(names.runAs, cli.command, {
|
|
10089
|
+
path: [],
|
|
10090
|
+
builtIn: false,
|
|
10091
|
+
names
|
|
10092
|
+
}),
|
|
10093
|
+
description: cli.description
|
|
10094
|
+
} : groupSpec(names, cli.commands, builtInCommands(cli, launch));
|
|
9452
10095
|
}
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
|
|
10096
|
+
//#endregion
|
|
10097
|
+
//#region ../agent-cli/dist/command-errors.js
|
|
10098
|
+
/**
|
|
10099
|
+
* `error`, or a bug naming each Error table code in it that the Command does not declare in its
|
|
10100
|
+
* `errors`. Runtime codes are never in the table, and a built-in's failures, `doctor` rows'
|
|
10101
|
+
* included, belong to no declaration, so both pass.
|
|
10102
|
+
*/
|
|
10103
|
+
function checkedCodes(error, { command, path, builtIn }, cli) {
|
|
10104
|
+
if (builtIn) return error;
|
|
10105
|
+
const table = errorTableOf(cli);
|
|
10106
|
+
const declared = new Set(command.errors ?? []);
|
|
10107
|
+
const undeclared = errorsOf(error).flatMap((leaf) => leaf instanceof CliError && Object.hasOwn(table, leaf.code) && !declared.has(leaf.code) ? [leaf.code] : []);
|
|
10108
|
+
if (undeclared.length === 0) return error;
|
|
10109
|
+
const label = commandLabel(path, cli.name).join(" ");
|
|
10110
|
+
const codes = [...new Set(undeclared)].join(", ");
|
|
10111
|
+
return new Error(`\`${label}\` threw ${codes}, which its errors do not declare`, { cause: error });
|
|
9463
10112
|
}
|
|
9464
10113
|
//#endregion
|
|
9465
|
-
//#region ../agent-cli/dist/
|
|
9466
|
-
|
|
9467
|
-
|
|
9468
|
-
|
|
9469
|
-
|
|
9470
|
-
|
|
10114
|
+
//#region ../agent-cli/dist/context/operator.js
|
|
10115
|
+
const NEEDS_OPERATOR = "NEEDS_OPERATOR";
|
|
10116
|
+
/** Fails with `NEEDS_OPERATOR` when a Coding agent runs an Operator Command. */
|
|
10117
|
+
function checkOperator({ operator, commandLine }, env, rerun) {
|
|
10118
|
+
if (!operator || !isAgent(env)) return;
|
|
10119
|
+
throw new CliError({
|
|
10120
|
+
code: NEEDS_OPERATOR,
|
|
10121
|
+
message: `\`${commandLine}\` must be run by a person at a terminal, not a Coding agent`,
|
|
10122
|
+
hint: "ask the operator to type ! then the Next step",
|
|
10123
|
+
next: [rerun]
|
|
10124
|
+
});
|
|
9471
10125
|
}
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
|
|
10126
|
+
//#endregion
|
|
10127
|
+
//#region ../agent-cli/dist/context/spill.js
|
|
10128
|
+
const STDOUT_BUDGET_CHARS = 3e4;
|
|
10129
|
+
const SPILL_RETENTION_MS = 6048e5;
|
|
10130
|
+
const PREVIEW_CHARS = 2e3;
|
|
10131
|
+
const SPILL_FILE = /^\d{4}-\d\d-\d\dT\d\d-\d\d-\d\d\.\d{3}Z-.+\.(json|txt)$/;
|
|
10132
|
+
function spillName(now, label, json) {
|
|
10133
|
+
return `${new Date(now).toISOString().replaceAll(":", "-")}-${label.join("-")}.${json ? "json" : "txt"}`;
|
|
9475
10134
|
}
|
|
9476
|
-
function
|
|
9477
|
-
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
}
|
|
9482
|
-
const outputs = command.outputs?.(plan);
|
|
9483
|
-
const cost = command.cost?.(plan);
|
|
9484
|
-
return {
|
|
9485
|
-
value: {
|
|
9486
|
-
plan,
|
|
9487
|
-
...outputs === void 0 ? {} : { outputs },
|
|
9488
|
-
...command.cost === void 0 ? {} : { cost: cost ?? null }
|
|
9489
|
-
},
|
|
9490
|
-
render: (style) => [
|
|
9491
|
-
renderPlan(style),
|
|
9492
|
-
...outputs === void 0 || outputs.length === 0 ? [] : ["outputs:", ...outputs.map((path) => ` ${path}`)],
|
|
9493
|
-
...cost === void 0 ? [] : [`cost: ${cost}`]
|
|
9494
|
-
].join("\n")
|
|
9495
|
-
};
|
|
10135
|
+
async function pruneOne(path, cutoff) {
|
|
10136
|
+
try {
|
|
10137
|
+
if ((await stat(path)).mtimeMs < cutoff) await rm(path, { force: true });
|
|
10138
|
+
} catch (error) {
|
|
10139
|
+
if (!isMissingFile(error)) throw error;
|
|
10140
|
+
}
|
|
9496
10141
|
}
|
|
9497
|
-
function
|
|
9498
|
-
const
|
|
9499
|
-
|
|
10142
|
+
async function pruneOld(folder, cutoff) {
|
|
10143
|
+
const names = (await readdir(folder)).filter((name) => SPILL_FILE.test(name));
|
|
10144
|
+
await Promise.all(names.map((name) => pruneOne(join(folder, name), cutoff)));
|
|
9500
10145
|
}
|
|
9501
|
-
async function
|
|
9502
|
-
|
|
9503
|
-
|
|
9504
|
-
|
|
9505
|
-
|
|
9506
|
-
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
let end = () => {};
|
|
9510
|
-
const ended = new Promise((resolve) => {
|
|
9511
|
-
end = resolve;
|
|
10146
|
+
async function prepare(folder, cutoff, target) {
|
|
10147
|
+
try {
|
|
10148
|
+
await mkdir(folder, { recursive: true });
|
|
10149
|
+
await pruneOld(folder, cutoff);
|
|
10150
|
+
} catch (error) {
|
|
10151
|
+
throw target.fileError(error, {
|
|
10152
|
+
path: folder,
|
|
10153
|
+
access: "write"
|
|
9512
10154
|
});
|
|
9513
|
-
const outcome = outcomeOf(await command.start(input, serveContextOf(ctx, end)), (value, style) => command.render(value, style));
|
|
9514
|
-
await started(outcome);
|
|
9515
|
-
await Promise.race([ended, untilAborted(ctx.signal)]);
|
|
9516
|
-
return outcome;
|
|
9517
10155
|
}
|
|
9518
|
-
|
|
9519
|
-
|
|
9520
|
-
const
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
|
|
9527
|
-
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
|
|
10156
|
+
}
|
|
10157
|
+
function tempRoot(env) {
|
|
10158
|
+
const { TMPDIR } = env;
|
|
10159
|
+
return TMPDIR === void 0 || TMPDIR === "" ? tmpdir() : TMPDIR;
|
|
10160
|
+
}
|
|
10161
|
+
function spillTo(target) {
|
|
10162
|
+
return async (printed, json) => {
|
|
10163
|
+
if (printed.length <= STDOUT_BUDGET_CHARS) return printed;
|
|
10164
|
+
const now = target.clock.now();
|
|
10165
|
+
const folder = join(tempRoot(target.env), target.cliName);
|
|
10166
|
+
await prepare(folder, now - SPILL_RETENTION_MS, target);
|
|
10167
|
+
const file = join(folder, spillName(now, target.label, json));
|
|
10168
|
+
await target.files.write(file, printed);
|
|
10169
|
+
const bytes = Buffer.byteLength(printed);
|
|
10170
|
+
const preview = printed.slice(0, PREVIEW_CHARS);
|
|
10171
|
+
return json ? `${JSON.stringify({
|
|
10172
|
+
file,
|
|
10173
|
+
bytes,
|
|
10174
|
+
preview
|
|
10175
|
+
})}\n` : `file: ${file}\nbytes: ${bytes}\npreview:\n${preview}\n`;
|
|
10176
|
+
};
|
|
10177
|
+
}
|
|
10178
|
+
//#endregion
|
|
10179
|
+
//#region ../../node_modules/.pnpm/@toon-format+toon@4.4.0/node_modules/@toon-format/toon/dist/index.mjs
|
|
10180
|
+
const NULL_LITERAL = "null";
|
|
10181
|
+
const DELIMITERS = {
|
|
10182
|
+
comma: ",",
|
|
10183
|
+
tab: " ",
|
|
10184
|
+
pipe: "|"
|
|
10185
|
+
};
|
|
10186
|
+
const DEFAULT_DELIMITER = DELIMITERS.comma;
|
|
10187
|
+
/**
|
|
10188
|
+
* Escapes special characters in a string for encoding.
|
|
10189
|
+
*
|
|
10190
|
+
* @remarks
|
|
10191
|
+
* Control characters outside `\n`, `\r`, `\t`, `\\`, and `"` are emitted as `\uXXXX`.
|
|
10192
|
+
*/
|
|
10193
|
+
function escapeString(value) {
|
|
10194
|
+
return value.replace(/\\/g, `\\\\`).replace(/"/g, `\\"`).replace(/\n/g, `\\n`).replace(/\r/g, `\\r`).replace(/\t/g, `\\t`).replace(/[\u0000-\u001F]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
10195
|
+
}
|
|
10196
|
+
function isBooleanOrNullLiteral(token) {
|
|
10197
|
+
return token === "true" || token === "false" || token === "null";
|
|
10198
|
+
}
|
|
10199
|
+
/**
|
|
10200
|
+
* Assigns an own data property without invoking inherited accessors.
|
|
10201
|
+
*
|
|
10202
|
+
* @remarks
|
|
10203
|
+
* Plain assignment of `__proto__` would hit the `Object.prototype` setter and
|
|
10204
|
+
* corrupt the prototype chain; `defineProperty` avoids that but is markedly
|
|
10205
|
+
* slower, so every other key takes plain assignment.
|
|
10206
|
+
*/
|
|
10207
|
+
function setOwnProperty(target, key, value) {
|
|
10208
|
+
if (key === "__proto__") {
|
|
10209
|
+
Object.defineProperty(target, key, {
|
|
10210
|
+
value,
|
|
10211
|
+
enumerable: true,
|
|
10212
|
+
writable: true,
|
|
10213
|
+
configurable: true
|
|
10214
|
+
});
|
|
10215
|
+
return;
|
|
9544
10216
|
}
|
|
9545
|
-
|
|
10217
|
+
target[key] = value;
|
|
9546
10218
|
}
|
|
9547
|
-
const
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
10219
|
+
const COMMENT_LINE_PATTERN = new RegExp(`(?:^?|\\n) *#`);
|
|
10220
|
+
/**
|
|
10221
|
+
* Pre-formatted string that the encoder emits verbatim at a primitive value
|
|
10222
|
+
* position, bypassing quoting, escaping, and number/keyword detection.
|
|
10223
|
+
*
|
|
10224
|
+
* Returned from a replacer for an object or array value, it is ignored and
|
|
10225
|
+
* the container is encoded normally.
|
|
10226
|
+
*/
|
|
10227
|
+
var RawString = class {
|
|
10228
|
+
constructor(value) {
|
|
10229
|
+
if (COMMENT_LINE_PATTERN.test(value)) throw new TypeError(`Raw string must not contain a line starting with "#": ${JSON.stringify(value)}`);
|
|
10230
|
+
this.value = value;
|
|
10231
|
+
}
|
|
10232
|
+
};
|
|
10233
|
+
function isRawString(value) {
|
|
10234
|
+
return value instanceof RawString;
|
|
10235
|
+
}
|
|
10236
|
+
const SURROGATE_PATTERN = /[\uD800-\uDFFF]/;
|
|
10237
|
+
function normalizeValue(value) {
|
|
10238
|
+
if (value === null) return null;
|
|
10239
|
+
if (isRawString(value)) return value;
|
|
10240
|
+
if (typeof value === "object" && value !== null && "toJSON" in value && typeof value.toJSON === "function") {
|
|
10241
|
+
const next = value.toJSON();
|
|
10242
|
+
if (next !== value) return normalizeValue(next);
|
|
10243
|
+
}
|
|
10244
|
+
if (typeof value === "string") {
|
|
10245
|
+
assertNoLoneSurrogate(value, "string value");
|
|
10246
|
+
return value;
|
|
10247
|
+
}
|
|
10248
|
+
if (typeof value === "boolean") return value;
|
|
10249
|
+
if (typeof value === "number") {
|
|
10250
|
+
if (Object.is(value, -0)) return 0;
|
|
10251
|
+
if (!Number.isFinite(value)) return null;
|
|
10252
|
+
return value;
|
|
10253
|
+
}
|
|
10254
|
+
if (typeof value === "bigint") {
|
|
10255
|
+
if (value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER) return Number(value);
|
|
10256
|
+
return value.toString();
|
|
10257
|
+
}
|
|
10258
|
+
if (value instanceof Date) return value.toISOString();
|
|
10259
|
+
if (Array.isArray(value)) return Array.from(value, normalizeValue);
|
|
10260
|
+
if (value instanceof Set) return Array.from(value).map(normalizeValue);
|
|
10261
|
+
if (value instanceof Map) return Object.fromEntries(Array.from(value, ([k, v]) => [String(k), normalizeValue(v)]));
|
|
10262
|
+
if (isPlainObject(value)) {
|
|
10263
|
+
const encodedValues = {};
|
|
10264
|
+
for (const key in value) if (Object.hasOwn(value, key)) {
|
|
10265
|
+
assertNoLoneSurrogate(key, "object key");
|
|
10266
|
+
setOwnProperty(encodedValues, key, normalizeValue(value[key]));
|
|
10267
|
+
}
|
|
10268
|
+
return encodedValues;
|
|
10269
|
+
}
|
|
10270
|
+
return null;
|
|
10271
|
+
}
|
|
10272
|
+
function assertNoLoneSurrogate(value, context) {
|
|
10273
|
+
if (!SURROGATE_PATTERN.test(value)) return;
|
|
10274
|
+
for (let index = 0; index < value.length; index++) {
|
|
10275
|
+
const code = value.charCodeAt(index);
|
|
10276
|
+
if (code < 55296 || code > 57343) continue;
|
|
10277
|
+
const isHighSurrogate = code <= 56319;
|
|
10278
|
+
const next = value.charCodeAt(index + 1);
|
|
10279
|
+
if (isHighSurrogate && next >= 56320 && next <= 57343) {
|
|
10280
|
+
index++;
|
|
10281
|
+
continue;
|
|
10282
|
+
}
|
|
10283
|
+
throw new TypeError(`Cannot encode ${context} containing an unpaired surrogate U+${code.toString(16).toUpperCase()} at index ${index}`);
|
|
9555
10284
|
}
|
|
9556
|
-
const parsed = manifestSchema.safeParse(manifest);
|
|
9557
|
-
return parsed.success ? parsed.data : NO_MANIFEST;
|
|
9558
10285
|
}
|
|
9559
|
-
|
|
9560
|
-
|
|
9561
|
-
const NO_INPUT = object({});
|
|
9562
|
-
const WHITESPACE = /\s/;
|
|
9563
|
-
function knownFlags(spec) {
|
|
9564
|
-
return [...spec.options.map((field) => ({
|
|
9565
|
-
flag: field.label,
|
|
9566
|
-
takes: field.type === "boolean" ? "nothing" : "optional value"
|
|
9567
|
-
})), ...spec.standardFlags.map(({ flag, takes }) => ({
|
|
9568
|
-
flag,
|
|
9569
|
-
takes
|
|
9570
|
-
}))];
|
|
10286
|
+
function isJsonPrimitive(value) {
|
|
10287
|
+
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
9571
10288
|
}
|
|
9572
|
-
function
|
|
9573
|
-
return
|
|
9574
|
-
...known.map(({ flag }) => flag),
|
|
9575
|
-
VERSION_FLAG,
|
|
9576
|
-
HELP_FLAG
|
|
9577
|
-
];
|
|
10289
|
+
function isEncodablePrimitive(value) {
|
|
10290
|
+
return isJsonPrimitive(value) || isRawString(value);
|
|
9578
10291
|
}
|
|
9579
|
-
function
|
|
9580
|
-
return
|
|
9581
|
-
const flag = word.split("=")[0] ?? word;
|
|
9582
|
-
return {
|
|
9583
|
-
flag,
|
|
9584
|
-
suggestion: closestFlag(flag, candidates)
|
|
9585
|
-
};
|
|
9586
|
-
});
|
|
10292
|
+
function isJsonArray(value) {
|
|
10293
|
+
return Array.isArray(value);
|
|
9587
10294
|
}
|
|
9588
|
-
function
|
|
9589
|
-
|
|
9590
|
-
const raw = all?.[all.length - 1];
|
|
9591
|
-
return field.type === "boolean" && raw === true && field.label === `--no-${field.name}` ? false : raw;
|
|
10295
|
+
function isJsonObject(value) {
|
|
10296
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && !isRawString(value);
|
|
9592
10297
|
}
|
|
9593
|
-
function
|
|
9594
|
-
|
|
9595
|
-
if (field.type !== "number" || typeof raw !== "string" || raw.trim() === "") return raw;
|
|
9596
|
-
const number = Number(raw);
|
|
9597
|
-
return Number.isNaN(number) ? raw : number;
|
|
10298
|
+
function isEmptyObject(value) {
|
|
10299
|
+
return Object.keys(value).length === 0;
|
|
9598
10300
|
}
|
|
9599
|
-
function
|
|
9600
|
-
|
|
10301
|
+
function isPlainObject(value) {
|
|
10302
|
+
if (value === null || typeof value !== "object") return false;
|
|
10303
|
+
const prototype = Object.getPrototypeOf(value);
|
|
10304
|
+
return prototype === null || prototype === Object.prototype;
|
|
9601
10305
|
}
|
|
9602
|
-
function
|
|
9603
|
-
|
|
9604
|
-
return schema.safeParse(input);
|
|
10306
|
+
function isArrayOfPrimitives(value) {
|
|
10307
|
+
return value.length === 0 || value.every((item) => isEncodablePrimitive(item));
|
|
9605
10308
|
}
|
|
9606
|
-
function
|
|
9607
|
-
|
|
9608
|
-
return result.error.issues.flatMap((issue) => {
|
|
9609
|
-
const field = [...values.keys()].find((candidate) => candidate.key === issue.path[0]);
|
|
9610
|
-
if (field === void 0) return [` ${issue.message}`];
|
|
9611
|
-
if (reported.includes(field)) return [];
|
|
9612
|
-
const raw = values.get(field);
|
|
9613
|
-
if (raw === void 0) return [` ${field.label}: required, ${howToPass(field)}`];
|
|
9614
|
-
if (field === fromStdin) return [` ${field.label} from stdin: ${issue.message}`];
|
|
9615
|
-
return Array.isArray(raw) ? [arrayIssueLine(field, raw, issue)] : [` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`];
|
|
9616
|
-
});
|
|
10309
|
+
function isArrayOfArrays(value) {
|
|
10310
|
+
return value.length === 0 || value.every((item) => isJsonArray(item));
|
|
9617
10311
|
}
|
|
9618
|
-
function
|
|
9619
|
-
|
|
9620
|
-
if (typeof element === "number") return ` ${field.label} ${JSON.stringify(raw[element])}: ${issue.message}`;
|
|
9621
|
-
return raw.length === 0 ? ` ${field.label}: ${issue.message}, pass ${field.usage}` : ` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`;
|
|
10312
|
+
function isArrayOfObjects(value) {
|
|
10313
|
+
return value.length === 0 || value.every((item) => isJsonObject(item));
|
|
9622
10314
|
}
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
|
|
9626
|
-
|
|
10315
|
+
const NUMERIC_LIKE_PATTERN = /^[+-]?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i;
|
|
10316
|
+
/** Narrows an arbitrary delimiter option, shared by the library and the CLI so both report it alike. */
|
|
10317
|
+
function assertValidDelimiter(delimiter) {
|
|
10318
|
+
if (!Object.values(DELIMITERS).includes(delimiter)) throw new TypeError(`Invalid delimiter ${JSON.stringify(delimiter)}. Valid delimiters are: comma (,), tab (\\t), pipe (|)`);
|
|
9627
10319
|
}
|
|
9628
|
-
|
|
9629
|
-
|
|
10320
|
+
/**
|
|
10321
|
+
* Checks if a key can be used without quotes.
|
|
10322
|
+
*
|
|
10323
|
+
* @remarks
|
|
10324
|
+
* Valid unquoted keys must start with a letter or underscore,
|
|
10325
|
+
* followed by letters, digits, underscores, or dots.
|
|
10326
|
+
*/
|
|
10327
|
+
function isValidUnquotedKey(key) {
|
|
10328
|
+
return /^[A-Z_][\w.]*$/i.test(key);
|
|
10329
|
+
}
|
|
10330
|
+
/** Determines if a string value can be safely encoded without quotes. */
|
|
10331
|
+
function isSafeUnquoted(value, delimiter = DEFAULT_DELIMITER) {
|
|
10332
|
+
if (!value) return false;
|
|
10333
|
+
if (/^[ \t]|[ \t]$/.test(value)) return false;
|
|
10334
|
+
if (isBooleanOrNullLiteral(value) || isNumericLike(value)) return false;
|
|
10335
|
+
if (value.includes(":")) return false;
|
|
10336
|
+
if (value.includes("\"") || value.includes("\\")) return false;
|
|
10337
|
+
if (/[[\]{}]/.test(value)) return false;
|
|
10338
|
+
if (/[\u0000-\u001F]/.test(value)) return false;
|
|
10339
|
+
if (value.includes(delimiter)) return false;
|
|
10340
|
+
if (value.startsWith("-")) return false;
|
|
10341
|
+
if (value.startsWith("#")) return false;
|
|
10342
|
+
return true;
|
|
9630
10343
|
}
|
|
9631
|
-
function
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9638
|
-
|
|
9639
|
-
|
|
9640
|
-
|
|
9641
|
-
|
|
9642
|
-
|
|
10344
|
+
function isNumericLike(value) {
|
|
10345
|
+
return NUMERIC_LIKE_PATTERN.test(value);
|
|
10346
|
+
}
|
|
10347
|
+
function encodePrimitive(value, delimiter) {
|
|
10348
|
+
if (isRawString(value)) return value.value;
|
|
10349
|
+
if (value === null) return NULL_LITERAL;
|
|
10350
|
+
if (typeof value === "boolean") return String(value);
|
|
10351
|
+
if (typeof value === "number") return String(value);
|
|
10352
|
+
return encodeStringLiteral(value, delimiter);
|
|
10353
|
+
}
|
|
10354
|
+
function encodeStringLiteral(value, delimiter = DEFAULT_DELIMITER) {
|
|
10355
|
+
if (isSafeUnquoted(value, delimiter)) return value;
|
|
10356
|
+
return `"${escapeString(value)}"`;
|
|
10357
|
+
}
|
|
10358
|
+
function encodeKey(key) {
|
|
10359
|
+
if (isValidUnquotedKey(key)) return key;
|
|
10360
|
+
return `"${escapeString(key)}"`;
|
|
10361
|
+
}
|
|
10362
|
+
function encodeAndJoinPrimitives(values, delimiter = DEFAULT_DELIMITER) {
|
|
10363
|
+
return values.map((v) => encodePrimitive(v, delimiter)).join(delimiter);
|
|
10364
|
+
}
|
|
10365
|
+
function formatHeader(length, options) {
|
|
10366
|
+
const key = options?.key;
|
|
10367
|
+
const fields = options?.fields;
|
|
10368
|
+
const delimiter = options?.delimiter ?? ",";
|
|
10369
|
+
let header = "";
|
|
10370
|
+
if (key != null) header += encodeKey(key);
|
|
10371
|
+
header += `[${length}${options?.keyed ? ":" : ""}${delimiter !== DEFAULT_DELIMITER ? delimiter : ""}]`;
|
|
10372
|
+
if (fields) header += `{${formatFieldSegment(fields, delimiter)}}`;
|
|
10373
|
+
header += ":";
|
|
10374
|
+
return header;
|
|
10375
|
+
}
|
|
10376
|
+
function formatFieldSegment(fields, delimiter) {
|
|
10377
|
+
return fields.map((field) => encodeKey(field.name) + (field.children ? `{${formatFieldSegment(field.children, delimiter)}}` : "")).join(delimiter);
|
|
10378
|
+
}
|
|
10379
|
+
/** Classifies rows into a tabular field list, or undefined when they are not uniformly tabular. */
|
|
10380
|
+
function extractTabularFields(rows) {
|
|
10381
|
+
if (rows.length === 0) return;
|
|
10382
|
+
const firstKeys = Object.keys(rows[0]);
|
|
10383
|
+
if (firstKeys.length === 0) return;
|
|
10384
|
+
for (const row of rows) {
|
|
10385
|
+
if (Object.keys(row).length !== firstKeys.length) return;
|
|
10386
|
+
for (const key of firstKeys) if (!Object.hasOwn(row, key)) return;
|
|
10387
|
+
}
|
|
10388
|
+
const fieldNodes = [];
|
|
10389
|
+
for (const key of firstKeys) {
|
|
10390
|
+
const fieldNode = classifyColumn(key, rows.map((row) => row[key]));
|
|
10391
|
+
if (!fieldNode) return;
|
|
10392
|
+
fieldNodes.push(fieldNode);
|
|
10393
|
+
}
|
|
10394
|
+
return fieldNodes;
|
|
10395
|
+
}
|
|
10396
|
+
/** Classifies an object's values as a keyed tabular field list (>=2 uniform non-empty object entries), or undefined. */
|
|
10397
|
+
function extractKeyedTabularFields(value) {
|
|
10398
|
+
const entryValues = Object.values(value);
|
|
10399
|
+
if (entryValues.length < 2) return;
|
|
10400
|
+
if (!entryValues.every((entryValue) => isJsonObject(entryValue) && !isEmptyObject(entryValue))) return;
|
|
10401
|
+
return extractTabularFields(entryValues);
|
|
10402
|
+
}
|
|
10403
|
+
/** Reads one row's leaf cells in the field order `extractTabularFields` produced. */
|
|
10404
|
+
function collectRowLeaves(row, fields) {
|
|
10405
|
+
const leaves = [];
|
|
10406
|
+
collectLeafValues(row, fields, leaves);
|
|
10407
|
+
return leaves;
|
|
10408
|
+
}
|
|
10409
|
+
function classifyColumn(name, values) {
|
|
10410
|
+
if (values.every((value) => isEncodablePrimitive(value))) return { name };
|
|
10411
|
+
if (!values.every((value) => isJsonObject(value) && !isEmptyObject(value))) return;
|
|
10412
|
+
const children = extractTabularFields(values);
|
|
10413
|
+
if (!children) return;
|
|
10414
|
+
return {
|
|
10415
|
+
name,
|
|
10416
|
+
children
|
|
10417
|
+
};
|
|
9643
10418
|
}
|
|
9644
|
-
function
|
|
9645
|
-
const
|
|
9646
|
-
|
|
10419
|
+
function collectLeafValues(row, fields, leaves) {
|
|
10420
|
+
for (const field of fields) {
|
|
10421
|
+
const value = row[field.name];
|
|
10422
|
+
if (field.children) collectLeafValues(value, field.children, leaves);
|
|
10423
|
+
else leaves.push(value);
|
|
10424
|
+
}
|
|
9647
10425
|
}
|
|
9648
|
-
|
|
9649
|
-
|
|
9650
|
-
|
|
10426
|
+
function* encodeJsonValue(value, options, depth) {
|
|
10427
|
+
if (isEncodablePrimitive(value)) {
|
|
10428
|
+
const encodedPrimitive = typeof value === "string" && value.startsWith("") ? `"${escapeString(value)}"` : encodePrimitive(value, options.delimiter);
|
|
10429
|
+
if (encodedPrimitive !== "") yield encodedPrimitive;
|
|
10430
|
+
return;
|
|
10431
|
+
}
|
|
10432
|
+
if (isJsonArray(value)) yield* encodeArrayLines(void 0, value, depth, options);
|
|
10433
|
+
else if (isJsonObject(value)) {
|
|
10434
|
+
const keyedFields = extractKeyedTabularFields(value);
|
|
10435
|
+
if (keyedFields) {
|
|
10436
|
+
yield* encodeKeyedObjectLines(void 0, value, keyedFields, depth, options);
|
|
10437
|
+
return;
|
|
10438
|
+
}
|
|
10439
|
+
yield* encodeObjectLines(value, depth, options);
|
|
10440
|
+
}
|
|
9651
10441
|
}
|
|
9652
|
-
|
|
9653
|
-
const
|
|
9654
|
-
return field === void 0 ? void 0 : {
|
|
9655
|
-
field,
|
|
9656
|
-
text: await read(field)
|
|
9657
|
-
};
|
|
10442
|
+
function* encodeObjectLines(value, depth, options) {
|
|
10443
|
+
for (const [key, val] of Object.entries(value)) yield* encodeKeyValuePairLines(key, val, depth, options);
|
|
9658
10444
|
}
|
|
9659
|
-
|
|
9660
|
-
const
|
|
9661
|
-
|
|
9662
|
-
|
|
9663
|
-
|
|
9664
|
-
|
|
9665
|
-
|
|
9666
|
-
|
|
9667
|
-
|
|
9668
|
-
|
|
9669
|
-
|
|
9670
|
-
|
|
9671
|
-
}
|
|
9672
|
-
|
|
9673
|
-
|
|
9674
|
-
const
|
|
9675
|
-
|
|
9676
|
-
|
|
9677
|
-
|
|
9678
|
-
|
|
9679
|
-
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
|
|
9683
|
-
|
|
9684
|
-
const
|
|
9685
|
-
|
|
9686
|
-
|
|
9687
|
-
|
|
9688
|
-
|
|
9689
|
-
|
|
9690
|
-
|
|
9691
|
-
|
|
9692
|
-
|
|
9693
|
-
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
|
|
9702
|
-
|
|
9703
|
-
|
|
9704
|
-
|
|
9705
|
-
|
|
9706
|
-
|
|
9707
|
-
|
|
9708
|
-
|
|
9709
|
-
|
|
10445
|
+
function* encodeKeyValuePairLines(key, value, depth, options) {
|
|
10446
|
+
const encodedKey = encodeKey(key);
|
|
10447
|
+
if (isEncodablePrimitive(value)) yield indentedLine(depth, `${encodedKey}: ${encodePrimitive(value, options.delimiter)}`, options.indentSize);
|
|
10448
|
+
else if (isJsonArray(value)) yield* encodeArrayLines(key, value, depth, options);
|
|
10449
|
+
else if (isJsonObject(value)) {
|
|
10450
|
+
const keyedFields = extractKeyedTabularFields(value);
|
|
10451
|
+
if (keyedFields) {
|
|
10452
|
+
yield* encodeKeyedObjectLines(key, value, keyedFields, depth, options);
|
|
10453
|
+
return;
|
|
10454
|
+
}
|
|
10455
|
+
yield indentedLine(depth, `${encodedKey}:`, options.indentSize);
|
|
10456
|
+
if (!isEmptyObject(value)) yield* encodeObjectLines(value, depth + 1, options);
|
|
10457
|
+
}
|
|
10458
|
+
}
|
|
10459
|
+
function* encodeKeyedObjectLines(key, value, fields, depth, options) {
|
|
10460
|
+
const entries = Object.entries(value);
|
|
10461
|
+
yield indentedLine(depth, formatHeader(entries.length, {
|
|
10462
|
+
key,
|
|
10463
|
+
fields,
|
|
10464
|
+
delimiter: options.delimiter,
|
|
10465
|
+
keyed: true
|
|
10466
|
+
}), options.indentSize);
|
|
10467
|
+
yield* encodeKeyedEntryRowsLines(entries, fields, depth + 1, options);
|
|
10468
|
+
}
|
|
10469
|
+
function* encodeKeyedEntryRowsLines(entries, fields, depth, options) {
|
|
10470
|
+
for (const [entryKey, entryValue] of entries) {
|
|
10471
|
+
const leaves = collectRowLeaves(entryValue, fields);
|
|
10472
|
+
yield indentedLine(depth, `${encodeKey(entryKey)}: ${encodeAndJoinPrimitives(leaves, options.delimiter)}`, options.indentSize);
|
|
10473
|
+
}
|
|
10474
|
+
}
|
|
10475
|
+
function* encodeArrayLines(key, value, depth, options) {
|
|
10476
|
+
if (value.length === 0) {
|
|
10477
|
+
yield indentedLine(depth, key != null ? `${encodeKey(key)}: []` : "[]", options.indentSize);
|
|
10478
|
+
return;
|
|
10479
|
+
}
|
|
10480
|
+
if (isArrayOfPrimitives(value)) {
|
|
10481
|
+
yield indentedLine(depth, encodeInlineArrayLine(value, options.delimiter, key), options.indentSize);
|
|
10482
|
+
return;
|
|
10483
|
+
}
|
|
10484
|
+
if (isArrayOfArrays(value)) {
|
|
10485
|
+
if (value.every((arr) => isArrayOfPrimitives(arr))) {
|
|
10486
|
+
yield* encodeArrayOfArraysAsListItemsLines(key, value, depth, options);
|
|
10487
|
+
return;
|
|
10488
|
+
}
|
|
10489
|
+
}
|
|
10490
|
+
if (isArrayOfObjects(value)) {
|
|
10491
|
+
const fields = extractTabularFields(value);
|
|
10492
|
+
if (fields) yield* encodeArrayOfObjectsAsTabularLines(key, value, fields, depth, options);
|
|
10493
|
+
else yield* encodeMixedArrayAsListItemsLines(key, value, depth, options);
|
|
10494
|
+
return;
|
|
10495
|
+
}
|
|
10496
|
+
yield* encodeMixedArrayAsListItemsLines(key, value, depth, options);
|
|
10497
|
+
}
|
|
10498
|
+
function* encodeArrayOfArraysAsListItemsLines(prefix, values, depth, options) {
|
|
10499
|
+
yield indentedLine(depth, formatHeader(values.length, {
|
|
10500
|
+
key: prefix,
|
|
10501
|
+
delimiter: options.delimiter
|
|
10502
|
+
}), options.indentSize);
|
|
10503
|
+
for (const arr of values) if (isArrayOfPrimitives(arr)) {
|
|
10504
|
+
const arrayLine = encodeInlineArrayLine(arr, options.delimiter);
|
|
10505
|
+
yield indentedListItem(depth + 1, arrayLine, options.indentSize);
|
|
10506
|
+
}
|
|
10507
|
+
}
|
|
10508
|
+
function encodeInlineArrayLine(values, delimiter, prefix) {
|
|
10509
|
+
const header = formatHeader(values.length, {
|
|
10510
|
+
key: prefix,
|
|
10511
|
+
delimiter
|
|
10512
|
+
});
|
|
10513
|
+
const joinedValue = encodeAndJoinPrimitives(values, delimiter);
|
|
10514
|
+
if (values.length === 0) return header;
|
|
10515
|
+
return `${header} ${joinedValue}`;
|
|
10516
|
+
}
|
|
10517
|
+
function* encodeArrayOfObjectsAsTabularLines(prefix, rows, fields, depth, options) {
|
|
10518
|
+
yield indentedLine(depth, formatHeader(rows.length, {
|
|
10519
|
+
key: prefix,
|
|
10520
|
+
fields,
|
|
10521
|
+
delimiter: options.delimiter
|
|
10522
|
+
}), options.indentSize);
|
|
10523
|
+
yield* writeTabularRowsLines(rows, fields, depth + 1, options);
|
|
10524
|
+
}
|
|
10525
|
+
function* writeTabularRowsLines(rows, fields, depth, options) {
|
|
10526
|
+
for (const row of rows) yield indentedLine(depth, encodeAndJoinPrimitives(collectRowLeaves(row, fields), options.delimiter), options.indentSize);
|
|
10527
|
+
}
|
|
10528
|
+
function* encodeMixedArrayAsListItemsLines(prefix, items, depth, options) {
|
|
10529
|
+
yield indentedLine(depth, formatHeader(items.length, {
|
|
10530
|
+
key: prefix,
|
|
10531
|
+
delimiter: options.delimiter
|
|
10532
|
+
}), options.indentSize);
|
|
10533
|
+
for (const item of items) yield* encodeListItemValueLines(item, depth + 1, options);
|
|
10534
|
+
}
|
|
10535
|
+
function* encodeObjectAsListItemLines(obj, depth, options) {
|
|
10536
|
+
if (isEmptyObject(obj)) {
|
|
10537
|
+
yield indentedLine(depth, "-", options.indentSize);
|
|
10538
|
+
return;
|
|
10539
|
+
}
|
|
10540
|
+
const entries = Object.entries(obj);
|
|
10541
|
+
const [firstKey, firstValue] = entries[0];
|
|
10542
|
+
const restEntries = entries.slice(1);
|
|
10543
|
+
if (isJsonArray(firstValue) && isArrayOfObjects(firstValue)) {
|
|
10544
|
+
const fields = extractTabularFields(firstValue);
|
|
10545
|
+
if (fields) {
|
|
10546
|
+
yield indentedListItem(depth, formatHeader(firstValue.length, {
|
|
10547
|
+
key: firstKey,
|
|
10548
|
+
fields,
|
|
10549
|
+
delimiter: options.delimiter
|
|
10550
|
+
}), options.indentSize);
|
|
10551
|
+
yield* writeTabularRowsLines(firstValue, fields, depth + 2, options);
|
|
10552
|
+
if (restEntries.length > 0) yield* encodeObjectLines(Object.fromEntries(restEntries), depth + 1, options);
|
|
10553
|
+
return;
|
|
10554
|
+
}
|
|
10555
|
+
}
|
|
10556
|
+
if (isJsonObject(firstValue)) {
|
|
10557
|
+
const keyedFields = extractKeyedTabularFields(firstValue);
|
|
10558
|
+
if (keyedFields) {
|
|
10559
|
+
const keyedEntries = Object.entries(firstValue);
|
|
10560
|
+
yield indentedListItem(depth, formatHeader(keyedEntries.length, {
|
|
10561
|
+
key: firstKey,
|
|
10562
|
+
fields: keyedFields,
|
|
10563
|
+
delimiter: options.delimiter,
|
|
10564
|
+
keyed: true
|
|
10565
|
+
}), options.indentSize);
|
|
10566
|
+
yield* encodeKeyedEntryRowsLines(keyedEntries, keyedFields, depth + 2, options);
|
|
10567
|
+
if (restEntries.length > 0) yield* encodeObjectLines(Object.fromEntries(restEntries), depth + 1, options);
|
|
10568
|
+
return;
|
|
10569
|
+
}
|
|
10570
|
+
}
|
|
10571
|
+
const encodedKey = encodeKey(firstKey);
|
|
10572
|
+
if (isEncodablePrimitive(firstValue)) yield indentedListItem(depth, `${encodedKey}: ${encodePrimitive(firstValue, options.delimiter)}`, options.indentSize);
|
|
10573
|
+
else if (isJsonArray(firstValue)) {
|
|
10574
|
+
if (firstValue.length === 0) yield indentedListItem(depth, `${encodedKey}: []`, options.indentSize);
|
|
10575
|
+
else if (isArrayOfPrimitives(firstValue)) yield indentedListItem(depth, `${encodedKey}${encodeInlineArrayLine(firstValue, options.delimiter)}`, options.indentSize);
|
|
10576
|
+
else {
|
|
10577
|
+
yield indentedListItem(depth, `${encodedKey}${formatHeader(firstValue.length, { delimiter: options.delimiter })}`, options.indentSize);
|
|
10578
|
+
for (const item of firstValue) yield* encodeListItemValueLines(item, depth + 2, options);
|
|
10579
|
+
}
|
|
10580
|
+
} else if (isJsonObject(firstValue)) {
|
|
10581
|
+
yield indentedListItem(depth, `${encodedKey}:`, options.indentSize);
|
|
10582
|
+
if (!isEmptyObject(firstValue)) yield* encodeObjectLines(firstValue, depth + 2, options);
|
|
10583
|
+
}
|
|
10584
|
+
if (restEntries.length > 0) yield* encodeObjectLines(Object.fromEntries(restEntries), depth + 1, options);
|
|
10585
|
+
}
|
|
10586
|
+
function* encodeListItemValueLines(value, depth, options) {
|
|
10587
|
+
if (isEncodablePrimitive(value)) yield indentedListItem(depth, encodePrimitive(value, options.delimiter), options.indentSize);
|
|
10588
|
+
else if (isJsonArray(value)) {
|
|
10589
|
+
if (isArrayOfPrimitives(value)) yield indentedListItem(depth, encodeInlineArrayLine(value, options.delimiter), options.indentSize);
|
|
10590
|
+
else {
|
|
10591
|
+
yield indentedListItem(depth, formatHeader(value.length, { delimiter: options.delimiter }), options.indentSize);
|
|
10592
|
+
for (const item of value) yield* encodeListItemValueLines(item, depth + 1, options);
|
|
10593
|
+
}
|
|
10594
|
+
} else if (isJsonObject(value)) yield* encodeObjectAsListItemLines(value, depth, options);
|
|
10595
|
+
}
|
|
10596
|
+
function indentedLine(depth, content, indentSize) {
|
|
10597
|
+
return " ".repeat(indentSize * depth) + content;
|
|
10598
|
+
}
|
|
10599
|
+
function indentedListItem(depth, content, indentSize) {
|
|
10600
|
+
return indentedLine(depth, "- " + content, indentSize);
|
|
9710
10601
|
}
|
|
9711
10602
|
/**
|
|
9712
|
-
*
|
|
9713
|
-
*
|
|
10603
|
+
* Applies a replacer function to a `JsonValue` and all its descendants.
|
|
10604
|
+
*
|
|
10605
|
+
* The replacer is called for the root (key='', path=[]), every object property
|
|
10606
|
+
* (key = property name), and every array element (key = string index).
|
|
9714
10607
|
*/
|
|
9715
|
-
|
|
9716
|
-
const
|
|
9717
|
-
|
|
9718
|
-
return
|
|
9719
|
-
input,
|
|
9720
|
-
flags: {
|
|
9721
|
-
json,
|
|
9722
|
-
dryRun: values.get(DRY_RUN_FLAG.flag) === true,
|
|
9723
|
-
confirm: typeof confirm === "string" ? confirm : void 0,
|
|
9724
|
-
yes: values.get(YES_FLAG.flag) === true,
|
|
9725
|
-
force: values.get(FORCE_FLAG.flag) === true,
|
|
9726
|
-
page,
|
|
9727
|
-
fields: spec.list === void 0 ? void 0 : selectedFields(values, spec.list.rowFields, spec.commandLine)
|
|
9728
|
-
}
|
|
9729
|
-
};
|
|
10608
|
+
function applyReplacer(root, replacer) {
|
|
10609
|
+
const replacedRoot = replacer("", root, []);
|
|
10610
|
+
if (replacedRoot === void 0) return transformChildren(root, replacer, []);
|
|
10611
|
+
return transformReplaced(root, replacedRoot, replacer, []);
|
|
9730
10612
|
}
|
|
9731
|
-
|
|
9732
|
-
|
|
9733
|
-
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
10613
|
+
/**
|
|
10614
|
+
* Resolves a replacer's (non-`undefined`) return value at a single position.
|
|
10615
|
+
*
|
|
10616
|
+
* A `RawString` only stands in for a primitive: returned for an object or
|
|
10617
|
+
* array value, it is ignored and the original container is traversed normally.
|
|
10618
|
+
*/
|
|
10619
|
+
function transformReplaced(original, replaced, replacer, path) {
|
|
10620
|
+
if (isRawString(replaced) && !isEncodablePrimitive(original)) return transformChildren(original, replacer, path);
|
|
10621
|
+
return transformChildren(normalizeValue(replaced), replacer, path);
|
|
9737
10622
|
}
|
|
9738
|
-
function
|
|
9739
|
-
|
|
9740
|
-
|
|
9741
|
-
|
|
9742
|
-
|
|
9743
|
-
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
10623
|
+
function transformChildren(value, replacer, path) {
|
|
10624
|
+
if (isJsonObject(value)) return transformObject(value, replacer, path);
|
|
10625
|
+
if (isJsonArray(value)) return transformArray(value, replacer, path);
|
|
10626
|
+
return value;
|
|
10627
|
+
}
|
|
10628
|
+
function transformObject(obj, replacer, path) {
|
|
10629
|
+
const result = {};
|
|
10630
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
10631
|
+
const childPath = [...path, key];
|
|
10632
|
+
const replacedValue = replacer(key, value, childPath);
|
|
10633
|
+
if (replacedValue === void 0) continue;
|
|
10634
|
+
setOwnProperty(result, key, transformReplaced(value, replacedValue, replacer, childPath));
|
|
9748
10635
|
}
|
|
9749
|
-
return
|
|
10636
|
+
return result;
|
|
9750
10637
|
}
|
|
9751
|
-
|
|
9752
|
-
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9756
|
-
|
|
10638
|
+
function transformArray(arr, replacer, path) {
|
|
10639
|
+
const result = [];
|
|
10640
|
+
for (let i = 0; i < arr.length; i++) {
|
|
10641
|
+
const value = arr[i];
|
|
10642
|
+
const childPath = [...path, i];
|
|
10643
|
+
const replacedValue = replacer(String(i), value, childPath);
|
|
10644
|
+
if (replacedValue === void 0) continue;
|
|
10645
|
+
result.push(transformReplaced(value, replacedValue, replacer, childPath));
|
|
10646
|
+
}
|
|
10647
|
+
return result;
|
|
10648
|
+
}
|
|
10649
|
+
/**
|
|
10650
|
+
* Encodes a JavaScript value into TOON format string.
|
|
10651
|
+
*
|
|
10652
|
+
* @example
|
|
10653
|
+
* ```ts
|
|
10654
|
+
* encode({ name: 'Ada', age: 30 })
|
|
10655
|
+
* // name: Ada
|
|
10656
|
+
* // age: 30
|
|
10657
|
+
*
|
|
10658
|
+
* encode({ users: [{ id: 1 }, { id: 2 }] })
|
|
10659
|
+
* // users[2]{id}:
|
|
10660
|
+
* // 1
|
|
10661
|
+
* // 2
|
|
10662
|
+
*
|
|
10663
|
+
* encode({ tags: [] })
|
|
10664
|
+
* // tags: []
|
|
10665
|
+
*
|
|
10666
|
+
* encode(data, { indentSize: 4 })
|
|
10667
|
+
* ```
|
|
10668
|
+
*/
|
|
10669
|
+
function encode(input, options) {
|
|
10670
|
+
return Array.from(encodeLines(input, options)).join("\n");
|
|
10671
|
+
}
|
|
10672
|
+
/**
|
|
10673
|
+
* Encodes a JavaScript value into TOON format as a sequence of lines.
|
|
10674
|
+
*
|
|
10675
|
+
* This function yields TOON lines one at a time without building the full string,
|
|
10676
|
+
* making it suitable for streaming large outputs to files, HTTP responses, or process stdout.
|
|
10677
|
+
*
|
|
10678
|
+
* @example
|
|
10679
|
+
* ```ts
|
|
10680
|
+
* // Stream to stdout
|
|
10681
|
+
* for (const line of encodeLines({ name: 'Ada', age: 30 })) {
|
|
10682
|
+
* console.log(line)
|
|
10683
|
+
* }
|
|
10684
|
+
*
|
|
10685
|
+
* // Collect to array
|
|
10686
|
+
* const lines = Array.from(encodeLines(data))
|
|
10687
|
+
*
|
|
10688
|
+
* // Equivalent to encode()
|
|
10689
|
+
* const toonString = Array.from(encodeLines(data, options)).join('\n')
|
|
10690
|
+
* ```
|
|
10691
|
+
*/
|
|
10692
|
+
function encodeLines(input, options) {
|
|
10693
|
+
const normalizedValue = normalizeValue(input);
|
|
10694
|
+
const resolvedOptions = resolveOptions(options);
|
|
10695
|
+
return encodeJsonValue(resolvedOptions.replacer ? applyReplacer(normalizedValue, resolvedOptions.replacer) : normalizedValue, resolvedOptions, 0);
|
|
10696
|
+
}
|
|
10697
|
+
function resolveOptions(options) {
|
|
10698
|
+
const delimiter = options?.delimiter ?? DEFAULT_DELIMITER;
|
|
10699
|
+
assertValidDelimiter(delimiter);
|
|
10700
|
+
return {
|
|
10701
|
+
indentSize: options?.indentSize ?? options?.indent ?? 2,
|
|
10702
|
+
delimiter,
|
|
10703
|
+
replacer: options?.replacer
|
|
9757
10704
|
};
|
|
9758
|
-
const fromFile = readDotenv(envFile, fileError)[name];
|
|
9759
|
-
return fromFile ? {
|
|
9760
|
-
value: fromFile,
|
|
9761
|
-
origin: {
|
|
9762
|
-
kind: "file",
|
|
9763
|
-
path: envFile
|
|
9764
|
-
}
|
|
9765
|
-
} : void 0;
|
|
9766
10705
|
}
|
|
9767
10706
|
//#endregion
|
|
9768
|
-
//#region ../agent-cli/dist/
|
|
9769
|
-
|
|
9770
|
-
const
|
|
9771
|
-
|
|
9772
|
-
|
|
9773
|
-
|
|
10707
|
+
//#region ../agent-cli/dist/context/confirm.js
|
|
10708
|
+
const CONFIRMATION_REQUIRED = "CONFIRMATION_REQUIRED";
|
|
10709
|
+
const CONFIRMATION_MISMATCH = "CONFIRMATION_MISMATCH";
|
|
10710
|
+
function checkConfirmation({ rerun, commandLine, given }, expected) {
|
|
10711
|
+
if (given === expected) return;
|
|
10712
|
+
const advice = {
|
|
10713
|
+
hint: "to confirm, run the Next step",
|
|
10714
|
+
next: [rerun({
|
|
10715
|
+
remove: [CONFIRM_FLAG.flag],
|
|
10716
|
+
add: [CONFIRM_FLAG.flag, expected]
|
|
10717
|
+
})]
|
|
10718
|
+
};
|
|
10719
|
+
if (given === void 0) throw new UsageError({
|
|
10720
|
+
code: CONFIRMATION_REQUIRED,
|
|
10721
|
+
message: `\`${commandLine}\` is destructive and needs ${CONFIRM_FLAG.flag}`,
|
|
10722
|
+
...advice
|
|
10723
|
+
});
|
|
10724
|
+
throw new UsageError({
|
|
10725
|
+
code: CONFIRMATION_MISMATCH,
|
|
10726
|
+
message: `${CONFIRM_FLAG.flag} ${JSON.stringify(given)} does not match the target of \`${commandLine}\``,
|
|
10727
|
+
...advice
|
|
10728
|
+
});
|
|
9774
10729
|
}
|
|
9775
|
-
|
|
9776
|
-
|
|
9777
|
-
|
|
9778
|
-
|
|
9779
|
-
|
|
9780
|
-
|
|
10730
|
+
//#endregion
|
|
10731
|
+
//#region ../agent-cli/dist/context/cost.js
|
|
10732
|
+
const NOT_CONFIRMED = "NOT_CONFIRMED";
|
|
10733
|
+
/** Refuses a run whose Plan states a cost the caller has not approved with `--yes`. */
|
|
10734
|
+
function checkCost({ rerun, commandLine, yes }, cost) {
|
|
10735
|
+
if (cost === void 0 || yes) return;
|
|
10736
|
+
throw new CliError({
|
|
10737
|
+
code: NOT_CONFIRMED,
|
|
10738
|
+
message: `\`${commandLine}\` needs ${YES_FLAG.flag}: ${cost}`,
|
|
10739
|
+
hint: "to approve the cost, run the Next step",
|
|
10740
|
+
next: [rerun({ add: [YES_FLAG.flag] })]
|
|
9781
10741
|
});
|
|
9782
|
-
return async () => {
|
|
9783
|
-
const waited = new AbortController();
|
|
9784
|
-
const capped = new Promise((resolve) => after(clock, SIDE_TASK_WAIT_MS, waited.signal, () => {
|
|
9785
|
-
const over = waitOver();
|
|
9786
|
-
failed(over);
|
|
9787
|
-
controller.abort(over);
|
|
9788
|
-
resolve();
|
|
9789
|
-
}));
|
|
9790
|
-
await Promise.race([running, capped]);
|
|
9791
|
-
waited.abort();
|
|
9792
|
-
};
|
|
9793
10742
|
}
|
|
9794
10743
|
//#endregion
|
|
9795
|
-
//#region ../agent-cli/dist/
|
|
9796
|
-
const
|
|
9797
|
-
|
|
9798
|
-
|
|
9799
|
-
|
|
9800
|
-
|
|
9801
|
-
|
|
10744
|
+
//#region ../agent-cli/dist/execute.js
|
|
10745
|
+
const PLAN_INDENT = " ";
|
|
10746
|
+
function outcomeOf(value, render) {
|
|
10747
|
+
return {
|
|
10748
|
+
value,
|
|
10749
|
+
render: (style) => render(value, style)
|
|
10750
|
+
};
|
|
9802
10751
|
}
|
|
9803
|
-
|
|
9804
|
-
|
|
9805
|
-
|
|
9806
|
-
|
|
9807
|
-
|
|
9808
|
-
|
|
10752
|
+
/**
|
|
10753
|
+
* The data a Command returned or delivered as it prints it: parsed by its `output` schema when it
|
|
10754
|
+
* declares one, so data the schema rejects fails the run as a bug.
|
|
10755
|
+
*/
|
|
10756
|
+
function dataOutcome(command, data, commandLine) {
|
|
10757
|
+
const render = command.render ?? ((value) => value === void 0 ? "" : encode(value));
|
|
10758
|
+
if (command.rows !== void 0 || command.output === void 0) return outcomeOf(data, render);
|
|
10759
|
+
const parsed = command.output.safeParse(data);
|
|
10760
|
+
if (!parsed.success) throw new Error(`\`${commandLine}\` produced data its output schema rejects:\n${prettifyError(parsed.error)}`);
|
|
10761
|
+
return outcomeOf(parsed.data, render);
|
|
10762
|
+
}
|
|
10763
|
+
function indented(text) {
|
|
10764
|
+
return text.split("\n").map((line) => `${PLAN_INDENT}${line}`).join("\n");
|
|
10765
|
+
}
|
|
10766
|
+
function dryRunOutcome(command, plan, commandLine) {
|
|
10767
|
+
const renderPlan = (style) => command.renderPlan === void 0 ? `Would run ${commandLine}:\n${indented(encode(plan))}` : command.renderPlan(plan, style);
|
|
10768
|
+
if (command.outputs === void 0 && command.cost === void 0) return {
|
|
10769
|
+
value: plan,
|
|
10770
|
+
render: renderPlan
|
|
10771
|
+
};
|
|
10772
|
+
const outputs = command.outputs?.(plan);
|
|
10773
|
+
const cost = command.cost?.(plan);
|
|
10774
|
+
return {
|
|
10775
|
+
value: {
|
|
10776
|
+
plan,
|
|
10777
|
+
...outputs === void 0 ? {} : { outputs },
|
|
10778
|
+
...command.cost === void 0 ? {} : { cost: cost ?? null }
|
|
10779
|
+
},
|
|
10780
|
+
render: (style) => [
|
|
10781
|
+
renderPlan(style),
|
|
10782
|
+
...outputs === void 0 || outputs.length === 0 ? [] : ["outputs:", ...outputs.map((path) => ` ${path}`)],
|
|
10783
|
+
...cost === void 0 ? [] : [`cost: ${cost}`]
|
|
10784
|
+
].join("\n")
|
|
10785
|
+
};
|
|
9809
10786
|
}
|
|
9810
|
-
|
|
9811
|
-
const
|
|
9812
|
-
|
|
10787
|
+
function serveContextOf(ctx, end) {
|
|
10788
|
+
const serveCtx = Object.create(ctx);
|
|
10789
|
+
return Object.assign(serveCtx, { end });
|
|
9813
10790
|
}
|
|
9814
|
-
async function
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
|
|
9821
|
-
|
|
10791
|
+
async function execute(command, input, ctx, { dryRun, confirm, yes, page, commandLine, started, files, guardOutputs }) {
|
|
10792
|
+
await checkTools(command.tools ?? [], ctx.env, ctx.rerun());
|
|
10793
|
+
const { env, envFile, fileError } = ctx;
|
|
10794
|
+
checkSecrets(command.secrets ?? [], {
|
|
10795
|
+
env,
|
|
10796
|
+
envFile,
|
|
10797
|
+
fileError
|
|
10798
|
+
}, ctx.rerun());
|
|
10799
|
+
if (command.rows !== void 0) {
|
|
10800
|
+
const { render } = command;
|
|
10801
|
+
return outcomeOf(await command.run({
|
|
10802
|
+
...input,
|
|
10803
|
+
...page
|
|
10804
|
+
}, ctx), (data, style) => render === void 0 ? encode(data.items) : render(data, style));
|
|
10805
|
+
}
|
|
10806
|
+
if (command.effect === "read" || command.effect === "act") return dataOutcome(command, await command.run(input, ctx), commandLine);
|
|
10807
|
+
if (command.effect === "serve") {
|
|
10808
|
+
let end = () => {};
|
|
10809
|
+
const ended = new Promise((resolve) => {
|
|
10810
|
+
end = resolve;
|
|
9822
10811
|
});
|
|
10812
|
+
const outcome = dataOutcome(command, await command.start(input, serveContextOf(ctx, end)), commandLine);
|
|
10813
|
+
await started(outcome);
|
|
10814
|
+
await Promise.race([ended, untilAborted(ctx.signal)]);
|
|
10815
|
+
return outcome;
|
|
9823
10816
|
}
|
|
10817
|
+
const plan = await command.plan(input, ctx);
|
|
10818
|
+
if (dryRun) return dryRunOutcome(command, plan, commandLine);
|
|
10819
|
+
const outputs = command.outputs?.(plan);
|
|
10820
|
+
await checkOutputs({
|
|
10821
|
+
rerun: ctx.rerun,
|
|
10822
|
+
commandLine,
|
|
10823
|
+
force: ctx.force,
|
|
10824
|
+
files: ctx.files
|
|
10825
|
+
}, outputs);
|
|
10826
|
+
checkCost({
|
|
10827
|
+
rerun: ctx.rerun,
|
|
10828
|
+
commandLine,
|
|
10829
|
+
yes
|
|
10830
|
+
}, command.cost?.(plan));
|
|
10831
|
+
if (command.effect === "destructive") checkConfirmation({
|
|
10832
|
+
rerun: ctx.rerun,
|
|
10833
|
+
commandLine,
|
|
10834
|
+
given: confirm
|
|
10835
|
+
}, command.confirm(plan));
|
|
10836
|
+
if (outputs !== void 0) {
|
|
10837
|
+
await probeOutputs({
|
|
10838
|
+
files,
|
|
10839
|
+
cwd: ctx.cwd,
|
|
10840
|
+
fileError: ctx.fileError
|
|
10841
|
+
}, outputs);
|
|
10842
|
+
if (!ctx.force) guardOutputs(outputs, ctx.rerun({ add: [FORCE_FLAG.flag] }));
|
|
10843
|
+
}
|
|
10844
|
+
return dataOutcome(command, await command.apply(plan, ctx), commandLine);
|
|
9824
10845
|
}
|
|
9825
|
-
|
|
9826
|
-
|
|
9827
|
-
|
|
9828
|
-
|
|
9829
|
-
|
|
9830
|
-
|
|
9831
|
-
|
|
9832
|
-
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
await target.files.write(file, printed);
|
|
9837
|
-
const bytes = Buffer.byteLength(printed);
|
|
9838
|
-
const preview = printed.slice(0, PREVIEW_CHARS);
|
|
9839
|
-
return json ? `${JSON.stringify({
|
|
9840
|
-
file,
|
|
9841
|
-
bytes,
|
|
9842
|
-
preview
|
|
9843
|
-
})}\n` : `file: ${file}\nbytes: ${bytes}\npreview:\n${preview}\n`;
|
|
9844
|
-
};
|
|
10846
|
+
const manifestSchema = object({ bugs: union([string(), object({ url: string() })]).transform((value) => typeof value === "string" ? value : value.url).optional().catch(void 0) });
|
|
10847
|
+
const NO_MANIFEST = {};
|
|
10848
|
+
function manifestAt(packageRoot) {
|
|
10849
|
+
let manifest;
|
|
10850
|
+
try {
|
|
10851
|
+
manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
|
|
10852
|
+
} catch {
|
|
10853
|
+
return NO_MANIFEST;
|
|
10854
|
+
}
|
|
10855
|
+
const parsed = manifestSchema.safeParse(manifest);
|
|
10856
|
+
return parsed.success ? parsed.data : NO_MANIFEST;
|
|
9845
10857
|
}
|
|
9846
10858
|
//#endregion
|
|
9847
10859
|
//#region ../agent-cli/dist/run-command.js
|
|
9848
10860
|
function stdinNeverEndedHint(callerLine) {
|
|
9849
10861
|
return `stdin never ended: pipe the text into \`${callerLine}\`, or redirect a file into it`;
|
|
9850
10862
|
}
|
|
10863
|
+
function runDeadlineAdvice(resumed, pipedLine) {
|
|
10864
|
+
return resumed === void 0 ? { hint: stdinNeverEndedHint(pipedLine) } : {
|
|
10865
|
+
hint: "run the Next step to continue the work",
|
|
10866
|
+
next: [resumed]
|
|
10867
|
+
};
|
|
10868
|
+
}
|
|
9851
10869
|
function selfOf(name, bin) {
|
|
9852
10870
|
return bin === void 0 ? [name] : [
|
|
9853
10871
|
process.execPath,
|
|
@@ -9867,7 +10885,7 @@ function portsOf(cli, replacement) {
|
|
|
9867
10885
|
return cli.ports ?? (() => ({}));
|
|
9868
10886
|
}
|
|
9869
10887
|
function portsBaseOf(scope, signal) {
|
|
9870
|
-
const { cli, options, packageRoot, progress, fileError,
|
|
10888
|
+
const { cli, options, packageRoot, progress, fileError, rerun, clock, files } = scope;
|
|
9871
10889
|
const { cwd, env } = options;
|
|
9872
10890
|
const envFile = envFileOf(cli.name, env);
|
|
9873
10891
|
return {
|
|
@@ -9883,7 +10901,7 @@ function portsBaseOf(scope, signal) {
|
|
|
9883
10901
|
envFile,
|
|
9884
10902
|
fileError,
|
|
9885
10903
|
version: cli.version,
|
|
9886
|
-
build:
|
|
10904
|
+
build: buildStamp(),
|
|
9887
10905
|
self: selfOf(cli.name, options.bin),
|
|
9888
10906
|
signal,
|
|
9889
10907
|
clock,
|
|
@@ -9894,7 +10912,7 @@ function portsBaseOf(scope, signal) {
|
|
|
9894
10912
|
signal
|
|
9895
10913
|
}, {
|
|
9896
10914
|
fileError,
|
|
9897
|
-
|
|
10915
|
+
rerun
|
|
9898
10916
|
}),
|
|
9899
10917
|
spawnDetached: contextSpawnDetached(spawnDetachedOf(options), {
|
|
9900
10918
|
cwd,
|
|
@@ -9902,23 +10920,30 @@ function portsBaseOf(scope, signal) {
|
|
|
9902
10920
|
signal
|
|
9903
10921
|
}, {
|
|
9904
10922
|
fileError,
|
|
9905
|
-
|
|
10923
|
+
rerun
|
|
9906
10924
|
})
|
|
9907
10925
|
};
|
|
9908
10926
|
}
|
|
9909
10927
|
function contextOf(portsBase, control, parts) {
|
|
9910
|
-
const { ports, project, force,
|
|
10928
|
+
const { ports, project, force, secrets = [], rerun, deliver, notice } = parts;
|
|
10929
|
+
const declared = new Set(secrets.map(({ name }) => name));
|
|
9911
10930
|
return {
|
|
9912
10931
|
...portsBase,
|
|
9913
|
-
|
|
9914
|
-
|
|
10932
|
+
secret: (name) => {
|
|
10933
|
+
if (!declared.has(name)) throw new Error(`ctx.secret("${name}") names a Secret the Command does not declare`);
|
|
10934
|
+
const secret = portsBase.secret(name);
|
|
10935
|
+
if (secret === void 0) throw new Error(`ctx.secret("${name}") found no value`);
|
|
10936
|
+
return secret;
|
|
10937
|
+
},
|
|
10938
|
+
fail: cliErrorOf,
|
|
10939
|
+
deadline: (ms, options) => control.deadline(ms, options),
|
|
9915
10940
|
runToEnd: (name, work) => control.runToEnd(name, work),
|
|
9916
10941
|
get ports() {
|
|
9917
10942
|
return ports();
|
|
9918
10943
|
},
|
|
9919
10944
|
project,
|
|
9920
10945
|
force,
|
|
9921
|
-
|
|
10946
|
+
rerun,
|
|
9922
10947
|
poll: (check, { intervalMs, signal: stop }) => poll(portsBase.clock, check, intervalMs, stop === void 0 ? control.signal : AbortSignal.any([control.signal, stop])),
|
|
9923
10948
|
deliver,
|
|
9924
10949
|
notice
|
|
@@ -9940,10 +10965,14 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
9940
10965
|
flags: knownFlags(routed.spec),
|
|
9941
10966
|
stdinArg: stdinArgOf(routed)
|
|
9942
10967
|
};
|
|
9943
|
-
const
|
|
9944
|
-
|
|
10968
|
+
const rerunOf = (change) => ({
|
|
10969
|
+
kind: "rerun",
|
|
10970
|
+
words: changedArgv(invocation, change),
|
|
10971
|
+
stdinArg: invocation.stdinArg
|
|
10972
|
+
});
|
|
10973
|
+
const rerun = rerunOf();
|
|
9945
10974
|
const fileError = fileErrorOf({
|
|
9946
|
-
|
|
10975
|
+
rerun,
|
|
9947
10976
|
env,
|
|
9948
10977
|
platform
|
|
9949
10978
|
});
|
|
@@ -9957,16 +10986,16 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
9957
10986
|
...invocation,
|
|
9958
10987
|
stdinArg: void 0
|
|
9959
10988
|
});
|
|
9960
|
-
let
|
|
10989
|
+
let resumed;
|
|
9961
10990
|
const control = new RunControl({
|
|
9962
10991
|
commandLine,
|
|
9963
|
-
|
|
10992
|
+
rerun,
|
|
9964
10993
|
outer: options.signal,
|
|
9965
10994
|
clock,
|
|
9966
10995
|
progress,
|
|
9967
10996
|
runDeadline: command.deadline === void 0 ? void 0 : {
|
|
9968
10997
|
ms: command.deadline.ms,
|
|
9969
|
-
|
|
10998
|
+
advice: () => runDeadlineAdvice(resumed, pipedLine)
|
|
9970
10999
|
}
|
|
9971
11000
|
});
|
|
9972
11001
|
const failed = (error, finishSideTask) => {
|
|
@@ -9978,7 +11007,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
9978
11007
|
};
|
|
9979
11008
|
let parsed;
|
|
9980
11009
|
try {
|
|
9981
|
-
checkOperator(routed.spec, env,
|
|
11010
|
+
checkOperator(routed.spec, env, rerun);
|
|
9982
11011
|
parsed = await parseCommand(routed, invocation, (field) => {
|
|
9983
11012
|
if (isTerminal(stdin)) progress(readingLine(field.name, platform));
|
|
9984
11013
|
return readStdin(stdin, control.signal, {
|
|
@@ -9990,7 +11019,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
9990
11019
|
return failed(error, noSideTask);
|
|
9991
11020
|
}
|
|
9992
11021
|
const { input, flags } = parsed;
|
|
9993
|
-
|
|
11022
|
+
resumed = command.deadline?.resume(input, rerunOf);
|
|
9994
11023
|
const outputs = outputsGuard(classifiedFiles(files, {
|
|
9995
11024
|
cwd,
|
|
9996
11025
|
fileError
|
|
@@ -10001,7 +11030,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10001
11030
|
packageRoot,
|
|
10002
11031
|
progress,
|
|
10003
11032
|
fileError,
|
|
10004
|
-
|
|
11033
|
+
rerun,
|
|
10005
11034
|
clock,
|
|
10006
11035
|
files: outputs.files
|
|
10007
11036
|
};
|
|
@@ -10027,7 +11056,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10027
11056
|
try {
|
|
10028
11057
|
project = builtIn || cli.project === void 0 ? void 0 : projectOf(cli.project, cwd, {
|
|
10029
11058
|
fileError,
|
|
10030
|
-
|
|
11059
|
+
rerun
|
|
10031
11060
|
});
|
|
10032
11061
|
} catch (error) {
|
|
10033
11062
|
return failed(error, finishSideTask);
|
|
@@ -10037,15 +11066,16 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10037
11066
|
ports: once(() => ports(portsBase)),
|
|
10038
11067
|
project,
|
|
10039
11068
|
force: flags.force,
|
|
10040
|
-
|
|
11069
|
+
secrets: command.secrets,
|
|
11070
|
+
rerun: rerunOf,
|
|
10041
11071
|
notice: (text) => write.stderr(noticeLine(text, routed.json)),
|
|
10042
11072
|
deliver: (data) => {
|
|
10043
|
-
delivered =
|
|
11073
|
+
delivered = () => dataOutcome(command, data, commandLine);
|
|
10044
11074
|
}
|
|
10045
11075
|
});
|
|
10046
11076
|
const spill = spillTo({
|
|
10047
11077
|
cliName: format.cliName,
|
|
10048
|
-
|
|
11078
|
+
label: commandLabel(routed.spec.path, format.cliName),
|
|
10049
11079
|
env,
|
|
10050
11080
|
clock,
|
|
10051
11081
|
files: outputs.files,
|
|
@@ -10054,7 +11084,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10054
11084
|
let served = false;
|
|
10055
11085
|
let settled;
|
|
10056
11086
|
try {
|
|
10057
|
-
const outcome = await control.settle(skillOf(cli, installOf(cli)).notice({
|
|
11087
|
+
const outcome = await control.settle(skillOf$1(cli, installOf(cli)).notice({
|
|
10058
11088
|
builtIn,
|
|
10059
11089
|
bin: options.bin
|
|
10060
11090
|
}, ctx).then(() => execute(command, input, ctx, {
|
|
@@ -10062,7 +11092,6 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10062
11092
|
confirm: flags.confirm,
|
|
10063
11093
|
yes: flags.yes,
|
|
10064
11094
|
page: flags.page,
|
|
10065
|
-
invocation,
|
|
10066
11095
|
commandLine,
|
|
10067
11096
|
started: async (outcome) => {
|
|
10068
11097
|
write.stdout(await startedOutput(outcome, format, spill));
|
|
@@ -10086,7 +11115,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10086
11115
|
};
|
|
10087
11116
|
settled = {
|
|
10088
11117
|
ok: false,
|
|
10089
|
-
error: control.errorAfter(error),
|
|
11118
|
+
error: checkedCodes(control.errorAfter(error), routed.spec, cli),
|
|
10090
11119
|
delivered
|
|
10091
11120
|
};
|
|
10092
11121
|
}
|
|
@@ -10170,6 +11199,10 @@ async function runWithProgress(cli, argv, options, write, stopNotice) {
|
|
|
10170
11199
|
}
|
|
10171
11200
|
async function routeAndRun(cli, argv, options, write, stopNotice) {
|
|
10172
11201
|
const runAs = runAsOf(cli);
|
|
11202
|
+
const root = rootSpec(cli, {
|
|
11203
|
+
bin: options.bin,
|
|
11204
|
+
node: options.node
|
|
11205
|
+
});
|
|
10173
11206
|
const format = {
|
|
10174
11207
|
cliName: cli.name,
|
|
10175
11208
|
env: options.env,
|
|
@@ -10180,16 +11213,10 @@ async function routeAndRun(cli, argv, options, write, stopNotice) {
|
|
|
10180
11213
|
flags: []
|
|
10181
11214
|
},
|
|
10182
11215
|
json: false,
|
|
10183
|
-
errors: cli
|
|
10184
|
-
stop: options.signal
|
|
11216
|
+
errors: errorTableOf(cli),
|
|
11217
|
+
stop: options.signal,
|
|
11218
|
+
...options.checkNextSteps === true ? { checkNextStep: (step) => nextStepProblem(root, runAs, step) } : {}
|
|
10185
11219
|
};
|
|
10186
|
-
const root = cli.commands === void 0 ? {
|
|
10187
|
-
...commandSpec(runAs, cli.command),
|
|
10188
|
-
description: cli.description
|
|
10189
|
-
} : groupSpec(runAs, cli.commands, builtInCommands(cli, {
|
|
10190
|
-
bin: options.bin,
|
|
10191
|
-
node: options.node
|
|
10192
|
-
}));
|
|
10193
11220
|
const routed = route(root, format.invocation);
|
|
10194
11221
|
const misused = (node) => isAgent(options.env) ? {
|
|
10195
11222
|
...format,
|
|
@@ -10216,10 +11243,22 @@ async function ranAlone(result) {
|
|
|
10216
11243
|
}
|
|
10217
11244
|
//#endregion
|
|
10218
11245
|
//#region ../agent-cli/dist/run-process.js
|
|
10219
|
-
|
|
10220
|
-
|
|
11246
|
+
const READER_GONE = /* @__PURE__ */ new Set(["EPIPE", "EOF"]);
|
|
11247
|
+
function writerTo(stream) {
|
|
11248
|
+
stream.on("error", (error) => {
|
|
11249
|
+
if (error.code === void 0 || !READER_GONE.has(error.code)) throw error;
|
|
11250
|
+
});
|
|
11251
|
+
return (text) => new Promise((resolve) => {
|
|
11252
|
+
if (stream.destroyed) {
|
|
11253
|
+
resolve();
|
|
11254
|
+
return;
|
|
11255
|
+
}
|
|
11256
|
+
stream.write(text, () => resolve());
|
|
11257
|
+
});
|
|
10221
11258
|
}
|
|
10222
11259
|
async function runProcess(cli) {
|
|
11260
|
+
const stdout = writerTo(process.stdout);
|
|
11261
|
+
const stderr = writerTo(process.stderr);
|
|
10223
11262
|
const stop = new AbortController();
|
|
10224
11263
|
const onSignal = (signal) => {
|
|
10225
11264
|
if (stop.signal.aborted) process.exit(SIGNAL_EXIT_CODES[signal]);
|
|
@@ -10237,11 +11276,11 @@ async function runProcess(cli) {
|
|
|
10237
11276
|
node: process.execPath,
|
|
10238
11277
|
stdin: process.stdin
|
|
10239
11278
|
}, {
|
|
10240
|
-
stdout: (text) =>
|
|
10241
|
-
stderr: (text) =>
|
|
10242
|
-
result: async (
|
|
10243
|
-
await
|
|
10244
|
-
await
|
|
11279
|
+
stdout: (text) => void stdout(text),
|
|
11280
|
+
stderr: (text) => void stderr(text),
|
|
11281
|
+
result: async (result) => {
|
|
11282
|
+
await stdout(result.stdout);
|
|
11283
|
+
await stderr(result.stderr);
|
|
10245
11284
|
}
|
|
10246
11285
|
}, "stopping… (Ctrl-C again to quit now)");
|
|
10247
11286
|
process.exitCode = result.exitCode;
|
|
@@ -10253,16 +11292,44 @@ async function runProcess(cli) {
|
|
|
10253
11292
|
}
|
|
10254
11293
|
//#endregion
|
|
10255
11294
|
//#region package.json
|
|
10256
|
-
var
|
|
10257
|
-
|
|
10258
|
-
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
"
|
|
10262
|
-
"
|
|
10263
|
-
|
|
11295
|
+
var package_default = {
|
|
11296
|
+
name: "@duyquangnvx/create-agent-cli",
|
|
11297
|
+
version: "0.18.0",
|
|
11298
|
+
description: "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.",
|
|
11299
|
+
type: "module",
|
|
11300
|
+
engines: { "node": ">=22.12.0" },
|
|
11301
|
+
bin: { "create-agent-cli": "./dist/bin.js" },
|
|
11302
|
+
files: [
|
|
11303
|
+
"dist",
|
|
11304
|
+
"partials",
|
|
11305
|
+
"template",
|
|
11306
|
+
"agents-section.md",
|
|
11307
|
+
"CHANGELOG.md"
|
|
11308
|
+
],
|
|
11309
|
+
publishConfig: {
|
|
11310
|
+
"registry": "https://registry.npmjs.org/",
|
|
11311
|
+
"access": "public"
|
|
11312
|
+
},
|
|
11313
|
+
scripts: {
|
|
11314
|
+
"build": "node -e \"require('node:fs').copyFileSync('../agent-cli/agents-section.md', 'agents-section.md')\" && tsdown",
|
|
11315
|
+
"prepack": "node -e \"require('node:fs').copyFileSync('../../CHANGELOG.md', 'CHANGELOG.md')\""
|
|
11316
|
+
},
|
|
11317
|
+
devDependencies: {
|
|
11318
|
+
"@duyquangnvx/agent-cli": "workspace:*",
|
|
11319
|
+
"tsdown": "0.23.0",
|
|
11320
|
+
"zod": "4.6.7"
|
|
11321
|
+
}
|
|
10264
11322
|
};
|
|
10265
11323
|
//#endregion
|
|
11324
|
+
//#region src/agents-section.ts
|
|
11325
|
+
const AGENTS_SECTION_FILE = new URL("../agents-section.md", import.meta.url);
|
|
11326
|
+
function agentsSection() {
|
|
11327
|
+
return readFile(AGENTS_SECTION_FILE, "utf8");
|
|
11328
|
+
}
|
|
11329
|
+
//#endregion
|
|
11330
|
+
//#region src/define.ts
|
|
11331
|
+
const { defineCli, defineCommand, cliError } = agentCli({ errors: { STEP_FAILED: { class: "operator" } } });
|
|
11332
|
+
//#endregion
|
|
10266
11333
|
//#region src/fill.ts
|
|
10267
11334
|
/** `text` with each `{{key}}` replaced by its value; `quoted` escapes values that land inside a double-quoted string. */
|
|
10268
11335
|
function fill(text, values, quoted) {
|
|
@@ -10277,29 +11344,55 @@ function fill(text, values, quoted) {
|
|
|
10277
11344
|
const PARTIALS_DIR = fileURLToPath(new URL("../partials/", import.meta.url));
|
|
10278
11345
|
const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
10279
11346
|
const COMMANDS_ANCHOR = " commands: {";
|
|
10280
|
-
const GLOBAL_INSTALL = ` install:
|
|
10281
|
-
|
|
10282
|
-
|
|
10283
|
-
|
|
10284
|
-
|
|
10285
|
-
|
|
10286
|
-
|
|
10287
|
-
|
|
11347
|
+
const GLOBAL_INSTALL = ` install: "global",\n`;
|
|
11348
|
+
const NO_SKILL_HUB = "<!-- Set `skill.source` in `defineCli` and `skillHub: { git }` in `scripts/release.ts` to the git URL of the Skill Hub each release commits the skill to, or set `skill.page` to the Skill Hub's page where each user copies their own install line and `skillHub: { api }` to the API Skill Hub each release publishes the skill to. Then put here what `node dist/bin.js doctor` gives in its `skill` row: the `! npx -y skills add` line of its fix, or the sentence naming the page. -->";
|
|
11349
|
+
function skillHubOf({ git, api, page }) {
|
|
11350
|
+
if (git !== void 0 && api !== void 0) throw new UsageError({
|
|
11351
|
+
code: "SKILL_HOMES_CONFLICT",
|
|
11352
|
+
message: "--skill-hub-git and --skill-hub-api each name the Skill Hub the skill goes to",
|
|
11353
|
+
hint: "pass one of them"
|
|
11354
|
+
});
|
|
11355
|
+
if (api !== void 0 && page === void 0) throw new UsageError({
|
|
11356
|
+
code: "SKILL_PAGE_MISSING",
|
|
11357
|
+
message: "--skill-hub-api needs --skill-page, the hub's page where each user copies their own install line",
|
|
11358
|
+
hint: "add --skill-page with the skill's page on the hub"
|
|
11359
|
+
});
|
|
11360
|
+
if (page !== void 0 && api === void 0) throw new UsageError({
|
|
11361
|
+
code: "SKILL_HUB_API_MISSING",
|
|
11362
|
+
message: "--skill-page names a page of an API Skill Hub, which --skill-hub-api names",
|
|
11363
|
+
hint: "add --skill-hub-api with the hub's URL"
|
|
11364
|
+
});
|
|
11365
|
+
if (git !== void 0) return {
|
|
11366
|
+
kind: "git",
|
|
11367
|
+
url: git
|
|
11368
|
+
};
|
|
11369
|
+
return api === void 0 || page === void 0 ? void 0 : {
|
|
11370
|
+
kind: "api",
|
|
11371
|
+
url: api,
|
|
11372
|
+
page
|
|
11373
|
+
};
|
|
11374
|
+
}
|
|
11375
|
+
function installModeOf(flags, dependency, binName) {
|
|
11376
|
+
const skillHub = skillHubOf(flags);
|
|
10288
11377
|
if (skillHub !== void 0 && dependency) throw new UsageError({
|
|
10289
11378
|
code: "SKILL_HOMES_CONFLICT",
|
|
10290
|
-
message:
|
|
10291
|
-
hint:
|
|
11379
|
+
message: `--skill-hub-${skillHub.kind} and --dependency each name where the skill comes from: a Dependency install ships it inside the package`,
|
|
11380
|
+
hint: `pass --dependency for a CLI each project pins, or --skill-hub-${skillHub.kind} for a global one whose skill each release puts on a Skill Hub`
|
|
10292
11381
|
});
|
|
10293
11382
|
if ((skillHub !== void 0 || dependency) && !SKILL_NAME.test(binName)) throw new UsageError({
|
|
10294
11383
|
code: "SKILL_NAME_INVALID",
|
|
10295
11384
|
message: `${binName} cannot name a skill, whose names are lowercase letters, digits and single hyphens`,
|
|
10296
|
-
hint: `choose a name such as my-cli, or leave out ${dependency ? "--dependency" :
|
|
11385
|
+
hint: `choose a name such as my-cli, or leave out ${dependency ? "--dependency" : `--skill-hub-${skillHub?.kind}`}`
|
|
10297
11386
|
});
|
|
10298
11387
|
return dependency ? { mode: "dependency" } : {
|
|
10299
11388
|
mode: "global",
|
|
10300
11389
|
skillHub
|
|
10301
11390
|
};
|
|
10302
11391
|
}
|
|
11392
|
+
function skillLineOf(skillHub, binName) {
|
|
11393
|
+
if (skillHub === void 0) return NO_SKILL_HUB;
|
|
11394
|
+
return skillHub.kind === "git" ? `\`! npx -y skills add ${skillHub.url} --skill ${binName} -g\`` : `The skill's line is your own: copy your install line from ${skillHub.page}, then type it.`;
|
|
11395
|
+
}
|
|
10303
11396
|
async function partialsOf(mode, values) {
|
|
10304
11397
|
const partial = async (name) => fill(await readFile(join(PARTIALS_DIR, mode, `${name}.md`), "utf8"), values, false).trimEnd();
|
|
10305
11398
|
const [installLines, skillCheck, installSteps, updateSteps, sandbox] = await Promise.all([
|
|
@@ -10318,9 +11411,8 @@ async function partialsOf(mode, values) {
|
|
|
10318
11411
|
};
|
|
10319
11412
|
}
|
|
10320
11413
|
async function globalSetup(skillHub, packageName, binName) {
|
|
10321
|
-
const skillLine = skillHub
|
|
11414
|
+
const skillLine = skillLineOf(skillHub, binName);
|
|
10322
11415
|
const runAs = runAsOf({ name: binName });
|
|
10323
|
-
const url = JSON.stringify(skillHub);
|
|
10324
11416
|
return {
|
|
10325
11417
|
values: {
|
|
10326
11418
|
runAs,
|
|
@@ -10335,15 +11427,18 @@ async function globalSetup(skillHub, packageName, binName) {
|
|
|
10335
11427
|
edits: skillHub === void 0 ? [] : [{
|
|
10336
11428
|
file: "src/cli.ts",
|
|
10337
11429
|
find: COMMANDS_ANCHOR,
|
|
10338
|
-
replace: ` skill:
|
|
11430
|
+
replace: ` skill: ${skillOf(skillHub)},\n${COMMANDS_ANCHOR}`
|
|
10339
11431
|
}, {
|
|
10340
11432
|
file: "scripts/release.ts",
|
|
10341
11433
|
find: " smoke: {",
|
|
10342
|
-
replace: ` skillHub: ${url},\n smoke: {`
|
|
11434
|
+
replace: ` skillHub: { ${skillHub.kind}: ${JSON.stringify(skillHub.url)} },\n smoke: {`
|
|
10343
11435
|
}],
|
|
10344
11436
|
files: []
|
|
10345
11437
|
};
|
|
10346
11438
|
}
|
|
11439
|
+
function skillOf(skillHub) {
|
|
11440
|
+
return skillHub.kind === "git" ? `{ source: ${JSON.stringify(skillHub.url)} }` : `{ page: ${JSON.stringify(skillHub.page)} }`;
|
|
11441
|
+
}
|
|
10347
11442
|
async function dependencySetup(packageName, binName) {
|
|
10348
11443
|
const runAs = runAsOf({
|
|
10349
11444
|
name: binName,
|
|
@@ -10365,7 +11460,7 @@ async function dependencySetup(packageName, binName) {
|
|
|
10365
11460
|
edits: [{
|
|
10366
11461
|
file: "src/cli.ts",
|
|
10367
11462
|
find: GLOBAL_INSTALL,
|
|
10368
|
-
replace: ` install:
|
|
11463
|
+
replace: ` install: "dependency",\n`
|
|
10369
11464
|
}, {
|
|
10370
11465
|
file: "src/cli.ts",
|
|
10371
11466
|
find: COMMANDS_ANCHOR,
|
|
@@ -10379,7 +11474,6 @@ async function installSetupOf(install, packageName, binName) {
|
|
|
10379
11474
|
}
|
|
10380
11475
|
//#endregion
|
|
10381
11476
|
//#region src/steps.ts
|
|
10382
|
-
const stepErrors = defineErrors({ STEP_FAILED: { class: "operator" } });
|
|
10383
11477
|
const INSTALL = [{
|
|
10384
11478
|
command: "pnpm",
|
|
10385
11479
|
args: ["install"]
|
|
@@ -10448,7 +11542,7 @@ function tail(output) {
|
|
|
10448
11542
|
return output.trimEnd().split(/\r?\n/).slice(-20).join("\n");
|
|
10449
11543
|
}
|
|
10450
11544
|
function stepFailed(problem, left, cwd, cause) {
|
|
10451
|
-
return cliError(
|
|
11545
|
+
return cliError("STEP_FAILED", {
|
|
10452
11546
|
message: problem,
|
|
10453
11547
|
hint: `fix the problem, then run in ${cwd}: ${left.map(stepLine).join(" && ")}`
|
|
10454
11548
|
}, { cause });
|
|
@@ -10497,10 +11591,9 @@ async function writeTemplate(root, files, values) {
|
|
|
10497
11591
|
}
|
|
10498
11592
|
//#endregion
|
|
10499
11593
|
//#region src/version.ts
|
|
10500
|
-
const version = version
|
|
11594
|
+
const version = package_default.version;
|
|
10501
11595
|
//#endregion
|
|
10502
11596
|
//#region src/create.ts
|
|
10503
|
-
const { defineCommand } = agentCli();
|
|
10504
11597
|
const PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?([a-z0-9][a-z0-9._-]*)$/;
|
|
10505
11598
|
function errorCode(error) {
|
|
10506
11599
|
return error instanceof Error && "code" in error ? error.code : void 0;
|
|
@@ -10540,82 +11633,81 @@ async function ensureFree(path) {
|
|
|
10540
11633
|
hint: "run `create-agent-cli <name>` with a name whose directory is free, or empty it first"
|
|
10541
11634
|
});
|
|
10542
11635
|
}
|
|
10543
|
-
const create = defineCommand({
|
|
10544
|
-
name: "create",
|
|
10545
|
-
description: "Create a new Agent CLI project in ./<name>",
|
|
10546
|
-
examples: [{
|
|
10547
|
-
command: "create-agent-cli weather --description \"Weather forecasts\"",
|
|
10548
|
-
note: "create ./weather, install dependencies and make the first commit"
|
|
10549
|
-
}],
|
|
10550
|
-
effect: "write",
|
|
10551
|
-
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") }),
|
|
10552
|
-
options: object({
|
|
10553
|
-
description: string().default("An Agent CLI.").describe("one line saying what the CLI does"),
|
|
10554
|
-
install: boolean().default(true).describe("run pnpm install"),
|
|
10555
|
-
git: boolean().default(true).describe("create a git repository with an initial commit"),
|
|
10556
|
-
repository: url({ protocol: /^https$/ }).optional().describe("the https URL of the CLI's git repository"),
|
|
10557
|
-
skillHub: url({ protocol: /^https$/ }).refine((url) => new URL(url).search === "" && new URL(url).hash === "", "must name the hub's repository with no query or fragment").refine((url) => new URL(url).pathname.endsWith(".git"), "must end in .git").optional().describe("the https git URL of the Skill Hub each release commits the CLI's skill to"),
|
|
10558
|
-
dependency: boolean().default(false).describe("install the CLI per project, as a devDependency, with its skill shipped inside the package")
|
|
10559
|
-
}),
|
|
10560
|
-
plan: async ({ name, description, install, git, repository, skillHub, dependency }, ctx) => {
|
|
10561
|
-
const binName = PACKAGE_NAME.exec(name)?.[1] ?? name;
|
|
10562
|
-
const mode = installModeOf(skillHub, dependency, binName);
|
|
10563
|
-
const path = resolve(ctx.cwd, binName);
|
|
10564
|
-
await ensureFree(path);
|
|
10565
|
-
const setup = await installSetupOf(mode, name, binName);
|
|
10566
|
-
const values = {
|
|
10567
|
-
packageName: name,
|
|
10568
|
-
binName,
|
|
10569
|
-
description,
|
|
10570
|
-
debugVariable: debugVariable(binName),
|
|
10571
|
-
runtimeVersion: version,
|
|
10572
|
-
...setup.values
|
|
10573
|
-
};
|
|
10574
|
-
return {
|
|
10575
|
-
path,
|
|
10576
|
-
values,
|
|
10577
|
-
files: await templateFiles(values),
|
|
10578
|
-
steps: stepsFor({
|
|
10579
|
-
install,
|
|
10580
|
-
git
|
|
10581
|
-
}),
|
|
10582
|
-
install,
|
|
10583
|
-
repository,
|
|
10584
|
-
edits: setup.edits,
|
|
10585
|
-
manifestFiles: setup.files
|
|
10586
|
-
};
|
|
10587
|
-
},
|
|
10588
|
-
apply: async (plan, ctx) => {
|
|
10589
|
-
await mkdir(plan.path, { recursive: true });
|
|
10590
|
-
await writeTemplate(plan.path, plan.files, plan.values);
|
|
10591
|
-
if (plan.repository !== void 0) await setRepository(plan.path, plan.repository);
|
|
10592
|
-
for (const edit of plan.edits) await applyEdit(plan.path, edit);
|
|
10593
|
-
if (plan.manifestFiles.length > 0) await addFiles(plan.path, plan.manifestFiles);
|
|
10594
|
-
await runSteps(plan.steps, plan.path, ctx);
|
|
10595
|
-
return {
|
|
10596
|
-
path: plan.path,
|
|
10597
|
-
next: `cd ${plan.values.binName} && pnpm ${plan.install ? "test" : "install"}`
|
|
10598
|
-
};
|
|
10599
|
-
},
|
|
10600
|
-
render: ({ path, next }) => `Created ${path}\nnext: ${next}`,
|
|
10601
|
-
renderPlan: (plan) => [
|
|
10602
|
-
`Would create ${plan.path}:`,
|
|
10603
|
-
...plan.files.map((file) => ` create ${file.target}`),
|
|
10604
|
-
...plan.steps.map((step) => ` run ${stepLine(step)}`)
|
|
10605
|
-
].join("\n")
|
|
10606
|
-
});
|
|
10607
|
-
//#endregion
|
|
10608
|
-
//#region src/cli.ts
|
|
10609
|
-
const { defineCli } = agentCli();
|
|
10610
11636
|
//#endregion
|
|
10611
11637
|
//#region src/bin.ts
|
|
10612
11638
|
await runProcess(defineCli({
|
|
10613
|
-
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
11639
|
+
manifest: package_default,
|
|
11640
|
+
command: defineCommand({
|
|
11641
|
+
description: "Create a new Agent CLI project in ./<name>",
|
|
11642
|
+
examples: [{
|
|
11643
|
+
command: "create-agent-cli weather --description \"Weather forecasts\"",
|
|
11644
|
+
note: "create ./weather, install dependencies and make the first commit"
|
|
11645
|
+
}],
|
|
11646
|
+
effect: "write",
|
|
11647
|
+
errors: ["STEP_FAILED"],
|
|
11648
|
+
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") }),
|
|
11649
|
+
options: object({
|
|
11650
|
+
description: string().default("An Agent CLI.").describe("one line saying what the CLI does"),
|
|
11651
|
+
install: boolean().default(true).describe("run pnpm install"),
|
|
11652
|
+
git: boolean().default(true).describe("create a git repository with an initial commit"),
|
|
11653
|
+
repository: url({ protocol: /^https$/ }).optional().describe("the https URL of the CLI's git repository"),
|
|
11654
|
+
skillHubGit: url({ protocol: /^https$/ }).refine((url) => new URL(url).search === "" && new URL(url).hash === "", "must name the hub's repository with no query or fragment").refine((url) => new URL(url).pathname.endsWith(".git"), "must end in .git").optional().describe("the https git URL of a git Skill Hub each release commits the CLI's skill to"),
|
|
11655
|
+
skillHubApi: url({ protocol: /^https$/ }).optional().describe("the https URL of an API Skill Hub each release publishes the CLI's skill to"),
|
|
11656
|
+
skillPage: url({ protocol: /^https$/ }).optional().describe("the https page of the skill on the API Skill Hub, where each user copies their own install line"),
|
|
11657
|
+
dependency: boolean().default(false).describe("install the CLI per project, as a devDependency, with its skill shipped inside the package")
|
|
11658
|
+
}),
|
|
11659
|
+
plan: async ({ name, description, install, git, repository, skillHubGit, skillHubApi, skillPage, dependency }, ctx) => {
|
|
11660
|
+
const binName = PACKAGE_NAME.exec(name)?.[1] ?? name;
|
|
11661
|
+
const mode = installModeOf({
|
|
11662
|
+
git: skillHubGit,
|
|
11663
|
+
api: skillHubApi,
|
|
11664
|
+
page: skillPage
|
|
11665
|
+
}, dependency, binName);
|
|
11666
|
+
const path = resolve(ctx.cwd, binName);
|
|
11667
|
+
await ensureFree(path);
|
|
11668
|
+
const setup = await installSetupOf(mode, name, binName);
|
|
11669
|
+
const values = {
|
|
11670
|
+
packageName: name,
|
|
11671
|
+
binName,
|
|
11672
|
+
description,
|
|
11673
|
+
debugVariable: debugVariable(binName),
|
|
11674
|
+
runtimeVersion: version,
|
|
11675
|
+
agentsSection: await agentsSection(),
|
|
11676
|
+
...setup.values
|
|
11677
|
+
};
|
|
11678
|
+
return {
|
|
11679
|
+
path,
|
|
11680
|
+
values,
|
|
11681
|
+
files: await templateFiles(values),
|
|
11682
|
+
steps: stepsFor({
|
|
11683
|
+
install,
|
|
11684
|
+
git
|
|
11685
|
+
}),
|
|
11686
|
+
install,
|
|
11687
|
+
repository,
|
|
11688
|
+
edits: setup.edits,
|
|
11689
|
+
manifestFiles: setup.files
|
|
11690
|
+
};
|
|
11691
|
+
},
|
|
11692
|
+
apply: async (plan, ctx) => {
|
|
11693
|
+
await mkdir(plan.path, { recursive: true });
|
|
11694
|
+
await writeTemplate(plan.path, plan.files, plan.values);
|
|
11695
|
+
if (plan.repository !== void 0) await setRepository(plan.path, plan.repository);
|
|
11696
|
+
for (const edit of plan.edits) await applyEdit(plan.path, edit);
|
|
11697
|
+
if (plan.manifestFiles.length > 0) await addFiles(plan.path, plan.manifestFiles);
|
|
11698
|
+
await runSteps(plan.steps, plan.path, ctx);
|
|
11699
|
+
return {
|
|
11700
|
+
path: plan.path,
|
|
11701
|
+
next: `cd ${plan.values.binName} && pnpm ${plan.install ? "test" : "install"}`
|
|
11702
|
+
};
|
|
11703
|
+
},
|
|
11704
|
+
render: ({ path, next }) => `Created ${path}\nnext: ${next}`,
|
|
11705
|
+
renderPlan: (plan) => [
|
|
11706
|
+
`Would create ${plan.path}:`,
|
|
11707
|
+
...plan.files.map((file) => ` create ${file.target}`),
|
|
11708
|
+
...plan.steps.map((step) => ` run ${stepLine(step)}`)
|
|
11709
|
+
].join("\n")
|
|
11710
|
+
})
|
|
10619
11711
|
}));
|
|
10620
11712
|
//#endregion
|
|
10621
11713
|
export {};
|