@duyquangnvx/create-agent-cli 0.17.0 → 0.19.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 +77 -0
- package/README.md +3 -3
- package/agents-section.md +5 -0
- package/dist/bin.js +2302 -1211
- 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 +24 -14
- 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 }) {
|
|
@@ -6444,7 +6492,7 @@ const RESERVED = new Map([
|
|
|
6444
6492
|
YES_FLAG.flag,
|
|
6445
6493
|
FORCE_FLAG.flag,
|
|
6446
6494
|
...LIST_FLAGS
|
|
6447
|
-
].map((flag) => [nameOf(flag), flag]));
|
|
6495
|
+
].map((flag) => [nameOf$1(flag), flag]));
|
|
6448
6496
|
/** The Standard flags of a Command with this Effect and declarations, and of a List Command. */
|
|
6449
6497
|
function standardFlagsFor(effect, { outputs, force, cost }, list) {
|
|
6450
6498
|
const forceFlag = force === void 0 ? FORCE_FLAG : {
|
|
@@ -6459,7 +6507,7 @@ function standardFlagsFor(effect, { outputs, force, cost }, list) {
|
|
|
6459
6507
|
];
|
|
6460
6508
|
}
|
|
6461
6509
|
/** Throws when the Command declares an arg or option under a Standard flag's name. */
|
|
6462
|
-
function checkNoStandardFlags(command) {
|
|
6510
|
+
function checkNoStandardFlags(command, label) {
|
|
6463
6511
|
const lines = [...argFields(command.args).map(({ key }) => ({
|
|
6464
6512
|
kind: "arg",
|
|
6465
6513
|
key
|
|
@@ -6470,40 +6518,46 @@ function checkNoStandardFlags(command) {
|
|
|
6470
6518
|
const flag = RESERVED.get(kebab(key));
|
|
6471
6519
|
return flag === void 0 ? [] : [` ${kind} '${key}' is the Standard flag ${flag}`];
|
|
6472
6520
|
});
|
|
6473
|
-
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"));
|
|
6474
6522
|
}
|
|
6475
6523
|
/** Throws when `force` is declared on a Command with no Plan, or says nothing. */
|
|
6476
|
-
function checkForce(command) {
|
|
6524
|
+
function checkForce(command, label) {
|
|
6477
6525
|
const force = "force" in command ? command.force : void 0;
|
|
6478
6526
|
if (force === void 0) return;
|
|
6479
|
-
if (!hasPlan(command)) throw new Error(`Command '${
|
|
6480
|
-
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`);
|
|
6481
6529
|
}
|
|
6482
6530
|
//#endregion
|
|
6483
|
-
//#region ../agent-cli/dist/define.js
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
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`);
|
|
6491
6544
|
}
|
|
6492
6545
|
function defineCommandFor() {
|
|
6493
|
-
return
|
|
6546
|
+
return declared;
|
|
6494
6547
|
}
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
return typeof node.effect === "string";
|
|
6548
|
+
function declared(command) {
|
|
6549
|
+
return command;
|
|
6498
6550
|
}
|
|
6551
|
+
const defineCommand$1 = defineCommandFor();
|
|
6499
6552
|
//#endregion
|
|
6500
|
-
//#region ../agent-cli/dist/project.js
|
|
6553
|
+
//#region ../agent-cli/dist/context/project.js
|
|
6501
6554
|
const PROJECT_INVALID = "PROJECT_INVALID";
|
|
6502
|
-
function invalid(path, problem,
|
|
6555
|
+
function invalid(path, problem, rerun, options) {
|
|
6503
6556
|
return new CliError({
|
|
6504
6557
|
code: PROJECT_INVALID,
|
|
6505
6558
|
message: `the Project file ${path} is invalid: ${problem}`,
|
|
6506
|
-
hint: `fix ${path}, then run
|
|
6559
|
+
hint: `fix ${path}, then run the Next step`,
|
|
6560
|
+
next: [rerun]
|
|
6507
6561
|
}, options);
|
|
6508
6562
|
}
|
|
6509
6563
|
function readText(path, fileError) {
|
|
@@ -6517,15 +6571,15 @@ function readText(path, fileError) {
|
|
|
6517
6571
|
});
|
|
6518
6572
|
}
|
|
6519
6573
|
}
|
|
6520
|
-
function parsed(path, text, schema,
|
|
6574
|
+
function parsed(path, text, schema, rerun) {
|
|
6521
6575
|
let json;
|
|
6522
6576
|
try {
|
|
6523
6577
|
json = JSON.parse(text);
|
|
6524
6578
|
} catch (error) {
|
|
6525
|
-
throw invalid(path, messageOf(error),
|
|
6579
|
+
throw invalid(path, messageOf(error), rerun, { cause: error });
|
|
6526
6580
|
}
|
|
6527
6581
|
const result = schema.safeParse(json);
|
|
6528
|
-
if (!result.success) throw invalid(path, prettifyError(result.error),
|
|
6582
|
+
if (!result.success) throw invalid(path, prettifyError(result.error), rerun);
|
|
6529
6583
|
return result.data;
|
|
6530
6584
|
}
|
|
6531
6585
|
function projectFrom(projectFile, folder, scope) {
|
|
@@ -6533,7 +6587,7 @@ function projectFrom(projectFile, folder, scope) {
|
|
|
6533
6587
|
const text = readText(path, scope.fileError);
|
|
6534
6588
|
if (text !== void 0) return {
|
|
6535
6589
|
root: folder,
|
|
6536
|
-
settings: parsed(path, text, projectFile.schema, scope.
|
|
6590
|
+
settings: parsed(path, text, projectFile.schema, scope.rerun)
|
|
6537
6591
|
};
|
|
6538
6592
|
const parent = dirname(folder);
|
|
6539
6593
|
return parent === folder ? void 0 : projectFrom(projectFile, parent, scope);
|
|
@@ -6543,7 +6597,110 @@ function projectOf(projectFile, cwd, scope) {
|
|
|
6543
6597
|
return projectFrom(projectFile, resolve(cwd), scope);
|
|
6544
6598
|
}
|
|
6545
6599
|
//#endregion
|
|
6546
|
-
//#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
|
|
6547
6704
|
const TOOL_MISSING = "TOOL_MISSING";
|
|
6548
6705
|
const WINDOWS_EXTENSIONS = ".COM;.EXE;.BAT;.CMD";
|
|
6549
6706
|
function pathOf(env) {
|
|
@@ -6573,23 +6730,21 @@ async function findTool(name, env) {
|
|
|
6573
6730
|
for (const file of candidates) if (await isExecutable(file)) return file;
|
|
6574
6731
|
}
|
|
6575
6732
|
/** Fails with `TOOL_MISSING`, naming every missing tool at once, unless all are on `PATH`. */
|
|
6576
|
-
async function checkTools(tools, env,
|
|
6733
|
+
async function checkTools(tools, env, rerun) {
|
|
6577
6734
|
const found = await Promise.all(tools.map((tool) => findTool(tool.name, env)));
|
|
6578
6735
|
const missing = tools.filter((_tool, index) => found[index] === void 0);
|
|
6579
6736
|
if (missing.length === 0) return;
|
|
6580
6737
|
const names = missing.map(({ name }) => name).join(", ");
|
|
6581
|
-
throw
|
|
6738
|
+
throw runtimeError({
|
|
6582
6739
|
code: TOOL_MISSING,
|
|
6583
6740
|
message: `${missing.length === 1 ? "a tool it runs is" : "tools it runs are"} not on PATH: ${names}`,
|
|
6584
|
-
hint:
|
|
6741
|
+
hint: "run the Next steps in order: each install, then the command again",
|
|
6742
|
+
next: [...missing.map(({ install }) => wholeLine(install)), rerun]
|
|
6585
6743
|
});
|
|
6586
6744
|
}
|
|
6587
|
-
function toolsIn(node) {
|
|
6588
|
-
return isCommand(node) ? [...node.tools ?? []] : Object.values(node).flatMap(toolsIn);
|
|
6589
|
-
}
|
|
6590
6745
|
/** One `doctor` row per distinct tool the CLI and its Commands declare, with its install command as the fix. */
|
|
6591
6746
|
function toolRows(tools, commands) {
|
|
6592
|
-
return
|
|
6747
|
+
return declaredIn(tools, commands, (command) => command.tools).map(({ name, install }) => ({
|
|
6593
6748
|
name,
|
|
6594
6749
|
run: async (ctx) => {
|
|
6595
6750
|
const file = await findTool(name, ctx.env);
|
|
@@ -6606,72 +6761,18 @@ function toolRows(tools, commands) {
|
|
|
6606
6761
|
}
|
|
6607
6762
|
//#endregion
|
|
6608
6763
|
//#region ../agent-cli/dist/version.js
|
|
6609
|
-
/** The
|
|
6610
|
-
function
|
|
6611
|
-
return
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
const MANAGERS = [
|
|
6616
|
-
"pnpm",
|
|
6617
|
-
"npm",
|
|
6618
|
-
"yarn",
|
|
6619
|
-
"bun"
|
|
6620
|
-
];
|
|
6621
|
-
const LOCKFILES = [
|
|
6622
|
-
["pnpm-lock.yaml", "pnpm"],
|
|
6623
|
-
["package-lock.json", "npm"],
|
|
6624
|
-
["yarn.lock", "yarn"],
|
|
6625
|
-
["bun.lock", "bun"],
|
|
6626
|
-
["bun.lockb", "bun"]
|
|
6627
|
-
];
|
|
6628
|
-
const manifestSchema$1 = object({
|
|
6629
|
-
packageManager: string().optional(),
|
|
6630
|
-
dependencies: record(string(), unknown()).optional(),
|
|
6631
|
-
devDependencies: record(string(), unknown()).optional()
|
|
6632
|
-
});
|
|
6633
|
-
/** `dir` and every folder above it, nearest first. */
|
|
6634
|
-
function ancestorsOf(dir) {
|
|
6635
|
-
const parent = dirname(dir);
|
|
6636
|
-
return parent === dir ? [dir] : [dir, ...ancestorsOf(parent)];
|
|
6637
|
-
}
|
|
6638
|
-
async function exists(path) {
|
|
6639
|
-
return await orMissing(stat(path)) !== void 0;
|
|
6640
|
-
}
|
|
6641
|
-
/** Whether `path` lies strictly inside `dir`. */
|
|
6642
|
-
function isInside(dir, path) {
|
|
6643
|
-
const inner = relative(dir, path);
|
|
6644
|
-
return inner !== "" && !inner.startsWith("..") && !isAbsolute(inner);
|
|
6645
|
-
}
|
|
6646
|
-
async function manifestIn(dir) {
|
|
6647
|
-
let text;
|
|
6648
|
-
try {
|
|
6649
|
-
text = await readFile(join(dir, "package.json"), "utf8");
|
|
6650
|
-
} catch (error) {
|
|
6651
|
-
if (isMissingFile(error)) return void 0;
|
|
6652
|
-
throw error;
|
|
6653
|
-
}
|
|
6654
|
-
let manifest;
|
|
6655
|
-
try {
|
|
6656
|
-
manifest = JSON.parse(text);
|
|
6657
|
-
} catch {
|
|
6658
|
-
return;
|
|
6659
|
-
}
|
|
6660
|
-
return manifestSchema$1.safeParse(manifest).data;
|
|
6661
|
-
}
|
|
6662
|
-
async function declaredManager(dir) {
|
|
6663
|
-
const name = (await manifestIn(dir))?.packageManager?.split("@")[0];
|
|
6664
|
-
return MANAGERS.find((manager) => manager === name);
|
|
6665
|
-
}
|
|
6666
|
-
async function lockfileRootOf(cwd) {
|
|
6667
|
-
for (const dir of ancestorsOf(cwd)) for (const [file, kind] of LOCKFILES) if (await exists(join(dir, file))) return {
|
|
6668
|
-
dir,
|
|
6669
|
-
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": "fb29229",
|
|
6768
|
+
"dirty": false,
|
|
6769
|
+
"builtAt": "2026-10-28T10:00:56.000Z"
|
|
6670
6770
|
};
|
|
6671
6771
|
}
|
|
6672
|
-
/** The
|
|
6673
|
-
|
|
6674
|
-
|
|
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}`;
|
|
6675
6776
|
}
|
|
6676
6777
|
//#endregion
|
|
6677
6778
|
//#region ../agent-cli/dist/tail.js
|
|
@@ -6680,7 +6781,7 @@ function lastLines(output, count) {
|
|
|
6680
6781
|
return output.trim().split("\n").slice(-count).join("\n");
|
|
6681
6782
|
}
|
|
6682
6783
|
//#endregion
|
|
6683
|
-
//#region ../agent-cli/dist/spawn.js
|
|
6784
|
+
//#region ../agent-cli/dist/context/spawn.js
|
|
6684
6785
|
const TOOL_FAILED = "TOOL_FAILED";
|
|
6685
6786
|
const STDERR_TAIL_LINES$1 = 20;
|
|
6686
6787
|
const SIGNAL_EXIT_BASE = 128;
|
|
@@ -6905,15 +7006,16 @@ function failedError(command, { exitCode, stderr }) {
|
|
|
6905
7006
|
hint: `the output of ${command} above says why it failed`
|
|
6906
7007
|
});
|
|
6907
7008
|
}
|
|
6908
|
-
function missingError(command,
|
|
7009
|
+
function missingError(command, rerun, cause) {
|
|
6909
7010
|
return new CliError({
|
|
6910
7011
|
code: TOOL_MISSING,
|
|
6911
7012
|
message: `${command} could not be started: it is not on PATH`,
|
|
6912
|
-
hint: `install ${command}, then run
|
|
7013
|
+
hint: `install ${command}, then run the Next step`,
|
|
7014
|
+
next: [rerun]
|
|
6913
7015
|
}, { cause });
|
|
6914
7016
|
}
|
|
6915
|
-
function startError(command, error, { fileError,
|
|
6916
|
-
if (isMissingFile(error)) return missingError(command,
|
|
7017
|
+
function startError(command, error, { fileError, rerun }) {
|
|
7018
|
+
if (isMissingFile(error)) return missingError(command, rerun, error);
|
|
6917
7019
|
return fileError(error, {
|
|
6918
7020
|
path: command,
|
|
6919
7021
|
access: "read"
|
|
@@ -7050,7 +7152,7 @@ const NO_LATEST = "NO_LATEST";
|
|
|
7050
7152
|
function npmContext(cli, registry, ctx, node, cwd) {
|
|
7051
7153
|
return {
|
|
7052
7154
|
cliName: cli.name,
|
|
7053
|
-
|
|
7155
|
+
rerun: ctx.rerun(),
|
|
7054
7156
|
registry,
|
|
7055
7157
|
cwd,
|
|
7056
7158
|
env: ctx.env,
|
|
@@ -7059,6 +7161,7 @@ function npmContext(cli, registry, ctx, node, cwd) {
|
|
|
7059
7161
|
};
|
|
7060
7162
|
}
|
|
7061
7163
|
const STDERR_TAIL_LINES = 10;
|
|
7164
|
+
const RUN_AGAIN = "run it again";
|
|
7062
7165
|
const RM_RETRIES = 3;
|
|
7063
7166
|
const NETWORK_CODES = /* @__PURE__ */ new Set([
|
|
7064
7167
|
"ENOTFOUND",
|
|
@@ -7122,27 +7225,31 @@ function failureOf(call, answer, ctx) {
|
|
|
7122
7225
|
const { label: registry, package: name, loginHint, unreachableHint } = ctx.registry;
|
|
7123
7226
|
const code = NPM_CODE.exec(answer.stderr)?.[1];
|
|
7124
7227
|
const output = tail$1(answer.stderr);
|
|
7125
|
-
const
|
|
7228
|
+
const next = [ctx.rerun];
|
|
7126
7229
|
if (code !== void 0 && NETWORK_CODES.has(code)) return new CliError({
|
|
7127
7230
|
code: REGISTRY_UNREACHABLE,
|
|
7128
7231
|
message: `npm could not reach ${registry} (${code})${output}`,
|
|
7129
|
-
hint: `${unreachableHint}, then ${
|
|
7232
|
+
hint: `${unreachableHint}, then ${RUN_AGAIN}`,
|
|
7233
|
+
next
|
|
7130
7234
|
});
|
|
7131
7235
|
if (code !== void 0 && AUTH_CODES.has(code)) return new CliError({
|
|
7132
7236
|
code: REGISTRY_AUTH,
|
|
7133
7237
|
message: `${registry} refused npm's credentials (${code})${output}`,
|
|
7134
|
-
hint: `${loginHint}, then ${
|
|
7238
|
+
hint: `${loginHint}, then ${RUN_AGAIN}`,
|
|
7239
|
+
next
|
|
7135
7240
|
});
|
|
7136
7241
|
if (call === "view" && code === "E404") return noLatest(ctx, `npm found no ${name}@latest on ${registry}: no version of it is published there`);
|
|
7137
|
-
if (call === "install") return
|
|
7242
|
+
if (call === "install") return runtimeError({
|
|
7138
7243
|
code: INSTALL_FAILED,
|
|
7139
7244
|
message: `npm could not install ${name}${code === void 0 ? "" : ` (${code})`}${output}`,
|
|
7140
|
-
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))]
|
|
7141
7247
|
});
|
|
7142
7248
|
return new CliError({
|
|
7143
7249
|
code: NPM_FAILED,
|
|
7144
7250
|
message: `npm ${call} failed with exit code ${answer.exitCode}${output}`,
|
|
7145
|
-
hint: `fix what npm reports, then ${
|
|
7251
|
+
hint: `fix what npm reports, then ${RUN_AGAIN}`,
|
|
7252
|
+
next
|
|
7146
7253
|
});
|
|
7147
7254
|
}
|
|
7148
7255
|
function noLatest(ctx, message) {
|
|
@@ -7218,10 +7325,73 @@ async function latestVersion(ctx) {
|
|
|
7218
7325
|
return version;
|
|
7219
7326
|
}
|
|
7220
7327
|
//#endregion
|
|
7221
|
-
//#region ../agent-cli/dist/built-ins/
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
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;
|
|
7225
7395
|
}
|
|
7226
7396
|
//#endregion
|
|
7227
7397
|
//#region ../agent-cli/dist/built-ins/install/dependency.js
|
|
@@ -7445,13 +7615,16 @@ async function skillCopies(cliName, version, { cwd, env }) {
|
|
|
7445
7615
|
}
|
|
7446
7616
|
return copies;
|
|
7447
7617
|
}
|
|
7448
|
-
|
|
7449
|
-
|
|
7618
|
+
const has = (copies, wanted) => copies.some(({ state }) => state === wanted);
|
|
7619
|
+
function addLineOf(cliName, from) {
|
|
7620
|
+
return "add" in from ? from.add : `npx -y skills add ${from.source} --skill ${cliName} -g`;
|
|
7621
|
+
}
|
|
7622
|
+
function fixFor(cliName, copies, from) {
|
|
7450
7623
|
const update = `npx -y skills update ${cliName}`;
|
|
7451
|
-
const add =
|
|
7624
|
+
const add = from === void 0 ? void 0 : addLineOf(cliName, from);
|
|
7452
7625
|
if (copies.length === 0) return add;
|
|
7453
|
-
if (has("unversioned") && add !== void 0) return has("behind") ? `${update} && ${add}` : add;
|
|
7454
|
-
return has("behind") || has("unversioned") ? update : void 0;
|
|
7626
|
+
if (has(copies, "unversioned") && add !== void 0) return has(copies, "behind") ? `${update} && ${add}` : add;
|
|
7627
|
+
return has(copies, "behind") || has(copies, "unversioned") ? update : void 0;
|
|
7455
7628
|
}
|
|
7456
7629
|
const SKILL_STATE_NOTES = {
|
|
7457
7630
|
current: "the same as this build",
|
|
@@ -7463,11 +7636,10 @@ const SKILL_STATE_NOTES = {
|
|
|
7463
7636
|
function describeCopy({ path, version, state }) {
|
|
7464
7637
|
return `${path}${version === void 0 ? "" : ` ${version}`} (${SKILL_STATE_NOTES[state]})`;
|
|
7465
7638
|
}
|
|
7466
|
-
/** A skill
|
|
7467
|
-
function hubSkill(cli,
|
|
7468
|
-
const
|
|
7469
|
-
const
|
|
7470
|
-
const fix = fixFor(cli.name, copies, source);
|
|
7639
|
+
/** A skill on a Skill Hub, which `from` says how to install; without it, no line adds it. */
|
|
7640
|
+
function hubSkill(cli, from) {
|
|
7641
|
+
const findingOf = (copies) => {
|
|
7642
|
+
const fix = fixFor(cli.name, copies, from);
|
|
7471
7643
|
const message = copies.length === 0 ? `no copy of the ${cli.name} skill is installed` : copies.map(describeCopy).join("; ");
|
|
7472
7644
|
return fix === void 0 ? {
|
|
7473
7645
|
state: "ok",
|
|
@@ -7484,10 +7656,14 @@ function hubSkill(cli, source) {
|
|
|
7484
7656
|
rows: [{
|
|
7485
7657
|
name: "skill",
|
|
7486
7658
|
advisory: true,
|
|
7487
|
-
run: (ctx) =>
|
|
7659
|
+
run: async (ctx) => findingOf(await skillCopies(cli.name, cli.version, ctx))
|
|
7488
7660
|
}],
|
|
7489
7661
|
notice: async () => {},
|
|
7490
|
-
|
|
7662
|
+
nextAt: async (version, ctx) => {
|
|
7663
|
+
const copies = await skillCopies(cli.name, version, ctx);
|
|
7664
|
+
const fix = fixFor(cli.name, copies, from);
|
|
7665
|
+
return fix === void 0 ? [] : [fix];
|
|
7666
|
+
}
|
|
7491
7667
|
};
|
|
7492
7668
|
}
|
|
7493
7669
|
//#endregion
|
|
@@ -7498,10 +7674,10 @@ function markersOf(name) {
|
|
|
7498
7674
|
end: `<!-- END:${name} -->`
|
|
7499
7675
|
};
|
|
7500
7676
|
}
|
|
7501
|
-
/** `text` with the CLI's
|
|
7502
|
-
function
|
|
7677
|
+
/** `text` with the CLI's Agents section between its markers, appended when they are missing; nothing else changes. */
|
|
7678
|
+
function withSection({ name, text: section }, text) {
|
|
7503
7679
|
const { begin, end } = markersOf(name);
|
|
7504
|
-
const whole = `${begin}\n${
|
|
7680
|
+
const whole = `${begin}\n${section}\n${end}`;
|
|
7505
7681
|
const start = text.indexOf(begin);
|
|
7506
7682
|
const stop = start === -1 ? -1 : text.indexOf(end, start);
|
|
7507
7683
|
if (stop !== -1) return `${text.slice(0, start)}${whole}${text.slice(stop + end.length)}`;
|
|
@@ -7516,7 +7692,7 @@ async function agentsMdAt(agents, root) {
|
|
|
7516
7692
|
agents,
|
|
7517
7693
|
change: "create"
|
|
7518
7694
|
};
|
|
7519
|
-
if (
|
|
7695
|
+
if (withSection(agents, existing) === existing) return {
|
|
7520
7696
|
path,
|
|
7521
7697
|
agents,
|
|
7522
7698
|
change: null
|
|
@@ -7544,15 +7720,15 @@ function agentsRow(agents, install) {
|
|
|
7544
7720
|
const fix = `${install.runAs} skill install`;
|
|
7545
7721
|
if (change === "rewrite") return {
|
|
7546
7722
|
state: "problem",
|
|
7547
|
-
message: `${path} holds a ${name}
|
|
7723
|
+
message: `${path} holds a ${name} Agents section other than the one ${fix} writes`,
|
|
7548
7724
|
fix
|
|
7549
7725
|
};
|
|
7550
7726
|
if (change !== null) return {
|
|
7551
7727
|
state: "problem",
|
|
7552
|
-
message: `${path} holds no ${name}
|
|
7728
|
+
message: `${path} holds no ${name} Agents section, so sessions in this repo do not know ${name}`,
|
|
7553
7729
|
fix
|
|
7554
7730
|
};
|
|
7555
|
-
const holds = `${path} holds the ${name}
|
|
7731
|
+
const holds = `${path} holds the ${name} Agents section`;
|
|
7556
7732
|
const [edit] = await handEditsAt(root);
|
|
7557
7733
|
return edit === void 0 ? {
|
|
7558
7734
|
state: "ok",
|
|
@@ -7565,7 +7741,7 @@ function agentsRow(agents, install) {
|
|
|
7565
7741
|
};
|
|
7566
7742
|
}
|
|
7567
7743
|
//#endregion
|
|
7568
|
-
//#region ../agent-cli/dist/agent.js
|
|
7744
|
+
//#region ../agent-cli/dist/context/agent.js
|
|
7569
7745
|
const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
|
|
7570
7746
|
const isSet = (name) => (env) => (env[name] ?? "") !== "";
|
|
7571
7747
|
const equals = (name, value) => (env) => env[name] === value;
|
|
@@ -7599,16 +7775,22 @@ function isAgent(env) {
|
|
|
7599
7775
|
return MARKERS.some((marker) => marker(env));
|
|
7600
7776
|
}
|
|
7601
7777
|
//#endregion
|
|
7602
|
-
//#region ../agent-cli/dist/errno.js
|
|
7778
|
+
//#region ../agent-cli/dist/context/errno.js
|
|
7603
7779
|
const PERMISSION_DENIED = "PERMISSION_DENIED";
|
|
7604
7780
|
const DISK_FULL = "DISK_FULL";
|
|
7605
7781
|
const NOT_FOUND = "NOT_FOUND";
|
|
7606
7782
|
const ALREADY_EXISTS = "ALREADY_EXISTS";
|
|
7607
7783
|
const NOT_A_FILE = "NOT_A_FILE";
|
|
7608
|
-
function
|
|
7609
|
-
if (platform === "win32") return
|
|
7610
|
-
|
|
7611
|
-
|
|
7784
|
+
function permissionAdvice({ path, access, rerun, env, platform }) {
|
|
7785
|
+
if (platform === "win32") return {
|
|
7786
|
+
hint: `a program may hold ${path} open: close it, then run the Next step`,
|
|
7787
|
+
next: [rerun]
|
|
7788
|
+
};
|
|
7789
|
+
if (!isAgent(env)) return { hint: `check the permissions of ${path} and its folder` };
|
|
7790
|
+
return {
|
|
7791
|
+
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`}`,
|
|
7792
|
+
next: [rerun]
|
|
7793
|
+
};
|
|
7612
7794
|
}
|
|
7613
7795
|
function fileErrorOf(scope) {
|
|
7614
7796
|
return (error, at) => classifyErrno(error, {
|
|
@@ -7625,13 +7807,14 @@ function classifyErrno(error, context) {
|
|
|
7625
7807
|
case "EBUSY": return new CliError({
|
|
7626
7808
|
code: PERMISSION_DENIED,
|
|
7627
7809
|
message: `permission denied: ${path}`,
|
|
7628
|
-
|
|
7810
|
+
...permissionAdvice(context)
|
|
7629
7811
|
}, { cause: error });
|
|
7630
7812
|
case "ENOSPC":
|
|
7631
7813
|
case "EDQUOT": return new CliError({
|
|
7632
7814
|
code: DISK_FULL,
|
|
7633
7815
|
message: `no space left on the disk holding ${path}`,
|
|
7634
|
-
hint:
|
|
7816
|
+
hint: "free space on that disk, then run the Next step",
|
|
7817
|
+
next: [context.rerun]
|
|
7635
7818
|
}, { cause: error });
|
|
7636
7819
|
case "ENOENT":
|
|
7637
7820
|
case "ENOTDIR":
|
|
@@ -7654,7 +7837,7 @@ function classifyErrno(error, context) {
|
|
|
7654
7837
|
}
|
|
7655
7838
|
}
|
|
7656
7839
|
//#endregion
|
|
7657
|
-
//#region ../agent-cli/dist/files.js
|
|
7840
|
+
//#region ../agent-cli/dist/context/files.js
|
|
7658
7841
|
const TEMP_FILE = /^\..+\.agent-cli-(\d+)\.tmp$/;
|
|
7659
7842
|
/** Where the Runtime writes `path` before moving it into place; a dead writer's is swept. */
|
|
7660
7843
|
function tempPathOf(path) {
|
|
@@ -7827,10 +8010,10 @@ function classifiedFiles(files, { cwd, fileError }) {
|
|
|
7827
8010
|
};
|
|
7828
8011
|
}
|
|
7829
8012
|
//#endregion
|
|
7830
|
-
//#region ../agent-cli/dist/outputs.js
|
|
8013
|
+
//#region ../agent-cli/dist/context/outputs.js
|
|
7831
8014
|
const OUTPUT_EXISTS = "OUTPUT_EXISTS";
|
|
7832
8015
|
/** Refuses a run that would overwrite existing outputs unless the caller passed `--force`. */
|
|
7833
|
-
async function checkOutputs({
|
|
8016
|
+
async function checkOutputs({ rerun, commandLine, force, files }, outputs) {
|
|
7834
8017
|
if (outputs === void 0 || force) return;
|
|
7835
8018
|
const found = await Promise.all(outputs.map((path) => files.exists(path)));
|
|
7836
8019
|
const existing = outputs.filter((_path, index) => found[index]);
|
|
@@ -7839,13 +8022,14 @@ async function checkOutputs({ invocation, commandLine, force, files }, outputs)
|
|
|
7839
8022
|
throw new CliError({
|
|
7840
8023
|
code: OUTPUT_EXISTS,
|
|
7841
8024
|
message: `\`${commandLine}\` would overwrite ${existing.join(", ")}`,
|
|
7842
|
-
hint: `to replace ${them}, run
|
|
8025
|
+
hint: `to replace ${them}, run the Next step`,
|
|
8026
|
+
next: [rerun({ add: [FORCE_FLAG.flag] })]
|
|
7843
8027
|
});
|
|
7844
8028
|
}
|
|
7845
8029
|
/** Guards the writes to declared outputs of `files`, whose paths resolve against `cwd`. */
|
|
7846
8030
|
function outputsGuard(files, cwd) {
|
|
7847
8031
|
const unwritten = /* @__PURE__ */ new Set();
|
|
7848
|
-
let
|
|
8032
|
+
let forceStep = [];
|
|
7849
8033
|
const exclusiveWrite = async (path, data, options) => {
|
|
7850
8034
|
const target = resolve(cwd, path);
|
|
7851
8035
|
unwritten.delete(target);
|
|
@@ -7860,7 +8044,8 @@ function outputsGuard(files, cwd) {
|
|
|
7860
8044
|
throw new CliError({
|
|
7861
8045
|
code: ALREADY_EXISTS,
|
|
7862
8046
|
message: error.message,
|
|
7863
|
-
hint:
|
|
8047
|
+
hint: "to replace it, run the Next step",
|
|
8048
|
+
next: [forceStep]
|
|
7864
8049
|
}, { cause: error });
|
|
7865
8050
|
}
|
|
7866
8051
|
};
|
|
@@ -7869,8 +8054,8 @@ function outputsGuard(files, cwd) {
|
|
|
7869
8054
|
...files,
|
|
7870
8055
|
write: (path, data, options) => unwritten.has(resolve(cwd, path)) ? exclusiveWrite(path, data, options) : files.write(path, data, options)
|
|
7871
8056
|
},
|
|
7872
|
-
guard: (outputs,
|
|
7873
|
-
|
|
8057
|
+
guard: (outputs, step) => {
|
|
8058
|
+
forceStep = step;
|
|
7874
8059
|
for (const path of outputs) unwritten.add(resolve(cwd, path));
|
|
7875
8060
|
}
|
|
7876
8061
|
};
|
|
@@ -7953,10 +8138,10 @@ async function planOf(cli, folder, agents, cwd, packageRoot) {
|
|
|
7953
8138
|
handEdits: agents === void 0 ? [] : await handEditsAt(root)
|
|
7954
8139
|
};
|
|
7955
8140
|
}
|
|
7956
|
-
const
|
|
8141
|
+
const SECTION_VERBS = {
|
|
7957
8142
|
create: "create",
|
|
7958
|
-
add: "add the
|
|
7959
|
-
rewrite: "rewrite the
|
|
8143
|
+
add: "add the Agents section to",
|
|
8144
|
+
rewrite: "rewrite the Agents section in"
|
|
7960
8145
|
};
|
|
7961
8146
|
function renderPlan(cli, plan) {
|
|
7962
8147
|
const files = [
|
|
@@ -7968,7 +8153,7 @@ function renderPlan(cli, plan) {
|
|
|
7968
8153
|
return [
|
|
7969
8154
|
files.length === 0 ? `the ${cli.name} skill at ${plan.copy} already matches the package` : `would copy the ${cli.name} skill to ${plan.copy}:`,
|
|
7970
8155
|
...files,
|
|
7971
|
-
...agentsMd === null ? [] : [agentsMd.change === null ? `${agentsMd.path} already holds the ${cli.name}
|
|
8156
|
+
...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}`],
|
|
7972
8157
|
...plan.handEdits.map((edit) => `by hand: ${edit}`)
|
|
7973
8158
|
].join("\n");
|
|
7974
8159
|
}
|
|
@@ -7976,7 +8161,7 @@ function renderInstalled(cli, data) {
|
|
|
7976
8161
|
const { written, removed, agentsMd } = data;
|
|
7977
8162
|
return [
|
|
7978
8163
|
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}`,
|
|
7979
|
-
...agentsMd === null ? [] : [agentsMd.changed ? `wrote the ${cli.name}
|
|
8164
|
+
...agentsMd === null ? [] : [agentsMd.changed ? `wrote the ${cli.name} Agents section in ${agentsMd.path}` : `${agentsMd.path} already holds the ${cli.name} Agents section`],
|
|
7980
8165
|
...data.handEdits.map((edit) => `by hand: ${edit}`)
|
|
7981
8166
|
].join("\n");
|
|
7982
8167
|
}
|
|
@@ -7984,21 +8169,20 @@ function editedRemovals(plan, ctx) {
|
|
|
7984
8169
|
const them = plan.remove.length === 1 ? "it" : "them";
|
|
7985
8170
|
return new CliError({
|
|
7986
8171
|
code: OUTPUT_EXISTS,
|
|
7987
|
-
message:
|
|
7988
|
-
hint: `to remove ${them}, run
|
|
8172
|
+
message: `skill install would remove ${plan.remove.map((file) => join(plan.copy, file)).join(", ")}`,
|
|
8173
|
+
hint: `to remove ${them}, run the Next step`,
|
|
8174
|
+
next: [ctx.rerun({ add: [FORCE_FLAG.flag] })]
|
|
7989
8175
|
});
|
|
7990
8176
|
}
|
|
7991
8177
|
/** The built-in `skill install`, for a CLI whose skill ships in its package. */
|
|
7992
|
-
function skillInstallCommand(cli, folder,
|
|
7993
|
-
const { runAs } = install;
|
|
8178
|
+
function skillInstallCommand(cli, folder, agents) {
|
|
7994
8179
|
return defineCommand$1({
|
|
7995
|
-
|
|
7996
|
-
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",
|
|
8180
|
+
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",
|
|
7997
8181
|
examples: [{
|
|
7998
|
-
command: `${
|
|
8182
|
+
command: `${cli.name} skill install`,
|
|
7999
8183
|
note: "install the skill this version ships"
|
|
8000
8184
|
}, {
|
|
8001
|
-
command: `${
|
|
8185
|
+
command: `${cli.name} skill install --dry-run`,
|
|
8002
8186
|
note: "show what it would change"
|
|
8003
8187
|
}],
|
|
8004
8188
|
effect: "write",
|
|
@@ -8013,7 +8197,7 @@ function skillInstallCommand(cli, folder, install, agents) {
|
|
|
8013
8197
|
const { agentsMd } = plan;
|
|
8014
8198
|
if (agentsMd !== null && agentsMd.change !== null) {
|
|
8015
8199
|
const existing = await orMissing(readFile(agentsMd.path, "utf8")) ?? "";
|
|
8016
|
-
await ctx.files.write(agentsMd.path,
|
|
8200
|
+
await ctx.files.write(agentsMd.path, withSection(agentsMd.agents, existing));
|
|
8017
8201
|
}
|
|
8018
8202
|
return {
|
|
8019
8203
|
copy: plan.copy,
|
|
@@ -8104,45 +8288,53 @@ function packagedSkill(cli, { packaged: folder, agents: text }, install) {
|
|
|
8104
8288
|
};
|
|
8105
8289
|
return {
|
|
8106
8290
|
kind: "packaged",
|
|
8107
|
-
builtIns: { skill: { install: skillInstallCommand(cli, folder,
|
|
8291
|
+
builtIns: { skill: { install: skillInstallCommand(cli, folder, agents) } },
|
|
8108
8292
|
rows: [{
|
|
8109
8293
|
name: "skill",
|
|
8110
8294
|
advisory: true,
|
|
8111
8295
|
run: (ctx) => findingOf(cli, folder, install, ctx)
|
|
8112
8296
|
}, ...agents === void 0 ? [] : [agentsRow(agents, install)]],
|
|
8113
8297
|
notice: (launch, ctx) => notice(cli, folder, install, launch, ctx),
|
|
8114
|
-
|
|
8298
|
+
nextAt: async (_version, ctx) => {
|
|
8299
|
+
const { fix } = await findingOf(cli, folder, install, ctx);
|
|
8300
|
+
return fix === void 0 ? [] : [fix];
|
|
8301
|
+
}
|
|
8115
8302
|
};
|
|
8116
8303
|
}
|
|
8117
8304
|
//#endregion
|
|
8118
8305
|
//#region ../agent-cli/dist/built-ins/skill/skill.js
|
|
8119
8306
|
/** A Packaged skill, or else a Skill Hub's, also for a CLI that declares no `skill`. */
|
|
8120
|
-
function skillOf(cli, install) {
|
|
8307
|
+
function skillOf$1(cli, install) {
|
|
8121
8308
|
const { skill } = cli;
|
|
8122
|
-
return skill !== void 0 && "packaged" in skill ? packagedSkill(cli, skill, install) : hubSkill(cli, skill
|
|
8309
|
+
return skill !== void 0 && "packaged" in skill ? packagedSkill(cli, skill, install) : hubSkill(cli, skill);
|
|
8123
8310
|
}
|
|
8124
8311
|
//#endregion
|
|
8125
|
-
//#region ../agent-cli/dist/interrupts.js
|
|
8312
|
+
//#region ../agent-cli/dist/context/interrupts.js
|
|
8126
8313
|
const INTERRUPTED = "INTERRUPTED";
|
|
8127
8314
|
const DEADLINE_EXCEEDED = "DEADLINE_EXCEEDED";
|
|
8128
8315
|
/** How long an interrupted Command may take to settle before the run ends without it. */
|
|
8129
8316
|
const GRACE_MS = 3e3;
|
|
8130
8317
|
const GRACE_OVER = Symbol("grace over");
|
|
8131
|
-
function interruptedError(
|
|
8318
|
+
function interruptedError(rerun) {
|
|
8132
8319
|
return new CliError({
|
|
8133
8320
|
code: INTERRUPTED,
|
|
8134
8321
|
message: "interrupted before it finished",
|
|
8135
|
-
hint:
|
|
8322
|
+
hint: "to finish it, run the Next step, unless it was stopped on purpose; if a tool timeout stopped it, give it longer",
|
|
8323
|
+
next: [rerun]
|
|
8136
8324
|
});
|
|
8137
8325
|
}
|
|
8138
|
-
|
|
8139
|
-
|
|
8326
|
+
const BOUND_WORDS = {
|
|
8327
|
+
deadline: "deadline",
|
|
8328
|
+
ignoreStop: "timeout"
|
|
8329
|
+
};
|
|
8330
|
+
function waitHint(bound) {
|
|
8331
|
+
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";
|
|
8140
8332
|
}
|
|
8141
|
-
function deadlineError(commandLine, ms,
|
|
8333
|
+
function deadlineError(commandLine, ms, advice, bound = "deadline") {
|
|
8142
8334
|
return new CliError({
|
|
8143
8335
|
code: DEADLINE_EXCEEDED,
|
|
8144
|
-
message: `${commandLine} ran past its ${ms} ms ${bound}`,
|
|
8145
|
-
|
|
8336
|
+
message: `${commandLine} ran past its ${ms} ms ${BOUND_WORDS[bound]}`,
|
|
8337
|
+
...advice
|
|
8146
8338
|
});
|
|
8147
8339
|
}
|
|
8148
8340
|
/** One Command run's cancellation: its signal, its deadlines and the steps it must finish. */
|
|
@@ -8150,24 +8342,24 @@ var RunControl = class {
|
|
|
8150
8342
|
signal;
|
|
8151
8343
|
#controller = new AbortController();
|
|
8152
8344
|
#commandLine;
|
|
8153
|
-
#
|
|
8345
|
+
#rerun;
|
|
8154
8346
|
#outer;
|
|
8155
|
-
#onOuterAbort = () => this.#controller.abort(interruptedError(this.#
|
|
8347
|
+
#onOuterAbort = () => this.#controller.abort(interruptedError(this.#rerun));
|
|
8156
8348
|
/** Each running must-finish step, tracked until it settles, with its name. */
|
|
8157
8349
|
#steps = /* @__PURE__ */ new Map();
|
|
8158
8350
|
#progress;
|
|
8159
8351
|
#clock;
|
|
8160
8352
|
#disposed = new AbortController();
|
|
8161
|
-
/** The reasons this run's deadlines
|
|
8353
|
+
/** The reasons this run's deadlines aborted with, to tell them in a Command's error. */
|
|
8162
8354
|
#abortReasons = /* @__PURE__ */ new WeakSet();
|
|
8163
8355
|
#graceCancel = new AbortController();
|
|
8164
8356
|
#endGrace = () => {};
|
|
8165
8357
|
#graceOver = new Promise((resolve) => {
|
|
8166
8358
|
this.#endGrace = resolve;
|
|
8167
8359
|
});
|
|
8168
|
-
constructor({ commandLine,
|
|
8360
|
+
constructor({ commandLine, rerun, outer, clock, progress, runDeadline }) {
|
|
8169
8361
|
this.#commandLine = commandLine;
|
|
8170
|
-
this.#
|
|
8362
|
+
this.#rerun = rerun;
|
|
8171
8363
|
this.#outer = outer;
|
|
8172
8364
|
this.#clock = clock;
|
|
8173
8365
|
this.#progress = progress;
|
|
@@ -8176,20 +8368,21 @@ var RunControl = class {
|
|
|
8176
8368
|
if (outer?.aborted === true) this.#onOuterAbort();
|
|
8177
8369
|
else outer?.addEventListener("abort", this.#onOuterAbort, { once: true });
|
|
8178
8370
|
if (runDeadline !== void 0) {
|
|
8179
|
-
const { ms,
|
|
8180
|
-
after(clock, ms, this.#disposed.signal, () => this.#controller.abort(deadlineError(commandLine, ms,
|
|
8371
|
+
const { ms, advice } = runDeadline;
|
|
8372
|
+
after(clock, ms, this.#disposed.signal, () => this.#controller.abort(deadlineError(commandLine, ms, advice())));
|
|
8181
8373
|
}
|
|
8182
8374
|
}
|
|
8183
|
-
deadline(ms) {
|
|
8184
|
-
return AbortSignal.any([this.signal, this.#abortsAfter(ms, "deadline")]);
|
|
8185
|
-
}
|
|
8186
|
-
timeout(ms) {
|
|
8187
|
-
return this.#abortsAfter(ms, "timeout");
|
|
8375
|
+
deadline(ms, options = {}) {
|
|
8376
|
+
return options.ignoreStop === true ? this.#abortsAfter(ms, "ignoreStop") : AbortSignal.any([this.signal, this.#abortsAfter(ms, "deadline")]);
|
|
8188
8377
|
}
|
|
8189
8378
|
#abortsAfter(ms, bound) {
|
|
8190
8379
|
const controller = new AbortController();
|
|
8191
8380
|
after(this.#clock, ms, this.#disposed.signal, () => {
|
|
8192
|
-
const
|
|
8381
|
+
const advice = {
|
|
8382
|
+
hint: waitHint(bound),
|
|
8383
|
+
next: [this.#rerun]
|
|
8384
|
+
};
|
|
8385
|
+
const reason = deadlineError(this.#commandLine, ms, advice, bound);
|
|
8193
8386
|
this.#abortReasons.add(reason);
|
|
8194
8387
|
controller.abort(reason);
|
|
8195
8388
|
});
|
|
@@ -8222,8 +8415,8 @@ var RunControl = class {
|
|
|
8222
8415
|
/**
|
|
8223
8416
|
* The error a run ends with: an interrupt or the run deadline outranks what the Command threw,
|
|
8224
8417
|
* unless the Command threw its own `INTERRUPTED`, saying what it finished before it stopped.
|
|
8225
|
-
* Otherwise each leaf that is not a `CliError` and whose cause chain holds a deadline's
|
|
8226
|
-
*
|
|
8418
|
+
* Otherwise each leaf that is not a `CliError` and whose cause chain holds a deadline's abort is
|
|
8419
|
+
* reported as that abort, so a declared error keeps its own code.
|
|
8227
8420
|
*/
|
|
8228
8421
|
errorAfter(error) {
|
|
8229
8422
|
if (this.signal.aborted) return error instanceof CliError && error.code === "INTERRUPTED" ? error : this.signal.reason;
|
|
@@ -8266,10 +8459,11 @@ function globalModulesDir(prefix) {
|
|
|
8266
8459
|
return process.platform === "win32" ? join(prefix, "node_modules") : join(prefix, "lib", "node_modules");
|
|
8267
8460
|
}
|
|
8268
8461
|
function notGlobal(ctx, message) {
|
|
8269
|
-
return
|
|
8462
|
+
return runtimeError({
|
|
8270
8463
|
code: NOT_GLOBAL_INSTALL,
|
|
8271
8464
|
message,
|
|
8272
|
-
hint:
|
|
8465
|
+
hint: "install it with npm by running the Next step, so its update Command can replace it",
|
|
8466
|
+
next: [wholeLine(installCommandLine(ctx.registry))]
|
|
8273
8467
|
});
|
|
8274
8468
|
}
|
|
8275
8469
|
/**
|
|
@@ -8404,10 +8598,6 @@ function renderUpdate(cli, install, update) {
|
|
|
8404
8598
|
...next
|
|
8405
8599
|
]).join("\n");
|
|
8406
8600
|
}
|
|
8407
|
-
async function skillNext(skill, latest, ctx) {
|
|
8408
|
-
const { fix } = await skill.findingAt(latest, ctx);
|
|
8409
|
-
return fix === void 0 ? [] : [fix];
|
|
8410
|
-
}
|
|
8411
8601
|
function interruptedAfterInstall(plan) {
|
|
8412
8602
|
return new CliError({
|
|
8413
8603
|
code: INTERRUPTED,
|
|
@@ -8418,7 +8608,6 @@ function interruptedAfterInstall(plan) {
|
|
|
8418
8608
|
/** The built-in `update`, for a CLI installed globally with npm. */
|
|
8419
8609
|
function updateCommand(cli, install, skill, { bin, node }) {
|
|
8420
8610
|
return defineCommand$1({
|
|
8421
|
-
name: "update",
|
|
8422
8611
|
description: "install the latest version of this CLI from its registry",
|
|
8423
8612
|
examples: [{
|
|
8424
8613
|
command: `${cli.name} update`,
|
|
@@ -8447,7 +8636,7 @@ function updateCommand(cli, install, skill, { bin, node }) {
|
|
|
8447
8636
|
latest,
|
|
8448
8637
|
installed: null,
|
|
8449
8638
|
upgrades: [],
|
|
8450
|
-
next: await
|
|
8639
|
+
next: await skill.nextAt(latest, ctx)
|
|
8451
8640
|
};
|
|
8452
8641
|
ctx.signal.throwIfAborted();
|
|
8453
8642
|
ctx.progress(`installing ${plan.package}@${latest} with the npm under ${prefix}…`);
|
|
@@ -8460,7 +8649,7 @@ function updateCommand(cli, install, skill, { bin, node }) {
|
|
|
8460
8649
|
prefix
|
|
8461
8650
|
},
|
|
8462
8651
|
upgrades: await upgradesOf(plan.packageDir, from, latest),
|
|
8463
|
-
next: await
|
|
8652
|
+
next: await skill.nextAt(latest, ctx)
|
|
8464
8653
|
};
|
|
8465
8654
|
if (ctx.signal.aborted) {
|
|
8466
8655
|
ctx.deliver(update);
|
|
@@ -8505,7 +8694,7 @@ function checkOf(cli, install, { bin, node }) {
|
|
|
8505
8694
|
function globalInstall(cli, install) {
|
|
8506
8695
|
const adapter = {
|
|
8507
8696
|
runAs: runAsOf(cli),
|
|
8508
|
-
builtIns: (launch) => ({ update: updateCommand(cli, install, skillOf(cli, adapter), launch) }),
|
|
8697
|
+
builtIns: (launch) => ({ update: updateCommand(cli, install, skillOf$1(cli, adapter), launch) }),
|
|
8509
8698
|
exitClasses: ["source"],
|
|
8510
8699
|
check: (launch) => checkOf(cli, install, launch)
|
|
8511
8700
|
};
|
|
@@ -8591,7 +8780,7 @@ function readProject(projectFile, ctx) {
|
|
|
8591
8780
|
ok: true,
|
|
8592
8781
|
project: projectOf(projectFile, ctx.cwd, {
|
|
8593
8782
|
fileError: ctx.fileError,
|
|
8594
|
-
|
|
8783
|
+
rerun: ctx.rerun()
|
|
8595
8784
|
})
|
|
8596
8785
|
};
|
|
8597
8786
|
} catch (error) {
|
|
@@ -8654,14 +8843,12 @@ function doctorChecks(cli, launch, read) {
|
|
|
8654
8843
|
...cli.project === void 0 ? [] : [projectRow(cli.project, read)],
|
|
8655
8844
|
...cli.doctor ?? [],
|
|
8656
8845
|
...toolRows(cli.tools ?? [], cli.commands),
|
|
8846
|
+
...secretRows(cli.secrets ?? [], cli.commands),
|
|
8657
8847
|
installRow(check),
|
|
8658
8848
|
registryRow(cli, check),
|
|
8659
|
-
...skillOf(cli, install).rows
|
|
8849
|
+
...skillOf$1(cli, install).rows
|
|
8660
8850
|
];
|
|
8661
8851
|
}
|
|
8662
|
-
//#endregion
|
|
8663
|
-
//#region ../agent-cli/dist/built-ins/doctor.js
|
|
8664
|
-
const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
|
|
8665
8852
|
const DEFAULT_DEADLINE_MS = 1e4;
|
|
8666
8853
|
const MS_PER_SECOND = 1e3;
|
|
8667
8854
|
const MIN_LABEL_WIDTH = 8;
|
|
@@ -8732,24 +8919,33 @@ function render({ rows, next }, style) {
|
|
|
8732
8919
|
return `${check.padEnd(width)}${label}${" ".repeat(stateWidth - state.length)}${message}`;
|
|
8733
8920
|
}), ...next.map((fix) => `${"next".padEnd(width)}${fix}`)].join("\n");
|
|
8734
8921
|
}
|
|
8735
|
-
function failure(cliName,
|
|
8736
|
-
const errors = problems.map(({ check, message, fix, code }) =>
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
8922
|
+
function failure(cliName, rerun, problems) {
|
|
8923
|
+
const errors = problems.map(({ check, message, fix, code }) => {
|
|
8924
|
+
const head = {
|
|
8925
|
+
code: code ?? "DOCTOR_PROBLEMS",
|
|
8926
|
+
message: `${cliName} doctor found a problem in ${check}: ${message}`
|
|
8927
|
+
};
|
|
8928
|
+
return runtimeError(fix === void 0 ? {
|
|
8929
|
+
...head,
|
|
8930
|
+
hint: "the row says what is wrong",
|
|
8931
|
+
next: []
|
|
8932
|
+
} : {
|
|
8933
|
+
...head,
|
|
8934
|
+
hint: "run the Next steps in order",
|
|
8935
|
+
next: [wholeLine(fix), rerun]
|
|
8936
|
+
});
|
|
8937
|
+
});
|
|
8741
8938
|
return new AggregateError(errors);
|
|
8742
8939
|
}
|
|
8743
8940
|
/** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
|
|
8744
8941
|
function doctorCommand(cli, launch) {
|
|
8745
8942
|
return defineCommand$1({
|
|
8746
|
-
name: "doctor",
|
|
8747
8943
|
description: "check the setup and say what fixes each problem",
|
|
8748
8944
|
examples: [{
|
|
8749
|
-
command: `${
|
|
8945
|
+
command: `${cli.name} doctor`,
|
|
8750
8946
|
note: "check the setup and list the commands that fix it"
|
|
8751
8947
|
}, {
|
|
8752
|
-
command: `${
|
|
8948
|
+
command: `${cli.name} doctor --json`,
|
|
8753
8949
|
note: "get the rows and fixes as data"
|
|
8754
8950
|
}],
|
|
8755
8951
|
effect: "read",
|
|
@@ -8769,7 +8965,7 @@ function doctorCommand(cli, launch) {
|
|
|
8769
8965
|
const problems = checked.filter(({ row, advisory }) => row.state === "problem" && !advisory).map(({ row }) => row);
|
|
8770
8966
|
if (problems.length > 0) {
|
|
8771
8967
|
ctx.deliver(report);
|
|
8772
|
-
throw failure(cli.name, ctx.
|
|
8968
|
+
throw failure(cli.name, ctx.rerun(), problems);
|
|
8773
8969
|
}
|
|
8774
8970
|
return report;
|
|
8775
8971
|
},
|
|
@@ -8787,53 +8983,104 @@ function builtInCommands(cli, launch) {
|
|
|
8787
8983
|
return {
|
|
8788
8984
|
doctor: doctorCommand(cli, launch),
|
|
8789
8985
|
...install.builtIns(launch),
|
|
8790
|
-
...skillOf(cli, install).builtIns
|
|
8986
|
+
...skillOf$1(cli, install).builtIns
|
|
8791
8987
|
};
|
|
8792
8988
|
}
|
|
8793
8989
|
//#endregion
|
|
8794
|
-
//#region ../agent-cli/dist/
|
|
8795
|
-
|
|
8796
|
-
|
|
8797
|
-
|
|
8798
|
-
if (given === expected) return;
|
|
8799
|
-
const hint = `to confirm, run \`${commandLineOf(invocation, {
|
|
8800
|
-
remove: [CONFIRM_FLAG.flag],
|
|
8801
|
-
add: [CONFIRM_FLAG.flag, expected]
|
|
8802
|
-
})}\``;
|
|
8803
|
-
if (given === void 0) throw new UsageError({
|
|
8804
|
-
code: CONFIRMATION_REQUIRED,
|
|
8805
|
-
message: `\`${commandLine}\` is destructive and needs ${CONFIRM_FLAG.flag}`,
|
|
8806
|
-
hint
|
|
8807
|
-
});
|
|
8808
|
-
throw new UsageError({
|
|
8809
|
-
code: CONFIRMATION_MISMATCH,
|
|
8810
|
-
message: `${CONFIRM_FLAG.flag} ${JSON.stringify(given)} does not match the target of \`${commandLine}\``,
|
|
8811
|
-
hint
|
|
8812
|
-
});
|
|
8990
|
+
//#region ../agent-cli/dist/command-spec.js
|
|
8991
|
+
/** The group's Commands and groups that help and suggestions may name: hidden Commands left out. */
|
|
8992
|
+
function visibleCommands({ commands }) {
|
|
8993
|
+
return Object.fromEntries(Object.entries(commands).filter(([, node]) => node.kind === "group" || !node.hidden));
|
|
8813
8994
|
}
|
|
8814
|
-
|
|
8815
|
-
|
|
8816
|
-
|
|
8817
|
-
|
|
8818
|
-
function
|
|
8819
|
-
if (
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8995
|
+
/** The words that label a Command in errors and spill files: its path, or the CLI's name for a single-Command CLI. */
|
|
8996
|
+
function commandLabel(path, cliName) {
|
|
8997
|
+
return path.length === 0 ? [cliName] : path;
|
|
8998
|
+
}
|
|
8999
|
+
function declaredOf(command) {
|
|
9000
|
+
if (!hasPlan(command)) return {
|
|
9001
|
+
outputs: false,
|
|
9002
|
+
force: void 0,
|
|
9003
|
+
cost: false
|
|
9004
|
+
};
|
|
9005
|
+
return {
|
|
9006
|
+
outputs: command.outputs !== void 0,
|
|
9007
|
+
force: command.force,
|
|
9008
|
+
cost: command.cost !== void 0
|
|
9009
|
+
};
|
|
9010
|
+
}
|
|
9011
|
+
function withRunAs(example, { name, runAs }) {
|
|
9012
|
+
const { command } = example;
|
|
9013
|
+
return command === name || command.startsWith(`${name} `) ? {
|
|
9014
|
+
...example,
|
|
9015
|
+
command: `${runAs}${command.slice(name.length)}`
|
|
9016
|
+
} : example;
|
|
9017
|
+
}
|
|
9018
|
+
function commandSpec(commandLine, command, { path, builtIn, names }) {
|
|
9019
|
+
const list = command.rows === void 0 ? void 0 : listSpec(command.rows);
|
|
9020
|
+
return {
|
|
9021
|
+
kind: "command",
|
|
9022
|
+
commandLine,
|
|
9023
|
+
path,
|
|
9024
|
+
command,
|
|
9025
|
+
builtIn,
|
|
9026
|
+
description: command.description,
|
|
9027
|
+
help: command.help,
|
|
9028
|
+
hidden: command.hidden === true,
|
|
9029
|
+
operator: command.operator === true,
|
|
9030
|
+
effect: command.effect,
|
|
9031
|
+
examples: command.examples.map((example) => withRunAs(example, names)),
|
|
9032
|
+
args: argFields(command.args),
|
|
9033
|
+
options: optionFields(command.options),
|
|
9034
|
+
standardFlags: standardFlagsFor(command.effect, declaredOf(command), list),
|
|
9035
|
+
list,
|
|
9036
|
+
output: list?.output ?? command.output
|
|
9037
|
+
};
|
|
9038
|
+
}
|
|
9039
|
+
function group(commandLine, commands) {
|
|
9040
|
+
return {
|
|
9041
|
+
kind: "group",
|
|
9042
|
+
commandLine,
|
|
9043
|
+
commands
|
|
9044
|
+
};
|
|
9045
|
+
}
|
|
9046
|
+
/** The root group of a multi-Command CLI: the author's Commands, then the Built-in Commands. */
|
|
9047
|
+
function groupSpec(names, commands, builtIns) {
|
|
9048
|
+
const { runAs } = names;
|
|
9049
|
+
return group(runAs, {
|
|
9050
|
+
...specsOf(runAs, commands, {
|
|
9051
|
+
path: [],
|
|
9052
|
+
builtIn: false,
|
|
9053
|
+
names
|
|
9054
|
+
}),
|
|
9055
|
+
...specsOf(runAs, builtIns, {
|
|
9056
|
+
path: [],
|
|
9057
|
+
builtIn: true,
|
|
9058
|
+
names
|
|
9059
|
+
})
|
|
8824
9060
|
});
|
|
8825
9061
|
}
|
|
9062
|
+
function specsOf(commandLine, commands, { path, builtIn, names }) {
|
|
9063
|
+
return Object.fromEntries(Object.entries(commands).map(([key, node]) => [key, specOf(`${commandLine} ${key}`, node, {
|
|
9064
|
+
path: [...path, key],
|
|
9065
|
+
builtIn,
|
|
9066
|
+
names
|
|
9067
|
+
})]));
|
|
9068
|
+
}
|
|
9069
|
+
function specOf(commandLine, node, place) {
|
|
9070
|
+
return isCommand(node) ? commandSpec(commandLine, node, place) : group(commandLine, specsOf(commandLine, node, place));
|
|
9071
|
+
}
|
|
8826
9072
|
//#endregion
|
|
8827
|
-
//#region ../agent-cli/dist/
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
|
|
8835
|
-
|
|
8836
|
-
|
|
9073
|
+
//#region ../agent-cli/dist/error-table.js
|
|
9074
|
+
/** The Error table a CLI declares, empty when it declares none. */
|
|
9075
|
+
function errorTableOf({ errors }) {
|
|
9076
|
+
return errors ?? {};
|
|
9077
|
+
}
|
|
9078
|
+
/** The `CliError` for a code of `Table`, as `cliError` and `ctx.fail` build it. */
|
|
9079
|
+
function cliErrorOf(code, init, options) {
|
|
9080
|
+
return new CliError({
|
|
9081
|
+
...init,
|
|
9082
|
+
code
|
|
9083
|
+
}, options);
|
|
8837
9084
|
}
|
|
8838
9085
|
//#endregion
|
|
8839
9086
|
//#region ../agent-cli/dist/exit-classes.js
|
|
@@ -8849,43 +9096,48 @@ const EXIT_CODES = {
|
|
|
8849
9096
|
bug: 70
|
|
8850
9097
|
};
|
|
8851
9098
|
const RUNTIME_EXIT_CLASSES = {
|
|
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
|
-
|
|
8879
|
-
|
|
9099
|
+
INVALID_INPUT: "caller",
|
|
9100
|
+
UNKNOWN_OPTION: "caller",
|
|
9101
|
+
UNKNOWN_COMMAND: "caller",
|
|
9102
|
+
UNKNOWN_FIELD: "caller",
|
|
9103
|
+
CONFIRMATION_REQUIRED: "caller",
|
|
9104
|
+
CONFIRMATION_MISMATCH: "caller",
|
|
9105
|
+
NOT_CONFIRMED: "operator",
|
|
9106
|
+
NEEDS_OPERATOR: "operator",
|
|
9107
|
+
OUTPUT_EXISTS: "caller",
|
|
9108
|
+
STDIN_STALLED: "caller",
|
|
9109
|
+
INTERRUPTED: "interrupted",
|
|
9110
|
+
DEADLINE_EXCEEDED: "wait",
|
|
9111
|
+
INTERNAL: "bug",
|
|
9112
|
+
PERMISSION_DENIED: "operator",
|
|
9113
|
+
DISK_FULL: "operator",
|
|
9114
|
+
NOT_FOUND: "caller",
|
|
9115
|
+
ALREADY_EXISTS: "caller",
|
|
9116
|
+
NOT_A_FILE: "caller",
|
|
9117
|
+
TOOL_FAILED: "operator",
|
|
9118
|
+
TOOL_MISSING: "operator",
|
|
9119
|
+
SECRET_MISSING: "operator",
|
|
9120
|
+
PROJECT_INVALID: "operator",
|
|
9121
|
+
DOCTOR_PROBLEMS: "operator",
|
|
9122
|
+
NOT_GLOBAL_INSTALL: "operator",
|
|
9123
|
+
REGISTRY_UNREACHABLE: "operator",
|
|
9124
|
+
REGISTRY_AUTH: "operator",
|
|
9125
|
+
INSTALL_FAILED: "operator",
|
|
9126
|
+
NPM_FAILED: "operator",
|
|
9127
|
+
NO_LATEST: "source"
|
|
8880
9128
|
};
|
|
9129
|
+
function isRuntimeCode(code) {
|
|
9130
|
+
return Object.hasOwn(RUNTIME_EXIT_CLASSES, code);
|
|
9131
|
+
}
|
|
8881
9132
|
/** The codes of `errors` that the Runtime already declares, which a CLI cannot redeclare. */
|
|
8882
9133
|
function runtimeCodesIn(errors) {
|
|
8883
|
-
return Object.keys(errors).filter(
|
|
9134
|
+
return Object.keys(errors).filter(isRuntimeCode);
|
|
8884
9135
|
}
|
|
8885
9136
|
function exitClassOfOne(error, errors) {
|
|
8886
9137
|
if (!(error instanceof CliError)) return "bug";
|
|
8887
9138
|
if (error instanceof UsageError) return "caller";
|
|
8888
|
-
|
|
9139
|
+
if (isRuntimeCode(error.code)) return RUNTIME_EXIT_CLASSES[error.code];
|
|
9140
|
+
return errors[error.code]?.class ?? "bug";
|
|
8889
9141
|
}
|
|
8890
9142
|
function isBug(error, errors) {
|
|
8891
9143
|
return exitClassOfOne(error, errors) === "bug";
|
|
@@ -8913,7 +9165,7 @@ function reachableExitClasses(cli) {
|
|
|
8913
9165
|
"wait",
|
|
8914
9166
|
...cli.commands === void 0 ? [] : installOf(cli).exitClasses
|
|
8915
9167
|
];
|
|
8916
|
-
const own = Object.values(cli
|
|
9168
|
+
const own = Object.values(errorTableOf(cli)).map((declaration) => declaration.class);
|
|
8917
9169
|
return /* @__PURE__ */ new Set([...runtime, ...own]);
|
|
8918
9170
|
}
|
|
8919
9171
|
/** The signal named by an interrupt's abort reason; any other reason counts as Ctrl-C. */
|
|
@@ -8930,17 +9182,33 @@ function exitCodeOf(error, errors, stop) {
|
|
|
8930
9182
|
}
|
|
8931
9183
|
//#endregion
|
|
8932
9184
|
//#region ../agent-cli/dist/agent-cli.js
|
|
8933
|
-
function checkOwnCodes(
|
|
8934
|
-
const redeclared = runtimeCodesIn(
|
|
8935
|
-
if (redeclared.length > 0) throw new Error(
|
|
8936
|
-
}
|
|
8937
|
-
function
|
|
8938
|
-
|
|
9185
|
+
function checkOwnCodes(errors) {
|
|
9186
|
+
const redeclared = runtimeCodesIn(errors);
|
|
9187
|
+
if (redeclared.length > 0) throw new Error(`The Error table declares ${redeclared.join(", ")}, an error code the Runtime already declares`);
|
|
9188
|
+
}
|
|
9189
|
+
function checkTree(commands, path, table) {
|
|
9190
|
+
for (const [key, node] of Object.entries(commands)) {
|
|
9191
|
+
const at = [...path, key];
|
|
9192
|
+
if (isCommand(node)) checkCommand(node, at.join(" "), table);
|
|
9193
|
+
else checkTree(node, at, table);
|
|
9194
|
+
}
|
|
9195
|
+
}
|
|
9196
|
+
function checkSkillAdd({ name, skill }) {
|
|
9197
|
+
if (skill === void 0 || !("add" in skill)) return;
|
|
9198
|
+
const declares = `${name} declares skill.add ${JSON.stringify(skill.add)}`;
|
|
9199
|
+
if (skill.add.trim() === "") throw new Error(`${declares}, which is empty`);
|
|
9200
|
+
if (/[\r\n]/.test(skill.add)) throw new Error(`${declares}, which holds a line break`);
|
|
9201
|
+
}
|
|
9202
|
+
function checkCli(cli) {
|
|
9203
|
+
const table = errorTableOf(cli);
|
|
9204
|
+
checkSkillAdd(cli);
|
|
8939
9205
|
if (cli.commands === void 0) {
|
|
8940
|
-
|
|
9206
|
+
checkCommand(cli.command, commandLabel([], cli.name).join(" "), table);
|
|
9207
|
+
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`);
|
|
8941
9208
|
return cli;
|
|
8942
9209
|
}
|
|
8943
9210
|
const { commands } = cli;
|
|
9211
|
+
checkTree(commands, [], table);
|
|
8944
9212
|
const taken = Object.keys(builtInCommands(cli, {
|
|
8945
9213
|
bin: void 0,
|
|
8946
9214
|
node: void 0
|
|
@@ -8948,111 +9216,545 @@ function defineCli$1(cli) {
|
|
|
8948
9216
|
if (taken.length > 0) throw new Error(`${cli.name} defines ${taken.join(", ")}, a built-in Command it cannot replace`);
|
|
8949
9217
|
return cli;
|
|
8950
9218
|
}
|
|
8951
|
-
|
|
8952
|
-
|
|
8953
|
-
|
|
8954
|
-
|
|
8955
|
-
function agentCli() {
|
|
8956
|
-
return {
|
|
8957
|
-
defineCommand: defineCommandFor(),
|
|
8958
|
-
defineCli: defineCli$1
|
|
8959
|
-
};
|
|
8960
|
-
}
|
|
8961
|
-
//#endregion
|
|
8962
|
-
//#region ../agent-cli/dist/error-table.js
|
|
8963
|
-
/**
|
|
8964
|
-
* Keeps each code's literal class and `details` schema, so `cliError` can type its throw sites;
|
|
8965
|
-
* `print` must name a string key of the code's `details`.
|
|
8966
|
-
*/
|
|
8967
|
-
function defineErrors(table) {
|
|
8968
|
-
return table;
|
|
8969
|
-
}
|
|
8970
|
-
/**
|
|
8971
|
-
* A `CliError` for a code of `table`, whose `details` must match the code's schema. The `hint`
|
|
8972
|
-
* names the next command to run and says whether running it again can help; `retryAt` (ISO 8601)
|
|
8973
|
-
* is allowed only on a wait-class code.
|
|
8974
|
-
*/
|
|
8975
|
-
function cliError(_table, code, init, options) {
|
|
8976
|
-
return new CliError({
|
|
8977
|
-
...init,
|
|
8978
|
-
code
|
|
8979
|
-
}, options);
|
|
8980
|
-
}
|
|
8981
|
-
//#endregion
|
|
8982
|
-
//#region ../agent-cli/dist/command-spec.js
|
|
8983
|
-
/** The group's Commands and groups that help and suggestions may name: hidden Commands left out. */
|
|
8984
|
-
function visibleCommands({ commands }) {
|
|
8985
|
-
return Object.fromEntries(Object.entries(commands).filter(([, node]) => node.kind === "group" || !node.hidden));
|
|
9219
|
+
function nameOf({ name, bin }) {
|
|
9220
|
+
const bins = typeof bin === "object" ? Object.keys(bin) : [];
|
|
9221
|
+
const [only] = bins;
|
|
9222
|
+
return bins.length === 1 && only !== void 0 ? only : name.replace(/^@[^/]+\//, "");
|
|
8986
9223
|
}
|
|
8987
|
-
function
|
|
8988
|
-
if (
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
cost: false
|
|
9224
|
+
function installFrom(name, manifest, install) {
|
|
9225
|
+
if (install === "dependency") return {
|
|
9226
|
+
mode: "dependency",
|
|
9227
|
+
package: manifest.name
|
|
8992
9228
|
};
|
|
8993
|
-
return {
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
9229
|
+
if (install !== "global") return {
|
|
9230
|
+
mode: "dependency",
|
|
9231
|
+
package: manifest.name,
|
|
9232
|
+
lockstep: install.lockstep
|
|
8997
9233
|
};
|
|
8998
|
-
|
|
8999
|
-
|
|
9000
|
-
path: [],
|
|
9001
|
-
builtIn: false
|
|
9002
|
-
};
|
|
9003
|
-
function commandSpec(commandLine, command, { path, builtIn } = SINGLE_COMMAND) {
|
|
9004
|
-
const list = command.rows === void 0 ? void 0 : listSpec(command.rows);
|
|
9234
|
+
const registry = manifest.publishConfig?.registry;
|
|
9235
|
+
if (registry === void 0) throw new Error(`${name} declares a Global install, which needs publishConfig.registry in its package.json`);
|
|
9005
9236
|
return {
|
|
9006
|
-
|
|
9007
|
-
|
|
9008
|
-
|
|
9009
|
-
command,
|
|
9010
|
-
builtIn,
|
|
9011
|
-
description: command.description,
|
|
9012
|
-
help: command.help,
|
|
9013
|
-
hidden: command.hidden === true,
|
|
9014
|
-
operator: command.operator === true,
|
|
9015
|
-
effect: command.effect,
|
|
9016
|
-
examples: command.examples,
|
|
9017
|
-
args: argFields(command.args),
|
|
9018
|
-
options: optionFields(command.options),
|
|
9019
|
-
standardFlags: standardFlagsFor(command.effect, declaredOf(command), list),
|
|
9020
|
-
list,
|
|
9021
|
-
output: list?.output ?? command.output
|
|
9237
|
+
mode: "global",
|
|
9238
|
+
package: manifest.name,
|
|
9239
|
+
registry
|
|
9022
9240
|
};
|
|
9023
9241
|
}
|
|
9024
|
-
function
|
|
9242
|
+
function resolved(cli) {
|
|
9243
|
+
const { manifest, ...declared } = cli;
|
|
9244
|
+
const name = nameOf(manifest);
|
|
9245
|
+
const about = {
|
|
9246
|
+
name,
|
|
9247
|
+
version: manifest.version,
|
|
9248
|
+
description: manifest.description
|
|
9249
|
+
};
|
|
9250
|
+
if (declared.commands === void 0) return {
|
|
9251
|
+
...declared,
|
|
9252
|
+
...about
|
|
9253
|
+
};
|
|
9254
|
+
const { install, ...rest } = declared;
|
|
9025
9255
|
return {
|
|
9026
|
-
|
|
9027
|
-
|
|
9028
|
-
|
|
9256
|
+
...rest,
|
|
9257
|
+
...about,
|
|
9258
|
+
...manifest.engines === void 0 ? {} : { engines: manifest.engines },
|
|
9259
|
+
...install === void 0 ? {} : { install: installFrom(name, manifest, install) }
|
|
9029
9260
|
};
|
|
9030
9261
|
}
|
|
9031
|
-
/**
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
|
|
9262
|
+
/**
|
|
9263
|
+
* Takes the CLI's ports factory, Project file and Error table once; the `defineCommand`,
|
|
9264
|
+
* `defineCli` and `cliError` it returns are typed by them.
|
|
9265
|
+
*/
|
|
9266
|
+
function agentCli(values = {}) {
|
|
9267
|
+
checkOwnCodes(errorTableOf(values));
|
|
9268
|
+
return {
|
|
9269
|
+
defineCommand: defineCommandFor(),
|
|
9270
|
+
defineCli: (cli) => checkCli({
|
|
9271
|
+
...resolved(cli),
|
|
9272
|
+
...values
|
|
9037
9273
|
}),
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
builtIn: true
|
|
9041
|
-
})
|
|
9042
|
-
});
|
|
9043
|
-
}
|
|
9044
|
-
function specsOf(commandLine, commands, { path, builtIn }) {
|
|
9045
|
-
return Object.fromEntries(Object.entries(commands).map(([key, node]) => [key, specOf(`${commandLine} ${key}`, node, {
|
|
9046
|
-
path: [...path, key],
|
|
9047
|
-
builtIn
|
|
9048
|
-
})]));
|
|
9049
|
-
}
|
|
9050
|
-
function specOf(commandLine, node, place) {
|
|
9051
|
-
return isCommand(node) ? commandSpec(commandLine, node, place) : group(commandLine, specsOf(commandLine, node, place));
|
|
9274
|
+
cliError: cliErrorOf
|
|
9275
|
+
};
|
|
9052
9276
|
}
|
|
9053
9277
|
//#endregion
|
|
9054
|
-
//#region ../agent-cli/dist/
|
|
9055
|
-
|
|
9278
|
+
//#region ../agent-cli/dist/context/side-task.js
|
|
9279
|
+
/** How long a run waits for its Side task once its output is written. */
|
|
9280
|
+
const SIDE_TASK_WAIT_MS = 1e3;
|
|
9281
|
+
const noSideTask = async () => {};
|
|
9282
|
+
function waitOver() {
|
|
9283
|
+
return new DOMException(`the side task ran past its ${SIDE_TASK_WAIT_MS} ms wait`, "TimeoutError");
|
|
9284
|
+
}
|
|
9285
|
+
function startSideTask(sideTask, runWith, { clock, failed }) {
|
|
9286
|
+
if (sideTask === void 0) return noSideTask;
|
|
9287
|
+
const controller = new AbortController();
|
|
9288
|
+
const { signal } = controller;
|
|
9289
|
+
const running = (async () => sideTask(runWith(signal)))().catch((error) => {
|
|
9290
|
+
if (!(signal.aborted && error === signal.reason)) failed(error);
|
|
9291
|
+
});
|
|
9292
|
+
return async () => {
|
|
9293
|
+
const waited = new AbortController();
|
|
9294
|
+
const capped = new Promise((resolve) => after(clock, SIDE_TASK_WAIT_MS, waited.signal, () => {
|
|
9295
|
+
const over = waitOver();
|
|
9296
|
+
failed(over);
|
|
9297
|
+
controller.abort(over);
|
|
9298
|
+
resolve();
|
|
9299
|
+
}));
|
|
9300
|
+
await Promise.race([running, capped]);
|
|
9301
|
+
waited.abort();
|
|
9302
|
+
};
|
|
9303
|
+
}
|
|
9304
|
+
//#endregion
|
|
9305
|
+
//#region ../agent-cli/dist/command-line/suggest.js
|
|
9306
|
+
const MAX_DISTANCE = 3;
|
|
9307
|
+
const MIN_SIMILARITY = .4;
|
|
9308
|
+
function distance(a, b) {
|
|
9309
|
+
const width = b.length + 1;
|
|
9310
|
+
const d = Array.from({ length: (a.length + 1) * width }, (_, k) => {
|
|
9311
|
+
const i = Math.floor(k / width);
|
|
9312
|
+
const j = k % width;
|
|
9313
|
+
return i === 0 || j === 0 ? i + j : 0;
|
|
9314
|
+
});
|
|
9315
|
+
const at = (i, j) => d[i * width + j] ?? 0;
|
|
9316
|
+
for (let i = 1; i <= a.length; i++) for (let j = 1; j <= b.length; j++) {
|
|
9317
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
9318
|
+
const edit = Math.min(at(i - 1, j) + 1, at(i, j - 1) + 1, at(i - 1, j - 1) + cost);
|
|
9319
|
+
const transposed = i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1];
|
|
9320
|
+
d[i * width + j] = transposed ? Math.min(edit, at(i - 2, j - 2) + 1) : edit;
|
|
9321
|
+
}
|
|
9322
|
+
return at(a.length, b.length);
|
|
9323
|
+
}
|
|
9324
|
+
function isClose(word, candidate) {
|
|
9325
|
+
const length = Math.max(word.length, candidate.length);
|
|
9326
|
+
const edits = distance(word, candidate);
|
|
9327
|
+
return candidate.length > 1 && edits < MAX_DISTANCE && (length - edits) / length > MIN_SIMILARITY;
|
|
9328
|
+
}
|
|
9329
|
+
/** The names closest to `word`, sorted, several when they tie, or none when nothing is close. */
|
|
9330
|
+
function closestNames(word, names) {
|
|
9331
|
+
const close = [...new Set(names)].filter((candidate) => isClose(word, candidate));
|
|
9332
|
+
const best = Math.min(...close.map((candidate) => distance(word, candidate)));
|
|
9333
|
+
return close.filter((candidate) => distance(word, candidate) === best).sort((a, b) => a.localeCompare(b));
|
|
9334
|
+
}
|
|
9335
|
+
/** The long flags closest to `flag`, sorted, or none for a short flag or when nothing is close. */
|
|
9336
|
+
function closestFlags(flag, flags) {
|
|
9337
|
+
if (!flag.startsWith("--")) return [];
|
|
9338
|
+
const names = flags.map((candidate) => candidate.slice(2));
|
|
9339
|
+
return closestNames(flag.slice(2), names).map((name) => `--${name}`);
|
|
9340
|
+
}
|
|
9341
|
+
/** The one long flag closest to `flag`, or none when nothing is close or several tie. */
|
|
9342
|
+
function closestFlag(flag, flags) {
|
|
9343
|
+
const closest = closestFlags(flag, flags);
|
|
9344
|
+
return closest.length === 1 ? closest[0] : void 0;
|
|
9345
|
+
}
|
|
9346
|
+
//#endregion
|
|
9347
|
+
//#region ../agent-cli/dist/command-line/parse-input.js
|
|
9348
|
+
const NO_INPUT = object({});
|
|
9349
|
+
const WHITESPACE = /\s/;
|
|
9350
|
+
function knownFlags(spec) {
|
|
9351
|
+
return [...spec.options.map((field) => ({
|
|
9352
|
+
flag: field.label,
|
|
9353
|
+
takes: field.type === "boolean" ? "nothing" : "optional value"
|
|
9354
|
+
})), ...spec.standardFlags.map(({ flag, takes }) => ({
|
|
9355
|
+
flag,
|
|
9356
|
+
takes
|
|
9357
|
+
}))];
|
|
9358
|
+
}
|
|
9359
|
+
function candidateFlags(known) {
|
|
9360
|
+
return [
|
|
9361
|
+
...known.map(({ flag }) => flag),
|
|
9362
|
+
VERSION_FLAG,
|
|
9363
|
+
HELP_FLAG
|
|
9364
|
+
];
|
|
9365
|
+
}
|
|
9366
|
+
function unknownOptionsOf(words, candidates) {
|
|
9367
|
+
return words.map((word) => {
|
|
9368
|
+
const flag = word.split("=")[0] ?? word;
|
|
9369
|
+
return {
|
|
9370
|
+
flag,
|
|
9371
|
+
suggestion: closestFlag(flag, candidates)
|
|
9372
|
+
};
|
|
9373
|
+
});
|
|
9374
|
+
}
|
|
9375
|
+
function optionValue(field, all) {
|
|
9376
|
+
if (field.variadic) return variadicValue(field, (all ?? []).filter((value) => value !== true));
|
|
9377
|
+
const raw = all?.[all.length - 1];
|
|
9378
|
+
return field.type === "boolean" && raw === true && field.label === `--no-${field.name}` ? false : raw;
|
|
9379
|
+
}
|
|
9380
|
+
function converted(field, raw) {
|
|
9381
|
+
if (Array.isArray(raw)) return raw.map((element) => converted(field, element));
|
|
9382
|
+
if (field.type !== "number" || typeof raw !== "string" || raw.trim() === "") return raw;
|
|
9383
|
+
const number = Number(raw);
|
|
9384
|
+
return Number.isNaN(number) ? raw : number;
|
|
9385
|
+
}
|
|
9386
|
+
function variadicValue(field, values) {
|
|
9387
|
+
return values.length === 0 && !field.required ? void 0 : values;
|
|
9388
|
+
}
|
|
9389
|
+
function parse(schema, values) {
|
|
9390
|
+
const input = Object.fromEntries([...values].filter(([, raw]) => raw !== void 0).map(([field, raw]) => [field.key, converted(field, raw)]));
|
|
9391
|
+
return schema.safeParse(input);
|
|
9392
|
+
}
|
|
9393
|
+
function issueLines(result, values, { howToPass, arrayIssueLine, reported = [], fromStdin }) {
|
|
9394
|
+
if (result.success) return [];
|
|
9395
|
+
return result.error.issues.flatMap((issue) => {
|
|
9396
|
+
const field = [...values.keys()].find((candidate) => candidate.key === issue.path[0]);
|
|
9397
|
+
if (field === void 0) return [` ${issue.message}`];
|
|
9398
|
+
if (reported.includes(field)) return [];
|
|
9399
|
+
const raw = values.get(field);
|
|
9400
|
+
if (raw === void 0) return [` ${field.label}: required, ${howToPass(field)}`];
|
|
9401
|
+
if (field === fromStdin) return [` ${field.label} from stdin: ${issue.message}`];
|
|
9402
|
+
return Array.isArray(raw) ? [arrayIssueLine(field, raw, issue)] : [` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`];
|
|
9403
|
+
});
|
|
9404
|
+
}
|
|
9405
|
+
function flagValuesIssueLine(field, raw, issue) {
|
|
9406
|
+
const [, element] = issue.path;
|
|
9407
|
+
if (typeof element === "number") return ` ${field.label} ${JSON.stringify(raw[element])}: ${issue.message}`;
|
|
9408
|
+
return raw.length === 0 ? ` ${field.label}: ${issue.message}, pass ${field.usage}` : ` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`;
|
|
9409
|
+
}
|
|
9410
|
+
function operandsIssueLine(field, raw, issue, first) {
|
|
9411
|
+
const [, element] = issue.path;
|
|
9412
|
+
if (typeof element === "number") return ` ${field.label} ${JSON.stringify(raw[element])} (argument ${first + element}): ${issue.message}`;
|
|
9413
|
+
return raw.length === 0 ? ` ${field.label}: ${issue.message}, pass them as arguments from ${first}` : ` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`;
|
|
9414
|
+
}
|
|
9415
|
+
function unknownLine({ flag, suggestion }) {
|
|
9416
|
+
return ` unknown option '${flag}'${suggestion === void 0 ? "" : ` (did you mean ${suggestion}?)`}`;
|
|
9417
|
+
}
|
|
9418
|
+
function invalidInput(commandLine, invocation, unknown, otherLines) {
|
|
9419
|
+
const renames = new Map(unknown.flatMap(({ flag, suggestion }) => suggestion === void 0 ? [] : [[flag, suggestion]]));
|
|
9420
|
+
const correctable = otherLines.length === 0 && renames.size === unknown.length;
|
|
9421
|
+
return new UsageError({
|
|
9422
|
+
code: INVALID_INPUT,
|
|
9423
|
+
message: [
|
|
9424
|
+
`invalid input for \`${commandLine}\``,
|
|
9425
|
+
...unknown.map(unknownLine),
|
|
9426
|
+
...otherLines
|
|
9427
|
+
].join("\n"),
|
|
9428
|
+
hint: correctable ? `did you mean \`${commandLineRenaming(invocation, renames)}\`?` : `run \`${commandLine} --help\` to see the expected input`
|
|
9429
|
+
});
|
|
9430
|
+
}
|
|
9431
|
+
function stdinFieldOf(spec, operands) {
|
|
9432
|
+
const index = spec.args.findIndex((field) => field.stdin);
|
|
9433
|
+
return operands[index]?.value === "-" ? spec.args[index] : void 0;
|
|
9434
|
+
}
|
|
9435
|
+
/** The name of the routed Command's arg given `-`, which takes its text from stdin. */
|
|
9436
|
+
function stdinArgOf({ spec, words }) {
|
|
9437
|
+
return stdinFieldOf(spec, tokenize(words, knownFlags(spec)).operands)?.name;
|
|
9438
|
+
}
|
|
9439
|
+
async function stdinTextOf(spec, operands, read) {
|
|
9440
|
+
const field = stdinFieldOf(spec, operands);
|
|
9441
|
+
return field === void 0 ? void 0 : {
|
|
9442
|
+
field,
|
|
9443
|
+
text: await read(field)
|
|
9444
|
+
};
|
|
9445
|
+
}
|
|
9446
|
+
async function parseInput(spec, words, invocation, readStdin) {
|
|
9447
|
+
const { command, args: argFields, options: optionFields } = spec;
|
|
9448
|
+
const pageFields = spec.list?.pageFields ?? [];
|
|
9449
|
+
const known = knownFlags(spec);
|
|
9450
|
+
const { operands, unknownOptions, values, occurrences } = tokenize(words, known);
|
|
9451
|
+
const stdin = await stdinTextOf(spec, operands, readStdin);
|
|
9452
|
+
if (values.get(CONFIRM_FLAG.flag) === true) throw invalidInputError(spec.commandLine, `option '${CONFIRM_FLAG.usage}' argument missing`);
|
|
9453
|
+
const missing = [...optionFields, ...pageFields].filter((field) => field.type !== "boolean" && (field.variadic ? occurrences.get(field.label)?.includes(true) : values.get(field.label) === true));
|
|
9454
|
+
const argValue = (field, index) => {
|
|
9455
|
+
if (field === stdin?.field) return stdin.text;
|
|
9456
|
+
if (!field.variadic) return operands[index]?.value;
|
|
9457
|
+
return variadicValue(field, operands.slice(index).filter((operand) => !operand.afterUnknownOption).map((operand) => operand.value));
|
|
9458
|
+
};
|
|
9459
|
+
const argValues = new Map(argFields.map((field, index) => [field, argValue(field, index)]));
|
|
9460
|
+
const extraOperands = argFields.some((field) => field.variadic) ? [] : operands.slice(argFields.length);
|
|
9461
|
+
const valuesOf = (fields) => new Map(fields.map((field) => [field, missing.includes(field) ? void 0 : optionValue(field, occurrences.get(field.label))]));
|
|
9462
|
+
const flagWording = {
|
|
9463
|
+
howToPass: (field) => `pass ${field.usage}`,
|
|
9464
|
+
arrayIssueLine: flagValuesIssueLine,
|
|
9465
|
+
reported: missing
|
|
9466
|
+
};
|
|
9467
|
+
const optionValues = valuesOf(optionFields);
|
|
9468
|
+
const pageValues = valuesOf(pageFields);
|
|
9469
|
+
const args = parse(command.args ?? NO_INPUT, argValues);
|
|
9470
|
+
const options = parse(command.options ?? NO_INPUT, optionValues);
|
|
9471
|
+
const page = parse(PAGE_INPUT, pageValues);
|
|
9472
|
+
const unknown = unknownOptionsOf(unknownOptions, candidateFlags(known));
|
|
9473
|
+
const otherLines = [
|
|
9474
|
+
...missing.map((field) => ` ${field.label}: missing value, pass ${field.usage}`),
|
|
9475
|
+
...extraOperands.filter((operand) => !operand.afterUnknownOption).map((operand) => ` unexpected argument ${JSON.stringify(operand.value)}`),
|
|
9476
|
+
...issueLines(args, argValues, {
|
|
9477
|
+
howToPass: (field) => `pass it as argument ${argFields.indexOf(field) + 1}`,
|
|
9478
|
+
arrayIssueLine: (field, raw, issue) => operandsIssueLine(field, raw, issue, argFields.indexOf(field) + 1),
|
|
9479
|
+
fromStdin: stdin?.field
|
|
9480
|
+
}),
|
|
9481
|
+
...issueLines(options, optionValues, flagWording),
|
|
9482
|
+
...issueLines(page, pageValues, flagWording)
|
|
9483
|
+
];
|
|
9484
|
+
if (unknown.length === 0 && otherLines.length === 0 && args.success && options.success && page.success) return {
|
|
9485
|
+
input: {
|
|
9486
|
+
...args.data,
|
|
9487
|
+
...options.data
|
|
9488
|
+
},
|
|
9489
|
+
page: page.data,
|
|
9490
|
+
values
|
|
9491
|
+
};
|
|
9492
|
+
const [onlyWord] = unknownOptions;
|
|
9493
|
+
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);
|
|
9494
|
+
const [only] = unknown;
|
|
9495
|
+
if (only !== void 0 && unknown.length === 1 && otherLines.length === 0) throw unknownOptionError(spec.commandLine, invocation, only.flag, only.suggestion === void 0 ? [] : [only.suggestion]);
|
|
9496
|
+
throw invalidInput(spec.commandLine, invocation, unknown, otherLines);
|
|
9497
|
+
}
|
|
9498
|
+
/**
|
|
9499
|
+
* The validated input and Standard flag values of the routed Command, or one usage error; the arg
|
|
9500
|
+
* given `-` takes its text from `readStdin`.
|
|
9501
|
+
*/
|
|
9502
|
+
async function parseCommand({ spec, words, json }, invocation, readStdin) {
|
|
9503
|
+
const { input, page, values } = await parseInput(spec, words, invocation, readStdin);
|
|
9504
|
+
const confirm = values.get(CONFIRM_FLAG.flag);
|
|
9505
|
+
return {
|
|
9506
|
+
input,
|
|
9507
|
+
flags: {
|
|
9508
|
+
json,
|
|
9509
|
+
dryRun: values.get(DRY_RUN_FLAG.flag) === true,
|
|
9510
|
+
confirm: typeof confirm === "string" ? confirm : void 0,
|
|
9511
|
+
yes: values.get(YES_FLAG.flag) === true,
|
|
9512
|
+
force: values.get(FORCE_FLAG.flag) === true,
|
|
9513
|
+
page,
|
|
9514
|
+
fields: spec.list === void 0 ? void 0 : selectedFields(values, spec.list.rowFields, spec.commandLine)
|
|
9515
|
+
}
|
|
9516
|
+
};
|
|
9517
|
+
}
|
|
9518
|
+
//#endregion
|
|
9519
|
+
//#region ../agent-cli/dist/command-line/route.js
|
|
9520
|
+
const GROUP_FLAGS = [
|
|
9521
|
+
HELP_FLAG,
|
|
9522
|
+
VERSION_FLAG,
|
|
9523
|
+
JSON_FLAG.flag
|
|
9524
|
+
];
|
|
9525
|
+
function beforeEnd(words) {
|
|
9526
|
+
const end = words.indexOf("--");
|
|
9527
|
+
return end === -1 ? words : words.slice(0, end);
|
|
9528
|
+
}
|
|
9529
|
+
function wantsHelp(words) {
|
|
9530
|
+
return beforeEnd(words).some((word) => word === "--help" || word === "-h");
|
|
9531
|
+
}
|
|
9532
|
+
function childOf(group, name) {
|
|
9533
|
+
return Object.hasOwn(group.commands, name) ? group.commands[name] : void 0;
|
|
9534
|
+
}
|
|
9535
|
+
function isFlagLike(word) {
|
|
9536
|
+
return word.length > 1 && word[0] === "-";
|
|
9537
|
+
}
|
|
9538
|
+
function walk(node, words, json, invocation) {
|
|
9539
|
+
const help = {
|
|
9540
|
+
kind: "help",
|
|
9541
|
+
node,
|
|
9542
|
+
json
|
|
9543
|
+
};
|
|
9544
|
+
if (node.kind === "command") return wantsHelp(words) ? help : {
|
|
9545
|
+
kind: "command",
|
|
9546
|
+
spec: node,
|
|
9547
|
+
words,
|
|
9548
|
+
json
|
|
9549
|
+
};
|
|
9550
|
+
const [first, ...rest] = words;
|
|
9551
|
+
if (first === void 0) return help;
|
|
9552
|
+
const child = childOf(node, first);
|
|
9553
|
+
if (child !== void 0) return walk(child, rest, json, invocation);
|
|
9554
|
+
if (first === "--") {
|
|
9555
|
+
const [name, ...after] = rest;
|
|
9556
|
+
if (name === void 0) return help;
|
|
9557
|
+
const named = childOf(node, name);
|
|
9558
|
+
if (named !== void 0) return walk(named, ["--", ...after], json, invocation);
|
|
9559
|
+
return unknownCommand(node, name, json);
|
|
9560
|
+
}
|
|
9561
|
+
if (wantsHelp(words)) return help;
|
|
9562
|
+
if (isFlagLike(first)) {
|
|
9563
|
+
const suggestions = closestFlags(first, GROUP_FLAGS);
|
|
9564
|
+
return {
|
|
9565
|
+
kind: "usage error",
|
|
9566
|
+
error: unknownOptionError(node.commandLine, invocation, first, suggestions),
|
|
9567
|
+
node,
|
|
9568
|
+
json
|
|
9569
|
+
};
|
|
9570
|
+
}
|
|
9571
|
+
return unknownCommand(node, first, json);
|
|
9572
|
+
}
|
|
9573
|
+
function unknownCommand(group, name, json) {
|
|
9574
|
+
const suggestions = closestNames(name, Object.keys(visibleCommands(group)));
|
|
9575
|
+
return {
|
|
9576
|
+
kind: "usage error",
|
|
9577
|
+
error: unknownCommandError(group.commandLine, name, suggestions),
|
|
9578
|
+
node: group,
|
|
9579
|
+
json
|
|
9580
|
+
};
|
|
9581
|
+
}
|
|
9582
|
+
/** Walks the caller's command line through the Commands to the one it names, or to a stop. */
|
|
9583
|
+
function route(root, invocation) {
|
|
9584
|
+
const { argv } = invocation;
|
|
9585
|
+
const options = beforeEnd(argv);
|
|
9586
|
+
const json = options.includes(JSON_FLAG.flag);
|
|
9587
|
+
if (options.includes("--version")) return {
|
|
9588
|
+
kind: "version",
|
|
9589
|
+
json
|
|
9590
|
+
};
|
|
9591
|
+
return walk(root, argv.filter((word, index) => !(index < options.length && word === JSON_FLAG.flag)), json, invocation);
|
|
9592
|
+
}
|
|
9593
|
+
//#endregion
|
|
9594
|
+
//#region ../agent-cli/dist/command-line/route-line.js
|
|
9595
|
+
/** Routes `argv`, the line's words after the Run-as, to a Command of `root`. */
|
|
9596
|
+
function routeLine(root, runAs, argv) {
|
|
9597
|
+
if (!argv.ok) return {
|
|
9598
|
+
ok: false,
|
|
9599
|
+
reason: `it does not tokenize: ${argv.reason}`
|
|
9600
|
+
};
|
|
9601
|
+
const invocation = {
|
|
9602
|
+
runAs,
|
|
9603
|
+
argv: argv.words,
|
|
9604
|
+
flags: []
|
|
9605
|
+
};
|
|
9606
|
+
const routed = route(root, invocation);
|
|
9607
|
+
switch (routed.kind) {
|
|
9608
|
+
case "usage error": return {
|
|
9609
|
+
ok: false,
|
|
9610
|
+
reason: routed.error.message
|
|
9611
|
+
};
|
|
9612
|
+
case "help":
|
|
9613
|
+
case "version": return {
|
|
9614
|
+
ok: false,
|
|
9615
|
+
reason: "it names no Command"
|
|
9616
|
+
};
|
|
9617
|
+
case "command": return {
|
|
9618
|
+
ok: true,
|
|
9619
|
+
routed,
|
|
9620
|
+
invocation
|
|
9621
|
+
};
|
|
9622
|
+
}
|
|
9623
|
+
}
|
|
9624
|
+
//#endregion
|
|
9625
|
+
//#region ../agent-cli/dist/command-line/shell-words.js
|
|
9626
|
+
const BLANK = /\s/;
|
|
9627
|
+
const SHELL_SYNTAX = /* @__PURE__ */ new Set([
|
|
9628
|
+
"|",
|
|
9629
|
+
"&",
|
|
9630
|
+
";",
|
|
9631
|
+
">",
|
|
9632
|
+
"(",
|
|
9633
|
+
")",
|
|
9634
|
+
"$",
|
|
9635
|
+
"`"
|
|
9636
|
+
]);
|
|
9637
|
+
const STDIN_REDIRECT = "<";
|
|
9638
|
+
const DOUBLE_QUOTE_ESCAPES = /* @__PURE__ */ new Set([
|
|
9639
|
+
"$",
|
|
9640
|
+
"`",
|
|
9641
|
+
"\"",
|
|
9642
|
+
"\\"
|
|
9643
|
+
]);
|
|
9644
|
+
function quotedFrom(line, start, quote) {
|
|
9645
|
+
let word = "";
|
|
9646
|
+
for (let index = start; index < line.length; index += 1) {
|
|
9647
|
+
const char = line[index] ?? "";
|
|
9648
|
+
if (char === quote) return {
|
|
9649
|
+
word,
|
|
9650
|
+
end: index + 1
|
|
9651
|
+
};
|
|
9652
|
+
const next = line[index + 1];
|
|
9653
|
+
if (quote === "\"" && char === "\\" && next !== void 0 && DOUBLE_QUOTE_ESCAPES.has(next)) {
|
|
9654
|
+
word += next;
|
|
9655
|
+
index += 1;
|
|
9656
|
+
} else word += char;
|
|
9657
|
+
}
|
|
9658
|
+
}
|
|
9659
|
+
function skipBlanks(line, start) {
|
|
9660
|
+
let index = start;
|
|
9661
|
+
while (BLANK.test(line[index] ?? "")) index += 1;
|
|
9662
|
+
return index;
|
|
9663
|
+
}
|
|
9664
|
+
function isBoundary(char) {
|
|
9665
|
+
return BLANK.test(char) || char === STDIN_REDIRECT || SHELL_SYNTAX.has(char);
|
|
9666
|
+
}
|
|
9667
|
+
function wordFrom(line, start) {
|
|
9668
|
+
let word = "";
|
|
9669
|
+
let index = start;
|
|
9670
|
+
while (index < line.length && !isBoundary(line[index] ?? "")) {
|
|
9671
|
+
const char = line[index] ?? "";
|
|
9672
|
+
if (char === "'" || char === "\"") {
|
|
9673
|
+
const quoted = quotedFrom(line, index + 1, char);
|
|
9674
|
+
if (quoted === void 0) return { reason: `its ${char} is never closed` };
|
|
9675
|
+
word += quoted.word;
|
|
9676
|
+
index = quoted.end;
|
|
9677
|
+
} else if (char === "\\") {
|
|
9678
|
+
word += line[index + 1] ?? "";
|
|
9679
|
+
index += 2;
|
|
9680
|
+
} else {
|
|
9681
|
+
word += char;
|
|
9682
|
+
index += 1;
|
|
9683
|
+
}
|
|
9684
|
+
}
|
|
9685
|
+
return {
|
|
9686
|
+
word,
|
|
9687
|
+
end: index
|
|
9688
|
+
};
|
|
9689
|
+
}
|
|
9690
|
+
/**
|
|
9691
|
+
* The words a POSIX shell would pass for `line`, without the file of a `< file` redirect; a reason
|
|
9692
|
+
* instead when a quote is left open or the line uses other shell syntax.
|
|
9693
|
+
*/
|
|
9694
|
+
function shellWords(line) {
|
|
9695
|
+
const words = [];
|
|
9696
|
+
let index = skipBlanks(line, 0);
|
|
9697
|
+
while (index < line.length) {
|
|
9698
|
+
const redirect = line[index] === STDIN_REDIRECT;
|
|
9699
|
+
if (redirect) index = skipBlanks(line, index + 1);
|
|
9700
|
+
const char = line[index];
|
|
9701
|
+
if (char === void 0 || char === STDIN_REDIRECT) return {
|
|
9702
|
+
ok: false,
|
|
9703
|
+
reason: "its `<` names no file"
|
|
9704
|
+
};
|
|
9705
|
+
if (SHELL_SYNTAX.has(char)) return {
|
|
9706
|
+
ok: false,
|
|
9707
|
+
reason: `it uses the shell's \`${char}\``
|
|
9708
|
+
};
|
|
9709
|
+
const scanned = wordFrom(line, index);
|
|
9710
|
+
if ("reason" in scanned) return {
|
|
9711
|
+
ok: false,
|
|
9712
|
+
reason: scanned.reason
|
|
9713
|
+
};
|
|
9714
|
+
if (!redirect) words.push(scanned.word);
|
|
9715
|
+
index = skipBlanks(line, scanned.end);
|
|
9716
|
+
}
|
|
9717
|
+
return {
|
|
9718
|
+
ok: true,
|
|
9719
|
+
words
|
|
9720
|
+
};
|
|
9721
|
+
}
|
|
9722
|
+
//#endregion
|
|
9723
|
+
//#region ../agent-cli/dist/check-next-steps.js
|
|
9724
|
+
function argvOf(words, runAs) {
|
|
9725
|
+
const line = shellWords(lineOf(words, runAs));
|
|
9726
|
+
const lead = shellWords(runAs);
|
|
9727
|
+
if (!lead.ok) return lead;
|
|
9728
|
+
if (!line.ok) return line;
|
|
9729
|
+
return {
|
|
9730
|
+
ok: true,
|
|
9731
|
+
words: line.words.slice(lead.words.length)
|
|
9732
|
+
};
|
|
9733
|
+
}
|
|
9734
|
+
/**
|
|
9735
|
+
* Why `step` would not run a Command of `root`, or `undefined` when it would. A line given whole is
|
|
9736
|
+
* not checked, since it may run another program.
|
|
9737
|
+
*/
|
|
9738
|
+
function nextStepProblem(root, runAs, step) {
|
|
9739
|
+
const words = wordsOf(step);
|
|
9740
|
+
if (words === void 0) return void 0;
|
|
9741
|
+
const line = routeLine(root, runAs, argvOf(words, runAs));
|
|
9742
|
+
if (!line.ok) return line.reason;
|
|
9743
|
+
const { routed } = line;
|
|
9744
|
+
const { unknownOptions } = tokenize(routed.words, knownFlags(routed.spec));
|
|
9745
|
+
return unknownOptions.length === 0 ? void 0 : `unknown option ${unknownOptions.join(", ")}`;
|
|
9746
|
+
}
|
|
9747
|
+
/** `error`, or a bug naming each of its Next steps that would not run. */
|
|
9748
|
+
function checkedNextSteps(error, check, runAs) {
|
|
9749
|
+
const problems = errorsOf(error).flatMap((leaf) => leaf instanceof CliError ? leaf.next.flatMap((step) => {
|
|
9750
|
+
const problem = check(step);
|
|
9751
|
+
return problem === void 0 ? [] : [`\`${lineOf(step, runAs)}\`, a Next step of ${leaf.code}: ${problem}`];
|
|
9752
|
+
}) : []);
|
|
9753
|
+
return problems.length === 0 ? error : new Error(`a Next step would not run: ${problems.join("; ")}`, { cause: error });
|
|
9754
|
+
}
|
|
9755
|
+
//#endregion
|
|
9756
|
+
//#region ../agent-cli/dist/help.js
|
|
9757
|
+
function table(rows) {
|
|
9056
9758
|
const width = Math.max(...rows.map(([left]) => left.length));
|
|
9057
9759
|
return rows.map(([left, right]) => right === "" ? ` ${left}` : ` ${left.padEnd(width)} ${right}`);
|
|
9058
9760
|
}
|
|
@@ -9172,7 +9874,7 @@ function inputSchema(schema) {
|
|
|
9172
9874
|
function optionsSchema(options) {
|
|
9173
9875
|
return inputSchema(object(Object.fromEntries(options.map(({ name, schema }) => [name, schema]))));
|
|
9174
9876
|
}
|
|
9175
|
-
function commandData(spec) {
|
|
9877
|
+
function commandData(spec, table) {
|
|
9176
9878
|
return {
|
|
9177
9879
|
name: spec.commandLine,
|
|
9178
9880
|
description: spec.description,
|
|
@@ -9180,6 +9882,11 @@ function commandData(spec) {
|
|
|
9180
9882
|
effect: spec.effect,
|
|
9181
9883
|
operator: spec.operator,
|
|
9182
9884
|
examples: spec.examples,
|
|
9885
|
+
secrets: spec.command.secrets ?? [],
|
|
9886
|
+
errors: (spec.command.errors ?? []).map((code) => ({
|
|
9887
|
+
code,
|
|
9888
|
+
class: table[code]?.class
|
|
9889
|
+
})),
|
|
9183
9890
|
args: inputSchema(spec.command.args ?? object({})),
|
|
9184
9891
|
options: optionsSchema(spec.options),
|
|
9185
9892
|
standardFlags: spec.standardFlags.map(({ usage, description, schema }) => ({
|
|
@@ -9190,13 +9897,13 @@ function commandData(spec) {
|
|
|
9190
9897
|
output: spec.output === void 0 ? null : toJSONSchema(spec.output, { unrepresentable: "any" })
|
|
9191
9898
|
};
|
|
9192
9899
|
}
|
|
9193
|
-
function nodeData(node) {
|
|
9194
|
-
return node.kind === "command" ? commandData(node) : groupData(node);
|
|
9900
|
+
function nodeData(node, table) {
|
|
9901
|
+
return node.kind === "command" ? commandData(node, table) : groupData(node, table);
|
|
9195
9902
|
}
|
|
9196
|
-
function groupData(group) {
|
|
9903
|
+
function groupData(group, table) {
|
|
9197
9904
|
return {
|
|
9198
9905
|
name: group.commandLine,
|
|
9199
|
-
commands: Object.values(visibleCommands(group)).map(nodeData)
|
|
9906
|
+
commands: Object.values(visibleCommands(group)).map((node) => nodeData(node, table))
|
|
9200
9907
|
};
|
|
9201
9908
|
}
|
|
9202
9909
|
function printed$1(data) {
|
|
@@ -9208,21 +9915,31 @@ function errorsData(errors) {
|
|
|
9208
9915
|
details: declaration.details === void 0 ? null : toJSONSchema(declaration.details, { unrepresentable: "any" })
|
|
9209
9916
|
}]));
|
|
9210
9917
|
}
|
|
9211
|
-
function
|
|
9212
|
-
return
|
|
9918
|
+
function publishedTable(table, root) {
|
|
9919
|
+
if (root.kind !== "command") return table;
|
|
9920
|
+
const declared = new Set(root.command.errors ?? []);
|
|
9921
|
+
return Object.fromEntries(Object.entries(table).filter(([code]) => declared.has(code)));
|
|
9922
|
+
}
|
|
9923
|
+
function cliHelpJson(cli, root) {
|
|
9924
|
+
const { name, version, description } = cli;
|
|
9925
|
+
const header = {
|
|
9213
9926
|
name,
|
|
9214
9927
|
version,
|
|
9215
|
-
description
|
|
9216
|
-
|
|
9928
|
+
description
|
|
9929
|
+
};
|
|
9930
|
+
const table = errorTableOf(cli);
|
|
9931
|
+
return printed$1({
|
|
9932
|
+
...header,
|
|
9933
|
+
...nodeData(root, table),
|
|
9217
9934
|
name,
|
|
9218
|
-
errors: errorsData(
|
|
9935
|
+
errors: errorsData(publishedTable(table, root))
|
|
9219
9936
|
});
|
|
9220
9937
|
}
|
|
9221
|
-
function groupHelpJson(group) {
|
|
9222
|
-
return printed$1(groupData(group));
|
|
9938
|
+
function groupHelpJson(group, table) {
|
|
9939
|
+
return printed$1(groupData(group, table));
|
|
9223
9940
|
}
|
|
9224
|
-
function commandHelpJson(spec) {
|
|
9225
|
-
return printed$1(commandData(spec));
|
|
9941
|
+
function commandHelpJson(spec, table) {
|
|
9942
|
+
return printed$1(commandData(spec, table));
|
|
9226
9943
|
}
|
|
9227
9944
|
//#endregion
|
|
9228
9945
|
//#region ../agent-cli/dist/output.js
|
|
@@ -9231,14 +9948,14 @@ function withTrailingNewline(text) {
|
|
|
9231
9948
|
return text === "" || text.endsWith("\n") ? text : `${text}\n`;
|
|
9232
9949
|
}
|
|
9233
9950
|
function printed(value, render, { json, invocation, style, fields }) {
|
|
9234
|
-
if (!(value instanceof Page)) return json ? `${JSON.stringify(value)}\n` : withTrailingNewline(render(style));
|
|
9951
|
+
if (!(value instanceof Page)) return json ? `${JSON.stringify(value ?? null)}\n` : withTrailingNewline(render(style));
|
|
9235
9952
|
const page = printedPage(value, invocation);
|
|
9236
|
-
if (fields === void 0) return json ? `${JSON.stringify(page)}\n` : `${withTrailingNewline(render(style))}${pageFooter(page)}`;
|
|
9953
|
+
if (fields === void 0) return json ? `${JSON.stringify(page)}\n` : `${withTrailingNewline(render(style))}${pageFooter(page, style)}`;
|
|
9237
9954
|
const rows = projected(page.items, fields);
|
|
9238
9955
|
return json ? `${JSON.stringify({
|
|
9239
9956
|
...page,
|
|
9240
9957
|
items: rows
|
|
9241
|
-
})}\n` : `${renderRows(rows, fields)}${pageFooter(page)}`;
|
|
9958
|
+
})}\n` : `${renderRows(rows, fields)}${pageFooter(page, style)}`;
|
|
9242
9959
|
}
|
|
9243
9960
|
/** A progress message as stderr carries it: one JSON object per line under `--json` (ADR 0006). */
|
|
9244
9961
|
function progressLine(message, json) {
|
|
@@ -9254,6 +9971,7 @@ function stderrLine(key, text, json) {
|
|
|
9254
9971
|
function errorText(error, format) {
|
|
9255
9972
|
const text = formatRuntimeError(error, {
|
|
9256
9973
|
...format,
|
|
9974
|
+
runAs: format.invocation.runAs,
|
|
9257
9975
|
isBug: (each) => isBug(each, format.errors)
|
|
9258
9976
|
});
|
|
9259
9977
|
const { usageHelp, json } = format;
|
|
@@ -9277,10 +9995,11 @@ const STOPPED_RESULT = {
|
|
|
9277
9995
|
exitCode: SUCCESS_EXIT_CODE
|
|
9278
9996
|
};
|
|
9279
9997
|
function errorResult(error, format) {
|
|
9998
|
+
const checked = format.checkNextStep === void 0 ? error : checkedNextSteps(error, format.checkNextStep, format.invocation.runAs);
|
|
9280
9999
|
return {
|
|
9281
10000
|
stdout: "",
|
|
9282
|
-
stderr: errorText(
|
|
9283
|
-
exitCode: exitCodeOf(
|
|
10001
|
+
stderr: errorText(checked, format),
|
|
10002
|
+
exitCode: exitCodeOf(checked, format.errors, format.stop)
|
|
9284
10003
|
};
|
|
9285
10004
|
}
|
|
9286
10005
|
async function commandResult(settled, format, spill) {
|
|
@@ -9294,12 +10013,18 @@ async function commandResult(settled, format, spill) {
|
|
|
9294
10013
|
return errorResult(spillError, format);
|
|
9295
10014
|
}
|
|
9296
10015
|
const { error, delivered } = settled;
|
|
10016
|
+
if (delivered === void 0) return errorResult(error, format);
|
|
10017
|
+
let outcome;
|
|
10018
|
+
try {
|
|
10019
|
+
outcome = delivered();
|
|
10020
|
+
} catch (rejected) {
|
|
10021
|
+
return errorResult(new AggregateError([...errorsOf(error), rejected]), format);
|
|
10022
|
+
}
|
|
9297
10023
|
const result = errorResult(error, format);
|
|
9298
|
-
if (delivered === void 0) return result;
|
|
9299
10024
|
try {
|
|
9300
10025
|
return {
|
|
9301
10026
|
...result,
|
|
9302
|
-
stdout: await stdoutOf(
|
|
10027
|
+
stdout: await stdoutOf(outcome, format, spill)
|
|
9303
10028
|
};
|
|
9304
10029
|
} catch (spillError) {
|
|
9305
10030
|
const both = new AggregateError([...errorsOf(error), spillError]);
|
|
@@ -9316,7 +10041,8 @@ function textHelp(node, root, cli, style) {
|
|
|
9316
10041
|
function helpOf(node, root, cli, style, json) {
|
|
9317
10042
|
if (!json) return textHelp(node, root, cli, style);
|
|
9318
10043
|
if (node === root) return cliHelpJson(cli, node);
|
|
9319
|
-
|
|
10044
|
+
const table = errorTableOf(cli);
|
|
10045
|
+
return node.kind === "command" ? commandHelpJson(node, table) : groupHelpJson(node, table);
|
|
9320
10046
|
}
|
|
9321
10047
|
function helpResult(node, root, cli, { style, json }) {
|
|
9322
10048
|
return {
|
|
@@ -9327,7 +10053,7 @@ function helpResult(node, root, cli, { style, json }) {
|
|
|
9327
10053
|
}
|
|
9328
10054
|
function versionResult(cli, packageRoot) {
|
|
9329
10055
|
return {
|
|
9330
|
-
stdout: `${(
|
|
10056
|
+
stdout: `${(buildStamp() === void 0 ? [versionLine(cli)] : [versionLine(cli), `changelog ${join(packageRoot, "CHANGELOG.md")}`]).join("\n")}\n`,
|
|
9331
10057
|
stderr: "",
|
|
9332
10058
|
exitCode: SUCCESS_EXIT_CODE
|
|
9333
10059
|
};
|
|
@@ -9347,509 +10073,795 @@ function packageRootOf(bin, cwd) {
|
|
|
9347
10073
|
}
|
|
9348
10074
|
}
|
|
9349
10075
|
//#endregion
|
|
9350
|
-
//#region ../agent-cli/dist/
|
|
9351
|
-
|
|
9352
|
-
|
|
9353
|
-
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
const i = Math.floor(k / width);
|
|
9357
|
-
const j = k % width;
|
|
9358
|
-
return i === 0 || j === 0 ? i + j : 0;
|
|
9359
|
-
});
|
|
9360
|
-
const at = (i, j) => d[i * width + j] ?? 0;
|
|
9361
|
-
for (let i = 1; i <= a.length; i++) for (let j = 1; j <= b.length; j++) {
|
|
9362
|
-
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
9363
|
-
const edit = Math.min(at(i - 1, j) + 1, at(i, j - 1) + 1, at(i - 1, j - 1) + cost);
|
|
9364
|
-
const transposed = i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1];
|
|
9365
|
-
d[i * width + j] = transposed ? Math.min(edit, at(i - 2, j - 2) + 1) : edit;
|
|
9366
|
-
}
|
|
9367
|
-
return at(a.length, b.length);
|
|
9368
|
-
}
|
|
9369
|
-
function isClose(word, candidate) {
|
|
9370
|
-
const length = Math.max(word.length, candidate.length);
|
|
9371
|
-
const edits = distance(word, candidate);
|
|
9372
|
-
return candidate.length > 1 && edits < MAX_DISTANCE && (length - edits) / length > MIN_SIMILARITY;
|
|
9373
|
-
}
|
|
9374
|
-
/** The names closest to `word`, sorted, several when they tie, or none when nothing is close. */
|
|
9375
|
-
function closestNames(word, names) {
|
|
9376
|
-
const close = [...new Set(names)].filter((candidate) => isClose(word, candidate));
|
|
9377
|
-
const best = Math.min(...close.map((candidate) => distance(word, candidate)));
|
|
9378
|
-
return close.filter((candidate) => distance(word, candidate) === best).sort((a, b) => a.localeCompare(b));
|
|
9379
|
-
}
|
|
9380
|
-
/** The long flags closest to `flag`, sorted, or none for a short flag or when nothing is close. */
|
|
9381
|
-
function closestFlags(flag, flags) {
|
|
9382
|
-
if (!flag.startsWith("--")) return [];
|
|
9383
|
-
const names = flags.map((candidate) => candidate.slice(2));
|
|
9384
|
-
return closestNames(flag.slice(2), names).map((name) => `--${name}`);
|
|
9385
|
-
}
|
|
9386
|
-
/** The one long flag closest to `flag`, or none when nothing is close or several tie. */
|
|
9387
|
-
function closestFlag(flag, flags) {
|
|
9388
|
-
const closest = closestFlags(flag, flags);
|
|
9389
|
-
return closest.length === 1 ? closest[0] : void 0;
|
|
9390
|
-
}
|
|
9391
|
-
//#endregion
|
|
9392
|
-
//#region ../agent-cli/dist/route.js
|
|
9393
|
-
const GROUP_FLAGS = [
|
|
9394
|
-
HELP_FLAG,
|
|
9395
|
-
VERSION_FLAG,
|
|
9396
|
-
JSON_FLAG.flag
|
|
9397
|
-
];
|
|
9398
|
-
function beforeEnd(words) {
|
|
9399
|
-
const end = words.indexOf("--");
|
|
9400
|
-
return end === -1 ? words : words.slice(0, end);
|
|
9401
|
-
}
|
|
9402
|
-
function wantsHelp(words) {
|
|
9403
|
-
return beforeEnd(words).some((word) => word === "--help" || word === "-h");
|
|
9404
|
-
}
|
|
9405
|
-
function childOf(group, name) {
|
|
9406
|
-
return Object.hasOwn(group.commands, name) ? group.commands[name] : void 0;
|
|
9407
|
-
}
|
|
9408
|
-
function isFlagLike(word) {
|
|
9409
|
-
return word.length > 1 && word[0] === "-";
|
|
9410
|
-
}
|
|
9411
|
-
function walk(node, words, json, invocation) {
|
|
9412
|
-
const help = {
|
|
9413
|
-
kind: "help",
|
|
9414
|
-
node,
|
|
9415
|
-
json
|
|
9416
|
-
};
|
|
9417
|
-
if (node.kind === "command") return wantsHelp(words) ? help : {
|
|
9418
|
-
kind: "command",
|
|
9419
|
-
spec: node,
|
|
9420
|
-
words,
|
|
9421
|
-
json
|
|
9422
|
-
};
|
|
9423
|
-
const [first, ...rest] = words;
|
|
9424
|
-
if (first === void 0) return help;
|
|
9425
|
-
const child = childOf(node, first);
|
|
9426
|
-
if (child !== void 0) return walk(child, rest, json, invocation);
|
|
9427
|
-
if (first === "--") {
|
|
9428
|
-
const [name, ...after] = rest;
|
|
9429
|
-
if (name === void 0) return help;
|
|
9430
|
-
const named = childOf(node, name);
|
|
9431
|
-
if (named !== void 0) return walk(named, ["--", ...after], json, invocation);
|
|
9432
|
-
return unknownCommand(node, name, json);
|
|
9433
|
-
}
|
|
9434
|
-
if (wantsHelp(words)) return help;
|
|
9435
|
-
if (isFlagLike(first)) {
|
|
9436
|
-
const suggestions = closestFlags(first, GROUP_FLAGS);
|
|
9437
|
-
return {
|
|
9438
|
-
kind: "usage error",
|
|
9439
|
-
error: unknownOptionError(node.commandLine, invocation, first, suggestions),
|
|
9440
|
-
node,
|
|
9441
|
-
json
|
|
9442
|
-
};
|
|
9443
|
-
}
|
|
9444
|
-
return unknownCommand(node, first, json);
|
|
9445
|
-
}
|
|
9446
|
-
function unknownCommand(group, name, json) {
|
|
9447
|
-
const suggestions = closestNames(name, Object.keys(visibleCommands(group)));
|
|
9448
|
-
return {
|
|
9449
|
-
kind: "usage error",
|
|
9450
|
-
error: unknownCommandError(group.commandLine, name, suggestions),
|
|
9451
|
-
node: group,
|
|
9452
|
-
json
|
|
10076
|
+
//#region ../agent-cli/dist/root-spec.js
|
|
10077
|
+
/** The CLI's Commands as routing and help see them, the Built-in Commands included. */
|
|
10078
|
+
function rootSpec(cli, launch) {
|
|
10079
|
+
const names = {
|
|
10080
|
+
name: cli.name,
|
|
10081
|
+
runAs: runAsOf(cli)
|
|
9453
10082
|
};
|
|
10083
|
+
return cli.commands === void 0 ? {
|
|
10084
|
+
...commandSpec(names.runAs, cli.command, {
|
|
10085
|
+
path: [],
|
|
10086
|
+
builtIn: false,
|
|
10087
|
+
names
|
|
10088
|
+
}),
|
|
10089
|
+
description: cli.description
|
|
10090
|
+
} : groupSpec(names, cli.commands, builtInCommands(cli, launch));
|
|
9454
10091
|
}
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
|
|
10092
|
+
//#endregion
|
|
10093
|
+
//#region ../agent-cli/dist/command-errors.js
|
|
10094
|
+
/**
|
|
10095
|
+
* `error`, or a bug naming each Error table code in it that the Command does not declare in its
|
|
10096
|
+
* `errors`. Runtime codes are never in the table, and a built-in's failures, `doctor` rows'
|
|
10097
|
+
* included, belong to no declaration, so both pass.
|
|
10098
|
+
*/
|
|
10099
|
+
function checkedCodes(error, { command, path, builtIn }, cli) {
|
|
10100
|
+
if (builtIn) return error;
|
|
10101
|
+
const table = errorTableOf(cli);
|
|
10102
|
+
const declared = new Set(command.errors ?? []);
|
|
10103
|
+
const undeclared = errorsOf(error).flatMap((leaf) => leaf instanceof CliError && Object.hasOwn(table, leaf.code) && !declared.has(leaf.code) ? [leaf.code] : []);
|
|
10104
|
+
if (undeclared.length === 0) return error;
|
|
10105
|
+
const label = commandLabel(path, cli.name).join(" ");
|
|
10106
|
+
const codes = [...new Set(undeclared)].join(", ");
|
|
10107
|
+
return new Error(`\`${label}\` threw ${codes}, which its errors do not declare`, { cause: error });
|
|
9465
10108
|
}
|
|
9466
10109
|
//#endregion
|
|
9467
|
-
//#region ../agent-cli/dist/
|
|
9468
|
-
|
|
9469
|
-
|
|
9470
|
-
|
|
9471
|
-
|
|
9472
|
-
|
|
10110
|
+
//#region ../agent-cli/dist/context/operator.js
|
|
10111
|
+
const NEEDS_OPERATOR = "NEEDS_OPERATOR";
|
|
10112
|
+
/** Fails with `NEEDS_OPERATOR` when a Coding agent runs an Operator Command. */
|
|
10113
|
+
function checkOperator({ operator, commandLine }, env, rerun) {
|
|
10114
|
+
if (!operator || !isAgent(env)) return;
|
|
10115
|
+
throw new CliError({
|
|
10116
|
+
code: NEEDS_OPERATOR,
|
|
10117
|
+
message: `\`${commandLine}\` must be run by a person at a terminal, not a Coding agent`,
|
|
10118
|
+
hint: "ask the operator to type ! then the Next step",
|
|
10119
|
+
next: [rerun]
|
|
10120
|
+
});
|
|
9473
10121
|
}
|
|
9474
|
-
|
|
9475
|
-
|
|
9476
|
-
|
|
10122
|
+
//#endregion
|
|
10123
|
+
//#region ../agent-cli/dist/context/spill.js
|
|
10124
|
+
const STDOUT_BUDGET_CHARS = 3e4;
|
|
10125
|
+
const SPILL_RETENTION_MS = 6048e5;
|
|
10126
|
+
const PREVIEW_CHARS = 2e3;
|
|
10127
|
+
const SPILL_FILE = /^\d{4}-\d\d-\d\dT\d\d-\d\d-\d\d\.\d{3}Z-.+\.(json|txt)$/;
|
|
10128
|
+
function spillName(now, label, json) {
|
|
10129
|
+
return `${new Date(now).toISOString().replaceAll(":", "-")}-${label.join("-")}.${json ? "json" : "txt"}`;
|
|
9477
10130
|
}
|
|
9478
|
-
function
|
|
9479
|
-
|
|
9480
|
-
|
|
9481
|
-
|
|
9482
|
-
|
|
9483
|
-
}
|
|
9484
|
-
const outputs = command.outputs?.(plan);
|
|
9485
|
-
const cost = command.cost?.(plan);
|
|
9486
|
-
return {
|
|
9487
|
-
value: {
|
|
9488
|
-
plan,
|
|
9489
|
-
...outputs === void 0 ? {} : { outputs },
|
|
9490
|
-
...command.cost === void 0 ? {} : { cost: cost ?? null }
|
|
9491
|
-
},
|
|
9492
|
-
render: (style) => [
|
|
9493
|
-
renderPlan(style),
|
|
9494
|
-
...outputs === void 0 || outputs.length === 0 ? [] : ["outputs:", ...outputs.map((path) => ` ${path}`)],
|
|
9495
|
-
...cost === void 0 ? [] : [`cost: ${cost}`]
|
|
9496
|
-
].join("\n")
|
|
9497
|
-
};
|
|
10131
|
+
async function pruneOne(path, cutoff) {
|
|
10132
|
+
try {
|
|
10133
|
+
if ((await stat(path)).mtimeMs < cutoff) await rm(path, { force: true });
|
|
10134
|
+
} catch (error) {
|
|
10135
|
+
if (!isMissingFile(error)) throw error;
|
|
10136
|
+
}
|
|
9498
10137
|
}
|
|
9499
|
-
function
|
|
9500
|
-
const
|
|
9501
|
-
|
|
10138
|
+
async function pruneOld(folder, cutoff) {
|
|
10139
|
+
const names = (await readdir(folder)).filter((name) => SPILL_FILE.test(name));
|
|
10140
|
+
await Promise.all(names.map((name) => pruneOne(join(folder, name), cutoff)));
|
|
9502
10141
|
}
|
|
9503
|
-
async function
|
|
9504
|
-
|
|
9505
|
-
|
|
9506
|
-
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
|
|
9510
|
-
|
|
9511
|
-
let end = () => {};
|
|
9512
|
-
const ended = new Promise((resolve) => {
|
|
9513
|
-
end = resolve;
|
|
10142
|
+
async function prepare(folder, cutoff, target) {
|
|
10143
|
+
try {
|
|
10144
|
+
await mkdir(folder, { recursive: true });
|
|
10145
|
+
await pruneOld(folder, cutoff);
|
|
10146
|
+
} catch (error) {
|
|
10147
|
+
throw target.fileError(error, {
|
|
10148
|
+
path: folder,
|
|
10149
|
+
access: "write"
|
|
9514
10150
|
});
|
|
9515
|
-
const outcome = outcomeOf(await command.start(input, serveContextOf(ctx, end)), (value, style) => command.render(value, style));
|
|
9516
|
-
await started(outcome);
|
|
9517
|
-
await Promise.race([ended, untilAborted(ctx.signal)]);
|
|
9518
|
-
return outcome;
|
|
9519
10151
|
}
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
const
|
|
9523
|
-
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
|
|
9527
|
-
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
10152
|
+
}
|
|
10153
|
+
function tempRoot(env) {
|
|
10154
|
+
const { TMPDIR } = env;
|
|
10155
|
+
return TMPDIR === void 0 || TMPDIR === "" ? tmpdir() : TMPDIR;
|
|
10156
|
+
}
|
|
10157
|
+
function spillTo(target) {
|
|
10158
|
+
return async (printed, json) => {
|
|
10159
|
+
if (printed.length <= STDOUT_BUDGET_CHARS) return printed;
|
|
10160
|
+
const now = target.clock.now();
|
|
10161
|
+
const folder = join(tempRoot(target.env), target.cliName);
|
|
10162
|
+
await prepare(folder, now - SPILL_RETENTION_MS, target);
|
|
10163
|
+
const file = join(folder, spillName(now, target.label, json));
|
|
10164
|
+
await target.files.write(file, printed);
|
|
10165
|
+
const bytes = Buffer.byteLength(printed);
|
|
10166
|
+
const preview = printed.slice(0, PREVIEW_CHARS);
|
|
10167
|
+
return json ? `${JSON.stringify({
|
|
10168
|
+
file,
|
|
10169
|
+
bytes,
|
|
10170
|
+
preview
|
|
10171
|
+
})}\n` : `file: ${file}\nbytes: ${bytes}\npreview:\n${preview}\n`;
|
|
10172
|
+
};
|
|
10173
|
+
}
|
|
10174
|
+
//#endregion
|
|
10175
|
+
//#region ../../node_modules/.pnpm/@toon-format+toon@4.4.0/node_modules/@toon-format/toon/dist/index.mjs
|
|
10176
|
+
const NULL_LITERAL = "null";
|
|
10177
|
+
const DELIMITERS = {
|
|
10178
|
+
comma: ",",
|
|
10179
|
+
tab: " ",
|
|
10180
|
+
pipe: "|"
|
|
10181
|
+
};
|
|
10182
|
+
const DEFAULT_DELIMITER = DELIMITERS.comma;
|
|
10183
|
+
/**
|
|
10184
|
+
* Escapes special characters in a string for encoding.
|
|
10185
|
+
*
|
|
10186
|
+
* @remarks
|
|
10187
|
+
* Control characters outside `\n`, `\r`, `\t`, `\\`, and `"` are emitted as `\uXXXX`.
|
|
10188
|
+
*/
|
|
10189
|
+
function escapeString(value) {
|
|
10190
|
+
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")}`);
|
|
10191
|
+
}
|
|
10192
|
+
function isBooleanOrNullLiteral(token) {
|
|
10193
|
+
return token === "true" || token === "false" || token === "null";
|
|
10194
|
+
}
|
|
10195
|
+
/**
|
|
10196
|
+
* Assigns an own data property without invoking inherited accessors.
|
|
10197
|
+
*
|
|
10198
|
+
* @remarks
|
|
10199
|
+
* Plain assignment of `__proto__` would hit the `Object.prototype` setter and
|
|
10200
|
+
* corrupt the prototype chain; `defineProperty` avoids that but is markedly
|
|
10201
|
+
* slower, so every other key takes plain assignment.
|
|
10202
|
+
*/
|
|
10203
|
+
function setOwnProperty(target, key, value) {
|
|
10204
|
+
if (key === "__proto__") {
|
|
10205
|
+
Object.defineProperty(target, key, {
|
|
10206
|
+
value,
|
|
10207
|
+
enumerable: true,
|
|
10208
|
+
writable: true,
|
|
10209
|
+
configurable: true
|
|
10210
|
+
});
|
|
10211
|
+
return;
|
|
9546
10212
|
}
|
|
9547
|
-
|
|
10213
|
+
target[key] = value;
|
|
9548
10214
|
}
|
|
9549
|
-
const
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
|
|
10215
|
+
const COMMENT_LINE_PATTERN = new RegExp(`(?:^?|\\n) *#`);
|
|
10216
|
+
/**
|
|
10217
|
+
* Pre-formatted string that the encoder emits verbatim at a primitive value
|
|
10218
|
+
* position, bypassing quoting, escaping, and number/keyword detection.
|
|
10219
|
+
*
|
|
10220
|
+
* Returned from a replacer for an object or array value, it is ignored and
|
|
10221
|
+
* the container is encoded normally.
|
|
10222
|
+
*/
|
|
10223
|
+
var RawString = class {
|
|
10224
|
+
constructor(value) {
|
|
10225
|
+
if (COMMENT_LINE_PATTERN.test(value)) throw new TypeError(`Raw string must not contain a line starting with "#": ${JSON.stringify(value)}`);
|
|
10226
|
+
this.value = value;
|
|
10227
|
+
}
|
|
10228
|
+
};
|
|
10229
|
+
function isRawString(value) {
|
|
10230
|
+
return value instanceof RawString;
|
|
10231
|
+
}
|
|
10232
|
+
const SURROGATE_PATTERN = /[\uD800-\uDFFF]/;
|
|
10233
|
+
function normalizeValue(value) {
|
|
10234
|
+
if (value === null) return null;
|
|
10235
|
+
if (isRawString(value)) return value;
|
|
10236
|
+
if (typeof value === "object" && value !== null && "toJSON" in value && typeof value.toJSON === "function") {
|
|
10237
|
+
const next = value.toJSON();
|
|
10238
|
+
if (next !== value) return normalizeValue(next);
|
|
10239
|
+
}
|
|
10240
|
+
if (typeof value === "string") {
|
|
10241
|
+
assertNoLoneSurrogate(value, "string value");
|
|
10242
|
+
return value;
|
|
10243
|
+
}
|
|
10244
|
+
if (typeof value === "boolean") return value;
|
|
10245
|
+
if (typeof value === "number") {
|
|
10246
|
+
if (Object.is(value, -0)) return 0;
|
|
10247
|
+
if (!Number.isFinite(value)) return null;
|
|
10248
|
+
return value;
|
|
10249
|
+
}
|
|
10250
|
+
if (typeof value === "bigint") {
|
|
10251
|
+
if (value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER) return Number(value);
|
|
10252
|
+
return value.toString();
|
|
10253
|
+
}
|
|
10254
|
+
if (value instanceof Date) return value.toISOString();
|
|
10255
|
+
if (Array.isArray(value)) return Array.from(value, normalizeValue);
|
|
10256
|
+
if (value instanceof Set) return Array.from(value).map(normalizeValue);
|
|
10257
|
+
if (value instanceof Map) return Object.fromEntries(Array.from(value, ([k, v]) => [String(k), normalizeValue(v)]));
|
|
10258
|
+
if (isPlainObject(value)) {
|
|
10259
|
+
const encodedValues = {};
|
|
10260
|
+
for (const key in value) if (Object.hasOwn(value, key)) {
|
|
10261
|
+
assertNoLoneSurrogate(key, "object key");
|
|
10262
|
+
setOwnProperty(encodedValues, key, normalizeValue(value[key]));
|
|
10263
|
+
}
|
|
10264
|
+
return encodedValues;
|
|
10265
|
+
}
|
|
10266
|
+
return null;
|
|
10267
|
+
}
|
|
10268
|
+
function assertNoLoneSurrogate(value, context) {
|
|
10269
|
+
if (!SURROGATE_PATTERN.test(value)) return;
|
|
10270
|
+
for (let index = 0; index < value.length; index++) {
|
|
10271
|
+
const code = value.charCodeAt(index);
|
|
10272
|
+
if (code < 55296 || code > 57343) continue;
|
|
10273
|
+
const isHighSurrogate = code <= 56319;
|
|
10274
|
+
const next = value.charCodeAt(index + 1);
|
|
10275
|
+
if (isHighSurrogate && next >= 56320 && next <= 57343) {
|
|
10276
|
+
index++;
|
|
10277
|
+
continue;
|
|
10278
|
+
}
|
|
10279
|
+
throw new TypeError(`Cannot encode ${context} containing an unpaired surrogate U+${code.toString(16).toUpperCase()} at index ${index}`);
|
|
9557
10280
|
}
|
|
9558
|
-
const parsed = manifestSchema.safeParse(manifest);
|
|
9559
|
-
return parsed.success ? parsed.data : NO_MANIFEST;
|
|
9560
10281
|
}
|
|
9561
|
-
|
|
9562
|
-
|
|
9563
|
-
const NO_INPUT = object({});
|
|
9564
|
-
const WHITESPACE = /\s/;
|
|
9565
|
-
function knownFlags(spec) {
|
|
9566
|
-
return [...spec.options.map((field) => ({
|
|
9567
|
-
flag: field.label,
|
|
9568
|
-
takes: field.type === "boolean" ? "nothing" : "optional value"
|
|
9569
|
-
})), ...spec.standardFlags.map(({ flag, takes }) => ({
|
|
9570
|
-
flag,
|
|
9571
|
-
takes
|
|
9572
|
-
}))];
|
|
10282
|
+
function isJsonPrimitive(value) {
|
|
10283
|
+
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
9573
10284
|
}
|
|
9574
|
-
function
|
|
9575
|
-
return
|
|
9576
|
-
...known.map(({ flag }) => flag),
|
|
9577
|
-
VERSION_FLAG,
|
|
9578
|
-
HELP_FLAG
|
|
9579
|
-
];
|
|
10285
|
+
function isEncodablePrimitive(value) {
|
|
10286
|
+
return isJsonPrimitive(value) || isRawString(value);
|
|
9580
10287
|
}
|
|
9581
|
-
function
|
|
9582
|
-
return
|
|
9583
|
-
const flag = word.split("=")[0] ?? word;
|
|
9584
|
-
return {
|
|
9585
|
-
flag,
|
|
9586
|
-
suggestion: closestFlag(flag, candidates)
|
|
9587
|
-
};
|
|
9588
|
-
});
|
|
10288
|
+
function isJsonArray(value) {
|
|
10289
|
+
return Array.isArray(value);
|
|
9589
10290
|
}
|
|
9590
|
-
function
|
|
9591
|
-
|
|
9592
|
-
const raw = all?.[all.length - 1];
|
|
9593
|
-
return field.type === "boolean" && raw === true && field.label === `--no-${field.name}` ? false : raw;
|
|
10291
|
+
function isJsonObject(value) {
|
|
10292
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && !isRawString(value);
|
|
9594
10293
|
}
|
|
9595
|
-
function
|
|
9596
|
-
|
|
9597
|
-
if (field.type !== "number" || typeof raw !== "string" || raw.trim() === "") return raw;
|
|
9598
|
-
const number = Number(raw);
|
|
9599
|
-
return Number.isNaN(number) ? raw : number;
|
|
10294
|
+
function isEmptyObject(value) {
|
|
10295
|
+
return Object.keys(value).length === 0;
|
|
9600
10296
|
}
|
|
9601
|
-
function
|
|
9602
|
-
|
|
10297
|
+
function isPlainObject(value) {
|
|
10298
|
+
if (value === null || typeof value !== "object") return false;
|
|
10299
|
+
const prototype = Object.getPrototypeOf(value);
|
|
10300
|
+
return prototype === null || prototype === Object.prototype;
|
|
9603
10301
|
}
|
|
9604
|
-
function
|
|
9605
|
-
|
|
9606
|
-
return schema.safeParse(input);
|
|
10302
|
+
function isArrayOfPrimitives(value) {
|
|
10303
|
+
return value.length === 0 || value.every((item) => isEncodablePrimitive(item));
|
|
9607
10304
|
}
|
|
9608
|
-
function
|
|
9609
|
-
|
|
9610
|
-
return result.error.issues.flatMap((issue) => {
|
|
9611
|
-
const field = [...values.keys()].find((candidate) => candidate.key === issue.path[0]);
|
|
9612
|
-
if (field === void 0) return [` ${issue.message}`];
|
|
9613
|
-
if (reported.includes(field)) return [];
|
|
9614
|
-
const raw = values.get(field);
|
|
9615
|
-
if (raw === void 0) return [` ${field.label}: required, ${howToPass(field)}`];
|
|
9616
|
-
if (field === fromStdin) return [` ${field.label} from stdin: ${issue.message}`];
|
|
9617
|
-
return Array.isArray(raw) ? [arrayIssueLine(field, raw, issue)] : [` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`];
|
|
9618
|
-
});
|
|
10305
|
+
function isArrayOfArrays(value) {
|
|
10306
|
+
return value.length === 0 || value.every((item) => isJsonArray(item));
|
|
9619
10307
|
}
|
|
9620
|
-
function
|
|
9621
|
-
|
|
9622
|
-
if (typeof element === "number") return ` ${field.label} ${JSON.stringify(raw[element])}: ${issue.message}`;
|
|
9623
|
-
return raw.length === 0 ? ` ${field.label}: ${issue.message}, pass ${field.usage}` : ` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`;
|
|
10308
|
+
function isArrayOfObjects(value) {
|
|
10309
|
+
return value.length === 0 || value.every((item) => isJsonObject(item));
|
|
9624
10310
|
}
|
|
9625
|
-
|
|
9626
|
-
|
|
9627
|
-
|
|
9628
|
-
|
|
10311
|
+
const NUMERIC_LIKE_PATTERN = /^[+-]?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i;
|
|
10312
|
+
/** Narrows an arbitrary delimiter option, shared by the library and the CLI so both report it alike. */
|
|
10313
|
+
function assertValidDelimiter(delimiter) {
|
|
10314
|
+
if (!Object.values(DELIMITERS).includes(delimiter)) throw new TypeError(`Invalid delimiter ${JSON.stringify(delimiter)}. Valid delimiters are: comma (,), tab (\\t), pipe (|)`);
|
|
9629
10315
|
}
|
|
9630
|
-
|
|
9631
|
-
|
|
10316
|
+
/**
|
|
10317
|
+
* Checks if a key can be used without quotes.
|
|
10318
|
+
*
|
|
10319
|
+
* @remarks
|
|
10320
|
+
* Valid unquoted keys must start with a letter or underscore,
|
|
10321
|
+
* followed by letters, digits, underscores, or dots.
|
|
10322
|
+
*/
|
|
10323
|
+
function isValidUnquotedKey(key) {
|
|
10324
|
+
return /^[A-Z_][\w.]*$/i.test(key);
|
|
10325
|
+
}
|
|
10326
|
+
/** Determines if a string value can be safely encoded without quotes. */
|
|
10327
|
+
function isSafeUnquoted(value, delimiter = DEFAULT_DELIMITER) {
|
|
10328
|
+
if (!value) return false;
|
|
10329
|
+
if (/^[ \t]|[ \t]$/.test(value)) return false;
|
|
10330
|
+
if (isBooleanOrNullLiteral(value) || isNumericLike(value)) return false;
|
|
10331
|
+
if (value.includes(":")) return false;
|
|
10332
|
+
if (value.includes("\"") || value.includes("\\")) return false;
|
|
10333
|
+
if (/[[\]{}]/.test(value)) return false;
|
|
10334
|
+
if (/[\u0000-\u001F]/.test(value)) return false;
|
|
10335
|
+
if (value.includes(delimiter)) return false;
|
|
10336
|
+
if (value.startsWith("-")) return false;
|
|
10337
|
+
if (value.startsWith("#")) return false;
|
|
10338
|
+
return true;
|
|
9632
10339
|
}
|
|
9633
|
-
function
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9638
|
-
|
|
9639
|
-
|
|
9640
|
-
|
|
9641
|
-
|
|
9642
|
-
|
|
9643
|
-
|
|
9644
|
-
|
|
10340
|
+
function isNumericLike(value) {
|
|
10341
|
+
return NUMERIC_LIKE_PATTERN.test(value);
|
|
10342
|
+
}
|
|
10343
|
+
function encodePrimitive(value, delimiter) {
|
|
10344
|
+
if (isRawString(value)) return value.value;
|
|
10345
|
+
if (value === null) return NULL_LITERAL;
|
|
10346
|
+
if (typeof value === "boolean") return String(value);
|
|
10347
|
+
if (typeof value === "number") return String(value);
|
|
10348
|
+
return encodeStringLiteral(value, delimiter);
|
|
10349
|
+
}
|
|
10350
|
+
function encodeStringLiteral(value, delimiter = DEFAULT_DELIMITER) {
|
|
10351
|
+
if (isSafeUnquoted(value, delimiter)) return value;
|
|
10352
|
+
return `"${escapeString(value)}"`;
|
|
10353
|
+
}
|
|
10354
|
+
function encodeKey(key) {
|
|
10355
|
+
if (isValidUnquotedKey(key)) return key;
|
|
10356
|
+
return `"${escapeString(key)}"`;
|
|
10357
|
+
}
|
|
10358
|
+
function encodeAndJoinPrimitives(values, delimiter = DEFAULT_DELIMITER) {
|
|
10359
|
+
return values.map((v) => encodePrimitive(v, delimiter)).join(delimiter);
|
|
10360
|
+
}
|
|
10361
|
+
function formatHeader(length, options) {
|
|
10362
|
+
const key = options?.key;
|
|
10363
|
+
const fields = options?.fields;
|
|
10364
|
+
const delimiter = options?.delimiter ?? ",";
|
|
10365
|
+
let header = "";
|
|
10366
|
+
if (key != null) header += encodeKey(key);
|
|
10367
|
+
header += `[${length}${options?.keyed ? ":" : ""}${delimiter !== DEFAULT_DELIMITER ? delimiter : ""}]`;
|
|
10368
|
+
if (fields) header += `{${formatFieldSegment(fields, delimiter)}}`;
|
|
10369
|
+
header += ":";
|
|
10370
|
+
return header;
|
|
10371
|
+
}
|
|
10372
|
+
function formatFieldSegment(fields, delimiter) {
|
|
10373
|
+
return fields.map((field) => encodeKey(field.name) + (field.children ? `{${formatFieldSegment(field.children, delimiter)}}` : "")).join(delimiter);
|
|
10374
|
+
}
|
|
10375
|
+
/** Classifies rows into a tabular field list, or undefined when they are not uniformly tabular. */
|
|
10376
|
+
function extractTabularFields(rows) {
|
|
10377
|
+
if (rows.length === 0) return;
|
|
10378
|
+
const firstKeys = Object.keys(rows[0]);
|
|
10379
|
+
if (firstKeys.length === 0) return;
|
|
10380
|
+
for (const row of rows) {
|
|
10381
|
+
if (Object.keys(row).length !== firstKeys.length) return;
|
|
10382
|
+
for (const key of firstKeys) if (!Object.hasOwn(row, key)) return;
|
|
10383
|
+
}
|
|
10384
|
+
const fieldNodes = [];
|
|
10385
|
+
for (const key of firstKeys) {
|
|
10386
|
+
const fieldNode = classifyColumn(key, rows.map((row) => row[key]));
|
|
10387
|
+
if (!fieldNode) return;
|
|
10388
|
+
fieldNodes.push(fieldNode);
|
|
10389
|
+
}
|
|
10390
|
+
return fieldNodes;
|
|
10391
|
+
}
|
|
10392
|
+
/** Classifies an object's values as a keyed tabular field list (>=2 uniform non-empty object entries), or undefined. */
|
|
10393
|
+
function extractKeyedTabularFields(value) {
|
|
10394
|
+
const entryValues = Object.values(value);
|
|
10395
|
+
if (entryValues.length < 2) return;
|
|
10396
|
+
if (!entryValues.every((entryValue) => isJsonObject(entryValue) && !isEmptyObject(entryValue))) return;
|
|
10397
|
+
return extractTabularFields(entryValues);
|
|
10398
|
+
}
|
|
10399
|
+
/** Reads one row's leaf cells in the field order `extractTabularFields` produced. */
|
|
10400
|
+
function collectRowLeaves(row, fields) {
|
|
10401
|
+
const leaves = [];
|
|
10402
|
+
collectLeafValues(row, fields, leaves);
|
|
10403
|
+
return leaves;
|
|
10404
|
+
}
|
|
10405
|
+
function classifyColumn(name, values) {
|
|
10406
|
+
if (values.every((value) => isEncodablePrimitive(value))) return { name };
|
|
10407
|
+
if (!values.every((value) => isJsonObject(value) && !isEmptyObject(value))) return;
|
|
10408
|
+
const children = extractTabularFields(values);
|
|
10409
|
+
if (!children) return;
|
|
10410
|
+
return {
|
|
10411
|
+
name,
|
|
10412
|
+
children
|
|
10413
|
+
};
|
|
9645
10414
|
}
|
|
9646
|
-
function
|
|
9647
|
-
const
|
|
9648
|
-
|
|
10415
|
+
function collectLeafValues(row, fields, leaves) {
|
|
10416
|
+
for (const field of fields) {
|
|
10417
|
+
const value = row[field.name];
|
|
10418
|
+
if (field.children) collectLeafValues(value, field.children, leaves);
|
|
10419
|
+
else leaves.push(value);
|
|
10420
|
+
}
|
|
9649
10421
|
}
|
|
9650
|
-
|
|
9651
|
-
|
|
9652
|
-
|
|
10422
|
+
function* encodeJsonValue(value, options, depth) {
|
|
10423
|
+
if (isEncodablePrimitive(value)) {
|
|
10424
|
+
const encodedPrimitive = typeof value === "string" && value.startsWith("") ? `"${escapeString(value)}"` : encodePrimitive(value, options.delimiter);
|
|
10425
|
+
if (encodedPrimitive !== "") yield encodedPrimitive;
|
|
10426
|
+
return;
|
|
10427
|
+
}
|
|
10428
|
+
if (isJsonArray(value)) yield* encodeArrayLines(void 0, value, depth, options);
|
|
10429
|
+
else if (isJsonObject(value)) {
|
|
10430
|
+
const keyedFields = extractKeyedTabularFields(value);
|
|
10431
|
+
if (keyedFields) {
|
|
10432
|
+
yield* encodeKeyedObjectLines(void 0, value, keyedFields, depth, options);
|
|
10433
|
+
return;
|
|
10434
|
+
}
|
|
10435
|
+
yield* encodeObjectLines(value, depth, options);
|
|
10436
|
+
}
|
|
9653
10437
|
}
|
|
9654
|
-
|
|
9655
|
-
const
|
|
9656
|
-
return field === void 0 ? void 0 : {
|
|
9657
|
-
field,
|
|
9658
|
-
text: await read(field)
|
|
9659
|
-
};
|
|
10438
|
+
function* encodeObjectLines(value, depth, options) {
|
|
10439
|
+
for (const [key, val] of Object.entries(value)) yield* encodeKeyValuePairLines(key, val, depth, options);
|
|
9660
10440
|
}
|
|
9661
|
-
|
|
9662
|
-
const
|
|
9663
|
-
|
|
9664
|
-
|
|
9665
|
-
|
|
9666
|
-
|
|
9667
|
-
|
|
9668
|
-
|
|
9669
|
-
|
|
9670
|
-
|
|
9671
|
-
|
|
9672
|
-
|
|
9673
|
-
}
|
|
9674
|
-
|
|
9675
|
-
|
|
9676
|
-
const
|
|
9677
|
-
|
|
9678
|
-
|
|
9679
|
-
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
|
|
9683
|
-
|
|
9684
|
-
|
|
9685
|
-
|
|
9686
|
-
const
|
|
9687
|
-
|
|
9688
|
-
|
|
9689
|
-
|
|
9690
|
-
|
|
9691
|
-
|
|
9692
|
-
|
|
9693
|
-
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
|
|
9702
|
-
|
|
9703
|
-
|
|
9704
|
-
|
|
9705
|
-
|
|
9706
|
-
|
|
9707
|
-
|
|
9708
|
-
|
|
9709
|
-
|
|
9710
|
-
|
|
9711
|
-
|
|
10441
|
+
function* encodeKeyValuePairLines(key, value, depth, options) {
|
|
10442
|
+
const encodedKey = encodeKey(key);
|
|
10443
|
+
if (isEncodablePrimitive(value)) yield indentedLine(depth, `${encodedKey}: ${encodePrimitive(value, options.delimiter)}`, options.indentSize);
|
|
10444
|
+
else if (isJsonArray(value)) yield* encodeArrayLines(key, value, depth, options);
|
|
10445
|
+
else if (isJsonObject(value)) {
|
|
10446
|
+
const keyedFields = extractKeyedTabularFields(value);
|
|
10447
|
+
if (keyedFields) {
|
|
10448
|
+
yield* encodeKeyedObjectLines(key, value, keyedFields, depth, options);
|
|
10449
|
+
return;
|
|
10450
|
+
}
|
|
10451
|
+
yield indentedLine(depth, `${encodedKey}:`, options.indentSize);
|
|
10452
|
+
if (!isEmptyObject(value)) yield* encodeObjectLines(value, depth + 1, options);
|
|
10453
|
+
}
|
|
10454
|
+
}
|
|
10455
|
+
function* encodeKeyedObjectLines(key, value, fields, depth, options) {
|
|
10456
|
+
const entries = Object.entries(value);
|
|
10457
|
+
yield indentedLine(depth, formatHeader(entries.length, {
|
|
10458
|
+
key,
|
|
10459
|
+
fields,
|
|
10460
|
+
delimiter: options.delimiter,
|
|
10461
|
+
keyed: true
|
|
10462
|
+
}), options.indentSize);
|
|
10463
|
+
yield* encodeKeyedEntryRowsLines(entries, fields, depth + 1, options);
|
|
10464
|
+
}
|
|
10465
|
+
function* encodeKeyedEntryRowsLines(entries, fields, depth, options) {
|
|
10466
|
+
for (const [entryKey, entryValue] of entries) {
|
|
10467
|
+
const leaves = collectRowLeaves(entryValue, fields);
|
|
10468
|
+
yield indentedLine(depth, `${encodeKey(entryKey)}: ${encodeAndJoinPrimitives(leaves, options.delimiter)}`, options.indentSize);
|
|
10469
|
+
}
|
|
10470
|
+
}
|
|
10471
|
+
function* encodeArrayLines(key, value, depth, options) {
|
|
10472
|
+
if (value.length === 0) {
|
|
10473
|
+
yield indentedLine(depth, key != null ? `${encodeKey(key)}: []` : "[]", options.indentSize);
|
|
10474
|
+
return;
|
|
10475
|
+
}
|
|
10476
|
+
if (isArrayOfPrimitives(value)) {
|
|
10477
|
+
yield indentedLine(depth, encodeInlineArrayLine(value, options.delimiter, key), options.indentSize);
|
|
10478
|
+
return;
|
|
10479
|
+
}
|
|
10480
|
+
if (isArrayOfArrays(value)) {
|
|
10481
|
+
if (value.every((arr) => isArrayOfPrimitives(arr))) {
|
|
10482
|
+
yield* encodeArrayOfArraysAsListItemsLines(key, value, depth, options);
|
|
10483
|
+
return;
|
|
10484
|
+
}
|
|
10485
|
+
}
|
|
10486
|
+
if (isArrayOfObjects(value)) {
|
|
10487
|
+
const fields = extractTabularFields(value);
|
|
10488
|
+
if (fields) yield* encodeArrayOfObjectsAsTabularLines(key, value, fields, depth, options);
|
|
10489
|
+
else yield* encodeMixedArrayAsListItemsLines(key, value, depth, options);
|
|
10490
|
+
return;
|
|
10491
|
+
}
|
|
10492
|
+
yield* encodeMixedArrayAsListItemsLines(key, value, depth, options);
|
|
10493
|
+
}
|
|
10494
|
+
function* encodeArrayOfArraysAsListItemsLines(prefix, values, depth, options) {
|
|
10495
|
+
yield indentedLine(depth, formatHeader(values.length, {
|
|
10496
|
+
key: prefix,
|
|
10497
|
+
delimiter: options.delimiter
|
|
10498
|
+
}), options.indentSize);
|
|
10499
|
+
for (const arr of values) if (isArrayOfPrimitives(arr)) {
|
|
10500
|
+
const arrayLine = encodeInlineArrayLine(arr, options.delimiter);
|
|
10501
|
+
yield indentedListItem(depth + 1, arrayLine, options.indentSize);
|
|
10502
|
+
}
|
|
10503
|
+
}
|
|
10504
|
+
function encodeInlineArrayLine(values, delimiter, prefix) {
|
|
10505
|
+
const header = formatHeader(values.length, {
|
|
10506
|
+
key: prefix,
|
|
10507
|
+
delimiter
|
|
10508
|
+
});
|
|
10509
|
+
const joinedValue = encodeAndJoinPrimitives(values, delimiter);
|
|
10510
|
+
if (values.length === 0) return header;
|
|
10511
|
+
return `${header} ${joinedValue}`;
|
|
10512
|
+
}
|
|
10513
|
+
function* encodeArrayOfObjectsAsTabularLines(prefix, rows, fields, depth, options) {
|
|
10514
|
+
yield indentedLine(depth, formatHeader(rows.length, {
|
|
10515
|
+
key: prefix,
|
|
10516
|
+
fields,
|
|
10517
|
+
delimiter: options.delimiter
|
|
10518
|
+
}), options.indentSize);
|
|
10519
|
+
yield* writeTabularRowsLines(rows, fields, depth + 1, options);
|
|
10520
|
+
}
|
|
10521
|
+
function* writeTabularRowsLines(rows, fields, depth, options) {
|
|
10522
|
+
for (const row of rows) yield indentedLine(depth, encodeAndJoinPrimitives(collectRowLeaves(row, fields), options.delimiter), options.indentSize);
|
|
10523
|
+
}
|
|
10524
|
+
function* encodeMixedArrayAsListItemsLines(prefix, items, depth, options) {
|
|
10525
|
+
yield indentedLine(depth, formatHeader(items.length, {
|
|
10526
|
+
key: prefix,
|
|
10527
|
+
delimiter: options.delimiter
|
|
10528
|
+
}), options.indentSize);
|
|
10529
|
+
for (const item of items) yield* encodeListItemValueLines(item, depth + 1, options);
|
|
10530
|
+
}
|
|
10531
|
+
function* encodeObjectAsListItemLines(obj, depth, options) {
|
|
10532
|
+
if (isEmptyObject(obj)) {
|
|
10533
|
+
yield indentedLine(depth, "-", options.indentSize);
|
|
10534
|
+
return;
|
|
10535
|
+
}
|
|
10536
|
+
const entries = Object.entries(obj);
|
|
10537
|
+
const [firstKey, firstValue] = entries[0];
|
|
10538
|
+
const restEntries = entries.slice(1);
|
|
10539
|
+
if (isJsonArray(firstValue) && isArrayOfObjects(firstValue)) {
|
|
10540
|
+
const fields = extractTabularFields(firstValue);
|
|
10541
|
+
if (fields) {
|
|
10542
|
+
yield indentedListItem(depth, formatHeader(firstValue.length, {
|
|
10543
|
+
key: firstKey,
|
|
10544
|
+
fields,
|
|
10545
|
+
delimiter: options.delimiter
|
|
10546
|
+
}), options.indentSize);
|
|
10547
|
+
yield* writeTabularRowsLines(firstValue, fields, depth + 2, options);
|
|
10548
|
+
if (restEntries.length > 0) yield* encodeObjectLines(Object.fromEntries(restEntries), depth + 1, options);
|
|
10549
|
+
return;
|
|
10550
|
+
}
|
|
10551
|
+
}
|
|
10552
|
+
if (isJsonObject(firstValue)) {
|
|
10553
|
+
const keyedFields = extractKeyedTabularFields(firstValue);
|
|
10554
|
+
if (keyedFields) {
|
|
10555
|
+
const keyedEntries = Object.entries(firstValue);
|
|
10556
|
+
yield indentedListItem(depth, formatHeader(keyedEntries.length, {
|
|
10557
|
+
key: firstKey,
|
|
10558
|
+
fields: keyedFields,
|
|
10559
|
+
delimiter: options.delimiter,
|
|
10560
|
+
keyed: true
|
|
10561
|
+
}), options.indentSize);
|
|
10562
|
+
yield* encodeKeyedEntryRowsLines(keyedEntries, keyedFields, depth + 2, options);
|
|
10563
|
+
if (restEntries.length > 0) yield* encodeObjectLines(Object.fromEntries(restEntries), depth + 1, options);
|
|
10564
|
+
return;
|
|
10565
|
+
}
|
|
10566
|
+
}
|
|
10567
|
+
const encodedKey = encodeKey(firstKey);
|
|
10568
|
+
if (isEncodablePrimitive(firstValue)) yield indentedListItem(depth, `${encodedKey}: ${encodePrimitive(firstValue, options.delimiter)}`, options.indentSize);
|
|
10569
|
+
else if (isJsonArray(firstValue)) {
|
|
10570
|
+
if (firstValue.length === 0) yield indentedListItem(depth, `${encodedKey}: []`, options.indentSize);
|
|
10571
|
+
else if (isArrayOfPrimitives(firstValue)) yield indentedListItem(depth, `${encodedKey}${encodeInlineArrayLine(firstValue, options.delimiter)}`, options.indentSize);
|
|
10572
|
+
else {
|
|
10573
|
+
yield indentedListItem(depth, `${encodedKey}${formatHeader(firstValue.length, { delimiter: options.delimiter })}`, options.indentSize);
|
|
10574
|
+
for (const item of firstValue) yield* encodeListItemValueLines(item, depth + 2, options);
|
|
10575
|
+
}
|
|
10576
|
+
} else if (isJsonObject(firstValue)) {
|
|
10577
|
+
yield indentedListItem(depth, `${encodedKey}:`, options.indentSize);
|
|
10578
|
+
if (!isEmptyObject(firstValue)) yield* encodeObjectLines(firstValue, depth + 2, options);
|
|
10579
|
+
}
|
|
10580
|
+
if (restEntries.length > 0) yield* encodeObjectLines(Object.fromEntries(restEntries), depth + 1, options);
|
|
10581
|
+
}
|
|
10582
|
+
function* encodeListItemValueLines(value, depth, options) {
|
|
10583
|
+
if (isEncodablePrimitive(value)) yield indentedListItem(depth, encodePrimitive(value, options.delimiter), options.indentSize);
|
|
10584
|
+
else if (isJsonArray(value)) {
|
|
10585
|
+
if (isArrayOfPrimitives(value)) yield indentedListItem(depth, encodeInlineArrayLine(value, options.delimiter), options.indentSize);
|
|
10586
|
+
else {
|
|
10587
|
+
yield indentedListItem(depth, formatHeader(value.length, { delimiter: options.delimiter }), options.indentSize);
|
|
10588
|
+
for (const item of value) yield* encodeListItemValueLines(item, depth + 1, options);
|
|
10589
|
+
}
|
|
10590
|
+
} else if (isJsonObject(value)) yield* encodeObjectAsListItemLines(value, depth, options);
|
|
10591
|
+
}
|
|
10592
|
+
function indentedLine(depth, content, indentSize) {
|
|
10593
|
+
return " ".repeat(indentSize * depth) + content;
|
|
10594
|
+
}
|
|
10595
|
+
function indentedListItem(depth, content, indentSize) {
|
|
10596
|
+
return indentedLine(depth, "- " + content, indentSize);
|
|
9712
10597
|
}
|
|
9713
10598
|
/**
|
|
9714
|
-
*
|
|
9715
|
-
*
|
|
10599
|
+
* Applies a replacer function to a `JsonValue` and all its descendants.
|
|
10600
|
+
*
|
|
10601
|
+
* The replacer is called for the root (key='', path=[]), every object property
|
|
10602
|
+
* (key = property name), and every array element (key = string index).
|
|
9716
10603
|
*/
|
|
9717
|
-
|
|
9718
|
-
const
|
|
9719
|
-
|
|
9720
|
-
return
|
|
9721
|
-
input,
|
|
9722
|
-
flags: {
|
|
9723
|
-
json,
|
|
9724
|
-
dryRun: values.get(DRY_RUN_FLAG.flag) === true,
|
|
9725
|
-
confirm: typeof confirm === "string" ? confirm : void 0,
|
|
9726
|
-
yes: values.get(YES_FLAG.flag) === true,
|
|
9727
|
-
force: values.get(FORCE_FLAG.flag) === true,
|
|
9728
|
-
page,
|
|
9729
|
-
fields: spec.list === void 0 ? void 0 : selectedFields(values, spec.list.rowFields, spec.commandLine)
|
|
9730
|
-
}
|
|
9731
|
-
};
|
|
10604
|
+
function applyReplacer(root, replacer) {
|
|
10605
|
+
const replacedRoot = replacer("", root, []);
|
|
10606
|
+
if (replacedRoot === void 0) return transformChildren(root, replacer, []);
|
|
10607
|
+
return transformReplaced(root, replacedRoot, replacer, []);
|
|
9732
10608
|
}
|
|
9733
|
-
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9737
|
-
|
|
9738
|
-
|
|
10609
|
+
/**
|
|
10610
|
+
* Resolves a replacer's (non-`undefined`) return value at a single position.
|
|
10611
|
+
*
|
|
10612
|
+
* A `RawString` only stands in for a primitive: returned for an object or
|
|
10613
|
+
* array value, it is ignored and the original container is traversed normally.
|
|
10614
|
+
*/
|
|
10615
|
+
function transformReplaced(original, replaced, replacer, path) {
|
|
10616
|
+
if (isRawString(replaced) && !isEncodablePrimitive(original)) return transformChildren(original, replacer, path);
|
|
10617
|
+
return transformChildren(normalizeValue(replaced), replacer, path);
|
|
9739
10618
|
}
|
|
9740
|
-
function
|
|
9741
|
-
|
|
9742
|
-
|
|
9743
|
-
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
|
|
10619
|
+
function transformChildren(value, replacer, path) {
|
|
10620
|
+
if (isJsonObject(value)) return transformObject(value, replacer, path);
|
|
10621
|
+
if (isJsonArray(value)) return transformArray(value, replacer, path);
|
|
10622
|
+
return value;
|
|
10623
|
+
}
|
|
10624
|
+
function transformObject(obj, replacer, path) {
|
|
10625
|
+
const result = {};
|
|
10626
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
10627
|
+
const childPath = [...path, key];
|
|
10628
|
+
const replacedValue = replacer(key, value, childPath);
|
|
10629
|
+
if (replacedValue === void 0) continue;
|
|
10630
|
+
setOwnProperty(result, key, transformReplaced(value, replacedValue, replacer, childPath));
|
|
9750
10631
|
}
|
|
9751
|
-
return
|
|
10632
|
+
return result;
|
|
9752
10633
|
}
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9756
|
-
|
|
9757
|
-
|
|
9758
|
-
|
|
10634
|
+
function transformArray(arr, replacer, path) {
|
|
10635
|
+
const result = [];
|
|
10636
|
+
for (let i = 0; i < arr.length; i++) {
|
|
10637
|
+
const value = arr[i];
|
|
10638
|
+
const childPath = [...path, i];
|
|
10639
|
+
const replacedValue = replacer(String(i), value, childPath);
|
|
10640
|
+
if (replacedValue === void 0) continue;
|
|
10641
|
+
result.push(transformReplaced(value, replacedValue, replacer, childPath));
|
|
10642
|
+
}
|
|
10643
|
+
return result;
|
|
10644
|
+
}
|
|
10645
|
+
/**
|
|
10646
|
+
* Encodes a JavaScript value into TOON format string.
|
|
10647
|
+
*
|
|
10648
|
+
* @example
|
|
10649
|
+
* ```ts
|
|
10650
|
+
* encode({ name: 'Ada', age: 30 })
|
|
10651
|
+
* // name: Ada
|
|
10652
|
+
* // age: 30
|
|
10653
|
+
*
|
|
10654
|
+
* encode({ users: [{ id: 1 }, { id: 2 }] })
|
|
10655
|
+
* // users[2]{id}:
|
|
10656
|
+
* // 1
|
|
10657
|
+
* // 2
|
|
10658
|
+
*
|
|
10659
|
+
* encode({ tags: [] })
|
|
10660
|
+
* // tags: []
|
|
10661
|
+
*
|
|
10662
|
+
* encode(data, { indentSize: 4 })
|
|
10663
|
+
* ```
|
|
10664
|
+
*/
|
|
10665
|
+
function encode(input, options) {
|
|
10666
|
+
return Array.from(encodeLines(input, options)).join("\n");
|
|
10667
|
+
}
|
|
10668
|
+
/**
|
|
10669
|
+
* Encodes a JavaScript value into TOON format as a sequence of lines.
|
|
10670
|
+
*
|
|
10671
|
+
* This function yields TOON lines one at a time without building the full string,
|
|
10672
|
+
* making it suitable for streaming large outputs to files, HTTP responses, or process stdout.
|
|
10673
|
+
*
|
|
10674
|
+
* @example
|
|
10675
|
+
* ```ts
|
|
10676
|
+
* // Stream to stdout
|
|
10677
|
+
* for (const line of encodeLines({ name: 'Ada', age: 30 })) {
|
|
10678
|
+
* console.log(line)
|
|
10679
|
+
* }
|
|
10680
|
+
*
|
|
10681
|
+
* // Collect to array
|
|
10682
|
+
* const lines = Array.from(encodeLines(data))
|
|
10683
|
+
*
|
|
10684
|
+
* // Equivalent to encode()
|
|
10685
|
+
* const toonString = Array.from(encodeLines(data, options)).join('\n')
|
|
10686
|
+
* ```
|
|
10687
|
+
*/
|
|
10688
|
+
function encodeLines(input, options) {
|
|
10689
|
+
const normalizedValue = normalizeValue(input);
|
|
10690
|
+
const resolvedOptions = resolveOptions(options);
|
|
10691
|
+
return encodeJsonValue(resolvedOptions.replacer ? applyReplacer(normalizedValue, resolvedOptions.replacer) : normalizedValue, resolvedOptions, 0);
|
|
10692
|
+
}
|
|
10693
|
+
function resolveOptions(options) {
|
|
10694
|
+
const delimiter = options?.delimiter ?? DEFAULT_DELIMITER;
|
|
10695
|
+
assertValidDelimiter(delimiter);
|
|
10696
|
+
return {
|
|
10697
|
+
indentSize: options?.indentSize ?? options?.indent ?? 2,
|
|
10698
|
+
delimiter,
|
|
10699
|
+
replacer: options?.replacer
|
|
9759
10700
|
};
|
|
9760
|
-
const fromFile = readDotenv(envFile, fileError)[name];
|
|
9761
|
-
return fromFile ? {
|
|
9762
|
-
value: fromFile,
|
|
9763
|
-
origin: {
|
|
9764
|
-
kind: "file",
|
|
9765
|
-
path: envFile
|
|
9766
|
-
}
|
|
9767
|
-
} : void 0;
|
|
9768
10701
|
}
|
|
9769
10702
|
//#endregion
|
|
9770
|
-
//#region ../agent-cli/dist/
|
|
9771
|
-
|
|
9772
|
-
const
|
|
9773
|
-
|
|
9774
|
-
|
|
9775
|
-
|
|
10703
|
+
//#region ../agent-cli/dist/context/confirm.js
|
|
10704
|
+
const CONFIRMATION_REQUIRED = "CONFIRMATION_REQUIRED";
|
|
10705
|
+
const CONFIRMATION_MISMATCH = "CONFIRMATION_MISMATCH";
|
|
10706
|
+
function checkConfirmation({ rerun, commandLine, given }, expected) {
|
|
10707
|
+
if (given === expected) return;
|
|
10708
|
+
const advice = {
|
|
10709
|
+
hint: "to confirm, run the Next step",
|
|
10710
|
+
next: [rerun({
|
|
10711
|
+
remove: [CONFIRM_FLAG.flag],
|
|
10712
|
+
add: [CONFIRM_FLAG.flag, expected]
|
|
10713
|
+
})]
|
|
10714
|
+
};
|
|
10715
|
+
if (given === void 0) throw new UsageError({
|
|
10716
|
+
code: CONFIRMATION_REQUIRED,
|
|
10717
|
+
message: `\`${commandLine}\` is destructive and needs ${CONFIRM_FLAG.flag}`,
|
|
10718
|
+
...advice
|
|
10719
|
+
});
|
|
10720
|
+
throw new UsageError({
|
|
10721
|
+
code: CONFIRMATION_MISMATCH,
|
|
10722
|
+
message: `${CONFIRM_FLAG.flag} ${JSON.stringify(given)} does not match the target of \`${commandLine}\``,
|
|
10723
|
+
...advice
|
|
10724
|
+
});
|
|
9776
10725
|
}
|
|
9777
|
-
|
|
9778
|
-
|
|
9779
|
-
|
|
9780
|
-
|
|
9781
|
-
|
|
9782
|
-
|
|
10726
|
+
//#endregion
|
|
10727
|
+
//#region ../agent-cli/dist/context/cost.js
|
|
10728
|
+
const NOT_CONFIRMED = "NOT_CONFIRMED";
|
|
10729
|
+
/** Refuses a run whose Plan states a cost the caller has not approved with `--yes`. */
|
|
10730
|
+
function checkCost({ rerun, commandLine, yes }, cost) {
|
|
10731
|
+
if (cost === void 0 || yes) return;
|
|
10732
|
+
throw new CliError({
|
|
10733
|
+
code: NOT_CONFIRMED,
|
|
10734
|
+
message: `\`${commandLine}\` needs ${YES_FLAG.flag}: ${cost}`,
|
|
10735
|
+
hint: "to approve the cost, run the Next step",
|
|
10736
|
+
next: [rerun({ add: [YES_FLAG.flag] })]
|
|
9783
10737
|
});
|
|
9784
|
-
return async () => {
|
|
9785
|
-
const waited = new AbortController();
|
|
9786
|
-
const capped = new Promise((resolve) => after(clock, SIDE_TASK_WAIT_MS, waited.signal, () => {
|
|
9787
|
-
const over = waitOver();
|
|
9788
|
-
failed(over);
|
|
9789
|
-
controller.abort(over);
|
|
9790
|
-
resolve();
|
|
9791
|
-
}));
|
|
9792
|
-
await Promise.race([running, capped]);
|
|
9793
|
-
waited.abort();
|
|
9794
|
-
};
|
|
9795
10738
|
}
|
|
9796
10739
|
//#endregion
|
|
9797
|
-
//#region ../agent-cli/dist/
|
|
9798
|
-
const
|
|
9799
|
-
|
|
9800
|
-
|
|
9801
|
-
|
|
9802
|
-
|
|
9803
|
-
|
|
10740
|
+
//#region ../agent-cli/dist/execute.js
|
|
10741
|
+
const PLAN_INDENT = " ";
|
|
10742
|
+
function outcomeOf(value, render) {
|
|
10743
|
+
return {
|
|
10744
|
+
value,
|
|
10745
|
+
render: (style) => render(value, style)
|
|
10746
|
+
};
|
|
9804
10747
|
}
|
|
9805
|
-
|
|
9806
|
-
|
|
9807
|
-
|
|
9808
|
-
|
|
9809
|
-
|
|
9810
|
-
|
|
10748
|
+
/**
|
|
10749
|
+
* The data a Command returned or delivered as it prints it: parsed by its `output` schema when it
|
|
10750
|
+
* declares one, so data the schema rejects fails the run as a bug.
|
|
10751
|
+
*/
|
|
10752
|
+
function dataOutcome(command, data, commandLine) {
|
|
10753
|
+
const render = command.render ?? ((value) => value === void 0 ? "" : encode(value));
|
|
10754
|
+
if (command.rows !== void 0 || command.output === void 0) return outcomeOf(data, render);
|
|
10755
|
+
const parsed = command.output.safeParse(data);
|
|
10756
|
+
if (!parsed.success) throw new Error(`\`${commandLine}\` produced data its output schema rejects:\n${prettifyError(parsed.error)}`);
|
|
10757
|
+
return outcomeOf(parsed.data, render);
|
|
10758
|
+
}
|
|
10759
|
+
function indented(text) {
|
|
10760
|
+
return text.split("\n").map((line) => `${PLAN_INDENT}${line}`).join("\n");
|
|
10761
|
+
}
|
|
10762
|
+
function dryRunOutcome(command, plan, commandLine) {
|
|
10763
|
+
const renderPlan = (style) => command.renderPlan === void 0 ? `Would run ${commandLine}:\n${indented(encode(plan))}` : command.renderPlan(plan, style);
|
|
10764
|
+
if (command.outputs === void 0 && command.cost === void 0) return {
|
|
10765
|
+
value: plan,
|
|
10766
|
+
render: renderPlan
|
|
10767
|
+
};
|
|
10768
|
+
const outputs = command.outputs?.(plan);
|
|
10769
|
+
const cost = command.cost?.(plan);
|
|
10770
|
+
return {
|
|
10771
|
+
value: {
|
|
10772
|
+
plan,
|
|
10773
|
+
...outputs === void 0 ? {} : { outputs },
|
|
10774
|
+
...command.cost === void 0 ? {} : { cost: cost ?? null }
|
|
10775
|
+
},
|
|
10776
|
+
render: (style) => [
|
|
10777
|
+
renderPlan(style),
|
|
10778
|
+
...outputs === void 0 || outputs.length === 0 ? [] : ["outputs:", ...outputs.map((path) => ` ${path}`)],
|
|
10779
|
+
...cost === void 0 ? [] : [`cost: ${cost}`]
|
|
10780
|
+
].join("\n")
|
|
10781
|
+
};
|
|
9811
10782
|
}
|
|
9812
|
-
|
|
9813
|
-
const
|
|
9814
|
-
|
|
10783
|
+
function serveContextOf(ctx, end) {
|
|
10784
|
+
const serveCtx = Object.create(ctx);
|
|
10785
|
+
return Object.assign(serveCtx, { end });
|
|
9815
10786
|
}
|
|
9816
|
-
async function
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
|
|
9821
|
-
|
|
9822
|
-
|
|
9823
|
-
|
|
10787
|
+
async function execute(command, input, ctx, { dryRun, confirm, yes, page, commandLine, started, files, guardOutputs }) {
|
|
10788
|
+
await checkTools(command.tools ?? [], ctx.env, ctx.rerun());
|
|
10789
|
+
const { env, envFile, fileError } = ctx;
|
|
10790
|
+
checkSecrets(command.secrets ?? [], {
|
|
10791
|
+
env,
|
|
10792
|
+
envFile,
|
|
10793
|
+
fileError
|
|
10794
|
+
}, ctx.rerun());
|
|
10795
|
+
if (command.rows !== void 0) {
|
|
10796
|
+
const { render } = command;
|
|
10797
|
+
return outcomeOf(await command.run({
|
|
10798
|
+
...input,
|
|
10799
|
+
...page
|
|
10800
|
+
}, ctx), (data, style) => render === void 0 ? encode(data.items) : render(data, style));
|
|
10801
|
+
}
|
|
10802
|
+
if (command.effect === "read" || command.effect === "act") return dataOutcome(command, await command.run(input, ctx), commandLine);
|
|
10803
|
+
if (command.effect === "serve") {
|
|
10804
|
+
let end = () => {};
|
|
10805
|
+
const ended = new Promise((resolve) => {
|
|
10806
|
+
end = resolve;
|
|
9824
10807
|
});
|
|
10808
|
+
const outcome = dataOutcome(command, await command.start(input, serveContextOf(ctx, end)), commandLine);
|
|
10809
|
+
await started(outcome);
|
|
10810
|
+
await Promise.race([ended, untilAborted(ctx.signal)]);
|
|
10811
|
+
return outcome;
|
|
9825
10812
|
}
|
|
10813
|
+
const plan = await command.plan(input, ctx);
|
|
10814
|
+
if (dryRun) return dryRunOutcome(command, plan, commandLine);
|
|
10815
|
+
const outputs = command.outputs?.(plan);
|
|
10816
|
+
await checkOutputs({
|
|
10817
|
+
rerun: ctx.rerun,
|
|
10818
|
+
commandLine,
|
|
10819
|
+
force: ctx.force,
|
|
10820
|
+
files: ctx.files
|
|
10821
|
+
}, outputs);
|
|
10822
|
+
checkCost({
|
|
10823
|
+
rerun: ctx.rerun,
|
|
10824
|
+
commandLine,
|
|
10825
|
+
yes
|
|
10826
|
+
}, command.cost?.(plan));
|
|
10827
|
+
if (command.effect === "destructive") checkConfirmation({
|
|
10828
|
+
rerun: ctx.rerun,
|
|
10829
|
+
commandLine,
|
|
10830
|
+
given: confirm
|
|
10831
|
+
}, command.confirm(plan));
|
|
10832
|
+
if (outputs !== void 0) {
|
|
10833
|
+
await probeOutputs({
|
|
10834
|
+
files,
|
|
10835
|
+
cwd: ctx.cwd,
|
|
10836
|
+
fileError: ctx.fileError
|
|
10837
|
+
}, outputs);
|
|
10838
|
+
if (!ctx.force) guardOutputs(outputs, ctx.rerun({ add: [FORCE_FLAG.flag] }));
|
|
10839
|
+
}
|
|
10840
|
+
return dataOutcome(command, await command.apply(plan, ctx), commandLine);
|
|
9826
10841
|
}
|
|
9827
|
-
|
|
9828
|
-
|
|
9829
|
-
|
|
9830
|
-
|
|
9831
|
-
|
|
9832
|
-
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
9837
|
-
|
|
9838
|
-
await target.files.write(file, printed);
|
|
9839
|
-
const bytes = Buffer.byteLength(printed);
|
|
9840
|
-
const preview = printed.slice(0, PREVIEW_CHARS);
|
|
9841
|
-
return json ? `${JSON.stringify({
|
|
9842
|
-
file,
|
|
9843
|
-
bytes,
|
|
9844
|
-
preview
|
|
9845
|
-
})}\n` : `file: ${file}\nbytes: ${bytes}\npreview:\n${preview}\n`;
|
|
9846
|
-
};
|
|
10842
|
+
const manifestSchema = object({ bugs: union([string(), object({ url: string() })]).transform((value) => typeof value === "string" ? value : value.url).optional().catch(void 0) });
|
|
10843
|
+
const NO_MANIFEST = {};
|
|
10844
|
+
function manifestAt(packageRoot) {
|
|
10845
|
+
let manifest;
|
|
10846
|
+
try {
|
|
10847
|
+
manifest = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
|
|
10848
|
+
} catch {
|
|
10849
|
+
return NO_MANIFEST;
|
|
10850
|
+
}
|
|
10851
|
+
const parsed = manifestSchema.safeParse(manifest);
|
|
10852
|
+
return parsed.success ? parsed.data : NO_MANIFEST;
|
|
9847
10853
|
}
|
|
9848
10854
|
//#endregion
|
|
9849
10855
|
//#region ../agent-cli/dist/run-command.js
|
|
9850
10856
|
function stdinNeverEndedHint(callerLine) {
|
|
9851
10857
|
return `stdin never ended: pipe the text into \`${callerLine}\`, or redirect a file into it`;
|
|
9852
10858
|
}
|
|
10859
|
+
function runDeadlineAdvice(resumed, pipedLine) {
|
|
10860
|
+
return resumed === void 0 ? { hint: stdinNeverEndedHint(pipedLine) } : {
|
|
10861
|
+
hint: "run the Next step to continue the work",
|
|
10862
|
+
next: [resumed]
|
|
10863
|
+
};
|
|
10864
|
+
}
|
|
9853
10865
|
function selfOf(name, bin) {
|
|
9854
10866
|
return bin === void 0 ? [name] : [
|
|
9855
10867
|
process.execPath,
|
|
@@ -9869,7 +10881,7 @@ function portsOf(cli, replacement) {
|
|
|
9869
10881
|
return cli.ports ?? (() => ({}));
|
|
9870
10882
|
}
|
|
9871
10883
|
function portsBaseOf(scope, signal) {
|
|
9872
|
-
const { cli, options, packageRoot, progress, fileError,
|
|
10884
|
+
const { cli, options, packageRoot, progress, fileError, rerun, clock, files } = scope;
|
|
9873
10885
|
const { cwd, env } = options;
|
|
9874
10886
|
const envFile = envFileOf(cli.name, env);
|
|
9875
10887
|
return {
|
|
@@ -9885,7 +10897,7 @@ function portsBaseOf(scope, signal) {
|
|
|
9885
10897
|
envFile,
|
|
9886
10898
|
fileError,
|
|
9887
10899
|
version: cli.version,
|
|
9888
|
-
build:
|
|
10900
|
+
build: buildStamp(),
|
|
9889
10901
|
self: selfOf(cli.name, options.bin),
|
|
9890
10902
|
signal,
|
|
9891
10903
|
clock,
|
|
@@ -9896,7 +10908,7 @@ function portsBaseOf(scope, signal) {
|
|
|
9896
10908
|
signal
|
|
9897
10909
|
}, {
|
|
9898
10910
|
fileError,
|
|
9899
|
-
|
|
10911
|
+
rerun
|
|
9900
10912
|
}),
|
|
9901
10913
|
spawnDetached: contextSpawnDetached(spawnDetachedOf(options), {
|
|
9902
10914
|
cwd,
|
|
@@ -9904,23 +10916,30 @@ function portsBaseOf(scope, signal) {
|
|
|
9904
10916
|
signal
|
|
9905
10917
|
}, {
|
|
9906
10918
|
fileError,
|
|
9907
|
-
|
|
10919
|
+
rerun
|
|
9908
10920
|
})
|
|
9909
10921
|
};
|
|
9910
10922
|
}
|
|
9911
10923
|
function contextOf(portsBase, control, parts) {
|
|
9912
|
-
const { ports, project, force,
|
|
10924
|
+
const { ports, project, force, secrets = [], rerun, deliver, notice } = parts;
|
|
10925
|
+
const declared = new Set(secrets.map(({ name }) => name));
|
|
9913
10926
|
return {
|
|
9914
10927
|
...portsBase,
|
|
9915
|
-
|
|
9916
|
-
|
|
10928
|
+
secret: (name) => {
|
|
10929
|
+
if (!declared.has(name)) throw new Error(`ctx.secret("${name}") names a Secret the Command does not declare`);
|
|
10930
|
+
const secret = portsBase.secret(name);
|
|
10931
|
+
if (secret === void 0) throw new Error(`ctx.secret("${name}") found no value`);
|
|
10932
|
+
return secret;
|
|
10933
|
+
},
|
|
10934
|
+
fail: cliErrorOf,
|
|
10935
|
+
deadline: (ms, options) => control.deadline(ms, options),
|
|
9917
10936
|
runToEnd: (name, work) => control.runToEnd(name, work),
|
|
9918
10937
|
get ports() {
|
|
9919
10938
|
return ports();
|
|
9920
10939
|
},
|
|
9921
10940
|
project,
|
|
9922
10941
|
force,
|
|
9923
|
-
|
|
10942
|
+
rerun,
|
|
9924
10943
|
poll: (check, { intervalMs, signal: stop }) => poll(portsBase.clock, check, intervalMs, stop === void 0 ? control.signal : AbortSignal.any([control.signal, stop])),
|
|
9925
10944
|
deliver,
|
|
9926
10945
|
notice
|
|
@@ -9942,10 +10961,14 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
9942
10961
|
flags: knownFlags(routed.spec),
|
|
9943
10962
|
stdinArg: stdinArgOf(routed)
|
|
9944
10963
|
};
|
|
9945
|
-
const
|
|
9946
|
-
|
|
10964
|
+
const rerunOf = (change) => ({
|
|
10965
|
+
kind: "rerun",
|
|
10966
|
+
words: changedArgv(invocation, change),
|
|
10967
|
+
stdinArg: invocation.stdinArg
|
|
10968
|
+
});
|
|
10969
|
+
const rerun = rerunOf();
|
|
9947
10970
|
const fileError = fileErrorOf({
|
|
9948
|
-
|
|
10971
|
+
rerun,
|
|
9949
10972
|
env,
|
|
9950
10973
|
platform
|
|
9951
10974
|
});
|
|
@@ -9959,16 +10982,16 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
9959
10982
|
...invocation,
|
|
9960
10983
|
stdinArg: void 0
|
|
9961
10984
|
});
|
|
9962
|
-
let
|
|
10985
|
+
let resumed;
|
|
9963
10986
|
const control = new RunControl({
|
|
9964
10987
|
commandLine,
|
|
9965
|
-
|
|
10988
|
+
rerun,
|
|
9966
10989
|
outer: options.signal,
|
|
9967
10990
|
clock,
|
|
9968
10991
|
progress,
|
|
9969
10992
|
runDeadline: command.deadline === void 0 ? void 0 : {
|
|
9970
10993
|
ms: command.deadline.ms,
|
|
9971
|
-
|
|
10994
|
+
advice: () => runDeadlineAdvice(resumed, pipedLine)
|
|
9972
10995
|
}
|
|
9973
10996
|
});
|
|
9974
10997
|
const failed = (error, finishSideTask) => {
|
|
@@ -9980,7 +11003,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
9980
11003
|
};
|
|
9981
11004
|
let parsed;
|
|
9982
11005
|
try {
|
|
9983
|
-
checkOperator(routed.spec, env,
|
|
11006
|
+
checkOperator(routed.spec, env, rerun);
|
|
9984
11007
|
parsed = await parseCommand(routed, invocation, (field) => {
|
|
9985
11008
|
if (isTerminal(stdin)) progress(readingLine(field.name, platform));
|
|
9986
11009
|
return readStdin(stdin, control.signal, {
|
|
@@ -9992,7 +11015,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
9992
11015
|
return failed(error, noSideTask);
|
|
9993
11016
|
}
|
|
9994
11017
|
const { input, flags } = parsed;
|
|
9995
|
-
|
|
11018
|
+
resumed = command.deadline?.resume(input, rerunOf);
|
|
9996
11019
|
const outputs = outputsGuard(classifiedFiles(files, {
|
|
9997
11020
|
cwd,
|
|
9998
11021
|
fileError
|
|
@@ -10003,7 +11026,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10003
11026
|
packageRoot,
|
|
10004
11027
|
progress,
|
|
10005
11028
|
fileError,
|
|
10006
|
-
|
|
11029
|
+
rerun,
|
|
10007
11030
|
clock,
|
|
10008
11031
|
files: outputs.files
|
|
10009
11032
|
};
|
|
@@ -10029,7 +11052,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10029
11052
|
try {
|
|
10030
11053
|
project = builtIn || cli.project === void 0 ? void 0 : projectOf(cli.project, cwd, {
|
|
10031
11054
|
fileError,
|
|
10032
|
-
|
|
11055
|
+
rerun
|
|
10033
11056
|
});
|
|
10034
11057
|
} catch (error) {
|
|
10035
11058
|
return failed(error, finishSideTask);
|
|
@@ -10039,15 +11062,16 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10039
11062
|
ports: once(() => ports(portsBase)),
|
|
10040
11063
|
project,
|
|
10041
11064
|
force: flags.force,
|
|
10042
|
-
|
|
11065
|
+
secrets: command.secrets,
|
|
11066
|
+
rerun: rerunOf,
|
|
10043
11067
|
notice: (text) => write.stderr(noticeLine(text, routed.json)),
|
|
10044
11068
|
deliver: (data) => {
|
|
10045
|
-
delivered =
|
|
11069
|
+
delivered = () => dataOutcome(command, data, commandLine);
|
|
10046
11070
|
}
|
|
10047
11071
|
});
|
|
10048
11072
|
const spill = spillTo({
|
|
10049
11073
|
cliName: format.cliName,
|
|
10050
|
-
|
|
11074
|
+
label: commandLabel(routed.spec.path, format.cliName),
|
|
10051
11075
|
env,
|
|
10052
11076
|
clock,
|
|
10053
11077
|
files: outputs.files,
|
|
@@ -10056,7 +11080,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10056
11080
|
let served = false;
|
|
10057
11081
|
let settled;
|
|
10058
11082
|
try {
|
|
10059
|
-
const outcome = await control.settle(skillOf(cli, installOf(cli)).notice({
|
|
11083
|
+
const outcome = await control.settle(skillOf$1(cli, installOf(cli)).notice({
|
|
10060
11084
|
builtIn,
|
|
10061
11085
|
bin: options.bin
|
|
10062
11086
|
}, ctx).then(() => execute(command, input, ctx, {
|
|
@@ -10064,7 +11088,6 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10064
11088
|
confirm: flags.confirm,
|
|
10065
11089
|
yes: flags.yes,
|
|
10066
11090
|
page: flags.page,
|
|
10067
|
-
invocation,
|
|
10068
11091
|
commandLine,
|
|
10069
11092
|
started: async (outcome) => {
|
|
10070
11093
|
write.stdout(await startedOutput(outcome, format, spill));
|
|
@@ -10088,7 +11111,7 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
10088
11111
|
};
|
|
10089
11112
|
settled = {
|
|
10090
11113
|
ok: false,
|
|
10091
|
-
error: control.errorAfter(error),
|
|
11114
|
+
error: checkedCodes(control.errorAfter(error), routed.spec, cli),
|
|
10092
11115
|
delivered
|
|
10093
11116
|
};
|
|
10094
11117
|
}
|
|
@@ -10172,6 +11195,10 @@ async function runWithProgress(cli, argv, options, write, stopNotice) {
|
|
|
10172
11195
|
}
|
|
10173
11196
|
async function routeAndRun(cli, argv, options, write, stopNotice) {
|
|
10174
11197
|
const runAs = runAsOf(cli);
|
|
11198
|
+
const root = rootSpec(cli, {
|
|
11199
|
+
bin: options.bin,
|
|
11200
|
+
node: options.node
|
|
11201
|
+
});
|
|
10175
11202
|
const format = {
|
|
10176
11203
|
cliName: cli.name,
|
|
10177
11204
|
env: options.env,
|
|
@@ -10182,16 +11209,10 @@ async function routeAndRun(cli, argv, options, write, stopNotice) {
|
|
|
10182
11209
|
flags: []
|
|
10183
11210
|
},
|
|
10184
11211
|
json: false,
|
|
10185
|
-
errors: cli
|
|
10186
|
-
stop: options.signal
|
|
11212
|
+
errors: errorTableOf(cli),
|
|
11213
|
+
stop: options.signal,
|
|
11214
|
+
...options.checkNextSteps === true ? { checkNextStep: (step) => nextStepProblem(root, runAs, step) } : {}
|
|
10187
11215
|
};
|
|
10188
|
-
const root = cli.commands === void 0 ? {
|
|
10189
|
-
...commandSpec(runAs, cli.command),
|
|
10190
|
-
description: cli.description
|
|
10191
|
-
} : groupSpec(runAs, cli.commands, builtInCommands(cli, {
|
|
10192
|
-
bin: options.bin,
|
|
10193
|
-
node: options.node
|
|
10194
|
-
}));
|
|
10195
11216
|
const routed = route(root, format.invocation);
|
|
10196
11217
|
const misused = (node) => isAgent(options.env) ? {
|
|
10197
11218
|
...format,
|
|
@@ -10218,10 +11239,22 @@ async function ranAlone(result) {
|
|
|
10218
11239
|
}
|
|
10219
11240
|
//#endregion
|
|
10220
11241
|
//#region ../agent-cli/dist/run-process.js
|
|
10221
|
-
|
|
10222
|
-
|
|
11242
|
+
const READER_GONE = /* @__PURE__ */ new Set(["EPIPE", "EOF"]);
|
|
11243
|
+
function writerTo(stream) {
|
|
11244
|
+
stream.on("error", (error) => {
|
|
11245
|
+
if (error.code === void 0 || !READER_GONE.has(error.code)) throw error;
|
|
11246
|
+
});
|
|
11247
|
+
return (text) => new Promise((resolve) => {
|
|
11248
|
+
if (stream.destroyed) {
|
|
11249
|
+
resolve();
|
|
11250
|
+
return;
|
|
11251
|
+
}
|
|
11252
|
+
stream.write(text, () => resolve());
|
|
11253
|
+
});
|
|
10223
11254
|
}
|
|
10224
11255
|
async function runProcess(cli) {
|
|
11256
|
+
const stdout = writerTo(process.stdout);
|
|
11257
|
+
const stderr = writerTo(process.stderr);
|
|
10225
11258
|
const stop = new AbortController();
|
|
10226
11259
|
const onSignal = (signal) => {
|
|
10227
11260
|
if (stop.signal.aborted) process.exit(SIGNAL_EXIT_CODES[signal]);
|
|
@@ -10239,11 +11272,11 @@ async function runProcess(cli) {
|
|
|
10239
11272
|
node: process.execPath,
|
|
10240
11273
|
stdin: process.stdin
|
|
10241
11274
|
}, {
|
|
10242
|
-
stdout: (text) =>
|
|
10243
|
-
stderr: (text) =>
|
|
10244
|
-
result: async (
|
|
10245
|
-
await
|
|
10246
|
-
await
|
|
11275
|
+
stdout: (text) => void stdout(text),
|
|
11276
|
+
stderr: (text) => void stderr(text),
|
|
11277
|
+
result: async (result) => {
|
|
11278
|
+
await stdout(result.stdout);
|
|
11279
|
+
await stderr(result.stderr);
|
|
10247
11280
|
}
|
|
10248
11281
|
}, "stopping… (Ctrl-C again to quit now)");
|
|
10249
11282
|
process.exitCode = result.exitCode;
|
|
@@ -10255,16 +11288,44 @@ async function runProcess(cli) {
|
|
|
10255
11288
|
}
|
|
10256
11289
|
//#endregion
|
|
10257
11290
|
//#region package.json
|
|
10258
|
-
var
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
"
|
|
10264
|
-
"
|
|
10265
|
-
|
|
11291
|
+
var package_default = {
|
|
11292
|
+
name: "@duyquangnvx/create-agent-cli",
|
|
11293
|
+
version: "0.19.0",
|
|
11294
|
+
description: "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.",
|
|
11295
|
+
type: "module",
|
|
11296
|
+
engines: { "node": ">=22.12.0" },
|
|
11297
|
+
bin: { "create-agent-cli": "./dist/bin.js" },
|
|
11298
|
+
files: [
|
|
11299
|
+
"dist",
|
|
11300
|
+
"partials",
|
|
11301
|
+
"template",
|
|
11302
|
+
"agents-section.md",
|
|
11303
|
+
"CHANGELOG.md"
|
|
11304
|
+
],
|
|
11305
|
+
publishConfig: {
|
|
11306
|
+
"registry": "https://registry.npmjs.org/",
|
|
11307
|
+
"access": "public"
|
|
11308
|
+
},
|
|
11309
|
+
scripts: {
|
|
11310
|
+
"build": "node -e \"require('node:fs').copyFileSync('../agent-cli/agents-section.md', 'agents-section.md')\" && tsdown",
|
|
11311
|
+
"prepack": "node -e \"require('node:fs').copyFileSync('../../CHANGELOG.md', 'CHANGELOG.md')\""
|
|
11312
|
+
},
|
|
11313
|
+
devDependencies: {
|
|
11314
|
+
"@duyquangnvx/agent-cli": "workspace:*",
|
|
11315
|
+
"tsdown": "0.23.0",
|
|
11316
|
+
"zod": "4.6.7"
|
|
11317
|
+
}
|
|
10266
11318
|
};
|
|
10267
11319
|
//#endregion
|
|
11320
|
+
//#region src/agents-section.ts
|
|
11321
|
+
const AGENTS_SECTION_FILE = new URL("../agents-section.md", import.meta.url);
|
|
11322
|
+
function agentsSection() {
|
|
11323
|
+
return readFile(AGENTS_SECTION_FILE, "utf8");
|
|
11324
|
+
}
|
|
11325
|
+
//#endregion
|
|
11326
|
+
//#region src/define.ts
|
|
11327
|
+
const { defineCli, defineCommand, cliError } = agentCli({ errors: { STEP_FAILED: { class: "operator" } } });
|
|
11328
|
+
//#endregion
|
|
10268
11329
|
//#region src/fill.ts
|
|
10269
11330
|
/** `text` with each `{{key}}` replaced by its value; `quoted` escapes values that land inside a double-quoted string. */
|
|
10270
11331
|
function fill(text, values, quoted) {
|
|
@@ -10279,29 +11340,60 @@ function fill(text, values, quoted) {
|
|
|
10279
11340
|
const PARTIALS_DIR = fileURLToPath(new URL("../partials/", import.meta.url));
|
|
10280
11341
|
const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
10281
11342
|
const COMMANDS_ANCHOR = " commands: {";
|
|
10282
|
-
const GLOBAL_INSTALL = ` install:
|
|
10283
|
-
|
|
10284
|
-
|
|
10285
|
-
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
|
|
11343
|
+
const GLOBAL_INSTALL = ` install: "global",\n`;
|
|
11344
|
+
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.add` to the whole line that installs the skill 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 line of its fix, after `! `. -->";
|
|
11345
|
+
function skillHubOf({ git, api, add }) {
|
|
11346
|
+
if (git !== void 0 && api !== void 0) throw new UsageError({
|
|
11347
|
+
code: "SKILL_HOMES_CONFLICT",
|
|
11348
|
+
message: "--skill-hub-git and --skill-hub-api each name the Skill Hub the skill goes to",
|
|
11349
|
+
hint: "pass one of them"
|
|
11350
|
+
});
|
|
11351
|
+
if (api !== void 0 && add === void 0) throw new UsageError({
|
|
11352
|
+
code: "SKILL_ADD_MISSING",
|
|
11353
|
+
message: "--skill-hub-api needs --skill-add, the whole line that installs the skill from the hub",
|
|
11354
|
+
hint: "add --skill-add with the hub's install line for the skill"
|
|
11355
|
+
});
|
|
11356
|
+
if (add !== void 0 && api === void 0) throw new UsageError({
|
|
11357
|
+
code: "SKILL_HUB_API_MISSING",
|
|
11358
|
+
message: "--skill-add is the install line of an API Skill Hub, which --skill-hub-api names",
|
|
11359
|
+
hint: "add --skill-hub-api with the hub's URL"
|
|
11360
|
+
});
|
|
11361
|
+
if (add !== void 0 && (add.trim() === "" || /[\r\n]/.test(add))) throw new UsageError({
|
|
11362
|
+
code: "SKILL_ADD_INVALID",
|
|
11363
|
+
message: `--skill-add ${JSON.stringify(add)} is not one command line`,
|
|
11364
|
+
hint: "pass the hub's install line for the skill, on one line"
|
|
11365
|
+
});
|
|
11366
|
+
if (git !== void 0) return {
|
|
11367
|
+
kind: "git",
|
|
11368
|
+
url: git
|
|
11369
|
+
};
|
|
11370
|
+
return api === void 0 || add === void 0 ? void 0 : {
|
|
11371
|
+
kind: "api",
|
|
11372
|
+
url: api,
|
|
11373
|
+
add
|
|
11374
|
+
};
|
|
11375
|
+
}
|
|
11376
|
+
function installModeOf(flags, dependency, binName) {
|
|
11377
|
+
const skillHub = skillHubOf(flags);
|
|
10290
11378
|
if (skillHub !== void 0 && dependency) throw new UsageError({
|
|
10291
11379
|
code: "SKILL_HOMES_CONFLICT",
|
|
10292
|
-
message:
|
|
10293
|
-
hint:
|
|
11380
|
+
message: `--skill-hub-${skillHub.kind} and --dependency each name where the skill comes from: a Dependency install ships it inside the package`,
|
|
11381
|
+
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`
|
|
10294
11382
|
});
|
|
10295
11383
|
if ((skillHub !== void 0 || dependency) && !SKILL_NAME.test(binName)) throw new UsageError({
|
|
10296
11384
|
code: "SKILL_NAME_INVALID",
|
|
10297
11385
|
message: `${binName} cannot name a skill, whose names are lowercase letters, digits and single hyphens`,
|
|
10298
|
-
hint: `choose a name such as my-cli, or leave out ${dependency ? "--dependency" :
|
|
11386
|
+
hint: `choose a name such as my-cli, or leave out ${dependency ? "--dependency" : `--skill-hub-${skillHub?.kind}`}`
|
|
10299
11387
|
});
|
|
10300
11388
|
return dependency ? { mode: "dependency" } : {
|
|
10301
11389
|
mode: "global",
|
|
10302
11390
|
skillHub
|
|
10303
11391
|
};
|
|
10304
11392
|
}
|
|
11393
|
+
function skillLineOf(skillHub, binName) {
|
|
11394
|
+
if (skillHub === void 0) return NO_SKILL_HUB;
|
|
11395
|
+
return skillHub.kind === "git" ? `\`! npx -y skills add ${skillHub.url} --skill ${binName} -g\`` : `\`! ${skillHub.add}\``;
|
|
11396
|
+
}
|
|
10305
11397
|
async function partialsOf(mode, values) {
|
|
10306
11398
|
const partial = async (name) => fill(await readFile(join(PARTIALS_DIR, mode, `${name}.md`), "utf8"), values, false).trimEnd();
|
|
10307
11399
|
const [installLines, skillCheck, installSteps, updateSteps, sandbox] = await Promise.all([
|
|
@@ -10320,9 +11412,8 @@ async function partialsOf(mode, values) {
|
|
|
10320
11412
|
};
|
|
10321
11413
|
}
|
|
10322
11414
|
async function globalSetup(skillHub, packageName, binName) {
|
|
10323
|
-
const skillLine = skillHub
|
|
11415
|
+
const skillLine = skillLineOf(skillHub, binName);
|
|
10324
11416
|
const runAs = runAsOf({ name: binName });
|
|
10325
|
-
const url = JSON.stringify(skillHub);
|
|
10326
11417
|
return {
|
|
10327
11418
|
values: {
|
|
10328
11419
|
runAs,
|
|
@@ -10337,15 +11428,18 @@ async function globalSetup(skillHub, packageName, binName) {
|
|
|
10337
11428
|
edits: skillHub === void 0 ? [] : [{
|
|
10338
11429
|
file: "src/cli.ts",
|
|
10339
11430
|
find: COMMANDS_ANCHOR,
|
|
10340
|
-
replace: ` skill:
|
|
11431
|
+
replace: ` skill: ${skillOf(skillHub)},\n${COMMANDS_ANCHOR}`
|
|
10341
11432
|
}, {
|
|
10342
11433
|
file: "scripts/release.ts",
|
|
10343
11434
|
find: " smoke: {",
|
|
10344
|
-
replace: ` skillHub: ${url},\n smoke: {`
|
|
11435
|
+
replace: ` skillHub: { ${skillHub.kind}: ${JSON.stringify(skillHub.url)} },\n smoke: {`
|
|
10345
11436
|
}],
|
|
10346
11437
|
files: []
|
|
10347
11438
|
};
|
|
10348
11439
|
}
|
|
11440
|
+
function skillOf(skillHub) {
|
|
11441
|
+
return skillHub.kind === "git" ? `{ source: ${JSON.stringify(skillHub.url)} }` : `{ add: ${JSON.stringify(skillHub.add)} }`;
|
|
11442
|
+
}
|
|
10349
11443
|
async function dependencySetup(packageName, binName) {
|
|
10350
11444
|
const runAs = runAsOf({
|
|
10351
11445
|
name: binName,
|
|
@@ -10367,7 +11461,7 @@ async function dependencySetup(packageName, binName) {
|
|
|
10367
11461
|
edits: [{
|
|
10368
11462
|
file: "src/cli.ts",
|
|
10369
11463
|
find: GLOBAL_INSTALL,
|
|
10370
|
-
replace: ` install:
|
|
11464
|
+
replace: ` install: "dependency",\n`
|
|
10371
11465
|
}, {
|
|
10372
11466
|
file: "src/cli.ts",
|
|
10373
11467
|
find: COMMANDS_ANCHOR,
|
|
@@ -10381,7 +11475,6 @@ async function installSetupOf(install, packageName, binName) {
|
|
|
10381
11475
|
}
|
|
10382
11476
|
//#endregion
|
|
10383
11477
|
//#region src/steps.ts
|
|
10384
|
-
const stepErrors = defineErrors({ STEP_FAILED: { class: "operator" } });
|
|
10385
11478
|
const INSTALL = [{
|
|
10386
11479
|
command: "pnpm",
|
|
10387
11480
|
args: ["install"]
|
|
@@ -10450,7 +11543,7 @@ function tail(output) {
|
|
|
10450
11543
|
return output.trimEnd().split(/\r?\n/).slice(-20).join("\n");
|
|
10451
11544
|
}
|
|
10452
11545
|
function stepFailed(problem, left, cwd, cause) {
|
|
10453
|
-
return cliError(
|
|
11546
|
+
return cliError("STEP_FAILED", {
|
|
10454
11547
|
message: problem,
|
|
10455
11548
|
hint: `fix the problem, then run in ${cwd}: ${left.map(stepLine).join(" && ")}`
|
|
10456
11549
|
}, { cause });
|
|
@@ -10499,10 +11592,9 @@ async function writeTemplate(root, files, values) {
|
|
|
10499
11592
|
}
|
|
10500
11593
|
//#endregion
|
|
10501
11594
|
//#region src/version.ts
|
|
10502
|
-
const version = version
|
|
11595
|
+
const version = package_default.version;
|
|
10503
11596
|
//#endregion
|
|
10504
11597
|
//#region src/create.ts
|
|
10505
|
-
const { defineCommand } = agentCli();
|
|
10506
11598
|
const PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?([a-z0-9][a-z0-9._-]*)$/;
|
|
10507
11599
|
function errorCode(error) {
|
|
10508
11600
|
return error instanceof Error && "code" in error ? error.code : void 0;
|
|
@@ -10542,82 +11634,81 @@ async function ensureFree(path) {
|
|
|
10542
11634
|
hint: "run `create-agent-cli <name>` with a name whose directory is free, or empty it first"
|
|
10543
11635
|
});
|
|
10544
11636
|
}
|
|
10545
|
-
const create = defineCommand({
|
|
10546
|
-
name: "create",
|
|
10547
|
-
description: "Create a new Agent CLI project in ./<name>",
|
|
10548
|
-
examples: [{
|
|
10549
|
-
command: "create-agent-cli weather --description \"Weather forecasts\"",
|
|
10550
|
-
note: "create ./weather, install dependencies and make the first commit"
|
|
10551
|
-
}],
|
|
10552
|
-
effect: "write",
|
|
10553
|
-
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") }),
|
|
10554
|
-
options: object({
|
|
10555
|
-
description: string().default("An Agent CLI.").describe("one line saying what the CLI does"),
|
|
10556
|
-
install: boolean().default(true).describe("run pnpm install"),
|
|
10557
|
-
git: boolean().default(true).describe("create a git repository with an initial commit"),
|
|
10558
|
-
repository: url({ protocol: /^https$/ }).optional().describe("the https URL of the CLI's git repository"),
|
|
10559
|
-
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"),
|
|
10560
|
-
dependency: boolean().default(false).describe("install the CLI per project, as a devDependency, with its skill shipped inside the package")
|
|
10561
|
-
}),
|
|
10562
|
-
plan: async ({ name, description, install, git, repository, skillHub, dependency }, ctx) => {
|
|
10563
|
-
const binName = PACKAGE_NAME.exec(name)?.[1] ?? name;
|
|
10564
|
-
const mode = installModeOf(skillHub, dependency, binName);
|
|
10565
|
-
const path = resolve(ctx.cwd, binName);
|
|
10566
|
-
await ensureFree(path);
|
|
10567
|
-
const setup = await installSetupOf(mode, name, binName);
|
|
10568
|
-
const values = {
|
|
10569
|
-
packageName: name,
|
|
10570
|
-
binName,
|
|
10571
|
-
description,
|
|
10572
|
-
debugVariable: debugVariable(binName),
|
|
10573
|
-
runtimeVersion: version,
|
|
10574
|
-
...setup.values
|
|
10575
|
-
};
|
|
10576
|
-
return {
|
|
10577
|
-
path,
|
|
10578
|
-
values,
|
|
10579
|
-
files: await templateFiles(values),
|
|
10580
|
-
steps: stepsFor({
|
|
10581
|
-
install,
|
|
10582
|
-
git
|
|
10583
|
-
}),
|
|
10584
|
-
install,
|
|
10585
|
-
repository,
|
|
10586
|
-
edits: setup.edits,
|
|
10587
|
-
manifestFiles: setup.files
|
|
10588
|
-
};
|
|
10589
|
-
},
|
|
10590
|
-
apply: async (plan, ctx) => {
|
|
10591
|
-
await mkdir(plan.path, { recursive: true });
|
|
10592
|
-
await writeTemplate(plan.path, plan.files, plan.values);
|
|
10593
|
-
if (plan.repository !== void 0) await setRepository(plan.path, plan.repository);
|
|
10594
|
-
for (const edit of plan.edits) await applyEdit(plan.path, edit);
|
|
10595
|
-
if (plan.manifestFiles.length > 0) await addFiles(plan.path, plan.manifestFiles);
|
|
10596
|
-
await runSteps(plan.steps, plan.path, ctx);
|
|
10597
|
-
return {
|
|
10598
|
-
path: plan.path,
|
|
10599
|
-
next: `cd ${plan.values.binName} && pnpm ${plan.install ? "test" : "install"}`
|
|
10600
|
-
};
|
|
10601
|
-
},
|
|
10602
|
-
render: ({ path, next }) => `Created ${path}\nnext: ${next}`,
|
|
10603
|
-
renderPlan: (plan) => [
|
|
10604
|
-
`Would create ${plan.path}:`,
|
|
10605
|
-
...plan.files.map((file) => ` create ${file.target}`),
|
|
10606
|
-
...plan.steps.map((step) => ` run ${stepLine(step)}`)
|
|
10607
|
-
].join("\n")
|
|
10608
|
-
});
|
|
10609
|
-
//#endregion
|
|
10610
|
-
//#region src/cli.ts
|
|
10611
|
-
const { defineCli } = agentCli();
|
|
10612
11637
|
//#endregion
|
|
10613
11638
|
//#region src/bin.ts
|
|
10614
11639
|
await runProcess(defineCli({
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
10619
|
-
|
|
10620
|
-
|
|
11640
|
+
manifest: package_default,
|
|
11641
|
+
command: defineCommand({
|
|
11642
|
+
description: "Create a new Agent CLI project in ./<name>",
|
|
11643
|
+
examples: [{
|
|
11644
|
+
command: "create-agent-cli weather --description \"Weather forecasts\"",
|
|
11645
|
+
note: "create ./weather, install dependencies and make the first commit"
|
|
11646
|
+
}],
|
|
11647
|
+
effect: "write",
|
|
11648
|
+
errors: ["STEP_FAILED"],
|
|
11649
|
+
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") }),
|
|
11650
|
+
options: object({
|
|
11651
|
+
description: string().default("An Agent CLI.").describe("one line saying what the CLI does"),
|
|
11652
|
+
install: boolean().default(true).describe("run pnpm install"),
|
|
11653
|
+
git: boolean().default(true).describe("create a git repository with an initial commit"),
|
|
11654
|
+
repository: url({ protocol: /^https$/ }).optional().describe("the https URL of the CLI's git repository"),
|
|
11655
|
+
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"),
|
|
11656
|
+
skillHubApi: url({ protocol: /^https$/ }).optional().describe("the https URL of an API Skill Hub each release publishes the CLI's skill to"),
|
|
11657
|
+
skillAdd: string().optional().describe("the whole line that installs the CLI's skill from the API Skill Hub"),
|
|
11658
|
+
dependency: boolean().default(false).describe("install the CLI per project, as a devDependency, with its skill shipped inside the package")
|
|
11659
|
+
}),
|
|
11660
|
+
plan: async ({ name, description, install, git, repository, skillHubGit, skillHubApi, skillAdd, dependency }, ctx) => {
|
|
11661
|
+
const binName = PACKAGE_NAME.exec(name)?.[1] ?? name;
|
|
11662
|
+
const mode = installModeOf({
|
|
11663
|
+
git: skillHubGit,
|
|
11664
|
+
api: skillHubApi,
|
|
11665
|
+
add: skillAdd
|
|
11666
|
+
}, dependency, binName);
|
|
11667
|
+
const path = resolve(ctx.cwd, binName);
|
|
11668
|
+
await ensureFree(path);
|
|
11669
|
+
const setup = await installSetupOf(mode, name, binName);
|
|
11670
|
+
const values = {
|
|
11671
|
+
packageName: name,
|
|
11672
|
+
binName,
|
|
11673
|
+
description,
|
|
11674
|
+
debugVariable: debugVariable(binName),
|
|
11675
|
+
runtimeVersion: version,
|
|
11676
|
+
agentsSection: await agentsSection(),
|
|
11677
|
+
...setup.values
|
|
11678
|
+
};
|
|
11679
|
+
return {
|
|
11680
|
+
path,
|
|
11681
|
+
values,
|
|
11682
|
+
files: await templateFiles(values),
|
|
11683
|
+
steps: stepsFor({
|
|
11684
|
+
install,
|
|
11685
|
+
git
|
|
11686
|
+
}),
|
|
11687
|
+
install,
|
|
11688
|
+
repository,
|
|
11689
|
+
edits: setup.edits,
|
|
11690
|
+
manifestFiles: setup.files
|
|
11691
|
+
};
|
|
11692
|
+
},
|
|
11693
|
+
apply: async (plan, ctx) => {
|
|
11694
|
+
await mkdir(plan.path, { recursive: true });
|
|
11695
|
+
await writeTemplate(plan.path, plan.files, plan.values);
|
|
11696
|
+
if (plan.repository !== void 0) await setRepository(plan.path, plan.repository);
|
|
11697
|
+
for (const edit of plan.edits) await applyEdit(plan.path, edit);
|
|
11698
|
+
if (plan.manifestFiles.length > 0) await addFiles(plan.path, plan.manifestFiles);
|
|
11699
|
+
await runSteps(plan.steps, plan.path, ctx);
|
|
11700
|
+
return {
|
|
11701
|
+
path: plan.path,
|
|
11702
|
+
next: `cd ${plan.values.binName} && pnpm ${plan.install ? "test" : "install"}`
|
|
11703
|
+
};
|
|
11704
|
+
},
|
|
11705
|
+
render: ({ path, next }) => `Created ${path}\nnext: ${next}`,
|
|
11706
|
+
renderPlan: (plan) => [
|
|
11707
|
+
`Would create ${plan.path}:`,
|
|
11708
|
+
...plan.files.map((file) => ` create ${file.target}`),
|
|
11709
|
+
...plan.steps.map((step) => ` run ${stepLine(step)}`)
|
|
11710
|
+
].join("\n")
|
|
11711
|
+
})
|
|
10621
11712
|
}));
|
|
10622
11713
|
//#endregion
|
|
10623
11714
|
export {};
|