@duyquangnvx/create-agent-cli 0.20.0 → 0.22.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/dist/bin.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { constants, homedir, tmpdir } from "node:os";
|
|
2
4
|
import { parseArgs, parseEnv } from "node:util";
|
|
3
|
-
import {
|
|
4
|
-
import { constants, existsSync, readFileSync, realpathSync } from "node:fs";
|
|
5
|
-
import { constants as constants$1, homedir, tmpdir } from "node:os";
|
|
5
|
+
import { constants as constants$1, existsSync, readFileSync, realpathSync } from "node:fs";
|
|
6
6
|
import { access, chmod, link, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
7
|
-
import {
|
|
7
|
+
import { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
8
8
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
10
|
//#region ../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/util.js
|
|
@@ -5740,40 +5740,6 @@ function untilAborted(signal) {
|
|
|
5740
5740
|
});
|
|
5741
5741
|
}
|
|
5742
5742
|
//#endregion
|
|
5743
|
-
//#region ../agent-cli/dist/clock.js
|
|
5744
|
-
const realClock = {
|
|
5745
|
-
now: () => Date.now(),
|
|
5746
|
-
sleep: (ms, signal) => new Promise((resolve, reject) => {
|
|
5747
|
-
if (signal?.aborted === true) {
|
|
5748
|
-
reject(signal.reason);
|
|
5749
|
-
return;
|
|
5750
|
-
}
|
|
5751
|
-
const onAbort = () => {
|
|
5752
|
-
clearTimeout(timer);
|
|
5753
|
-
reject(signal?.reason);
|
|
5754
|
-
};
|
|
5755
|
-
const timer = setTimeout(() => {
|
|
5756
|
-
signal?.removeEventListener("abort", onAbort);
|
|
5757
|
-
resolve();
|
|
5758
|
-
}, ms);
|
|
5759
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
5760
|
-
})
|
|
5761
|
-
};
|
|
5762
|
-
/** Runs `then` once `ms` have passed on `clock`; aborting `cancel` drops it. */
|
|
5763
|
-
function after(clock, ms, cancel, then) {
|
|
5764
|
-
clock.sleep(ms, cancel).then(then, (error) => {
|
|
5765
|
-
if (!cancel.aborted) throw error;
|
|
5766
|
-
});
|
|
5767
|
-
}
|
|
5768
|
-
async function poll(clock, check, intervalMs, signal) {
|
|
5769
|
-
for (;;) {
|
|
5770
|
-
signal.throwIfAborted();
|
|
5771
|
-
const value = await check();
|
|
5772
|
-
if (value !== void 0) return value;
|
|
5773
|
-
await clock.sleep(intervalMs, signal);
|
|
5774
|
-
}
|
|
5775
|
-
}
|
|
5776
|
-
//#endregion
|
|
5777
5743
|
//#region ../agent-cli/dist/command-line/tokenize.js
|
|
5778
5744
|
const NEGATIVE_NUMBER = /^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/;
|
|
5779
5745
|
function isOptionLike(word) {
|
|
@@ -5926,6 +5892,9 @@ function wholeLine(line) {
|
|
|
5926
5892
|
function isWords(step) {
|
|
5927
5893
|
return Array.isArray(step);
|
|
5928
5894
|
}
|
|
5895
|
+
function isRerun(step) {
|
|
5896
|
+
return !isWords(step) && step.kind === "rerun";
|
|
5897
|
+
}
|
|
5929
5898
|
/** The words after the Run-as, or `undefined` for a line given whole. */
|
|
5930
5899
|
function wordsOf(step) {
|
|
5931
5900
|
if (isWords(step)) return step;
|
|
@@ -6081,1006 +6050,1081 @@ function formatRuntimeError(error, format) {
|
|
|
6081
6050
|
return errors.map((each) => errorLines(each, format)).join("");
|
|
6082
6051
|
}
|
|
6083
6052
|
//#endregion
|
|
6084
|
-
//#region ../agent-cli/dist/
|
|
6085
|
-
|
|
6086
|
-
function
|
|
6087
|
-
return
|
|
6088
|
-
}
|
|
6089
|
-
function endOfInputKeys(platform) {
|
|
6090
|
-
return platform === "win32" ? "Ctrl-Z then Enter" : "Ctrl-D";
|
|
6091
|
-
}
|
|
6092
|
-
/** The progress line shown before reading a terminal, so a person isn't left facing silence. */
|
|
6093
|
-
function readingLine(name, platform) {
|
|
6094
|
-
return `reading <${name}> from stdin; end it with ${endOfInputKeys(platform)}`;
|
|
6095
|
-
}
|
|
6096
|
-
function isTerminal(source) {
|
|
6097
|
-
return typeof source !== "string" && "isTTY" in source && source.isTTY === true;
|
|
6053
|
+
//#region ../agent-cli/dist/tail.js
|
|
6054
|
+
/** The last `count` lines of a child's output, trimmed; empty when it wrote nothing. */
|
|
6055
|
+
function lastLines(output, count) {
|
|
6056
|
+
return output.trim().split("\n").slice(-count).join("\n");
|
|
6098
6057
|
}
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
return new CliError({
|
|
6104
|
-
code: STDIN_STALLED,
|
|
6105
|
-
message: `stdin sent nothing for ${STDIN_IDLE_MS} ms`,
|
|
6106
|
-
hint: `stdin never ended: close the pipe or heredoc that feeds \`${callerLine}\`, pass the text as an argument instead, or write a slow producer's output to a file and redirect it in`
|
|
6107
|
-
});
|
|
6058
|
+
//#endregion
|
|
6059
|
+
//#region ../agent-cli/dist/define.js
|
|
6060
|
+
function isCommand(node) {
|
|
6061
|
+
return typeof node.effect === "string";
|
|
6108
6062
|
}
|
|
6063
|
+
//#endregion
|
|
6064
|
+
//#region ../agent-cli/dist/context/declared.js
|
|
6109
6065
|
/**
|
|
6110
|
-
*
|
|
6111
|
-
* `
|
|
6066
|
+
* What the CLI declares itself (`own`) and every Command under `commands` declares, each name once,
|
|
6067
|
+
* for a `doctor` row: a Command requires only its own, but `doctor` checks them all.
|
|
6112
6068
|
*/
|
|
6113
|
-
function
|
|
6114
|
-
|
|
6115
|
-
return new
|
|
6116
|
-
const chunks = [];
|
|
6117
|
-
let idleWindow = new AbortController();
|
|
6118
|
-
const watchIdle = () => {
|
|
6119
|
-
idleWindow.abort();
|
|
6120
|
-
idleWindow = new AbortController();
|
|
6121
|
-
if (isTerminal(source)) return;
|
|
6122
|
-
after(idle.clock, STDIN_IDLE_MS, idleWindow.signal, () => {
|
|
6123
|
-
stop();
|
|
6124
|
-
reject(idle.stalled());
|
|
6125
|
-
});
|
|
6126
|
-
};
|
|
6127
|
-
const onData = (chunk) => {
|
|
6128
|
-
chunks.push(chunk instanceof Uint8Array ? chunk : Buffer.from(String(chunk)));
|
|
6129
|
-
watchIdle();
|
|
6130
|
-
};
|
|
6131
|
-
const onEnd = () => {
|
|
6132
|
-
stop();
|
|
6133
|
-
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
6134
|
-
};
|
|
6135
|
-
const onError = (error) => {
|
|
6136
|
-
stop();
|
|
6137
|
-
reject(error);
|
|
6138
|
-
};
|
|
6139
|
-
const onAbort = () => {
|
|
6140
|
-
stop();
|
|
6141
|
-
reject(signal.reason);
|
|
6142
|
-
};
|
|
6143
|
-
const stop = () => {
|
|
6144
|
-
source.off("data", onData).off("end", onEnd).off("error", onError).pause();
|
|
6145
|
-
signal.removeEventListener("abort", onAbort);
|
|
6146
|
-
idleWindow.abort();
|
|
6147
|
-
};
|
|
6148
|
-
if (signal.aborted) {
|
|
6149
|
-
reject(signal.reason);
|
|
6150
|
-
return;
|
|
6151
|
-
}
|
|
6152
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
6153
|
-
watchIdle();
|
|
6154
|
-
source.on("data", onData).once("end", onEnd).once("error", onError);
|
|
6155
|
-
});
|
|
6069
|
+
function declaredIn(own, commands, needsOf) {
|
|
6070
|
+
const walk = (node) => isCommand(node) ? [...needsOf(node) ?? []] : Object.values(node).flatMap(walk);
|
|
6071
|
+
return [...new Map([...own, ...walk(commands)].map((need) => [need.name, need])).values()];
|
|
6156
6072
|
}
|
|
6157
6073
|
//#endregion
|
|
6158
|
-
//#region ../agent-cli/dist/
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
return key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
6074
|
+
//#region ../agent-cli/dist/context/tools.js
|
|
6075
|
+
const TOOL_MISSING = "TOOL_MISSING";
|
|
6076
|
+
const WINDOWS_EXTENSIONS = ".COM;.EXE;.BAT;.CMD";
|
|
6077
|
+
function pathOf(env) {
|
|
6078
|
+
return env[Object.keys(env).find((name) => name.toUpperCase() === "PATH") ?? "PATH"] ?? "";
|
|
6164
6079
|
}
|
|
6165
|
-
function
|
|
6166
|
-
|
|
6167
|
-
return schema instanceof ZodBoolean ? "boolean" : "string";
|
|
6080
|
+
function extensionsOf(env) {
|
|
6081
|
+
return process.platform === "win32" ? (env.PATHEXT ?? WINDOWS_EXTENSIONS).split(";") : [""];
|
|
6168
6082
|
}
|
|
6169
|
-
function
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
if (current instanceof ZodDefault || current instanceof ZodPrefault) defaultValue = current.def.defaultValue;
|
|
6177
|
-
required = false;
|
|
6178
|
-
current = current.unwrap();
|
|
6179
|
-
description ??= current.description;
|
|
6180
|
-
stdin ||= isStdinSchema(current);
|
|
6083
|
+
async function isExecutable(file) {
|
|
6084
|
+
try {
|
|
6085
|
+
await access(file, constants$1.X_OK);
|
|
6086
|
+
return true;
|
|
6087
|
+
} catch (error) {
|
|
6088
|
+
if (isNothingThere(error) || errnoOf(error) === "EACCES") return false;
|
|
6089
|
+
throw error;
|
|
6181
6090
|
}
|
|
6182
|
-
const variadic = current instanceof ZodArray;
|
|
6183
|
-
if (current instanceof ZodArray) current = current.element;
|
|
6184
|
-
return {
|
|
6185
|
-
type: typeOf(current),
|
|
6186
|
-
required,
|
|
6187
|
-
defaultValue,
|
|
6188
|
-
description,
|
|
6189
|
-
choices: current instanceof ZodEnum ? current.options.map(String) : void 0,
|
|
6190
|
-
variadic,
|
|
6191
|
-
stdin
|
|
6192
|
-
};
|
|
6193
6091
|
}
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6092
|
+
/** The file names `name` may have on `PATH`: itself when it already ends in one of the extensions. */
|
|
6093
|
+
function fileNamesOf(name, env) {
|
|
6094
|
+
const extensions = extensionsOf(env);
|
|
6095
|
+
const own = extname(name).toUpperCase();
|
|
6096
|
+
return own !== "" && extensions.some((extension) => extension.toUpperCase() === own) ? [name] : extensions.map((extension) => `${name}${extension}`);
|
|
6198
6097
|
}
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
const
|
|
6202
|
-
return
|
|
6203
|
-
key,
|
|
6204
|
-
name: key,
|
|
6205
|
-
schema,
|
|
6206
|
-
...described,
|
|
6207
|
-
label,
|
|
6208
|
-
usage: label
|
|
6209
|
-
};
|
|
6098
|
+
/** Where `name` is found on `PATH` from `env`, or undefined. */
|
|
6099
|
+
async function findTool(name, env) {
|
|
6100
|
+
const candidates = pathOf(env).split(delimiter).filter((folder) => folder !== "").flatMap((folder) => fileNamesOf(name, env).map((file) => join(folder, file)));
|
|
6101
|
+
for (const file of candidates) if (await isExecutable(file)) return file;
|
|
6210
6102
|
}
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
const
|
|
6214
|
-
const
|
|
6215
|
-
|
|
6216
|
-
const
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
label,
|
|
6224
|
-
usage
|
|
6225
|
-
};
|
|
6103
|
+
/** Fails with `TOOL_MISSING`, naming every missing tool at once, unless all are on `PATH`. */
|
|
6104
|
+
async function checkTools(tools, env, rerun) {
|
|
6105
|
+
const found = await Promise.all(tools.map((tool) => findTool(tool.name, env)));
|
|
6106
|
+
const missing = tools.filter((_tool, index) => found[index] === void 0);
|
|
6107
|
+
if (missing.length === 0) return;
|
|
6108
|
+
const names = missing.map(({ name }) => name).join(", ");
|
|
6109
|
+
throw runtimeError({
|
|
6110
|
+
code: TOOL_MISSING,
|
|
6111
|
+
message: `${missing.length === 1 ? "a tool it runs is" : "tools it runs are"} not on PATH: ${names}`,
|
|
6112
|
+
hint: "run the Next steps in order: each install, then the command again",
|
|
6113
|
+
next: [...missing.map(({ install }) => wholeLine(install)), rerun]
|
|
6114
|
+
});
|
|
6226
6115
|
}
|
|
6227
|
-
|
|
6228
|
-
|
|
6116
|
+
/** One `doctor` row per distinct tool the CLI and its Commands declare, with its install command as the fix. */
|
|
6117
|
+
function toolRows(tools, commands) {
|
|
6118
|
+
return declaredIn(tools, commands, (command) => command.tools).map(({ name, install }) => ({
|
|
6119
|
+
name,
|
|
6120
|
+
run: async (ctx) => {
|
|
6121
|
+
const file = await findTool(name, ctx.env);
|
|
6122
|
+
return file === void 0 ? {
|
|
6123
|
+
state: "problem",
|
|
6124
|
+
message: `${name} is not on PATH`,
|
|
6125
|
+
fix: install
|
|
6126
|
+
} : {
|
|
6127
|
+
state: "ok",
|
|
6128
|
+
message: `found at ${file}`
|
|
6129
|
+
};
|
|
6130
|
+
}
|
|
6131
|
+
}));
|
|
6229
6132
|
}
|
|
6230
|
-
|
|
6231
|
-
|
|
6133
|
+
//#endregion
|
|
6134
|
+
//#region ../agent-cli/dist/context/spawn.js
|
|
6135
|
+
const TOOL_FAILED = "TOOL_FAILED";
|
|
6136
|
+
const STDERR_TAIL_LINES$1 = 20;
|
|
6137
|
+
const SIGNAL_EXIT_BASE = 128;
|
|
6138
|
+
const BATCH_FILE = /\.(?:cmd|bat)$/i;
|
|
6139
|
+
const CMD_SHIM = /\.cmd$/i;
|
|
6140
|
+
const CMD_META = /([()\][%!^"`<>&|;, *?])/g;
|
|
6141
|
+
const PATH_SEPARATOR = /[\\/]/;
|
|
6142
|
+
const TRAILING_CR = /\r$/;
|
|
6143
|
+
const LINE_END = /\r\n|\r(?!$)|\n/;
|
|
6144
|
+
function isWhole(input) {
|
|
6145
|
+
return typeof input === "string" || input instanceof Uint8Array;
|
|
6232
6146
|
}
|
|
6233
|
-
function
|
|
6234
|
-
return
|
|
6147
|
+
function escapedForCmd(text) {
|
|
6148
|
+
return text.replace(CMD_META, "^$1");
|
|
6235
6149
|
}
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
if (misplaced.length > 0) throw new Error(`Command '${name}' declares array arg ${keysOf(misplaced)} before its last arg; only the last arg may be an array`);
|
|
6150
|
+
function batchArgument(arg, shim) {
|
|
6151
|
+
const escaped = escapedForCmd(`"${arg.replace(/(\\*)"/g, "$1$1\\\"").replace(/(\\*)$/, "$1$1")}"`);
|
|
6152
|
+
return shim ? escapedForCmd(escaped) : escaped;
|
|
6240
6153
|
}
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6154
|
+
function batchCommandLine(command, file, args) {
|
|
6155
|
+
const shim = CMD_SHIM.test(file);
|
|
6156
|
+
return [escapedForCmd(command), ...args.map((arg) => batchArgument(arg, shim))].join(" ");
|
|
6157
|
+
}
|
|
6158
|
+
async function windowsLaunch(command, args, env) {
|
|
6159
|
+
const file = PATH_SEPARATOR.test(command) ? command : await findTool(command, env);
|
|
6160
|
+
if (file === void 0 || !BATCH_FILE.test(file)) return {
|
|
6161
|
+
command,
|
|
6162
|
+
args,
|
|
6163
|
+
shell: false
|
|
6164
|
+
};
|
|
6165
|
+
return {
|
|
6166
|
+
command: batchCommandLine(command, file, args),
|
|
6167
|
+
args: [],
|
|
6168
|
+
shell: true
|
|
6169
|
+
};
|
|
6170
|
+
}
|
|
6171
|
+
function stop(child) {
|
|
6172
|
+
if (process.platform !== "win32" || child.pid === void 0) {
|
|
6173
|
+
child.kill();
|
|
6174
|
+
return Promise.resolve();
|
|
6249
6175
|
}
|
|
6176
|
+
const pid = String(child.pid);
|
|
6177
|
+
return new Promise((resolve) => {
|
|
6178
|
+
const taskkill = spawn("taskkill", [
|
|
6179
|
+
"/pid",
|
|
6180
|
+
pid,
|
|
6181
|
+
"/t",
|
|
6182
|
+
"/f"
|
|
6183
|
+
], {
|
|
6184
|
+
stdio: "ignore",
|
|
6185
|
+
windowsHide: true
|
|
6186
|
+
});
|
|
6187
|
+
taskkill.once("error", () => {
|
|
6188
|
+
child.kill();
|
|
6189
|
+
resolve();
|
|
6190
|
+
});
|
|
6191
|
+
taskkill.once("exit", () => resolve());
|
|
6192
|
+
});
|
|
6250
6193
|
}
|
|
6251
|
-
|
|
6252
|
-
|
|
6194
|
+
/** Calls `onLine` with each complete line pushed, and with the unterminated rest at the end. */
|
|
6195
|
+
function lineSplitter(onLine) {
|
|
6196
|
+
let rest = "";
|
|
6197
|
+
return {
|
|
6198
|
+
push(text) {
|
|
6199
|
+
if (onLine === void 0) return;
|
|
6200
|
+
const lines = (rest + text).split(LINE_END);
|
|
6201
|
+
rest = lines.pop() ?? "";
|
|
6202
|
+
for (const line of lines) onLine(line);
|
|
6203
|
+
},
|
|
6204
|
+
end() {
|
|
6205
|
+
if (rest !== "") onLine?.(rest.replace(TRAILING_CR, ""));
|
|
6206
|
+
rest = "";
|
|
6207
|
+
}
|
|
6208
|
+
};
|
|
6253
6209
|
}
|
|
6254
|
-
/**
|
|
6255
|
-
function
|
|
6256
|
-
|
|
6257
|
-
|
|
6210
|
+
/** `onLine`, passing what it throws to `fail` and called no more once `failed()`. */
|
|
6211
|
+
function guarded(onLine, failed, fail) {
|
|
6212
|
+
if (onLine === void 0) return void 0;
|
|
6213
|
+
return (line) => {
|
|
6214
|
+
if (failed()) return;
|
|
6215
|
+
try {
|
|
6216
|
+
onLine(line);
|
|
6217
|
+
} catch (error) {
|
|
6218
|
+
fail(error);
|
|
6219
|
+
}
|
|
6220
|
+
};
|
|
6258
6221
|
}
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
const
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6222
|
+
/** Settles once the child has taken what was written, or its stdin has closed. */
|
|
6223
|
+
function drained(stdin) {
|
|
6224
|
+
return new Promise((resolve) => {
|
|
6225
|
+
const done = () => {
|
|
6226
|
+
stdin.off("drain", done);
|
|
6227
|
+
stdin.off("close", done);
|
|
6228
|
+
resolve();
|
|
6229
|
+
};
|
|
6230
|
+
stdin.on("drain", done);
|
|
6231
|
+
stdin.on("close", done);
|
|
6269
6232
|
});
|
|
6270
6233
|
}
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6234
|
+
/**
|
|
6235
|
+
* Writes `input` to the child's stdin and ends it, stopping once the child is gone or the run
|
|
6236
|
+
* aborts.
|
|
6237
|
+
*/
|
|
6238
|
+
async function feed(stdin, input, signal) {
|
|
6239
|
+
stdin.on("error", () => void 0);
|
|
6240
|
+
const chunks = isWhole(input) ? [input] : input;
|
|
6241
|
+
for await (const chunk of chunks) {
|
|
6242
|
+
if (signal.aborted || stdin.destroyed) return;
|
|
6243
|
+
if (!stdin.write(chunk)) await drained(stdin);
|
|
6244
|
+
}
|
|
6245
|
+
stdin.end();
|
|
6246
|
+
}
|
|
6247
|
+
/**
|
|
6248
|
+
* Runs a child process to its end; it is killed on abort, and the promise settles only once it has
|
|
6249
|
+
* exited. A `detached` child leaves the terminal's process group on POSIX, and so its Ctrl-C.
|
|
6250
|
+
*/
|
|
6251
|
+
async function spawnChild(command, args, { cwd, env, signal, onLine, stdin, detached = false }) {
|
|
6252
|
+
signal.throwIfAborted();
|
|
6253
|
+
const launch = await launchOf(command, args, env);
|
|
6254
|
+
signal.throwIfAborted();
|
|
6255
|
+
return new Promise((resolve, reject) => {
|
|
6256
|
+
const child = spawn(launch.command, launch.args, {
|
|
6257
|
+
cwd,
|
|
6258
|
+
env,
|
|
6259
|
+
shell: launch.shell,
|
|
6260
|
+
windowsHide: true,
|
|
6261
|
+
stdio: [
|
|
6262
|
+
stdin === void 0 ? "ignore" : "pipe",
|
|
6263
|
+
"pipe",
|
|
6264
|
+
"pipe"
|
|
6265
|
+
],
|
|
6266
|
+
detached: detached && process.platform !== "win32"
|
|
6267
|
+
});
|
|
6268
|
+
let stopped = Promise.resolve();
|
|
6269
|
+
const kill = () => {
|
|
6270
|
+
stopped = stop(child);
|
|
6271
|
+
};
|
|
6272
|
+
signal.addEventListener("abort", kill, { once: true });
|
|
6273
|
+
let callerFailure;
|
|
6274
|
+
const fail = (error) => {
|
|
6275
|
+
if (callerFailure !== void 0) return;
|
|
6276
|
+
callerFailure = { error };
|
|
6277
|
+
kill();
|
|
6278
|
+
};
|
|
6279
|
+
let stdout = "";
|
|
6280
|
+
let stderr = "";
|
|
6281
|
+
const lines = guarded(onLine, () => callerFailure !== void 0, fail);
|
|
6282
|
+
const stdoutLines = lineSplitter(lines);
|
|
6283
|
+
const stderrLines = lineSplitter(lines);
|
|
6284
|
+
child.stdout?.setEncoding("utf8").on("data", (chunk) => {
|
|
6285
|
+
stdout += chunk;
|
|
6286
|
+
stdoutLines.push(chunk);
|
|
6287
|
+
});
|
|
6288
|
+
child.stderr?.setEncoding("utf8").on("data", (chunk) => {
|
|
6289
|
+
stderr += chunk;
|
|
6290
|
+
stderrLines.push(chunk);
|
|
6291
|
+
});
|
|
6292
|
+
if (stdin !== void 0 && child.stdin !== null) feed(child.stdin, stdin, signal).catch(fail);
|
|
6293
|
+
child.on("error", (error) => {
|
|
6294
|
+
signal.removeEventListener("abort", kill);
|
|
6295
|
+
reject(error);
|
|
6296
|
+
});
|
|
6297
|
+
child.on("close", (code, killedBy) => {
|
|
6298
|
+
signal.removeEventListener("abort", kill);
|
|
6299
|
+
if (signal.aborted) {
|
|
6300
|
+
stopped.then(() => reject(signal.reason));
|
|
6301
|
+
return;
|
|
6302
|
+
}
|
|
6303
|
+
stdoutLines.end();
|
|
6304
|
+
stderrLines.end();
|
|
6305
|
+
if (callerFailure !== void 0) {
|
|
6306
|
+
const { error } = callerFailure;
|
|
6307
|
+
stopped.then(() => reject(error));
|
|
6308
|
+
return;
|
|
6309
|
+
}
|
|
6310
|
+
resolve({
|
|
6311
|
+
stdout,
|
|
6312
|
+
stderr,
|
|
6313
|
+
exitCode: code ?? SIGNAL_EXIT_BASE + (killedBy === null ? 0 : constants.signals[killedBy])
|
|
6314
|
+
});
|
|
6315
|
+
});
|
|
6278
6316
|
});
|
|
6279
6317
|
}
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6318
|
+
async function launchOf(command, args, env) {
|
|
6319
|
+
return process.platform === "win32" ? windowsLaunch(command, args, env) : {
|
|
6320
|
+
command,
|
|
6321
|
+
args,
|
|
6322
|
+
shell: false
|
|
6323
|
+
};
|
|
6324
|
+
}
|
|
6325
|
+
/**
|
|
6326
|
+
* Starts a child in its own process group (its own console on Windows) with no stdio, and settles
|
|
6327
|
+
* once it has started; the parent neither waits for it nor keeps it from exiting.
|
|
6328
|
+
*/
|
|
6329
|
+
const realSpawnDetached = async (command, args, { cwd, env }) => {
|
|
6330
|
+
const launch = await launchOf(command, args, env);
|
|
6331
|
+
return new Promise((resolve, reject) => {
|
|
6332
|
+
const child = spawn(launch.command, launch.args, {
|
|
6333
|
+
cwd,
|
|
6334
|
+
env,
|
|
6335
|
+
shell: launch.shell,
|
|
6336
|
+
windowsHide: true,
|
|
6337
|
+
stdio: "ignore",
|
|
6338
|
+
detached: true
|
|
6339
|
+
});
|
|
6340
|
+
child.unref();
|
|
6341
|
+
child.once("error", reject);
|
|
6342
|
+
child.once("spawn", () => {
|
|
6343
|
+
child.off("error", reject);
|
|
6344
|
+
const { pid } = child;
|
|
6345
|
+
if (pid === void 0) reject(/* @__PURE__ */ new Error(`${command} started without a pid`));
|
|
6346
|
+
else resolve({ pid });
|
|
6347
|
+
});
|
|
6285
6348
|
});
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6349
|
+
};
|
|
6350
|
+
const realSpawn = (command, args, options) => spawnChild(command, args, options);
|
|
6351
|
+
function failedError(command, { exitCode, stderr }) {
|
|
6352
|
+
const tail = lastLines(stderr, STDERR_TAIL_LINES$1);
|
|
6353
|
+
return new CliError({
|
|
6354
|
+
code: TOOL_FAILED,
|
|
6355
|
+
message: tail === "" ? `${command} exited with ${exitCode} and wrote nothing to stderr` : `${command} exited with ${exitCode}; its stderr ends:\n${tail}`,
|
|
6356
|
+
hint: `the output of ${command} above says why it failed`
|
|
6290
6357
|
});
|
|
6291
6358
|
}
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6359
|
+
var MissingToolError = class extends CliError {
|
|
6360
|
+
tool;
|
|
6361
|
+
constructor(tool, rerun, cause) {
|
|
6362
|
+
super({
|
|
6363
|
+
code: TOOL_MISSING,
|
|
6364
|
+
message: `${tool} could not be started: it is not on PATH`,
|
|
6365
|
+
hint: `install ${tool}, then run the Next step`,
|
|
6366
|
+
next: [rerun]
|
|
6367
|
+
}, { cause });
|
|
6368
|
+
this.tool = tool;
|
|
6369
|
+
}
|
|
6370
|
+
};
|
|
6371
|
+
function missingToolOf(error) {
|
|
6372
|
+
return error instanceof MissingToolError ? error.tool : void 0;
|
|
6373
|
+
}
|
|
6374
|
+
function startError(command, error, { fileError, rerun }) {
|
|
6375
|
+
if (isMissingFile(error)) return new MissingToolError(command, rerun, error);
|
|
6376
|
+
return fileError(error, {
|
|
6377
|
+
path: command,
|
|
6378
|
+
access: "read"
|
|
6299
6379
|
});
|
|
6300
6380
|
}
|
|
6301
|
-
function
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
}
|
|
6308
|
-
//#endregion
|
|
6309
|
-
//#region ../agent-cli/dist/list.js
|
|
6310
|
-
const UNKNOWN_FIELD = "UNKNOWN_FIELD";
|
|
6311
|
-
const DEFAULT_PAGE_LIMIT = 20;
|
|
6312
|
-
const FIELDS_FLAG = "--fields";
|
|
6313
|
-
const SEPARATOR = ",";
|
|
6314
|
-
const COLUMN_SEPARATOR = " ";
|
|
6315
|
-
const UNSAFE_IN_COLUMN = /[\t\n\r]/;
|
|
6316
|
-
const PAGE_INPUT = object({
|
|
6317
|
-
limit: number().int().positive().default(DEFAULT_PAGE_LIMIT),
|
|
6318
|
-
cursor: string().min(1).optional()
|
|
6319
|
-
});
|
|
6320
|
-
var Page = class {
|
|
6321
|
-
items;
|
|
6322
|
-
nextCursor;
|
|
6323
|
-
constructor(items, nextCursor) {
|
|
6324
|
-
this.items = items;
|
|
6325
|
-
this.nextCursor = nextCursor;
|
|
6381
|
+
async function* reported(stream, onError) {
|
|
6382
|
+
try {
|
|
6383
|
+
yield* stream;
|
|
6384
|
+
} catch (error) {
|
|
6385
|
+
onError(error);
|
|
6386
|
+
throw error;
|
|
6326
6387
|
}
|
|
6327
|
-
};
|
|
6328
|
-
const PAGE_FLAG_DESCRIPTIONS = {
|
|
6329
|
-
limit: `how many rows to show, a positive whole number (default: ${DEFAULT_PAGE_LIMIT})`,
|
|
6330
|
-
cursor: "where to start, as given by the previous page's next"
|
|
6331
|
-
};
|
|
6332
|
-
function pageFlag(key) {
|
|
6333
|
-
const field = optionField(key, PAGE_INPUT.shape[key]);
|
|
6334
|
-
return {
|
|
6335
|
-
flag: field.label,
|
|
6336
|
-
usage: field.usage,
|
|
6337
|
-
description: PAGE_FLAG_DESCRIPTIONS[key],
|
|
6338
|
-
takes: "optional value",
|
|
6339
|
-
schema: field.schema
|
|
6340
|
-
};
|
|
6341
6388
|
}
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6389
|
+
/** `input`, a stream passing each error it throws to `onError` before the reader sees it. */
|
|
6390
|
+
function reporting(input, onError) {
|
|
6391
|
+
return input === void 0 || isWhole(input) ? input : reported(input, onError);
|
|
6392
|
+
}
|
|
6393
|
+
/** `onLine`, passing each error it throws to `onError` before its caller sees it. */
|
|
6394
|
+
function reportingLines(onLine, onError) {
|
|
6395
|
+
if (onLine === void 0) return void 0;
|
|
6396
|
+
return (line) => {
|
|
6397
|
+
try {
|
|
6398
|
+
onLine(line);
|
|
6399
|
+
} catch (error) {
|
|
6400
|
+
onError(error);
|
|
6401
|
+
throw error;
|
|
6402
|
+
}
|
|
6349
6403
|
};
|
|
6350
6404
|
}
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
};
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6405
|
+
function contextSpawn(run, defaults, scope) {
|
|
6406
|
+
return async (command, args = [], options = {}) => {
|
|
6407
|
+
let callerFailure;
|
|
6408
|
+
const caller = (error) => {
|
|
6409
|
+
callerFailure = { error };
|
|
6410
|
+
};
|
|
6411
|
+
let result;
|
|
6412
|
+
try {
|
|
6413
|
+
result = await run(command, args, {
|
|
6414
|
+
cwd: options.cwd ?? defaults.cwd,
|
|
6415
|
+
env: options.env ?? defaults.env,
|
|
6416
|
+
signal: defaults.signal,
|
|
6417
|
+
onLine: reportingLines(options.onLine, caller),
|
|
6418
|
+
stdin: reporting(options.stdin, caller)
|
|
6419
|
+
});
|
|
6420
|
+
} catch (error) {
|
|
6421
|
+
throw callerFailure?.error === error ? error : startError(command, error, scope);
|
|
6422
|
+
}
|
|
6423
|
+
if (options.check === true && result.exitCode !== 0) throw failedError(command, result);
|
|
6424
|
+
return result;
|
|
6368
6425
|
};
|
|
6369
6426
|
}
|
|
6370
|
-
|
|
6371
|
-
|
|
6427
|
+
/** `ctx.spawnDetached`: `run` bound to the run's cwd and env, its start failures classified by errno. */
|
|
6428
|
+
function contextSpawnDetached(run, defaults, scope) {
|
|
6429
|
+
return async (command, args = [], options = {}) => {
|
|
6430
|
+
defaults.signal.throwIfAborted();
|
|
6431
|
+
try {
|
|
6432
|
+
return await run(command, args, {
|
|
6433
|
+
cwd: options.cwd ?? defaults.cwd,
|
|
6434
|
+
env: options.env ?? defaults.env
|
|
6435
|
+
});
|
|
6436
|
+
} catch (error) {
|
|
6437
|
+
throw startError(command, error, scope);
|
|
6438
|
+
}
|
|
6439
|
+
};
|
|
6372
6440
|
}
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6441
|
+
//#endregion
|
|
6442
|
+
//#region ../agent-cli/dist/clock.js
|
|
6443
|
+
const realClock = {
|
|
6444
|
+
now: () => Date.now(),
|
|
6445
|
+
sleep: (ms, signal) => new Promise((resolve, reject) => {
|
|
6446
|
+
if (signal?.aborted === true) {
|
|
6447
|
+
reject(signal.reason);
|
|
6448
|
+
return;
|
|
6449
|
+
}
|
|
6450
|
+
const onAbort = () => {
|
|
6451
|
+
clearTimeout(timer);
|
|
6452
|
+
reject(signal?.reason);
|
|
6453
|
+
};
|
|
6454
|
+
const timer = setTimeout(() => {
|
|
6455
|
+
signal?.removeEventListener("abort", onAbort);
|
|
6456
|
+
resolve();
|
|
6457
|
+
}, ms);
|
|
6458
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
6459
|
+
})
|
|
6460
|
+
};
|
|
6461
|
+
/** Runs `then` once `ms` have passed on `clock`; aborting `cancel` drops it. */
|
|
6462
|
+
function after(clock, ms, cancel, then) {
|
|
6463
|
+
clock.sleep(ms, cancel).then(then, (error) => {
|
|
6464
|
+
if (!cancel.aborted) throw error;
|
|
6389
6465
|
});
|
|
6390
|
-
return names;
|
|
6391
|
-
}
|
|
6392
|
-
function fieldOf(row, field) {
|
|
6393
|
-
return typeof row === "object" && row !== null ? row[field] : void 0;
|
|
6394
|
-
}
|
|
6395
|
-
function projected(rows, fields) {
|
|
6396
|
-
return rows.map((row) => Object.fromEntries(fields.map((field) => [field, fieldOf(row, field)])));
|
|
6397
|
-
}
|
|
6398
|
-
function cell(value) {
|
|
6399
|
-
if (value === void 0 || value === null) return "";
|
|
6400
|
-
return typeof value === "string" && !UNSAFE_IN_COLUMN.test(value) ? value : JSON.stringify(value);
|
|
6401
|
-
}
|
|
6402
|
-
/** Selected rows as text: a header line of the field names, then one tab-separated line per row. */
|
|
6403
|
-
function renderRows(rows, fields) {
|
|
6404
|
-
return `${[fields, ...rows.map((row) => fields.map((field) => cell(row[field])))].map((line) => line.join(COLUMN_SEPARATOR)).join("\n")}\n`;
|
|
6405
6466
|
}
|
|
6406
|
-
function
|
|
6407
|
-
|
|
6408
|
-
|
|
6467
|
+
async function poll(clock, check, intervalMs, signal) {
|
|
6468
|
+
for (;;) {
|
|
6469
|
+
signal.throwIfAborted();
|
|
6470
|
+
const value = await check();
|
|
6471
|
+
if (value !== void 0) return value;
|
|
6472
|
+
await clock.sleep(intervalMs, signal);
|
|
6473
|
+
}
|
|
6409
6474
|
}
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
words: changedArgv(invocation, {
|
|
6416
|
-
remove: [PAGE_FLAGS.cursor.flag],
|
|
6417
|
-
add: cursorWords(page.nextCursor)
|
|
6418
|
-
}),
|
|
6419
|
-
stdinArg: invocation.stdinArg
|
|
6420
|
-
}, invocation.runAs)
|
|
6421
|
-
};
|
|
6475
|
+
//#endregion
|
|
6476
|
+
//#region ../agent-cli/dist/context/stdin.js
|
|
6477
|
+
const STDIN_META = "stdin";
|
|
6478
|
+
function isStdinSchema(schema) {
|
|
6479
|
+
return globalRegistry$1.get(schema)?.[STDIN_META] === true;
|
|
6422
6480
|
}
|
|
6423
|
-
|
|
6424
|
-
|
|
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`;
|
|
6481
|
+
function endOfInputKeys(platform) {
|
|
6482
|
+
return platform === "win32" ? "Ctrl-Z then Enter" : "Ctrl-D";
|
|
6426
6483
|
}
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
function hasPlan(command) {
|
|
6431
|
-
return command.effect === "write" || command.effect === "destructive";
|
|
6484
|
+
/** The progress line shown before reading a terminal, so a person isn't left facing silence. */
|
|
6485
|
+
function readingLine(name, platform) {
|
|
6486
|
+
return `reading <${name}> from stdin; end it with ${endOfInputKeys(platform)}`;
|
|
6432
6487
|
}
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
const HELP_FLAG = "--help";
|
|
6436
|
-
const VERSION_FLAG = "--version";
|
|
6437
|
-
const ROUTING_FLAGS = [
|
|
6438
|
-
HELP_FLAG,
|
|
6439
|
-
"-h",
|
|
6440
|
-
VERSION_FLAG
|
|
6441
|
-
];
|
|
6442
|
-
function nameOf$1(flag) {
|
|
6443
|
-
return flag.replace(/^--?/, "");
|
|
6488
|
+
function isTerminal(source) {
|
|
6489
|
+
return typeof source !== "string" && "isTTY" in source && source.isTTY === true;
|
|
6444
6490
|
}
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6491
|
+
const STDIN_STALLED = "STDIN_STALLED";
|
|
6492
|
+
/** How long a stdin that is not a terminal may send nothing, from the start of the read and from each chunk. */
|
|
6493
|
+
const STDIN_IDLE_MS = 3e4;
|
|
6494
|
+
function stdinStalled(callerLine) {
|
|
6495
|
+
return new CliError({
|
|
6496
|
+
code: STDIN_STALLED,
|
|
6497
|
+
message: `stdin sent nothing for ${STDIN_IDLE_MS} ms`,
|
|
6498
|
+
hint: `stdin never ended: close the pipe or heredoc that feeds \`${callerLine}\`, pass the text as an argument instead, or write a slow producer's output to a file and redirect it in`
|
|
6499
|
+
});
|
|
6451
6500
|
}
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
}
|
|
6478
|
-
const
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
const forceFlag = force === void 0 ? FORCE_FLAG : {
|
|
6499
|
-
...FORCE_FLAG,
|
|
6500
|
-
description: force
|
|
6501
|
-
};
|
|
6502
|
-
return [
|
|
6503
|
-
...EFFECT_FLAGS[effect],
|
|
6504
|
-
...outputs || force !== void 0 ? [forceFlag] : [],
|
|
6505
|
-
...cost ? [YES_FLAG] : [],
|
|
6506
|
-
...list?.standardFlags ?? []
|
|
6507
|
-
];
|
|
6508
|
-
}
|
|
6509
|
-
/** Throws when the Command declares an arg or option under a Standard flag's name. */
|
|
6510
|
-
function checkNoStandardFlags(command, label) {
|
|
6511
|
-
const lines = [...argFields(command.args).map(({ key }) => ({
|
|
6512
|
-
kind: "arg",
|
|
6513
|
-
key
|
|
6514
|
-
})), ...optionFields(command.options).map(({ key }) => ({
|
|
6515
|
-
kind: "option",
|
|
6516
|
-
key
|
|
6517
|
-
}))].flatMap(({ kind, key }) => {
|
|
6518
|
-
const flag = RESERVED.get(kebab(key));
|
|
6519
|
-
return flag === void 0 ? [] : [` ${kind} '${key}' is the Standard flag ${flag}`];
|
|
6501
|
+
/**
|
|
6502
|
+
* The whole of `source` as UTF-8; rejects with the signal's reason once it aborts, and with
|
|
6503
|
+
* `idle.stalled()` once a stream that is not a terminal sends nothing for `STDIN_IDLE_MS`.
|
|
6504
|
+
*/
|
|
6505
|
+
function readStdin(source, signal, idle) {
|
|
6506
|
+
if (typeof source === "string") return signal.aborted ? Promise.reject(signal.reason) : Promise.resolve(source);
|
|
6507
|
+
return new Promise((resolve, reject) => {
|
|
6508
|
+
const chunks = [];
|
|
6509
|
+
let idleWindow = new AbortController();
|
|
6510
|
+
const watchIdle = () => {
|
|
6511
|
+
idleWindow.abort();
|
|
6512
|
+
idleWindow = new AbortController();
|
|
6513
|
+
if (isTerminal(source)) return;
|
|
6514
|
+
after(idle.clock, STDIN_IDLE_MS, idleWindow.signal, () => {
|
|
6515
|
+
stop();
|
|
6516
|
+
reject(idle.stalled());
|
|
6517
|
+
});
|
|
6518
|
+
};
|
|
6519
|
+
const onData = (chunk) => {
|
|
6520
|
+
chunks.push(chunk instanceof Uint8Array ? chunk : Buffer.from(String(chunk)));
|
|
6521
|
+
watchIdle();
|
|
6522
|
+
};
|
|
6523
|
+
const onEnd = () => {
|
|
6524
|
+
stop();
|
|
6525
|
+
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
6526
|
+
};
|
|
6527
|
+
const onError = (error) => {
|
|
6528
|
+
stop();
|
|
6529
|
+
reject(error);
|
|
6530
|
+
};
|
|
6531
|
+
const onAbort = () => {
|
|
6532
|
+
stop();
|
|
6533
|
+
reject(signal.reason);
|
|
6534
|
+
};
|
|
6535
|
+
const stop = () => {
|
|
6536
|
+
source.off("data", onData).off("end", onEnd).off("error", onError).pause();
|
|
6537
|
+
signal.removeEventListener("abort", onAbort);
|
|
6538
|
+
idleWindow.abort();
|
|
6539
|
+
};
|
|
6540
|
+
if (signal.aborted) {
|
|
6541
|
+
reject(signal.reason);
|
|
6542
|
+
return;
|
|
6543
|
+
}
|
|
6544
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
6545
|
+
watchIdle();
|
|
6546
|
+
source.on("data", onData).once("end", onEnd).once("error", onError);
|
|
6520
6547
|
});
|
|
6521
|
-
if (lines.length > 0) throw new Error([`Command '${label}' declares Standard flags the Runtime adds; rename them:`, ...lines].join("\n"));
|
|
6522
|
-
}
|
|
6523
|
-
/** Throws when `force` is declared on a Command with no Plan, or says nothing. */
|
|
6524
|
-
function checkForce(command, label) {
|
|
6525
|
-
const force = "force" in command ? command.force : void 0;
|
|
6526
|
-
if (force === void 0) return;
|
|
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`);
|
|
6529
6548
|
}
|
|
6530
6549
|
//#endregion
|
|
6531
|
-
//#region ../agent-cli/dist/
|
|
6532
|
-
|
|
6533
|
-
|
|
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`);
|
|
6544
|
-
}
|
|
6545
|
-
function defineCommandFor() {
|
|
6546
|
-
return declared;
|
|
6550
|
+
//#region ../agent-cli/dist/command-line/input.js
|
|
6551
|
+
function isWrapper(schema) {
|
|
6552
|
+
return schema instanceof ZodOptional || schema instanceof ZodNullable || schema instanceof ZodDefault || schema instanceof ZodPrefault;
|
|
6547
6553
|
}
|
|
6548
|
-
function
|
|
6549
|
-
return
|
|
6554
|
+
function kebab(key) {
|
|
6555
|
+
return key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
6550
6556
|
}
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
const PROJECT_INVALID = "PROJECT_INVALID";
|
|
6555
|
-
function invalid(path, problem, rerun, options) {
|
|
6556
|
-
return new CliError({
|
|
6557
|
-
code: PROJECT_INVALID,
|
|
6558
|
-
message: `the Project file ${path} is invalid: ${problem}`,
|
|
6559
|
-
hint: `fix ${path}, then run the Next step`,
|
|
6560
|
-
next: [rerun]
|
|
6561
|
-
}, options);
|
|
6557
|
+
function typeOf(schema) {
|
|
6558
|
+
if (schema instanceof ZodNumber) return "number";
|
|
6559
|
+
return schema instanceof ZodBoolean ? "boolean" : "string";
|
|
6562
6560
|
}
|
|
6563
|
-
function
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6561
|
+
function describe(schema) {
|
|
6562
|
+
let current = schema;
|
|
6563
|
+
let description = current.description;
|
|
6564
|
+
let required = true;
|
|
6565
|
+
let defaultValue;
|
|
6566
|
+
let stdin = isStdinSchema(current);
|
|
6567
|
+
while (isWrapper(current)) {
|
|
6568
|
+
if (current instanceof ZodDefault || current instanceof ZodPrefault) defaultValue = current.def.defaultValue;
|
|
6569
|
+
required = false;
|
|
6570
|
+
current = current.unwrap();
|
|
6571
|
+
description ??= current.description;
|
|
6572
|
+
stdin ||= isStdinSchema(current);
|
|
6572
6573
|
}
|
|
6574
|
+
const variadic = current instanceof ZodArray;
|
|
6575
|
+
if (current instanceof ZodArray) current = current.element;
|
|
6576
|
+
return {
|
|
6577
|
+
type: typeOf(current),
|
|
6578
|
+
required,
|
|
6579
|
+
defaultValue,
|
|
6580
|
+
description,
|
|
6581
|
+
choices: current instanceof ZodEnum ? current.options.map(String) : void 0,
|
|
6582
|
+
variadic,
|
|
6583
|
+
stdin
|
|
6584
|
+
};
|
|
6573
6585
|
}
|
|
6574
|
-
function
|
|
6575
|
-
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
} catch (error) {
|
|
6579
|
-
throw invalid(path, messageOf(error), rerun, { cause: error });
|
|
6580
|
-
}
|
|
6581
|
-
const result = schema.safeParse(json);
|
|
6582
|
-
if (!result.success) throw invalid(path, prettifyError(result.error), rerun);
|
|
6583
|
-
return result.data;
|
|
6586
|
+
function argLabel(key, { variadic, required, stdin }) {
|
|
6587
|
+
if (stdin) return required ? `<${key}|->` : `[${key}|-]`;
|
|
6588
|
+
if (!variadic) return `<${key}>`;
|
|
6589
|
+
return required ? `<${key}...>` : `[${key}...]`;
|
|
6584
6590
|
}
|
|
6585
|
-
function
|
|
6586
|
-
const
|
|
6587
|
-
const
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
+
function argField(key, schema) {
|
|
6592
|
+
const described = describe(schema);
|
|
6593
|
+
const label = argLabel(key, described);
|
|
6594
|
+
return {
|
|
6595
|
+
key,
|
|
6596
|
+
name: key,
|
|
6597
|
+
schema,
|
|
6598
|
+
...described,
|
|
6599
|
+
label,
|
|
6600
|
+
usage: label
|
|
6591
6601
|
};
|
|
6592
|
-
const parent = dirname(folder);
|
|
6593
|
-
return parent === folder ? void 0 : projectFrom(projectFile, parent, scope);
|
|
6594
6602
|
}
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6603
|
+
function optionField(key, schema) {
|
|
6604
|
+
const described = describe(schema);
|
|
6605
|
+
const name = kebab(key);
|
|
6606
|
+
const isBoolean = described.type === "boolean";
|
|
6607
|
+
const label = isBoolean && described.defaultValue === true ? `--no-${name}` : `--${name}`;
|
|
6608
|
+
const value = `<${described.choices?.join("|") ?? "value"}>${described.variadic ? "..." : ""}`;
|
|
6609
|
+
const usage = isBoolean ? label : `${label} ${value}`;
|
|
6610
|
+
return {
|
|
6611
|
+
key,
|
|
6612
|
+
name,
|
|
6613
|
+
schema,
|
|
6614
|
+
...described,
|
|
6615
|
+
label,
|
|
6616
|
+
usage
|
|
6617
|
+
};
|
|
6598
6618
|
}
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
function isCommand(node) {
|
|
6602
|
-
return typeof node.effect === "string";
|
|
6619
|
+
function fieldsOf(schema, toField) {
|
|
6620
|
+
return schema === void 0 ? [] : Object.entries(schema.shape).map(([key, value]) => toField(key, value));
|
|
6603
6621
|
}
|
|
6604
|
-
|
|
6605
|
-
|
|
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()];
|
|
6622
|
+
function argFields(schema) {
|
|
6623
|
+
return fieldsOf(schema, argField);
|
|
6613
6624
|
}
|
|
6614
|
-
|
|
6615
|
-
|
|
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");
|
|
6625
|
+
function keysOf(fields) {
|
|
6626
|
+
return fields.map(({ key }) => `'${key}'`).join(", ");
|
|
6621
6627
|
}
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6628
|
+
/** Throws when an arg that takes every remaining operand is not the last arg. */
|
|
6629
|
+
function checkArrayArgLast(name, args) {
|
|
6630
|
+
const misplaced = argFields(args).slice(0, -1).filter((field) => field.variadic);
|
|
6631
|
+
if (misplaced.length > 0) throw new Error(`Command '${name}' declares array arg ${keysOf(misplaced)} before its last arg; only the last arg may be an array`);
|
|
6632
|
+
}
|
|
6633
|
+
/** Throws unless at most one arg, and no option, is marked with `orStdin`. */
|
|
6634
|
+
function checkStdinFields(name, args, options) {
|
|
6635
|
+
const stdinArgs = argFields(args).filter((field) => field.stdin);
|
|
6636
|
+
if (stdinArgs.length > 1) throw new Error(`Command '${name}' marks args ${keysOf(stdinArgs)} with orStdin; only one arg may read stdin`);
|
|
6637
|
+
const stdinOptions = optionFields(options).filter((field) => field.stdin);
|
|
6638
|
+
if (stdinOptions.length > 0) {
|
|
6639
|
+
const noun = stdinOptions.length === 1 ? "option" : "options";
|
|
6640
|
+
throw new Error(`Command '${name}' marks ${noun} ${keysOf(stdinOptions)} with orStdin; only an arg may read stdin`);
|
|
6632
6641
|
}
|
|
6633
|
-
return parseEnv(text);
|
|
6634
6642
|
}
|
|
6635
|
-
|
|
6636
|
-
|
|
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;
|
|
6643
|
+
function optionFields(schema) {
|
|
6644
|
+
return fieldsOf(schema, optionField);
|
|
6650
6645
|
}
|
|
6651
|
-
|
|
6652
|
-
|
|
6646
|
+
/** Throws when an option is an array of booleans, which a switch cannot express. */
|
|
6647
|
+
function checkNoBooleanArrayOption(name, options) {
|
|
6648
|
+
const booleans = optionFields(options).filter((field) => field.variadic && field.type === "boolean");
|
|
6649
|
+
if (booleans.length > 0) throw new Error(`Command '${name}' declares boolean array option ${keysOf(booleans)}; a switch cannot repeat, use a boolean`);
|
|
6653
6650
|
}
|
|
6654
|
-
|
|
6655
|
-
|
|
6651
|
+
//#endregion
|
|
6652
|
+
//#region ../agent-cli/dist/command-line/usage.js
|
|
6653
|
+
const INVALID_INPUT = "INVALID_INPUT";
|
|
6654
|
+
const UNKNOWN_OPTION = "UNKNOWN_OPTION";
|
|
6655
|
+
const UNKNOWN_COMMAND = "UNKNOWN_COMMAND";
|
|
6656
|
+
function unknownError({ code, problem, commandLine, corrections, listed }) {
|
|
6657
|
+
return new UsageError({
|
|
6658
|
+
code,
|
|
6659
|
+
message: `${problem} for \`${commandLine}\``,
|
|
6660
|
+
hint: corrections.length === 0 ? `run \`${commandLine} --help\` to see the ${listed}` : `did you mean ${corrections.map((correction) => `\`${correction}\``).join(" or ")}?`
|
|
6661
|
+
});
|
|
6656
6662
|
}
|
|
6657
|
-
function
|
|
6658
|
-
return
|
|
6663
|
+
function unknownOptionError(commandLine, invocation, flag, suggestions) {
|
|
6664
|
+
return unknownError({
|
|
6665
|
+
code: UNKNOWN_OPTION,
|
|
6666
|
+
problem: `unknown option '${flag}'`,
|
|
6667
|
+
commandLine,
|
|
6668
|
+
corrections: suggestions.map((name) => commandLineRenaming(invocation, /* @__PURE__ */ new Map([[flag, name]]))),
|
|
6669
|
+
listed: "options"
|
|
6670
|
+
});
|
|
6659
6671
|
}
|
|
6660
|
-
/**
|
|
6661
|
-
function
|
|
6662
|
-
const
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6672
|
+
/** Text opening with `-` was read as an option, where the Command could have read it from stdin. */
|
|
6673
|
+
function stdinTextError(commandLine, invocation, word) {
|
|
6674
|
+
const withStdin = commandLineOf(invocation, {
|
|
6675
|
+
remove: [word],
|
|
6676
|
+
add: ["-"]
|
|
6677
|
+
});
|
|
6678
|
+
return new UsageError({
|
|
6679
|
+
code: UNKNOWN_OPTION,
|
|
6680
|
+
message: `unknown option '${word}' for \`${commandLine}\``,
|
|
6681
|
+
hint: `to pass text opening with \`-\`, pass \`-\` and send the text on stdin through a heredoc: \`${withStdin} <<'EOF'\`, then the text, then \`EOF\``
|
|
6670
6682
|
});
|
|
6671
6683
|
}
|
|
6672
|
-
function
|
|
6673
|
-
return
|
|
6684
|
+
function unknownCommandError(commandLine, name, suggestions) {
|
|
6685
|
+
return unknownError({
|
|
6686
|
+
code: UNKNOWN_COMMAND,
|
|
6687
|
+
problem: `unknown command '${name}'`,
|
|
6688
|
+
commandLine,
|
|
6689
|
+
corrections: suggestions.map((suggestion) => `${commandLine} ${suggestion}`),
|
|
6690
|
+
listed: "commands"
|
|
6691
|
+
});
|
|
6674
6692
|
}
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
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
|
-
}];
|
|
6693
|
+
function invalidInputError(commandLine, problem) {
|
|
6694
|
+
return new UsageError({
|
|
6695
|
+
code: INVALID_INPUT,
|
|
6696
|
+
message: problem,
|
|
6697
|
+
hint: `run \`${commandLine} --help\` to see the expected input`
|
|
6698
|
+
});
|
|
6701
6699
|
}
|
|
6702
6700
|
//#endregion
|
|
6703
|
-
//#region ../agent-cli/dist/
|
|
6704
|
-
const
|
|
6705
|
-
const
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6701
|
+
//#region ../agent-cli/dist/list.js
|
|
6702
|
+
const UNKNOWN_FIELD = "UNKNOWN_FIELD";
|
|
6703
|
+
const DEFAULT_PAGE_LIMIT = 20;
|
|
6704
|
+
const FIELDS_FLAG = "--fields";
|
|
6705
|
+
const SEPARATOR = ",";
|
|
6706
|
+
const COLUMN_SEPARATOR = " ";
|
|
6707
|
+
const UNSAFE_IN_COLUMN = /[\t\n\r]/;
|
|
6708
|
+
const PAGE_INPUT = object({
|
|
6709
|
+
limit: number().int().positive().default(DEFAULT_PAGE_LIMIT),
|
|
6710
|
+
cursor: string().min(1).optional()
|
|
6711
|
+
});
|
|
6712
|
+
var Page = class {
|
|
6713
|
+
items;
|
|
6714
|
+
nextCursor;
|
|
6715
|
+
constructor(items, nextCursor) {
|
|
6716
|
+
this.items = items;
|
|
6717
|
+
this.nextCursor = nextCursor;
|
|
6719
6718
|
}
|
|
6719
|
+
};
|
|
6720
|
+
const PAGE_FLAG_DESCRIPTIONS = {
|
|
6721
|
+
limit: `how many rows to show, a positive whole number (default: ${DEFAULT_PAGE_LIMIT})`,
|
|
6722
|
+
cursor: "where to start, as given by the previous page's next"
|
|
6723
|
+
};
|
|
6724
|
+
function pageFlag(key) {
|
|
6725
|
+
const field = optionField(key, PAGE_INPUT.shape[key]);
|
|
6726
|
+
return {
|
|
6727
|
+
flag: field.label,
|
|
6728
|
+
usage: field.usage,
|
|
6729
|
+
description: PAGE_FLAG_DESCRIPTIONS[key],
|
|
6730
|
+
takes: "optional value",
|
|
6731
|
+
schema: field.schema
|
|
6732
|
+
};
|
|
6720
6733
|
}
|
|
6721
|
-
|
|
6722
|
-
function fileNamesOf(name, env) {
|
|
6723
|
-
const extensions = extensionsOf(env);
|
|
6724
|
-
const own = extname(name).toUpperCase();
|
|
6725
|
-
return own !== "" && extensions.some((extension) => extension.toUpperCase() === own) ? [name] : extensions.map((extension) => `${name}${extension}`);
|
|
6726
|
-
}
|
|
6727
|
-
/** Where `name` is found on `PATH` from `env`, or undefined. */
|
|
6728
|
-
async function findTool(name, env) {
|
|
6729
|
-
const candidates = pathOf(env).split(delimiter).filter((folder) => folder !== "").flatMap((folder) => fileNamesOf(name, env).map((file) => join(folder, file)));
|
|
6730
|
-
for (const file of candidates) if (await isExecutable(file)) return file;
|
|
6731
|
-
}
|
|
6732
|
-
/** Fails with `TOOL_MISSING`, naming every missing tool at once, unless all are on `PATH`. */
|
|
6733
|
-
async function checkTools(tools, env, rerun) {
|
|
6734
|
-
const found = await Promise.all(tools.map((tool) => findTool(tool.name, env)));
|
|
6735
|
-
const missing = tools.filter((_tool, index) => found[index] === void 0);
|
|
6736
|
-
if (missing.length === 0) return;
|
|
6737
|
-
const names = missing.map(({ name }) => name).join(", ");
|
|
6738
|
-
throw runtimeError({
|
|
6739
|
-
code: TOOL_MISSING,
|
|
6740
|
-
message: `${missing.length === 1 ? "a tool it runs is" : "tools it runs are"} not on PATH: ${names}`,
|
|
6741
|
-
hint: "run the Next steps in order: each install, then the command again",
|
|
6742
|
-
next: [...missing.map(({ install }) => wholeLine(install)), rerun]
|
|
6743
|
-
});
|
|
6744
|
-
}
|
|
6745
|
-
/** One `doctor` row per distinct tool the CLI and its Commands declare, with its install command as the fix. */
|
|
6746
|
-
function toolRows(tools, commands) {
|
|
6747
|
-
return declaredIn(tools, commands, (command) => command.tools).map(({ name, install }) => ({
|
|
6748
|
-
name,
|
|
6749
|
-
run: async (ctx) => {
|
|
6750
|
-
const file = await findTool(name, ctx.env);
|
|
6751
|
-
return file === void 0 ? {
|
|
6752
|
-
state: "problem",
|
|
6753
|
-
message: `${name} is not on PATH`,
|
|
6754
|
-
fix: install
|
|
6755
|
-
} : {
|
|
6756
|
-
state: "ok",
|
|
6757
|
-
message: `found at ${file}`
|
|
6758
|
-
};
|
|
6759
|
-
}
|
|
6760
|
-
}));
|
|
6761
|
-
}
|
|
6762
|
-
//#endregion
|
|
6763
|
-
//#region ../agent-cli/dist/version.js
|
|
6764
|
-
/** The bundler's stamp, absent when the CLI runs unbundled. Read per call, so a test can define it. */
|
|
6765
|
-
function buildStamp() {
|
|
6734
|
+
function fieldsFlag(rowFields) {
|
|
6766
6735
|
return {
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6736
|
+
flag: FIELDS_FLAG,
|
|
6737
|
+
usage: `${FIELDS_FLAG} <a,b>`,
|
|
6738
|
+
description: `print only these comma-separated fields of each row (any of: ${rowFields.join(", ")})`,
|
|
6739
|
+
takes: "optional value",
|
|
6740
|
+
schema: string()
|
|
6770
6741
|
};
|
|
6771
6742
|
}
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6743
|
+
const PAGE_FIELDS = optionFields(PAGE_INPUT);
|
|
6744
|
+
const PAGE_FLAGS = {
|
|
6745
|
+
limit: pageFlag("limit"),
|
|
6746
|
+
cursor: pageFlag("cursor")
|
|
6747
|
+
};
|
|
6748
|
+
/** The Standard flags every List Command gets, as the caller types them. */
|
|
6749
|
+
const LIST_FLAGS = [...Object.values(PAGE_FLAGS).map(({ flag }) => flag), FIELDS_FLAG];
|
|
6750
|
+
function listSpec(rows) {
|
|
6751
|
+
const rowFields = Object.keys(rows.shape);
|
|
6752
|
+
return {
|
|
6753
|
+
rowFields,
|
|
6754
|
+
pageFields: PAGE_FIELDS,
|
|
6755
|
+
standardFlags: [...Object.values(PAGE_FLAGS), fieldsFlag(rowFields)],
|
|
6756
|
+
output: object({
|
|
6757
|
+
items: array(rows),
|
|
6758
|
+
next: string().optional()
|
|
6759
|
+
})
|
|
6760
|
+
};
|
|
6776
6761
|
}
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
/** The last `count` lines of a child's output, trimmed; empty when it wrote nothing. */
|
|
6780
|
-
function lastLines(output, count) {
|
|
6781
|
-
return output.trim().split("\n").slice(-count).join("\n");
|
|
6762
|
+
function quoted(names) {
|
|
6763
|
+
return names.map((name) => `'${name}'`).join(", ");
|
|
6782
6764
|
}
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
const
|
|
6786
|
-
|
|
6787
|
-
const
|
|
6788
|
-
const
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6765
|
+
/** The fields the caller asked for, in their order, or undefined when they gave no `--fields`. */
|
|
6766
|
+
function selectedFields(values, rowFields, commandLine) {
|
|
6767
|
+
const raw = values.get(FIELDS_FLAG);
|
|
6768
|
+
if (raw === void 0) return;
|
|
6769
|
+
const hint = `pass ${FIELDS_FLAG} with any of: ${rowFields.join(", ")}`;
|
|
6770
|
+
const names = typeof raw === "string" ? raw.split(SEPARATOR).filter((name) => name !== "") : [];
|
|
6771
|
+
if (names.length === 0) throw new UsageError({
|
|
6772
|
+
code: INVALID_INPUT,
|
|
6773
|
+
message: `${FIELDS_FLAG}: missing value for \`${commandLine}\``,
|
|
6774
|
+
hint
|
|
6775
|
+
});
|
|
6776
|
+
const unknown = names.filter((name) => !rowFields.includes(name));
|
|
6777
|
+
if (unknown.length > 0) throw new UsageError({
|
|
6778
|
+
code: UNKNOWN_FIELD,
|
|
6779
|
+
message: `unknown field ${quoted(unknown)} for \`${commandLine}\``,
|
|
6780
|
+
hint
|
|
6781
|
+
});
|
|
6782
|
+
return names;
|
|
6796
6783
|
}
|
|
6797
|
-
function
|
|
6798
|
-
return
|
|
6784
|
+
function fieldOf(row, field) {
|
|
6785
|
+
return typeof row === "object" && row !== null ? row[field] : void 0;
|
|
6799
6786
|
}
|
|
6800
|
-
function
|
|
6801
|
-
|
|
6802
|
-
return shim ? escapedForCmd(escaped) : escaped;
|
|
6787
|
+
function projected(rows, fields) {
|
|
6788
|
+
return rows.map((row) => Object.fromEntries(fields.map((field) => [field, fieldOf(row, field)])));
|
|
6803
6789
|
}
|
|
6804
|
-
function
|
|
6805
|
-
|
|
6806
|
-
return
|
|
6790
|
+
function cell(value) {
|
|
6791
|
+
if (value === void 0 || value === null) return "";
|
|
6792
|
+
return typeof value === "string" && !UNSAFE_IN_COLUMN.test(value) ? value : JSON.stringify(value);
|
|
6807
6793
|
}
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
};
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6794
|
+
/** Selected rows as text: a header line of the field names, then one tab-separated line per row. */
|
|
6795
|
+
function renderRows(rows, fields) {
|
|
6796
|
+
return `${[fields, ...rows.map((row) => fields.map((field) => cell(row[field])))].map((line) => line.join(COLUMN_SEPARATOR)).join("\n")}\n`;
|
|
6797
|
+
}
|
|
6798
|
+
function cursorWords(cursor) {
|
|
6799
|
+
const { flag } = PAGE_FLAGS.cursor;
|
|
6800
|
+
return cursor.startsWith("-") ? [`${flag}=${cursor}`] : [flag, cursor];
|
|
6801
|
+
}
|
|
6802
|
+
function printedPage(page, invocation) {
|
|
6803
|
+
return page.nextCursor === void 0 ? { items: page.items } : {
|
|
6804
|
+
items: page.items,
|
|
6805
|
+
next: lineOf({
|
|
6806
|
+
kind: "rerun",
|
|
6807
|
+
words: changedArgv(invocation, {
|
|
6808
|
+
remove: [PAGE_FLAGS.cursor.flag],
|
|
6809
|
+
add: cursorWords(page.nextCursor)
|
|
6810
|
+
}),
|
|
6811
|
+
stdinArg: invocation.stdinArg
|
|
6812
|
+
}, invocation.runAs)
|
|
6819
6813
|
};
|
|
6820
6814
|
}
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
return Promise.resolve();
|
|
6825
|
-
}
|
|
6826
|
-
const pid = String(child.pid);
|
|
6827
|
-
return new Promise((resolve) => {
|
|
6828
|
-
const taskkill = spawn("taskkill", [
|
|
6829
|
-
"/pid",
|
|
6830
|
-
pid,
|
|
6831
|
-
"/t",
|
|
6832
|
-
"/f"
|
|
6833
|
-
], {
|
|
6834
|
-
stdio: "ignore",
|
|
6835
|
-
windowsHide: true
|
|
6836
|
-
});
|
|
6837
|
-
taskkill.once("error", () => {
|
|
6838
|
-
child.kill();
|
|
6839
|
-
resolve();
|
|
6840
|
-
});
|
|
6841
|
-
taskkill.once("exit", () => resolve());
|
|
6842
|
-
});
|
|
6815
|
+
/** The lines that end a rendered page, so the caller always knows whether and how to get more. */
|
|
6816
|
+
function pageFooter({ items, next }, style) {
|
|
6817
|
+
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`;
|
|
6843
6818
|
}
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
|
|
6819
|
+
//#endregion
|
|
6820
|
+
//#region ../agent-cli/dist/planned.js
|
|
6821
|
+
/** Whether `command` changes something through a Plan: a write or destructive Command. */
|
|
6822
|
+
function hasPlan(command) {
|
|
6823
|
+
return command.effect === "write" || command.effect === "destructive";
|
|
6824
|
+
}
|
|
6825
|
+
//#endregion
|
|
6826
|
+
//#region ../agent-cli/dist/command-line/flags.js
|
|
6827
|
+
const HELP_FLAG = "--help";
|
|
6828
|
+
const VERSION_FLAG = "--version";
|
|
6829
|
+
const ROUTING_FLAGS = [
|
|
6830
|
+
HELP_FLAG,
|
|
6831
|
+
"-h",
|
|
6832
|
+
VERSION_FLAG
|
|
6833
|
+
];
|
|
6834
|
+
function nameOf$1(flag) {
|
|
6835
|
+
return flag.replace(/^--?/, "");
|
|
6836
|
+
}
|
|
6837
|
+
function standardFlag(flag, { placeholder, ...rest }) {
|
|
6847
6838
|
return {
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
rest = lines.pop() ?? "";
|
|
6852
|
-
for (const line of lines) onLine(line);
|
|
6853
|
-
},
|
|
6854
|
-
end() {
|
|
6855
|
-
if (rest !== "") onLine?.(rest.replace(TRAILING_CR, ""));
|
|
6856
|
-
rest = "";
|
|
6857
|
-
}
|
|
6839
|
+
flag,
|
|
6840
|
+
usage: placeholder === void 0 ? flag : `${flag} ${placeholder}`,
|
|
6841
|
+
...rest
|
|
6858
6842
|
};
|
|
6859
6843
|
}
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6844
|
+
const JSON_FLAG = standardFlag("--json", {
|
|
6845
|
+
description: "print the result as JSON",
|
|
6846
|
+
takes: "nothing",
|
|
6847
|
+
schema: boolean()
|
|
6848
|
+
});
|
|
6849
|
+
const DRY_RUN_FLAG = standardFlag("--dry-run", {
|
|
6850
|
+
description: "print the Plan without changing anything",
|
|
6851
|
+
takes: "nothing",
|
|
6852
|
+
schema: boolean()
|
|
6853
|
+
});
|
|
6854
|
+
const CONFIRM_FLAG = standardFlag("--confirm", {
|
|
6855
|
+
placeholder: "<target>",
|
|
6856
|
+
description: "name the target to confirm the change; an error hint gives the exact command",
|
|
6857
|
+
takes: "value",
|
|
6858
|
+
schema: string()
|
|
6859
|
+
});
|
|
6860
|
+
const YES_FLAG = standardFlag("--yes", {
|
|
6861
|
+
description: "approve the cost the run states; --dry-run shows it",
|
|
6862
|
+
takes: "nothing",
|
|
6863
|
+
schema: boolean()
|
|
6864
|
+
});
|
|
6865
|
+
const FORCE_FLAG = standardFlag("--force", {
|
|
6866
|
+
description: "replace a file the run writes that already exists; --dry-run lists every file it writes",
|
|
6867
|
+
takes: "nothing",
|
|
6868
|
+
schema: boolean()
|
|
6869
|
+
});
|
|
6870
|
+
const EFFECT_FLAGS = {
|
|
6871
|
+
read: [JSON_FLAG],
|
|
6872
|
+
act: [JSON_FLAG],
|
|
6873
|
+
write: [JSON_FLAG, DRY_RUN_FLAG],
|
|
6874
|
+
destructive: [
|
|
6875
|
+
JSON_FLAG,
|
|
6876
|
+
DRY_RUN_FLAG,
|
|
6877
|
+
CONFIRM_FLAG
|
|
6878
|
+
],
|
|
6879
|
+
serve: [JSON_FLAG]
|
|
6880
|
+
};
|
|
6881
|
+
const RESERVED = new Map([
|
|
6882
|
+
...ROUTING_FLAGS,
|
|
6883
|
+
...EFFECT_FLAGS.destructive.map(({ flag }) => flag),
|
|
6884
|
+
YES_FLAG.flag,
|
|
6885
|
+
FORCE_FLAG.flag,
|
|
6886
|
+
...LIST_FLAGS
|
|
6887
|
+
].map((flag) => [nameOf$1(flag), flag]));
|
|
6888
|
+
/** The Standard flags of a Command with this Effect and declarations, and of a List Command. */
|
|
6889
|
+
function standardFlagsFor(effect, { outputs, force, cost }, list) {
|
|
6890
|
+
const forceFlag = force === void 0 ? FORCE_FLAG : {
|
|
6891
|
+
...FORCE_FLAG,
|
|
6892
|
+
description: force
|
|
6870
6893
|
};
|
|
6894
|
+
return [
|
|
6895
|
+
...EFFECT_FLAGS[effect],
|
|
6896
|
+
...outputs || force !== void 0 ? [forceFlag] : [],
|
|
6897
|
+
...cost ? [YES_FLAG] : [],
|
|
6898
|
+
...list?.standardFlags ?? []
|
|
6899
|
+
];
|
|
6871
6900
|
}
|
|
6872
|
-
/**
|
|
6873
|
-
function
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
6901
|
+
/** Throws when the Command declares an arg or option under a Standard flag's name. */
|
|
6902
|
+
function checkNoStandardFlags(command, label) {
|
|
6903
|
+
const lines = [...argFields(command.args).map(({ key }) => ({
|
|
6904
|
+
kind: "arg",
|
|
6905
|
+
key
|
|
6906
|
+
})), ...optionFields(command.options).map(({ key }) => ({
|
|
6907
|
+
kind: "option",
|
|
6908
|
+
key
|
|
6909
|
+
}))].flatMap(({ kind, key }) => {
|
|
6910
|
+
const flag = RESERVED.get(kebab(key));
|
|
6911
|
+
return flag === void 0 ? [] : [` ${kind} '${key}' is the Standard flag ${flag}`];
|
|
6882
6912
|
});
|
|
6913
|
+
if (lines.length > 0) throw new Error([`Command '${label}' declares Standard flags the Runtime adds; rename them:`, ...lines].join("\n"));
|
|
6883
6914
|
}
|
|
6884
|
-
/**
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
const chunks = isWhole(input) ? [input] : input;
|
|
6891
|
-
for await (const chunk of chunks) {
|
|
6892
|
-
if (signal.aborted || stdin.destroyed) return;
|
|
6893
|
-
if (!stdin.write(chunk)) await drained(stdin);
|
|
6894
|
-
}
|
|
6895
|
-
stdin.end();
|
|
6915
|
+
/** Throws when `force` is declared on a Command with no Plan, or says nothing. */
|
|
6916
|
+
function checkForce(command, label) {
|
|
6917
|
+
const force = "force" in command ? command.force : void 0;
|
|
6918
|
+
if (force === void 0) return;
|
|
6919
|
+
if (!hasPlan(command)) throw new Error(`Command '${label}' declares force, which only a write or destructive Command may`);
|
|
6920
|
+
if (force.trim() === "") throw new Error(`Command '${label}' declares an empty force; say what ${FORCE_FLAG.flag} replaces`);
|
|
6896
6921
|
}
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
cwd,
|
|
6908
|
-
env,
|
|
6909
|
-
shell: launch.shell,
|
|
6910
|
-
windowsHide: true,
|
|
6911
|
-
stdio: [
|
|
6912
|
-
stdin === void 0 ? "ignore" : "pipe",
|
|
6913
|
-
"pipe",
|
|
6914
|
-
"pipe"
|
|
6915
|
-
],
|
|
6916
|
-
detached: detached && process.platform !== "win32"
|
|
6917
|
-
});
|
|
6918
|
-
let stopped = Promise.resolve();
|
|
6919
|
-
const kill = () => {
|
|
6920
|
-
stopped = stop(child);
|
|
6921
|
-
};
|
|
6922
|
-
signal.addEventListener("abort", kill, { once: true });
|
|
6923
|
-
let callerFailure;
|
|
6924
|
-
const fail = (error) => {
|
|
6925
|
-
if (callerFailure !== void 0) return;
|
|
6926
|
-
callerFailure = { error };
|
|
6927
|
-
kill();
|
|
6928
|
-
};
|
|
6929
|
-
let stdout = "";
|
|
6930
|
-
let stderr = "";
|
|
6931
|
-
const lines = guarded(onLine, () => callerFailure !== void 0, fail);
|
|
6932
|
-
const stdoutLines = lineSplitter(lines);
|
|
6933
|
-
const stderrLines = lineSplitter(lines);
|
|
6934
|
-
child.stdout?.setEncoding("utf8").on("data", (chunk) => {
|
|
6935
|
-
stdout += chunk;
|
|
6936
|
-
stdoutLines.push(chunk);
|
|
6937
|
-
});
|
|
6938
|
-
child.stderr?.setEncoding("utf8").on("data", (chunk) => {
|
|
6939
|
-
stderr += chunk;
|
|
6940
|
-
stderrLines.push(chunk);
|
|
6941
|
-
});
|
|
6942
|
-
if (stdin !== void 0 && child.stdin !== null) feed(child.stdin, stdin, signal).catch(fail);
|
|
6943
|
-
child.on("error", (error) => {
|
|
6944
|
-
signal.removeEventListener("abort", kill);
|
|
6945
|
-
reject(error);
|
|
6946
|
-
});
|
|
6947
|
-
child.on("close", (code, killedBy) => {
|
|
6948
|
-
signal.removeEventListener("abort", kill);
|
|
6949
|
-
if (signal.aborted) {
|
|
6950
|
-
stopped.then(() => reject(signal.reason));
|
|
6951
|
-
return;
|
|
6952
|
-
}
|
|
6953
|
-
stdoutLines.end();
|
|
6954
|
-
stderrLines.end();
|
|
6955
|
-
if (callerFailure !== void 0) {
|
|
6956
|
-
const { error } = callerFailure;
|
|
6957
|
-
stopped.then(() => reject(error));
|
|
6958
|
-
return;
|
|
6959
|
-
}
|
|
6960
|
-
resolve({
|
|
6961
|
-
stdout,
|
|
6962
|
-
stderr,
|
|
6963
|
-
exitCode: code ?? SIGNAL_EXIT_BASE + (killedBy === null ? 0 : constants$1.signals[killedBy])
|
|
6964
|
-
});
|
|
6965
|
-
});
|
|
6966
|
-
});
|
|
6922
|
+
//#endregion
|
|
6923
|
+
//#region ../agent-cli/dist/define-command.js
|
|
6924
|
+
/** Throws when the Command's declaration breaks a rule its type cannot express; `label` names it. */
|
|
6925
|
+
function checkCommand(command, label, table) {
|
|
6926
|
+
checkNoStandardFlags(command, label);
|
|
6927
|
+
checkForce(command, label);
|
|
6928
|
+
checkArrayArgLast(label, command.args);
|
|
6929
|
+
checkStdinFields(label, command.args, command.options);
|
|
6930
|
+
checkNoBooleanArrayOption(label, command.options);
|
|
6931
|
+
checkErrors(command, label, table);
|
|
6967
6932
|
}
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
args,
|
|
6972
|
-
shell: false
|
|
6973
|
-
};
|
|
6933
|
+
function checkErrors(command, label, table) {
|
|
6934
|
+
const unknown = (command.errors ?? []).filter((code) => !Object.hasOwn(table, code));
|
|
6935
|
+
if (unknown.length > 0) throw new Error(`${label} declares ${unknown.join(", ")} in errors, a code the Error table lacks`);
|
|
6974
6936
|
}
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
const launch = await launchOf(command, args, env);
|
|
6981
|
-
return new Promise((resolve, reject) => {
|
|
6982
|
-
const child = spawn(launch.command, launch.args, {
|
|
6983
|
-
cwd,
|
|
6984
|
-
env,
|
|
6985
|
-
shell: launch.shell,
|
|
6986
|
-
windowsHide: true,
|
|
6987
|
-
stdio: "ignore",
|
|
6988
|
-
detached: true
|
|
6989
|
-
});
|
|
6990
|
-
child.unref();
|
|
6991
|
-
child.once("error", reject);
|
|
6992
|
-
child.once("spawn", () => {
|
|
6993
|
-
child.off("error", reject);
|
|
6994
|
-
const { pid } = child;
|
|
6995
|
-
if (pid === void 0) reject(/* @__PURE__ */ new Error(`${command} started without a pid`));
|
|
6996
|
-
else resolve({ pid });
|
|
6997
|
-
});
|
|
6998
|
-
});
|
|
6999
|
-
};
|
|
7000
|
-
const realSpawn = (command, args, options) => spawnChild(command, args, options);
|
|
7001
|
-
function failedError(command, { exitCode, stderr }) {
|
|
7002
|
-
const tail = lastLines(stderr, STDERR_TAIL_LINES$1);
|
|
7003
|
-
return new CliError({
|
|
7004
|
-
code: TOOL_FAILED,
|
|
7005
|
-
message: tail === "" ? `${command} exited with ${exitCode} and wrote nothing to stderr` : `${command} exited with ${exitCode}; its stderr ends:\n${tail}`,
|
|
7006
|
-
hint: `the output of ${command} above says why it failed`
|
|
7007
|
-
});
|
|
6937
|
+
function defineCommandFor() {
|
|
6938
|
+
return declared;
|
|
6939
|
+
}
|
|
6940
|
+
function declared(command) {
|
|
6941
|
+
return command;
|
|
7008
6942
|
}
|
|
7009
|
-
|
|
6943
|
+
const defineCommand$1 = defineCommandFor();
|
|
6944
|
+
//#endregion
|
|
6945
|
+
//#region ../agent-cli/dist/context/project.js
|
|
6946
|
+
const PROJECT_INVALID = "PROJECT_INVALID";
|
|
6947
|
+
function invalid(path, problem, rerun, options) {
|
|
7010
6948
|
return new CliError({
|
|
7011
|
-
code:
|
|
7012
|
-
message:
|
|
7013
|
-
hint: `
|
|
6949
|
+
code: PROJECT_INVALID,
|
|
6950
|
+
message: `the Project file ${path} is invalid: ${problem}`,
|
|
6951
|
+
hint: `fix ${path}, then run the Next step`,
|
|
7014
6952
|
next: [rerun]
|
|
7015
|
-
},
|
|
6953
|
+
}, options);
|
|
7016
6954
|
}
|
|
7017
|
-
function
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
6955
|
+
function readText(path, fileError) {
|
|
6956
|
+
try {
|
|
6957
|
+
return readFileSync(path, "utf8");
|
|
6958
|
+
} catch (error) {
|
|
6959
|
+
if (isMissingFile(error)) return void 0;
|
|
6960
|
+
throw fileError(error, {
|
|
6961
|
+
path,
|
|
6962
|
+
access: "read"
|
|
6963
|
+
});
|
|
6964
|
+
}
|
|
6965
|
+
}
|
|
6966
|
+
function parsed(path, text, schema, rerun) {
|
|
6967
|
+
let json;
|
|
6968
|
+
try {
|
|
6969
|
+
json = JSON.parse(text);
|
|
6970
|
+
} catch (error) {
|
|
6971
|
+
throw invalid(path, messageOf(error), rerun, { cause: error });
|
|
6972
|
+
}
|
|
6973
|
+
const result = schema.safeParse(json);
|
|
6974
|
+
if (!result.success) throw invalid(path, prettifyError(result.error), rerun);
|
|
6975
|
+
return result.data;
|
|
6976
|
+
}
|
|
6977
|
+
function projectFrom(projectFile, folder, scope) {
|
|
6978
|
+
const path = join(folder, projectFile.file);
|
|
6979
|
+
const text = readText(path, scope.fileError);
|
|
6980
|
+
if (text !== void 0) return {
|
|
6981
|
+
root: folder,
|
|
6982
|
+
settings: parsed(path, text, projectFile.schema, scope.rerun)
|
|
6983
|
+
};
|
|
6984
|
+
const parent = dirname(folder);
|
|
6985
|
+
return parent === folder ? void 0 : projectFrom(projectFile, parent, scope);
|
|
6986
|
+
}
|
|
6987
|
+
/** The nearest Project file at or above `cwd`, parsed by its schema; undefined when there is none. */
|
|
6988
|
+
function projectOf(projectFile, cwd, scope) {
|
|
6989
|
+
return projectFrom(projectFile, resolve(cwd), scope);
|
|
7023
6990
|
}
|
|
7024
|
-
|
|
6991
|
+
//#endregion
|
|
6992
|
+
//#region ../agent-cli/dist/context/secrets.js
|
|
6993
|
+
const SECRET_MISSING = "SECRET_MISSING";
|
|
6994
|
+
/** `$XDG_CONFIG_HOME/<cli>/.env`, with `~/.config` when the variable is unset or empty. */
|
|
6995
|
+
function envFileOf(cliName, env) {
|
|
6996
|
+
const config = env.XDG_CONFIG_HOME || join(env.HOME || homedir(), ".config");
|
|
6997
|
+
return join(config, cliName, ".env");
|
|
6998
|
+
}
|
|
6999
|
+
function readDotenv(path, fileError) {
|
|
7000
|
+
let text;
|
|
7025
7001
|
try {
|
|
7026
|
-
|
|
7002
|
+
text = readFileSync(path, "utf8");
|
|
7027
7003
|
} catch (error) {
|
|
7028
|
-
|
|
7029
|
-
throw error
|
|
7004
|
+
if (isMissingFile(error)) return {};
|
|
7005
|
+
throw fileError(error, {
|
|
7006
|
+
path,
|
|
7007
|
+
access: "read"
|
|
7008
|
+
});
|
|
7030
7009
|
}
|
|
7010
|
+
return parseEnv(text);
|
|
7031
7011
|
}
|
|
7032
|
-
/** `
|
|
7033
|
-
function
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
if (onLine === void 0) return void 0;
|
|
7039
|
-
return (line) => {
|
|
7040
|
-
try {
|
|
7041
|
-
onLine(line);
|
|
7042
|
-
} catch (error) {
|
|
7043
|
-
onError(error);
|
|
7044
|
-
throw error;
|
|
7045
|
-
}
|
|
7012
|
+
/** Looks `name` up in the env, then in `envFile`; an empty value counts as unset. */
|
|
7013
|
+
function secretOf({ envFile, env, fileError }, name) {
|
|
7014
|
+
const fromEnv = env[name];
|
|
7015
|
+
if (fromEnv) return {
|
|
7016
|
+
value: fromEnv,
|
|
7017
|
+
origin: { kind: "env" }
|
|
7046
7018
|
};
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
};
|
|
7054
|
-
let result;
|
|
7055
|
-
try {
|
|
7056
|
-
result = await run(command, args, {
|
|
7057
|
-
cwd: options.cwd ?? defaults.cwd,
|
|
7058
|
-
env: options.env ?? defaults.env,
|
|
7059
|
-
signal: defaults.signal,
|
|
7060
|
-
onLine: reportingLines(options.onLine, caller),
|
|
7061
|
-
stdin: reporting(options.stdin, caller)
|
|
7062
|
-
});
|
|
7063
|
-
} catch (error) {
|
|
7064
|
-
throw callerFailure?.error === error ? error : startError(command, error, scope);
|
|
7019
|
+
const fromFile = readDotenv(envFile, fileError)[name];
|
|
7020
|
+
return fromFile ? {
|
|
7021
|
+
value: fromFile,
|
|
7022
|
+
origin: {
|
|
7023
|
+
kind: "file",
|
|
7024
|
+
path: envFile
|
|
7065
7025
|
}
|
|
7066
|
-
|
|
7067
|
-
return result;
|
|
7068
|
-
};
|
|
7026
|
+
} : void 0;
|
|
7069
7027
|
}
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7028
|
+
function missingIn(scope, secrets) {
|
|
7029
|
+
return secrets.filter(({ name }) => secretOf(scope, name) === void 0);
|
|
7030
|
+
}
|
|
7031
|
+
function getItFrom({ get }) {
|
|
7032
|
+
return `(get it from ${get})`;
|
|
7033
|
+
}
|
|
7034
|
+
function whereToGet(secrets) {
|
|
7035
|
+
return secrets.map((secret) => `${secret.name} ${getItFrom(secret)}`).join(", ");
|
|
7036
|
+
}
|
|
7037
|
+
/** Fails with `SECRET_MISSING`, naming every missing Secret at once, unless all are set. */
|
|
7038
|
+
function checkSecrets(secrets, scope, rerun) {
|
|
7039
|
+
const missing = missingIn(scope, secrets);
|
|
7040
|
+
if (missing.length === 0) return;
|
|
7041
|
+
const names = missing.map(({ name }) => name).join(", ");
|
|
7042
|
+
throw new CliError({
|
|
7043
|
+
code: SECRET_MISSING,
|
|
7044
|
+
message: `${missing.length === 1 ? "a Secret it needs is" : "Secrets it needs are"} not set: ${names}`,
|
|
7045
|
+
hint: `set ${whereToGet(missing)} in the environment or in ${scope.envFile}, then run the Next step`,
|
|
7046
|
+
next: [rerun]
|
|
7047
|
+
});
|
|
7048
|
+
}
|
|
7049
|
+
function originOf({ origin }) {
|
|
7050
|
+
return origin.kind === "env" ? "the environment" : origin.path;
|
|
7051
|
+
}
|
|
7052
|
+
/** The `doctor` row over every distinct Secret the CLI and its Commands declare; none without any. */
|
|
7053
|
+
function secretRows(secrets, commands) {
|
|
7054
|
+
const declared = declaredIn(secrets, commands, (command) => command.secrets);
|
|
7055
|
+
if (declared.length === 0) return [];
|
|
7056
|
+
return [{
|
|
7057
|
+
name: "secrets",
|
|
7058
|
+
run: ({ env, envFile, fileError }) => {
|
|
7059
|
+
const read = declared.map((declaration) => ({
|
|
7060
|
+
declaration,
|
|
7061
|
+
secret: secretOf({
|
|
7062
|
+
env,
|
|
7063
|
+
envFile,
|
|
7064
|
+
fileError
|
|
7065
|
+
}, declaration.name)
|
|
7066
|
+
}));
|
|
7067
|
+
const missing = read.filter(({ secret }) => secret === void 0);
|
|
7068
|
+
if (missing.length > 0) return {
|
|
7069
|
+
state: "problem",
|
|
7070
|
+
message: `${missing.map(({ declaration }) => `${declaration.name} is not set ${getItFrom(declaration)}`).join(", ")}; add ${missing.length === 1 ? "it" : "them"} to ${envFile} or the environment`
|
|
7071
|
+
};
|
|
7072
|
+
return {
|
|
7073
|
+
state: "ok",
|
|
7074
|
+
message: read.flatMap(({ declaration, secret }) => secret === void 0 ? [] : [`${declaration.name} from ${originOf(secret)}`]).join(", ")
|
|
7075
|
+
};
|
|
7081
7076
|
}
|
|
7077
|
+
}];
|
|
7078
|
+
}
|
|
7079
|
+
//#endregion
|
|
7080
|
+
//#region ../agent-cli/dist/version.js
|
|
7081
|
+
/** The bundler's stamp, absent when the CLI runs unbundled. Read per call, so a test can define it. */
|
|
7082
|
+
function buildStamp() {
|
|
7083
|
+
return {
|
|
7084
|
+
"sha": "4664298",
|
|
7085
|
+
"dirty": false,
|
|
7086
|
+
"builtAt": "2026-11-02T04:03:08.000Z"
|
|
7082
7087
|
};
|
|
7083
7088
|
}
|
|
7089
|
+
/** The first line of `--version`: the version, and the commit and time of a stamped build. */
|
|
7090
|
+
function versionLine({ version }) {
|
|
7091
|
+
const build = buildStamp();
|
|
7092
|
+
return build === void 0 ? version : `${version} (${build.sha}${build.dirty ? "+dirty" : ""}) built ${build.builtAt}`;
|
|
7093
|
+
}
|
|
7094
|
+
//#endregion
|
|
7095
|
+
//#region ../agent-cli/dist/context/agent.js
|
|
7096
|
+
const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
|
|
7097
|
+
const isSet = (name) => (env) => (env[name] ?? "") !== "";
|
|
7098
|
+
const equals = (name, value) => (env) => env[name] === value;
|
|
7099
|
+
const MARKERS = [
|
|
7100
|
+
(env) => AGENT_NAME.test(env.AI_AGENT ?? ""),
|
|
7101
|
+
equals("AGENT", "amp"),
|
|
7102
|
+
isSet("CODEX_SANDBOX"),
|
|
7103
|
+
isSet("CODEX_CI"),
|
|
7104
|
+
isSet("CODEX_THREAD_ID"),
|
|
7105
|
+
isSet("GEMINI_CLI"),
|
|
7106
|
+
isSet("COPILOT_CLI"),
|
|
7107
|
+
isSet("OPENCODE"),
|
|
7108
|
+
isSet("ANTIGRAVITY_AGENT"),
|
|
7109
|
+
isSet("AUGMENT_AGENT"),
|
|
7110
|
+
isSet("REPL_ID"),
|
|
7111
|
+
isSet("CLAUDE_CODE_IS_COWORK"),
|
|
7112
|
+
isSet("CLAUDECODE"),
|
|
7113
|
+
isSet("CLAUDE_CODE"),
|
|
7114
|
+
isSet("CURSOR_TRACE_ID"),
|
|
7115
|
+
isSet("CURSOR_AGENT"),
|
|
7116
|
+
equals("CURSOR_EXTENSION_HOST_ROLE", "agent-exec"),
|
|
7117
|
+
equals("TERM_PROGRAM", "kiro"),
|
|
7118
|
+
(env) => ["/.pi/agent", "\\.pi\\agent"].some((dir) => (env.PATH ?? "").includes(dir)),
|
|
7119
|
+
isSet("GOOSE_PROVIDER")
|
|
7120
|
+
];
|
|
7121
|
+
/**
|
|
7122
|
+
* Whether a Coding agent, not a person, is running the Agent CLI. Some Coding agents run commands
|
|
7123
|
+
* in a PTY, so a TTY alone doesn't mean a person is watching.
|
|
7124
|
+
*/
|
|
7125
|
+
function isAgent(env) {
|
|
7126
|
+
return MARKERS.some((marker) => marker(env));
|
|
7127
|
+
}
|
|
7084
7128
|
//#endregion
|
|
7085
7129
|
//#region ../agent-cli/dist/built-ins/semver.js
|
|
7086
7130
|
const VERSION = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
@@ -7221,8 +7265,14 @@ function tail$1(stderr) {
|
|
|
7221
7265
|
const lines = lastLines(stderr, STDERR_TAIL_LINES);
|
|
7222
7266
|
return lines === "" ? "" : `\n${lines}`;
|
|
7223
7267
|
}
|
|
7268
|
+
function authHint(code, ctx) {
|
|
7269
|
+
const { label: registry, loginHint } = ctx.registry;
|
|
7270
|
+
const login = `${loginHint}, then ${RUN_AGAIN}`;
|
|
7271
|
+
if (code !== "E403" || !isAgent(ctx.env)) return login;
|
|
7272
|
+
return `a Coding agent's sandbox may refuse ${registry} with a 403: ask your user to type ! and ${RUN_AGAIN}, or to allow ${registry} in the sandbox's network list; if it fails outside the sandbox too, ${login}`;
|
|
7273
|
+
}
|
|
7224
7274
|
function failureOf(call, answer, ctx) {
|
|
7225
|
-
const { label: registry, package: name,
|
|
7275
|
+
const { label: registry, package: name, unreachableHint } = ctx.registry;
|
|
7226
7276
|
const code = NPM_CODE.exec(answer.stderr)?.[1];
|
|
7227
7277
|
const output = tail$1(answer.stderr);
|
|
7228
7278
|
const next = [ctx.rerun];
|
|
@@ -7235,7 +7285,7 @@ function failureOf(call, answer, ctx) {
|
|
|
7235
7285
|
if (code !== void 0 && AUTH_CODES.has(code)) return new CliError({
|
|
7236
7286
|
code: REGISTRY_AUTH,
|
|
7237
7287
|
message: `${registry} refused npm's credentials (${code})${output}`,
|
|
7238
|
-
hint:
|
|
7288
|
+
hint: authHint(code, ctx),
|
|
7239
7289
|
next
|
|
7240
7290
|
});
|
|
7241
7291
|
if (call === "view" && code === "E404") return noLatest(ctx, `npm found no ${name}@latest on ${registry}: no version of it is published there`);
|
|
@@ -7475,7 +7525,7 @@ function packagesOf(install) {
|
|
|
7475
7525
|
function isUnchecked(standing) {
|
|
7476
7526
|
return standing.kind === "source" || standing.kind === "linked";
|
|
7477
7527
|
}
|
|
7478
|
-
function skippedFor(cli, install, standing) {
|
|
7528
|
+
function skippedFor$1(cli, install, standing) {
|
|
7479
7529
|
return {
|
|
7480
7530
|
state: "skipped",
|
|
7481
7531
|
message: standing.kind === "source" ? `not checked: ${cli.name} runs from source, not from an install` : `not checked: ${install.package} links to ${standing.copy.realDir}, so the workspace decides its version`
|
|
@@ -7500,7 +7550,7 @@ function installFinding(cli, runAs, install, { cwd, root, standing }) {
|
|
|
7500
7550
|
const lines = root === void 0 ? void 0 : LINES[root.manager];
|
|
7501
7551
|
switch (standing.kind) {
|
|
7502
7552
|
case "source":
|
|
7503
|
-
case "linked": return skippedFor(cli, install, standing);
|
|
7553
|
+
case "linked": return skippedFor$1(cli, install, standing);
|
|
7504
7554
|
case "missing": return problem(`no package ${searchedFrom(cwd, root)} depends on ${install.package}`, lines?.add(packagesOf(install)));
|
|
7505
7555
|
case "listed": return problem(`${standing.manifest} lists ${install.package}, but no copy of it is installed at or above ${cwd}`, lines?.install);
|
|
7506
7556
|
case "unreadable": return problem(`${standing.manifest} is not a package.json with a version: ${standing.reason}`, lines?.install);
|
|
@@ -7546,7 +7596,7 @@ function checkOf$1(cli, install, runAs, { bin, node }) {
|
|
|
7546
7596
|
install: async (ctx) => installFinding(cli, runAs, install, await surveyed(ctx.cwd)),
|
|
7547
7597
|
release: async (ctx) => {
|
|
7548
7598
|
const { cwd, root, standing } = await surveyed(ctx.cwd);
|
|
7549
|
-
if (isUnchecked(standing)) return { skipped: skippedFor(cli, install, standing) };
|
|
7599
|
+
if (isUnchecked(standing)) return { skipped: skippedFor$1(cli, install, standing) };
|
|
7550
7600
|
return {
|
|
7551
7601
|
npm: npmContext(cli, registryOf(install, root?.dir), ctx, node, root?.dir ?? cwd),
|
|
7552
7602
|
advise: (latest) => adviceFor(install, root, latest)
|
|
@@ -7659,6 +7709,7 @@ function hubSkill(cli, from) {
|
|
|
7659
7709
|
run: async (ctx) => findingOf(await skillCopies(cli.name, cli.version, ctx))
|
|
7660
7710
|
}],
|
|
7661
7711
|
notice: async () => {},
|
|
7712
|
+
differing: async (place) => (await skillCopies(cli.name, cli.version, place)).filter(({ state }) => state !== "current" && state !== "unreadable").map(describeCopy),
|
|
7662
7713
|
nextAt: async (version, ctx) => {
|
|
7663
7714
|
const copies = await skillCopies(cli.name, version, ctx);
|
|
7664
7715
|
const fix = fixFor(cli.name, copies, from);
|
|
@@ -7741,40 +7792,6 @@ function agentsRow(agents, install) {
|
|
|
7741
7792
|
};
|
|
7742
7793
|
}
|
|
7743
7794
|
//#endregion
|
|
7744
|
-
//#region ../agent-cli/dist/context/agent.js
|
|
7745
|
-
const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
|
|
7746
|
-
const isSet = (name) => (env) => (env[name] ?? "") !== "";
|
|
7747
|
-
const equals = (name, value) => (env) => env[name] === value;
|
|
7748
|
-
const MARKERS = [
|
|
7749
|
-
(env) => AGENT_NAME.test(env.AI_AGENT ?? ""),
|
|
7750
|
-
equals("AGENT", "amp"),
|
|
7751
|
-
isSet("CODEX_SANDBOX"),
|
|
7752
|
-
isSet("CODEX_CI"),
|
|
7753
|
-
isSet("CODEX_THREAD_ID"),
|
|
7754
|
-
isSet("GEMINI_CLI"),
|
|
7755
|
-
isSet("COPILOT_CLI"),
|
|
7756
|
-
isSet("OPENCODE"),
|
|
7757
|
-
isSet("ANTIGRAVITY_AGENT"),
|
|
7758
|
-
isSet("AUGMENT_AGENT"),
|
|
7759
|
-
isSet("REPL_ID"),
|
|
7760
|
-
isSet("CLAUDE_CODE_IS_COWORK"),
|
|
7761
|
-
isSet("CLAUDECODE"),
|
|
7762
|
-
isSet("CLAUDE_CODE"),
|
|
7763
|
-
isSet("CURSOR_TRACE_ID"),
|
|
7764
|
-
isSet("CURSOR_AGENT"),
|
|
7765
|
-
equals("CURSOR_EXTENSION_HOST_ROLE", "agent-exec"),
|
|
7766
|
-
equals("TERM_PROGRAM", "kiro"),
|
|
7767
|
-
(env) => ["/.pi/agent", "\\.pi\\agent"].some((dir) => (env.PATH ?? "").includes(dir)),
|
|
7768
|
-
isSet("GOOSE_PROVIDER")
|
|
7769
|
-
];
|
|
7770
|
-
/**
|
|
7771
|
-
* Whether a Coding agent, not a person, is running the Agent CLI. Some Coding agents run commands
|
|
7772
|
-
* in a PTY, so a TTY alone doesn't mean a person is watching.
|
|
7773
|
-
*/
|
|
7774
|
-
function isAgent(env) {
|
|
7775
|
-
return MARKERS.some((marker) => marker(env));
|
|
7776
|
-
}
|
|
7777
|
-
//#endregion
|
|
7778
7795
|
//#region ../agent-cli/dist/context/errno.js
|
|
7779
7796
|
const PERMISSION_DENIED = "PERMISSION_DENIED";
|
|
7780
7797
|
const DISK_FULL = "DISK_FULL";
|
|
@@ -8295,6 +8312,15 @@ function packagedSkill(cli, { packaged: folder, agents: text }, install) {
|
|
|
8295
8312
|
run: (ctx) => findingOf(cli, folder, install, ctx)
|
|
8296
8313
|
}, ...agents === void 0 ? [] : [agentsRow(agents, install)]],
|
|
8297
8314
|
notice: (launch, ctx) => notice(cli, folder, install, launch, ctx),
|
|
8315
|
+
differing: async ({ cwd, packageRoot }) => {
|
|
8316
|
+
const { copy } = await skillCopyOf(cli, cwd);
|
|
8317
|
+
const { copyVersion, packageVersion, same } = await skillVersionsOf(join(packageRoot, folder), copy);
|
|
8318
|
+
return copyVersion === void 0 || same ? [] : [compared(cli.name, {
|
|
8319
|
+
copy,
|
|
8320
|
+
copyVersion,
|
|
8321
|
+
packageVersion
|
|
8322
|
+
}, false)];
|
|
8323
|
+
},
|
|
8298
8324
|
nextAt: async (_version, ctx) => {
|
|
8299
8325
|
const { fix } = await findingOf(cli, folder, install, ctx);
|
|
8300
8326
|
return fix === void 0 ? [] : [fix];
|
|
@@ -8759,12 +8785,21 @@ function nodeRow(cli) {
|
|
|
8759
8785
|
};
|
|
8760
8786
|
}
|
|
8761
8787
|
/** A row's thrown error as its problem: a `CliError` with its hint and code, anything else a bug. */
|
|
8762
|
-
function problemOfError(name, error) {
|
|
8763
|
-
if (error instanceof CliError)
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
|
|
8788
|
+
function problemOfError(name, error, runAs) {
|
|
8789
|
+
if (error instanceof CliError) {
|
|
8790
|
+
const message = `${error.message}; ${error.hint}`;
|
|
8791
|
+
const fix = error.next.find((step) => !isRerun(step));
|
|
8792
|
+
return fix === void 0 ? {
|
|
8793
|
+
state: "problem",
|
|
8794
|
+
message,
|
|
8795
|
+
code: error.code
|
|
8796
|
+
} : {
|
|
8797
|
+
state: "problem",
|
|
8798
|
+
message,
|
|
8799
|
+
fix: lineOf(fix, runAs),
|
|
8800
|
+
code: error.code
|
|
8801
|
+
};
|
|
8802
|
+
}
|
|
8768
8803
|
return {
|
|
8769
8804
|
state: "problem",
|
|
8770
8805
|
message: `the ${name} row hit a bug: ${messageOf(error)}`
|
|
@@ -8790,11 +8825,11 @@ function readProject(projectFile, ctx) {
|
|
|
8790
8825
|
};
|
|
8791
8826
|
}
|
|
8792
8827
|
}
|
|
8793
|
-
function projectRow({ file }, read) {
|
|
8828
|
+
function projectRow({ file }, { read, runAs }) {
|
|
8794
8829
|
return {
|
|
8795
8830
|
name: "project",
|
|
8796
8831
|
run: (ctx) => {
|
|
8797
|
-
if (!read.ok) return problemOfError("project", read.error);
|
|
8832
|
+
if (!read.ok) return problemOfError("project", read.error, runAs);
|
|
8798
8833
|
return ok(read.project === void 0 ? `none found: no ${file} at or above ${ctx.cwd}` : join(read.project.root, file));
|
|
8799
8834
|
}
|
|
8800
8835
|
};
|
|
@@ -8834,20 +8869,24 @@ function registryRow(cli, check) {
|
|
|
8834
8869
|
};
|
|
8835
8870
|
}
|
|
8836
8871
|
/** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
|
|
8837
|
-
function doctorChecks(cli, launch,
|
|
8872
|
+
function doctorChecks(cli, launch, scope) {
|
|
8838
8873
|
const install = installOf(cli);
|
|
8839
8874
|
const check = install.check(launch);
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
|
|
8875
|
+
const tools = toolRows(cli.tools ?? [], cli.commands);
|
|
8876
|
+
return {
|
|
8877
|
+
checks: [
|
|
8878
|
+
buildRow(cli),
|
|
8879
|
+
nodeRow(cli),
|
|
8880
|
+
...cli.project === void 0 ? [] : [projectRow(cli.project, scope)],
|
|
8881
|
+
...cli.doctor ?? [],
|
|
8882
|
+
...tools,
|
|
8883
|
+
...secretRows(cli.secrets ?? [], cli.commands),
|
|
8884
|
+
installRow(check),
|
|
8885
|
+
registryRow(cli, check),
|
|
8886
|
+
...skillOf$1(cli, install).rows
|
|
8887
|
+
],
|
|
8888
|
+
tools: new Set(tools.map(({ name }) => name))
|
|
8889
|
+
};
|
|
8851
8890
|
}
|
|
8852
8891
|
const DEFAULT_DEADLINE_MS = 1e4;
|
|
8853
8892
|
const MS_PER_SECOND = 1e3;
|
|
@@ -8867,14 +8906,14 @@ const reportSchema = object({
|
|
|
8867
8906
|
})),
|
|
8868
8907
|
next: array(string())
|
|
8869
8908
|
});
|
|
8870
|
-
function problemOf(check, error, { signal, deadline, ms }) {
|
|
8909
|
+
function problemOf(check, error, { signal, deadline, ms, runAs }) {
|
|
8871
8910
|
if (!signal.aborted && deadline.aborted && error === deadline.reason) return {
|
|
8872
8911
|
state: "problem",
|
|
8873
8912
|
message: `${check.name} did not answer within ${ms / MS_PER_SECOND} s`
|
|
8874
8913
|
};
|
|
8875
|
-
return problemOfError(check.name, error);
|
|
8914
|
+
return problemOfError(check.name, error, runAs);
|
|
8876
8915
|
}
|
|
8877
|
-
function rowContext(ctx, signal, read) {
|
|
8916
|
+
function rowContext(ctx, signal, { read }) {
|
|
8878
8917
|
return Object.create(ctx, {
|
|
8879
8918
|
signal: { value: signal },
|
|
8880
8919
|
project: { get: () => {
|
|
@@ -8883,21 +8922,36 @@ function rowContext(ctx, signal, read) {
|
|
|
8883
8922
|
} }
|
|
8884
8923
|
});
|
|
8885
8924
|
}
|
|
8886
|
-
|
|
8925
|
+
function skippedFor(error, { read, tools }) {
|
|
8926
|
+
if (!read.ok && error === read.error) return {
|
|
8927
|
+
state: "skipped",
|
|
8928
|
+
message: "the Project file is unusable; the project row says why"
|
|
8929
|
+
};
|
|
8930
|
+
const tool = missingToolOf(error);
|
|
8931
|
+
if (tool !== void 0 && tools.has(tool)) return {
|
|
8932
|
+
state: "skipped",
|
|
8933
|
+
message: `${tool} is not on PATH; the ${tool} row says why`
|
|
8934
|
+
};
|
|
8935
|
+
}
|
|
8936
|
+
async function rowOf(check, ctx, { read, runAs, tools }) {
|
|
8887
8937
|
const ms = check.deadlineMs ?? DEFAULT_DEADLINE_MS;
|
|
8888
8938
|
const signal = ctx.deadline(ms);
|
|
8889
8939
|
let finding;
|
|
8890
8940
|
try {
|
|
8891
|
-
finding = await Promise.race([Promise.resolve().then(() => check.run(rowContext(ctx, signal,
|
|
8941
|
+
finding = await Promise.race([Promise.resolve().then(() => check.run(rowContext(ctx, signal, {
|
|
8942
|
+
read,
|
|
8943
|
+
runAs
|
|
8944
|
+
}))), untilAborted(signal)]);
|
|
8892
8945
|
} catch (error) {
|
|
8893
8946
|
if (ctx.signal.aborted) return void 0;
|
|
8894
|
-
finding =
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
}
|
|
8947
|
+
finding = skippedFor(error, {
|
|
8948
|
+
read,
|
|
8949
|
+
tools
|
|
8950
|
+
}) ?? problemOf(check, error, {
|
|
8898
8951
|
signal: ctx.signal,
|
|
8899
8952
|
deadline: signal,
|
|
8900
|
-
ms
|
|
8953
|
+
ms,
|
|
8954
|
+
runAs
|
|
8901
8955
|
});
|
|
8902
8956
|
}
|
|
8903
8957
|
return {
|
|
@@ -8908,8 +8962,10 @@ async function rowOf(check, ctx, read) {
|
|
|
8908
8962
|
advisory: check.advisory === true
|
|
8909
8963
|
};
|
|
8910
8964
|
}
|
|
8911
|
-
function nextOf(
|
|
8912
|
-
|
|
8965
|
+
function nextOf(checked, doctorLine) {
|
|
8966
|
+
const fixes = checked.flatMap(({ row }) => row.fix === void 0 ? [] : [row.fix]);
|
|
8967
|
+
const unfixed = checked.some(({ row, advisory }) => advisory && row.state === "problem" && row.fix === void 0);
|
|
8968
|
+
return [...new Set(unfixed ? [...fixes, doctorLine] : fixes)];
|
|
8913
8969
|
}
|
|
8914
8970
|
function render({ rows, next }, style) {
|
|
8915
8971
|
const width = Math.max(MIN_LABEL_WIDTH, ...rows.map(({ check }) => check.length)) + 2;
|
|
@@ -8927,8 +8983,8 @@ function failure(cliName, rerun, problems) {
|
|
|
8927
8983
|
};
|
|
8928
8984
|
return runtimeError(fix === void 0 ? {
|
|
8929
8985
|
...head,
|
|
8930
|
-
hint: "the row says
|
|
8931
|
-
next: []
|
|
8986
|
+
hint: "fix what the row says, then run the Next step",
|
|
8987
|
+
next: [rerun]
|
|
8932
8988
|
} : {
|
|
8933
8989
|
...head,
|
|
8934
8990
|
hint: "run the Next steps in order",
|
|
@@ -8951,12 +9007,18 @@ function doctorCommand(cli, launch) {
|
|
|
8951
9007
|
effect: "read",
|
|
8952
9008
|
output: reportSchema,
|
|
8953
9009
|
run: async (_input, ctx) => {
|
|
8954
|
-
const
|
|
8955
|
-
|
|
8956
|
-
|
|
9010
|
+
const rowsScope = {
|
|
9011
|
+
read: readProject(cli.project, ctx),
|
|
9012
|
+
runAs: runAsOf(cli)
|
|
9013
|
+
};
|
|
9014
|
+
const { checks, tools } = doctorChecks(cli, launch, rowsScope);
|
|
9015
|
+
const checked = (await Promise.all(checks.map((check) => rowOf(check, ctx, {
|
|
9016
|
+
...rowsScope,
|
|
9017
|
+
tools
|
|
9018
|
+
})))).filter((row) => row !== void 0);
|
|
8957
9019
|
const report = {
|
|
8958
|
-
rows,
|
|
8959
|
-
next: nextOf(
|
|
9020
|
+
rows: checked.map(({ row }) => row),
|
|
9021
|
+
next: nextOf(checked, lineOf(ctx.rerun(), rowsScope.runAs))
|
|
8960
9022
|
};
|
|
8961
9023
|
if (ctx.signal.aborted) {
|
|
8962
9024
|
ctx.deliver(report);
|
|
@@ -9226,18 +9288,26 @@ function installFrom(name, manifest, install) {
|
|
|
9226
9288
|
mode: "dependency",
|
|
9227
9289
|
package: manifest.name
|
|
9228
9290
|
};
|
|
9229
|
-
if (install
|
|
9291
|
+
if (install === "global") return {
|
|
9292
|
+
mode: "global",
|
|
9293
|
+
package: manifest.name,
|
|
9294
|
+
registry: publishedTo(name, manifest)
|
|
9295
|
+
};
|
|
9296
|
+
if (install.mode === "global") return {
|
|
9297
|
+
mode: "global",
|
|
9298
|
+
package: manifest.name,
|
|
9299
|
+
registry: install.registry
|
|
9300
|
+
};
|
|
9301
|
+
return {
|
|
9230
9302
|
mode: "dependency",
|
|
9231
9303
|
package: manifest.name,
|
|
9232
9304
|
lockstep: install.lockstep
|
|
9233
9305
|
};
|
|
9306
|
+
}
|
|
9307
|
+
function publishedTo(name, manifest) {
|
|
9234
9308
|
const registry = manifest.publishConfig?.registry;
|
|
9235
9309
|
if (registry === void 0) throw new Error(`${name} declares a Global install, which needs publishConfig.registry in its package.json`);
|
|
9236
|
-
return
|
|
9237
|
-
mode: "global",
|
|
9238
|
-
package: manifest.name,
|
|
9239
|
-
registry
|
|
9240
|
-
};
|
|
9310
|
+
return registry;
|
|
9241
9311
|
}
|
|
9242
9312
|
function resolved(cli) {
|
|
9243
9313
|
const { manifest, ...declared } = cli;
|
|
@@ -9302,6 +9372,30 @@ function startSideTask(sideTask, runWith, { clock, failed }) {
|
|
|
9302
9372
|
};
|
|
9303
9373
|
}
|
|
9304
9374
|
//#endregion
|
|
9375
|
+
//#region ../agent-cli/dist/built-ins/skill/usage-hint.js
|
|
9376
|
+
const SKILL_USAGE_CODES = /* @__PURE__ */ new Set([
|
|
9377
|
+
UNKNOWN_OPTION,
|
|
9378
|
+
UNKNOWN_COMMAND,
|
|
9379
|
+
INVALID_INPUT
|
|
9380
|
+
]);
|
|
9381
|
+
/** A usage error whose hint names each Skill copy that differs from this build, since one may have named the input. */
|
|
9382
|
+
async function withDifferingSkill(error, cli, place, runAs) {
|
|
9383
|
+
if (!(error instanceof UsageError) || !SKILL_USAGE_CODES.has(error.code)) return error;
|
|
9384
|
+
let differing;
|
|
9385
|
+
try {
|
|
9386
|
+
differing = await skillOf$1(cli, installOf(cli)).differing(place);
|
|
9387
|
+
} catch (lookup) {
|
|
9388
|
+
if (errnoOf(lookup) === void 0) throw lookup;
|
|
9389
|
+
return error;
|
|
9390
|
+
}
|
|
9391
|
+
if (differing.length === 0) return error;
|
|
9392
|
+
return new UsageError({
|
|
9393
|
+
code: error.code,
|
|
9394
|
+
message: error.message,
|
|
9395
|
+
hint: `${error.hint}; the ${cli.name} skill may name what this build does not know: ${differing.join("; ")}; run \`${runAs} doctor\` to see how to update it`
|
|
9396
|
+
});
|
|
9397
|
+
}
|
|
9398
|
+
//#endregion
|
|
9305
9399
|
//#region ../agent-cli/dist/command-line/suggest.js
|
|
9306
9400
|
const MAX_DISTANCE = 3;
|
|
9307
9401
|
const MIN_SIMILARITY = .4;
|
|
@@ -11012,7 +11106,11 @@ async function runCommand(cli, routed, options, write, baseFormat) {
|
|
|
11012
11106
|
});
|
|
11013
11107
|
});
|
|
11014
11108
|
} catch (error) {
|
|
11015
|
-
return failed(error,
|
|
11109
|
+
return failed(await withDifferingSkill(error, cli, {
|
|
11110
|
+
cwd,
|
|
11111
|
+
env,
|
|
11112
|
+
packageRoot
|
|
11113
|
+
}, invocation.runAs), noSideTask);
|
|
11016
11114
|
}
|
|
11017
11115
|
const { input, flags } = parsed;
|
|
11018
11116
|
resumed = command.deadline?.resume(input, rerunOf);
|
|
@@ -11224,10 +11322,16 @@ async function routeAndRun(cli, argv, options, write, stopNotice) {
|
|
|
11224
11322
|
...format,
|
|
11225
11323
|
json: routed.json
|
|
11226
11324
|
}));
|
|
11227
|
-
case "usage error":
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11325
|
+
case "usage error": {
|
|
11326
|
+
const place = {
|
|
11327
|
+
...options,
|
|
11328
|
+
packageRoot: packageRootOf(options.bin, options.cwd)
|
|
11329
|
+
};
|
|
11330
|
+
return ranAlone(errorResult(await withDifferingSkill(routed.error, cli, place, runAs), {
|
|
11331
|
+
...misused(routed.node),
|
|
11332
|
+
json: routed.json
|
|
11333
|
+
}));
|
|
11334
|
+
}
|
|
11231
11335
|
case "command": return whileStopping(options.signal, stopNotice === void 0 ? void 0 : () => write.stderr(stopLine(stopNotice, routed.json)), () => runCommand(cli, routed, options, write, misused(routed.spec)));
|
|
11232
11336
|
}
|
|
11233
11337
|
}
|
|
@@ -11290,7 +11394,7 @@ async function runProcess(cli) {
|
|
|
11290
11394
|
//#region package.json
|
|
11291
11395
|
var package_default = {
|
|
11292
11396
|
name: "@duyquangnvx/create-agent-cli",
|
|
11293
|
-
version: "0.
|
|
11397
|
+
version: "0.22.0",
|
|
11294
11398
|
description: "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.",
|
|
11295
11399
|
type: "module",
|
|
11296
11400
|
engines: { "node": ">=22.12.0" },
|