@duyquangnvx/create-agent-cli 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/dist/bin.js +1171 -524
- package/package.json +2 -2
- package/template/skills/{{binName}}/SKILL.md +3 -1
- package/template/src/cli.ts +22 -3
- package/template/test/cli.test.ts +52 -2
package/dist/bin.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs, parseEnv } from "node:util";
|
|
2
3
|
import { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
3
|
-
import { access, lstat, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
4
|
+
import { access, chmod, link, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
5
|
+
import { constants, existsSync, readFileSync, realpathSync } from "node:fs";
|
|
6
|
+
import { constants as constants$1, homedir, tmpdir } from "node:os";
|
|
4
7
|
import { spawn } from "node:child_process";
|
|
5
|
-
import {
|
|
6
|
-
import { constants as constants$1, existsSync, readFileSync, realpathSync } from "node:fs";
|
|
7
|
-
import { parseArgs, parseEnv } from "node:util";
|
|
8
|
+
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
8
9
|
import { fileURLToPath } from "node:url";
|
|
9
10
|
//#region ../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/core/util.js
|
|
10
11
|
function getEnumValues(entries) {
|
|
@@ -2817,7 +2818,7 @@ function bucketFor(state, inst) {
|
|
|
2817
2818
|
return bucket;
|
|
2818
2819
|
}
|
|
2819
2820
|
let handoff;
|
|
2820
|
-
const open = [];
|
|
2821
|
+
const open$1 = [];
|
|
2821
2822
|
const memo = {
|
|
2822
2823
|
alloc(_inst, payload, empty) {
|
|
2823
2824
|
const bucket = handoff;
|
|
@@ -2828,7 +2829,7 @@ const memo = {
|
|
|
2828
2829
|
issues: null
|
|
2829
2830
|
};
|
|
2830
2831
|
bucket.set(payload.value, entry);
|
|
2831
|
-
open.push(entry);
|
|
2832
|
+
open$1.push(entry);
|
|
2832
2833
|
return empty;
|
|
2833
2834
|
},
|
|
2834
2835
|
guard(inst) {
|
|
@@ -2894,10 +2895,10 @@ const memo = {
|
|
|
2894
2895
|
return payload;
|
|
2895
2896
|
}
|
|
2896
2897
|
handoff = bucket;
|
|
2897
|
-
const depth = open.length;
|
|
2898
|
+
const depth = open$1.length;
|
|
2898
2899
|
const result = base(payload, ctx);
|
|
2899
2900
|
handoff = void 0;
|
|
2900
|
-
const entry = open.length > depth ? open.pop() : void 0;
|
|
2901
|
+
const entry = open$1.length > depth ? open$1.pop() : void 0;
|
|
2901
2902
|
if (result instanceof Promise) return result.then((r) => {
|
|
2902
2903
|
if (entry) entry.issues = r.issues.length ? cloneIssues(r.issues) : NO_ISSUES;
|
|
2903
2904
|
return r;
|
|
@@ -5581,6 +5582,54 @@ function untilAborted(signal) {
|
|
|
5581
5582
|
});
|
|
5582
5583
|
}
|
|
5583
5584
|
//#endregion
|
|
5585
|
+
//#region ../agent-cli/dist/stdin.js
|
|
5586
|
+
const STDIN_META = "stdin";
|
|
5587
|
+
function isStdinSchema(schema) {
|
|
5588
|
+
return globalRegistry.get(schema)?.[STDIN_META] === true;
|
|
5589
|
+
}
|
|
5590
|
+
function endOfInputKeys(platform) {
|
|
5591
|
+
return platform === "win32" ? "Ctrl-Z then Enter" : "Ctrl-D";
|
|
5592
|
+
}
|
|
5593
|
+
/** The progress line shown before reading a terminal, so a person isn't left facing silence. */
|
|
5594
|
+
function readingLine(name, platform) {
|
|
5595
|
+
return `reading <${name}> from stdin; end it with ${endOfInputKeys(platform)}`;
|
|
5596
|
+
}
|
|
5597
|
+
function isTerminal(source) {
|
|
5598
|
+
return typeof source !== "string" && "isTTY" in source && source.isTTY === true;
|
|
5599
|
+
}
|
|
5600
|
+
/** The whole of `source` as UTF-8; rejects with the signal's reason once it aborts. */
|
|
5601
|
+
function readStdin(source, signal) {
|
|
5602
|
+
if (typeof source === "string") return signal.aborted ? Promise.reject(signal.reason) : Promise.resolve(source);
|
|
5603
|
+
return new Promise((resolve, reject) => {
|
|
5604
|
+
const chunks = [];
|
|
5605
|
+
const onData = (chunk) => {
|
|
5606
|
+
chunks.push(chunk instanceof Uint8Array ? chunk : Buffer.from(String(chunk)));
|
|
5607
|
+
};
|
|
5608
|
+
const onEnd = () => {
|
|
5609
|
+
stop();
|
|
5610
|
+
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
5611
|
+
};
|
|
5612
|
+
const onError = (error) => {
|
|
5613
|
+
stop();
|
|
5614
|
+
reject(error);
|
|
5615
|
+
};
|
|
5616
|
+
const onAbort = () => {
|
|
5617
|
+
stop();
|
|
5618
|
+
reject(signal.reason);
|
|
5619
|
+
};
|
|
5620
|
+
const stop = () => {
|
|
5621
|
+
source.off("data", onData).off("end", onEnd).off("error", onError).pause();
|
|
5622
|
+
signal.removeEventListener("abort", onAbort);
|
|
5623
|
+
};
|
|
5624
|
+
if (signal.aborted) {
|
|
5625
|
+
reject(signal.reason);
|
|
5626
|
+
return;
|
|
5627
|
+
}
|
|
5628
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
5629
|
+
source.on("data", onData).once("end", onEnd).once("error", onError);
|
|
5630
|
+
});
|
|
5631
|
+
}
|
|
5632
|
+
//#endregion
|
|
5584
5633
|
//#region ../agent-cli/dist/input.js
|
|
5585
5634
|
function isWrapper(schema) {
|
|
5586
5635
|
return schema instanceof ZodOptional || schema instanceof ZodNullable || schema instanceof ZodDefault || schema instanceof ZodPrefault;
|
|
@@ -5597,27 +5646,39 @@ function describe(schema) {
|
|
|
5597
5646
|
let description = current.description;
|
|
5598
5647
|
let required = true;
|
|
5599
5648
|
let defaultValue;
|
|
5649
|
+
let stdin = isStdinSchema(current);
|
|
5600
5650
|
while (isWrapper(current)) {
|
|
5601
5651
|
if (current instanceof ZodDefault || current instanceof ZodPrefault) defaultValue = current.def.defaultValue;
|
|
5602
5652
|
required = false;
|
|
5603
5653
|
current = current.unwrap();
|
|
5604
5654
|
description ??= current.description;
|
|
5655
|
+
stdin ||= isStdinSchema(current);
|
|
5605
5656
|
}
|
|
5657
|
+
const variadic = current instanceof ZodArray;
|
|
5658
|
+
if (current instanceof ZodArray) current = current.element;
|
|
5606
5659
|
return {
|
|
5607
5660
|
type: typeOf(current),
|
|
5608
5661
|
required,
|
|
5609
5662
|
defaultValue,
|
|
5610
5663
|
description,
|
|
5611
|
-
choices: current instanceof ZodEnum ? current.options.map(String) : void 0
|
|
5664
|
+
choices: current instanceof ZodEnum ? current.options.map(String) : void 0,
|
|
5665
|
+
variadic,
|
|
5666
|
+
stdin
|
|
5612
5667
|
};
|
|
5613
5668
|
}
|
|
5669
|
+
function argLabel(key, { variadic, required, stdin }) {
|
|
5670
|
+
if (stdin) return required ? `<${key}|->` : `[${key}|-]`;
|
|
5671
|
+
if (!variadic) return `<${key}>`;
|
|
5672
|
+
return required ? `<${key}...>` : `[${key}...]`;
|
|
5673
|
+
}
|
|
5614
5674
|
function argField(key, schema) {
|
|
5615
|
-
const
|
|
5675
|
+
const described = describe(schema);
|
|
5676
|
+
const label = argLabel(key, described);
|
|
5616
5677
|
return {
|
|
5617
5678
|
key,
|
|
5618
5679
|
name: key,
|
|
5619
5680
|
schema,
|
|
5620
|
-
...
|
|
5681
|
+
...described,
|
|
5621
5682
|
label,
|
|
5622
5683
|
usage: label
|
|
5623
5684
|
};
|
|
@@ -5627,7 +5688,8 @@ function optionField(key, schema) {
|
|
|
5627
5688
|
const name = kebab(key);
|
|
5628
5689
|
const isBoolean = described.type === "boolean";
|
|
5629
5690
|
const label = isBoolean && described.defaultValue === true ? `--no-${name}` : `--${name}`;
|
|
5630
|
-
const
|
|
5691
|
+
const value = `<${described.choices?.join("|") ?? "value"}>${described.variadic ? "..." : ""}`;
|
|
5692
|
+
const usage = isBoolean ? label : `${label} ${value}`;
|
|
5631
5693
|
return {
|
|
5632
5694
|
key,
|
|
5633
5695
|
name,
|
|
@@ -5643,9 +5705,32 @@ function fieldsOf$1(schema, toField) {
|
|
|
5643
5705
|
function argFields(schema) {
|
|
5644
5706
|
return fieldsOf$1(schema, argField);
|
|
5645
5707
|
}
|
|
5708
|
+
function keysOf(fields) {
|
|
5709
|
+
return fields.map(({ key }) => `'${key}'`).join(", ");
|
|
5710
|
+
}
|
|
5711
|
+
/** Throws when an arg that takes every remaining operand is not the last arg. */
|
|
5712
|
+
function checkArrayArgLast(name, args) {
|
|
5713
|
+
const misplaced = argFields(args).slice(0, -1).filter((field) => field.variadic);
|
|
5714
|
+
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`);
|
|
5715
|
+
}
|
|
5716
|
+
/** Throws unless at most one arg, and no option, is marked with `orStdin`. */
|
|
5717
|
+
function checkStdinFields(name, args, options) {
|
|
5718
|
+
const stdinArgs = argFields(args).filter((field) => field.stdin);
|
|
5719
|
+
if (stdinArgs.length > 1) throw new Error(`Command '${name}' marks args ${keysOf(stdinArgs)} with orStdin; only one arg may read stdin`);
|
|
5720
|
+
const stdinOptions = optionFields(options).filter((field) => field.stdin);
|
|
5721
|
+
if (stdinOptions.length > 0) {
|
|
5722
|
+
const noun = stdinOptions.length === 1 ? "option" : "options";
|
|
5723
|
+
throw new Error(`Command '${name}' marks ${noun} ${keysOf(stdinOptions)} with orStdin; only an arg may read stdin`);
|
|
5724
|
+
}
|
|
5725
|
+
}
|
|
5646
5726
|
function optionFields(schema) {
|
|
5647
5727
|
return fieldsOf$1(schema, optionField);
|
|
5648
5728
|
}
|
|
5729
|
+
/** Throws when an option is an array of booleans, which a switch cannot express. */
|
|
5730
|
+
function checkNoBooleanArrayOption(name, options) {
|
|
5731
|
+
const booleans = optionFields(options).filter((field) => field.variadic && field.type === "boolean");
|
|
5732
|
+
if (booleans.length > 0) throw new Error(`Command '${name}' declares boolean array option ${keysOf(booleans)}; a switch cannot repeat, use a boolean`);
|
|
5733
|
+
}
|
|
5649
5734
|
//#endregion
|
|
5650
5735
|
//#region ../agent-cli/dist/errors.js
|
|
5651
5736
|
var CliError = class extends Error {
|
|
@@ -5676,6 +5761,9 @@ function errnoOf(error) {
|
|
|
5676
5761
|
function isMissingFile(error) {
|
|
5677
5762
|
return errnoOf(error) === "ENOENT";
|
|
5678
5763
|
}
|
|
5764
|
+
function isNothingThere(error) {
|
|
5765
|
+
return isMissingFile(error) || errnoOf(error) === "ENOTDIR";
|
|
5766
|
+
}
|
|
5679
5767
|
function debugVariable(cliName) {
|
|
5680
5768
|
return `${cliName.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_DEBUG`;
|
|
5681
5769
|
}
|
|
@@ -5740,6 +5828,89 @@ function formatRuntimeError(error, format) {
|
|
|
5740
5828
|
}
|
|
5741
5829
|
return errors.map((each) => errorLines(each, format)).join("");
|
|
5742
5830
|
}
|
|
5831
|
+
//#endregion
|
|
5832
|
+
//#region ../agent-cli/dist/tokenize.js
|
|
5833
|
+
const NEGATIVE_NUMBER = /^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/;
|
|
5834
|
+
function isOptionLike(word) {
|
|
5835
|
+
return word !== void 0 && word.length > 1 && word[0] === "-" && !NEGATIVE_NUMBER.test(word);
|
|
5836
|
+
}
|
|
5837
|
+
function parseArgsOptions(known) {
|
|
5838
|
+
return Object.fromEntries(known.map(({ flag, takes }) => [flag.slice(2), { type: takes === "value" ? "string" : "boolean" }]));
|
|
5839
|
+
}
|
|
5840
|
+
function flagItem(token, { flag, takes }, words) {
|
|
5841
|
+
if (takes !== "optional value" || token.inlineValue === true) return {
|
|
5842
|
+
kind: "flag",
|
|
5843
|
+
flag,
|
|
5844
|
+
value: token.value ?? true
|
|
5845
|
+
};
|
|
5846
|
+
const took = token.index + 1;
|
|
5847
|
+
const next = words[took];
|
|
5848
|
+
return next === void 0 || isOptionLike(next) ? {
|
|
5849
|
+
kind: "flag",
|
|
5850
|
+
flag,
|
|
5851
|
+
value: true
|
|
5852
|
+
} : {
|
|
5853
|
+
kind: "flag",
|
|
5854
|
+
flag,
|
|
5855
|
+
value: next,
|
|
5856
|
+
took
|
|
5857
|
+
};
|
|
5858
|
+
}
|
|
5859
|
+
function itemOf(token, words, byFlag) {
|
|
5860
|
+
const word = words[token.index] ?? "";
|
|
5861
|
+
if (token.kind === "option-terminator") return { kind: "end" };
|
|
5862
|
+
if (token.kind === "positional" || NEGATIVE_NUMBER.test(word)) return {
|
|
5863
|
+
kind: "operand",
|
|
5864
|
+
value: word
|
|
5865
|
+
};
|
|
5866
|
+
const flag = byFlag.get(token.rawName);
|
|
5867
|
+
return flag === void 0 || flag.takes === "nothing" && token.inlineValue === true ? {
|
|
5868
|
+
kind: "unknown option",
|
|
5869
|
+
word
|
|
5870
|
+
} : flagItem(token, flag, words);
|
|
5871
|
+
}
|
|
5872
|
+
/** Splits a Command's words into operands, unknown options and the values of known flags. */
|
|
5873
|
+
function tokenize(words, known) {
|
|
5874
|
+
const byFlag = new Map(known.map((flag) => [flag.flag, flag]));
|
|
5875
|
+
const { tokens } = parseArgs({
|
|
5876
|
+
args: [...words],
|
|
5877
|
+
options: parseArgsOptions(known),
|
|
5878
|
+
strict: false,
|
|
5879
|
+
allowPositionals: true,
|
|
5880
|
+
tokens: true
|
|
5881
|
+
});
|
|
5882
|
+
const operands = [];
|
|
5883
|
+
const unknownOptions = [];
|
|
5884
|
+
const occurrences = /* @__PURE__ */ new Map();
|
|
5885
|
+
const done = /* @__PURE__ */ new Set();
|
|
5886
|
+
let literal = false;
|
|
5887
|
+
let afterUnknownOption = false;
|
|
5888
|
+
for (const token of tokens) {
|
|
5889
|
+
if (done.has(token.index)) continue;
|
|
5890
|
+
done.add(token.index);
|
|
5891
|
+
const item = itemOf(token, words, byFlag);
|
|
5892
|
+
if (item.kind === "end") literal = true;
|
|
5893
|
+
else if (item.kind === "operand") {
|
|
5894
|
+
operands.push({
|
|
5895
|
+
value: item.value,
|
|
5896
|
+
afterUnknownOption: !literal && afterUnknownOption
|
|
5897
|
+
});
|
|
5898
|
+
afterUnknownOption = false;
|
|
5899
|
+
} else if (item.kind === "unknown option") {
|
|
5900
|
+
unknownOptions.push(item.word);
|
|
5901
|
+
afterUnknownOption = true;
|
|
5902
|
+
} else {
|
|
5903
|
+
occurrences.set(item.flag, [...occurrences.get(item.flag) ?? [], item.value]);
|
|
5904
|
+
if (item.took !== void 0) done.add(item.took);
|
|
5905
|
+
}
|
|
5906
|
+
}
|
|
5907
|
+
return {
|
|
5908
|
+
operands,
|
|
5909
|
+
unknownOptions,
|
|
5910
|
+
values: new Map([...occurrences].map(([flag, all]) => [flag, all[all.length - 1] ?? true])),
|
|
5911
|
+
occurrences
|
|
5912
|
+
};
|
|
5913
|
+
}
|
|
5743
5914
|
const SHELL_SAFE = /^[\w@%+=:,./-]+$/;
|
|
5744
5915
|
function quoted$1(token) {
|
|
5745
5916
|
return SHELL_SAFE.test(token) ? token : `'${token.replaceAll("'", `'\\''`)}'`;
|
|
@@ -5747,10 +5918,6 @@ function quoted$1(token) {
|
|
|
5747
5918
|
function pasteable(cliName, tokens) {
|
|
5748
5919
|
return [cliName, ...tokens].map(quoted$1).join(" ");
|
|
5749
5920
|
}
|
|
5750
|
-
/** The caller's command line as typed, ready to paste. */
|
|
5751
|
-
function commandLineOf({ cliName, argv }) {
|
|
5752
|
-
return pasteable(cliName, argv);
|
|
5753
|
-
}
|
|
5754
5921
|
function split(argv) {
|
|
5755
5922
|
const end = argv.indexOf("--");
|
|
5756
5923
|
return end === -1 ? {
|
|
@@ -5761,19 +5928,29 @@ function split(argv) {
|
|
|
5761
5928
|
operands: argv.slice(end)
|
|
5762
5929
|
};
|
|
5763
5930
|
}
|
|
5764
|
-
function
|
|
5765
|
-
return
|
|
5931
|
+
function tookValue(takes, next) {
|
|
5932
|
+
return takes === "value" || takes === "optional value" && next !== void 0 && !isOptionLike(next);
|
|
5933
|
+
}
|
|
5934
|
+
function without(flag, takes, tokens) {
|
|
5935
|
+
const kept = [];
|
|
5936
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
5937
|
+
const token = tokens[index] ?? "";
|
|
5938
|
+
if (token === flag) {
|
|
5939
|
+
if (tookValue(takes, tokens[index + 1])) index += 1;
|
|
5940
|
+
} else if (!token.startsWith(`${flag}=`)) kept.push(token);
|
|
5941
|
+
}
|
|
5942
|
+
return kept;
|
|
5766
5943
|
}
|
|
5767
5944
|
/**
|
|
5768
|
-
* The caller's command line, ready to paste, with
|
|
5769
|
-
*
|
|
5945
|
+
* The caller's command line as typed, ready to paste, with each flag in `remove` dropped along with
|
|
5946
|
+
* its value and the words in `add` placed before any `--`.
|
|
5770
5947
|
*/
|
|
5771
|
-
function
|
|
5948
|
+
function commandLineOf({ cliName, argv, flags }, { add = [], remove = [] } = {}) {
|
|
5772
5949
|
const { options, operands } = split(argv);
|
|
5773
|
-
const
|
|
5950
|
+
const takes = new Map(flags.map((known) => [known.flag, known.takes]));
|
|
5774
5951
|
return pasteable(cliName, [
|
|
5775
|
-
...without(flag, options),
|
|
5776
|
-
...
|
|
5952
|
+
...remove.reduce((tokens, flag) => without(flag, takes.get(flag) ?? "nothing", tokens), options),
|
|
5953
|
+
...add,
|
|
5777
5954
|
...operands
|
|
5778
5955
|
]);
|
|
5779
5956
|
}
|
|
@@ -5926,7 +6103,10 @@ function renderRows(rows, fields) {
|
|
|
5926
6103
|
function printedPage(page, invocation) {
|
|
5927
6104
|
return page.nextCursor === void 0 ? { items: page.items } : {
|
|
5928
6105
|
items: page.items,
|
|
5929
|
-
next:
|
|
6106
|
+
next: commandLineOf(invocation, {
|
|
6107
|
+
remove: [PAGE_FLAGS.cursor.flag],
|
|
6108
|
+
add: [PAGE_FLAGS.cursor.flag, String(page.nextCursor)]
|
|
6109
|
+
})
|
|
5930
6110
|
};
|
|
5931
6111
|
}
|
|
5932
6112
|
/** The line that ends a rendered page, so the caller always knows whether and how to get more. */
|
|
@@ -5935,6 +6115,12 @@ function pageFooter({ items, next }) {
|
|
|
5935
6115
|
return `${items.length} shown; ${more}\n`;
|
|
5936
6116
|
}
|
|
5937
6117
|
//#endregion
|
|
6118
|
+
//#region ../agent-cli/dist/planned.js
|
|
6119
|
+
/** Whether `command` changes something through a Plan: a write or destructive Command. */
|
|
6120
|
+
function hasPlan(command) {
|
|
6121
|
+
return command.effect === "write" || command.effect === "destructive";
|
|
6122
|
+
}
|
|
6123
|
+
//#endregion
|
|
5938
6124
|
//#region ../agent-cli/dist/flags.js
|
|
5939
6125
|
const HELP_FLAG = "--help";
|
|
5940
6126
|
const VERSION_FLAG = "--version";
|
|
@@ -5997,10 +6183,14 @@ const RESERVED = new Map([
|
|
|
5997
6183
|
...LIST_FLAGS
|
|
5998
6184
|
].map((flag) => [nameOf(flag), flag]));
|
|
5999
6185
|
/** The Standard flags of a Command with this Effect and declarations, and of a List Command. */
|
|
6000
|
-
function standardFlagsFor(effect, { outputs, cost }, list) {
|
|
6186
|
+
function standardFlagsFor(effect, { outputs, force, cost }, list) {
|
|
6187
|
+
const forceFlag = force === void 0 ? FORCE_FLAG : {
|
|
6188
|
+
...FORCE_FLAG,
|
|
6189
|
+
description: force
|
|
6190
|
+
};
|
|
6001
6191
|
return [
|
|
6002
6192
|
...EFFECT_FLAGS[effect],
|
|
6003
|
-
...outputs ? [
|
|
6193
|
+
...outputs || force !== void 0 ? [forceFlag] : [],
|
|
6004
6194
|
...cost ? [YES_FLAG] : [],
|
|
6005
6195
|
...list?.standardFlags ?? []
|
|
6006
6196
|
];
|
|
@@ -6019,10 +6209,21 @@ function checkNoStandardFlags(command) {
|
|
|
6019
6209
|
});
|
|
6020
6210
|
if (lines.length > 0) throw new Error([`Command '${command.name}' declares Standard flags the Runtime adds; rename them:`, ...lines].join("\n"));
|
|
6021
6211
|
}
|
|
6212
|
+
/** Throws when `force` is declared on a Command with no Plan, or says nothing. */
|
|
6213
|
+
function checkForce(command) {
|
|
6214
|
+
const force = "force" in command ? command.force : void 0;
|
|
6215
|
+
if (force === void 0) return;
|
|
6216
|
+
if (!hasPlan(command)) throw new Error(`Command '${command.name}' declares force, which only a write or destructive Command may`);
|
|
6217
|
+
if (force.trim() === "") throw new Error(`Command '${command.name}' declares an empty force; say what ${FORCE_FLAG.flag} replaces`);
|
|
6218
|
+
}
|
|
6022
6219
|
//#endregion
|
|
6023
6220
|
//#region ../agent-cli/dist/define.js
|
|
6024
6221
|
function checkedCommand(command) {
|
|
6025
6222
|
checkNoStandardFlags(command);
|
|
6223
|
+
checkForce(command);
|
|
6224
|
+
checkArrayArgLast(command.name, command.args);
|
|
6225
|
+
checkStdinFields(command.name, command.args, command.options);
|
|
6226
|
+
checkNoBooleanArrayOption(command.name, command.options);
|
|
6026
6227
|
return command;
|
|
6027
6228
|
}
|
|
6028
6229
|
function defineCommandFor() {
|
|
@@ -6100,22 +6301,259 @@ function lastLines(output, count) {
|
|
|
6100
6301
|
return output.trim().split("\n").slice(-count).join("\n");
|
|
6101
6302
|
}
|
|
6102
6303
|
//#endregion
|
|
6304
|
+
//#region ../agent-cli/dist/tools.js
|
|
6305
|
+
const TOOL_MISSING = "TOOL_MISSING";
|
|
6306
|
+
const WINDOWS_EXTENSIONS = ".COM;.EXE;.BAT;.CMD";
|
|
6307
|
+
function pathOf(env) {
|
|
6308
|
+
return env[Object.keys(env).find((name) => name.toUpperCase() === "PATH") ?? "PATH"] ?? "";
|
|
6309
|
+
}
|
|
6310
|
+
function extensionsOf(env) {
|
|
6311
|
+
return process.platform === "win32" ? (env.PATHEXT ?? WINDOWS_EXTENSIONS).split(";") : [""];
|
|
6312
|
+
}
|
|
6313
|
+
async function isExecutable(file) {
|
|
6314
|
+
try {
|
|
6315
|
+
await access(file, constants.X_OK);
|
|
6316
|
+
return true;
|
|
6317
|
+
} catch (error) {
|
|
6318
|
+
if (isNothingThere(error) || errnoOf(error) === "EACCES") return false;
|
|
6319
|
+
throw error;
|
|
6320
|
+
}
|
|
6321
|
+
}
|
|
6322
|
+
/** The file names `name` may have on `PATH`: itself when it already ends in one of the extensions. */
|
|
6323
|
+
function fileNamesOf(name, env) {
|
|
6324
|
+
const extensions = extensionsOf(env);
|
|
6325
|
+
const own = extname(name).toUpperCase();
|
|
6326
|
+
return own !== "" && extensions.some((extension) => extension.toUpperCase() === own) ? [name] : extensions.map((extension) => `${name}${extension}`);
|
|
6327
|
+
}
|
|
6328
|
+
/** Where `name` is found on `PATH` from `env`, or undefined. */
|
|
6329
|
+
async function findTool(name, env) {
|
|
6330
|
+
const candidates = pathOf(env).split(delimiter).filter((folder) => folder !== "").flatMap((folder) => fileNamesOf(name, env).map((file) => join(folder, file)));
|
|
6331
|
+
for (const file of candidates) if (await isExecutable(file)) return file;
|
|
6332
|
+
}
|
|
6333
|
+
/** Fails with `TOOL_MISSING`, naming every missing tool at once, unless all are on `PATH`. */
|
|
6334
|
+
async function checkTools(tools, env) {
|
|
6335
|
+
const found = await Promise.all(tools.map((tool) => findTool(tool.name, env)));
|
|
6336
|
+
const missing = tools.filter((_tool, index) => found[index] === void 0);
|
|
6337
|
+
if (missing.length === 0) return;
|
|
6338
|
+
const names = missing.map(({ name }) => name).join(", ");
|
|
6339
|
+
throw new CliError({
|
|
6340
|
+
code: TOOL_MISSING,
|
|
6341
|
+
message: `${missing.length === 1 ? "a tool it runs is" : "tools it runs are"} not on PATH: ${names}`,
|
|
6342
|
+
hint: `install ${missing.length === 1 ? "it" : "them"}, then run the same command again: ${missing.map(({ install }) => install).join("; ")}`
|
|
6343
|
+
});
|
|
6344
|
+
}
|
|
6345
|
+
function toolsIn(node) {
|
|
6346
|
+
return isCommand(node) ? [...node.tools ?? []] : Object.values(node).flatMap(toolsIn);
|
|
6347
|
+
}
|
|
6348
|
+
/** One `doctor` row per distinct tool the CLI and its Commands declare, with its install command as the fix. */
|
|
6349
|
+
function toolRows(tools, commands) {
|
|
6350
|
+
return [...new Map([...tools, ...toolsIn(commands)].map((tool) => [tool.name, tool])).values()].map(({ name, install }) => ({
|
|
6351
|
+
name,
|
|
6352
|
+
run: async (ctx) => {
|
|
6353
|
+
const file = await findTool(name, ctx.env);
|
|
6354
|
+
return file === void 0 ? {
|
|
6355
|
+
state: "problem",
|
|
6356
|
+
message: `${name} is not on PATH`,
|
|
6357
|
+
fix: install
|
|
6358
|
+
} : {
|
|
6359
|
+
state: "ok",
|
|
6360
|
+
message: `found at ${file}`
|
|
6361
|
+
};
|
|
6362
|
+
}
|
|
6363
|
+
}));
|
|
6364
|
+
}
|
|
6365
|
+
//#endregion
|
|
6366
|
+
//#region ../agent-cli/dist/spawn.js
|
|
6367
|
+
const TOOL_FAILED = "TOOL_FAILED";
|
|
6368
|
+
const STDERR_TAIL_LINES$1 = 20;
|
|
6369
|
+
const SIGNAL_EXIT_BASE = 128;
|
|
6370
|
+
const BATCH_FILE = /\.(?:cmd|bat)$/i;
|
|
6371
|
+
const CMD_SHIM = /\.cmd$/i;
|
|
6372
|
+
const CMD_META = /([()\][%!^"`<>&|;, *?])/g;
|
|
6373
|
+
const PATH_SEPARATOR = /[\\/]/;
|
|
6374
|
+
const TRAILING_CR = /\r$/;
|
|
6375
|
+
function escapedForCmd(text) {
|
|
6376
|
+
return text.replace(CMD_META, "^$1");
|
|
6377
|
+
}
|
|
6378
|
+
function batchArgument(arg, shim) {
|
|
6379
|
+
const escaped = escapedForCmd(`"${arg.replace(/(\\*)"/g, "$1$1\\\"").replace(/(\\*)$/, "$1$1")}"`);
|
|
6380
|
+
return shim ? escapedForCmd(escaped) : escaped;
|
|
6381
|
+
}
|
|
6382
|
+
function batchCommandLine(command, file, args) {
|
|
6383
|
+
const shim = CMD_SHIM.test(file);
|
|
6384
|
+
return [escapedForCmd(command), ...args.map((arg) => batchArgument(arg, shim))].join(" ");
|
|
6385
|
+
}
|
|
6386
|
+
async function windowsLaunch(command, args, env) {
|
|
6387
|
+
const file = PATH_SEPARATOR.test(command) ? command : await findTool(command, env);
|
|
6388
|
+
if (file === void 0 || !BATCH_FILE.test(file)) return {
|
|
6389
|
+
command,
|
|
6390
|
+
args,
|
|
6391
|
+
shell: false
|
|
6392
|
+
};
|
|
6393
|
+
return {
|
|
6394
|
+
command: batchCommandLine(command, file, args),
|
|
6395
|
+
args: [],
|
|
6396
|
+
shell: true
|
|
6397
|
+
};
|
|
6398
|
+
}
|
|
6399
|
+
function stop(child) {
|
|
6400
|
+
if (process.platform !== "win32" || child.pid === void 0) {
|
|
6401
|
+
child.kill();
|
|
6402
|
+
return Promise.resolve();
|
|
6403
|
+
}
|
|
6404
|
+
const pid = String(child.pid);
|
|
6405
|
+
return new Promise((resolve) => {
|
|
6406
|
+
const taskkill = spawn("taskkill", [
|
|
6407
|
+
"/pid",
|
|
6408
|
+
pid,
|
|
6409
|
+
"/t",
|
|
6410
|
+
"/f"
|
|
6411
|
+
], {
|
|
6412
|
+
stdio: "ignore",
|
|
6413
|
+
windowsHide: true
|
|
6414
|
+
});
|
|
6415
|
+
taskkill.once("error", () => {
|
|
6416
|
+
child.kill();
|
|
6417
|
+
resolve();
|
|
6418
|
+
});
|
|
6419
|
+
taskkill.once("exit", () => resolve());
|
|
6420
|
+
});
|
|
6421
|
+
}
|
|
6422
|
+
/** Calls `onLine` with each complete line pushed, and with the unterminated rest at the end. */
|
|
6423
|
+
function lineSplitter(onLine) {
|
|
6424
|
+
let rest = "";
|
|
6425
|
+
const emit = (line) => onLine?.(line.replace(TRAILING_CR, ""));
|
|
6426
|
+
return {
|
|
6427
|
+
push(text) {
|
|
6428
|
+
if (onLine === void 0) return;
|
|
6429
|
+
const lines = (rest + text).split("\n");
|
|
6430
|
+
rest = lines.pop() ?? "";
|
|
6431
|
+
for (const line of lines) emit(line);
|
|
6432
|
+
},
|
|
6433
|
+
end() {
|
|
6434
|
+
if (rest !== "") emit(rest);
|
|
6435
|
+
rest = "";
|
|
6436
|
+
}
|
|
6437
|
+
};
|
|
6438
|
+
}
|
|
6439
|
+
/**
|
|
6440
|
+
* Runs a child process to its end; it is killed on abort, and the promise settles only once it has
|
|
6441
|
+
* exited. A `detached` child leaves the terminal's process group on POSIX, and so its Ctrl-C.
|
|
6442
|
+
*/
|
|
6443
|
+
async function spawnChild(command, args, { cwd, env, signal, onLine, detached = false }) {
|
|
6444
|
+
signal.throwIfAborted();
|
|
6445
|
+
const launch = process.platform === "win32" ? await windowsLaunch(command, args, env) : {
|
|
6446
|
+
command,
|
|
6447
|
+
args,
|
|
6448
|
+
shell: false
|
|
6449
|
+
};
|
|
6450
|
+
signal.throwIfAborted();
|
|
6451
|
+
return new Promise((resolve, reject) => {
|
|
6452
|
+
const child = spawn(launch.command, launch.args, {
|
|
6453
|
+
cwd,
|
|
6454
|
+
env,
|
|
6455
|
+
shell: launch.shell,
|
|
6456
|
+
windowsHide: true,
|
|
6457
|
+
stdio: [
|
|
6458
|
+
"ignore",
|
|
6459
|
+
"pipe",
|
|
6460
|
+
"pipe"
|
|
6461
|
+
],
|
|
6462
|
+
detached: detached && process.platform !== "win32"
|
|
6463
|
+
});
|
|
6464
|
+
let stdout = "";
|
|
6465
|
+
let stderr = "";
|
|
6466
|
+
const stdoutLines = lineSplitter(onLine);
|
|
6467
|
+
const stderrLines = lineSplitter(onLine);
|
|
6468
|
+
child.stdout.setEncoding("utf8").on("data", (chunk) => {
|
|
6469
|
+
stdout += chunk;
|
|
6470
|
+
stdoutLines.push(chunk);
|
|
6471
|
+
});
|
|
6472
|
+
child.stderr.setEncoding("utf8").on("data", (chunk) => {
|
|
6473
|
+
stderr += chunk;
|
|
6474
|
+
stderrLines.push(chunk);
|
|
6475
|
+
});
|
|
6476
|
+
let stopped = Promise.resolve();
|
|
6477
|
+
const kill = () => {
|
|
6478
|
+
stopped = stop(child);
|
|
6479
|
+
};
|
|
6480
|
+
signal.addEventListener("abort", kill, { once: true });
|
|
6481
|
+
child.on("error", (error) => {
|
|
6482
|
+
signal.removeEventListener("abort", kill);
|
|
6483
|
+
reject(error);
|
|
6484
|
+
});
|
|
6485
|
+
child.on("close", (code, killedBy) => {
|
|
6486
|
+
signal.removeEventListener("abort", kill);
|
|
6487
|
+
if (signal.aborted) {
|
|
6488
|
+
stopped.then(() => reject(signal.reason));
|
|
6489
|
+
return;
|
|
6490
|
+
}
|
|
6491
|
+
stdoutLines.end();
|
|
6492
|
+
stderrLines.end();
|
|
6493
|
+
resolve({
|
|
6494
|
+
stdout,
|
|
6495
|
+
stderr,
|
|
6496
|
+
exitCode: code ?? SIGNAL_EXIT_BASE + (killedBy === null ? 0 : constants$1.signals[killedBy])
|
|
6497
|
+
});
|
|
6498
|
+
});
|
|
6499
|
+
});
|
|
6500
|
+
}
|
|
6501
|
+
const realSpawn = (command, args, options) => spawnChild(command, args, options);
|
|
6502
|
+
function failedError(command, { exitCode, stderr }) {
|
|
6503
|
+
const tail = lastLines(stderr, STDERR_TAIL_LINES$1);
|
|
6504
|
+
return new CliError({
|
|
6505
|
+
code: TOOL_FAILED,
|
|
6506
|
+
message: tail === "" ? `${command} exited with ${exitCode} and wrote nothing to stderr` : `${command} exited with ${exitCode}; its stderr ends:\n${tail}`,
|
|
6507
|
+
hint: `the output of ${command} above says why it failed`
|
|
6508
|
+
});
|
|
6509
|
+
}
|
|
6510
|
+
function missingError(command, cause) {
|
|
6511
|
+
return new CliError({
|
|
6512
|
+
code: TOOL_MISSING,
|
|
6513
|
+
message: `${command} could not be started: it is not on PATH`,
|
|
6514
|
+
hint: `install ${command}, then run the same command again`
|
|
6515
|
+
}, { cause });
|
|
6516
|
+
}
|
|
6517
|
+
/** `ctx.spawn`: `spawn` bound to the run, its start failures classified by errno. */
|
|
6518
|
+
function contextSpawn(run, defaults, fileError) {
|
|
6519
|
+
return async (command, args = [], options = {}) => {
|
|
6520
|
+
let result;
|
|
6521
|
+
try {
|
|
6522
|
+
result = await run(command, args, {
|
|
6523
|
+
cwd: options.cwd ?? defaults.cwd,
|
|
6524
|
+
env: options.env ?? defaults.env,
|
|
6525
|
+
signal: defaults.signal,
|
|
6526
|
+
onLine: options.progress === true ? defaults.progress : void 0
|
|
6527
|
+
});
|
|
6528
|
+
} catch (error) {
|
|
6529
|
+
if (isMissingFile(error)) throw missingError(command, error);
|
|
6530
|
+
throw fileError(error, {
|
|
6531
|
+
path: command,
|
|
6532
|
+
access: "read"
|
|
6533
|
+
});
|
|
6534
|
+
}
|
|
6535
|
+
if (options.check === true && result.exitCode !== 0) throw failedError(command, result);
|
|
6536
|
+
return result;
|
|
6537
|
+
};
|
|
6538
|
+
}
|
|
6539
|
+
//#endregion
|
|
6103
6540
|
//#region ../agent-cli/dist/npm.js
|
|
6104
6541
|
const REGISTRY_UNREACHABLE = "REGISTRY_UNREACHABLE";
|
|
6105
6542
|
const REGISTRY_AUTH = "REGISTRY_AUTH";
|
|
6106
6543
|
const INSTALL_FAILED = "INSTALL_FAILED";
|
|
6107
6544
|
const NPM_FAILED = "NPM_FAILED";
|
|
6108
6545
|
const NO_LATEST = "NO_LATEST";
|
|
6109
|
-
function npmContext(cli, install, ctx) {
|
|
6546
|
+
function npmContext(cli, install, ctx, node) {
|
|
6110
6547
|
return {
|
|
6111
6548
|
cliName: cli.name,
|
|
6112
6549
|
install,
|
|
6113
6550
|
env: ctx.env,
|
|
6114
|
-
signal: ctx.signal
|
|
6551
|
+
signal: ctx.signal,
|
|
6552
|
+
node
|
|
6115
6553
|
};
|
|
6116
6554
|
}
|
|
6117
6555
|
const NPMJS = "https://registry.npmjs.org/";
|
|
6118
|
-
const STDERR_TAIL_LINES
|
|
6556
|
+
const STDERR_TAIL_LINES = 10;
|
|
6119
6557
|
const RM_RETRIES = 3;
|
|
6120
6558
|
const NETWORK_CODES = /* @__PURE__ */ new Set([
|
|
6121
6559
|
"ENOTFOUND",
|
|
@@ -6145,40 +6583,36 @@ function installCommandLine(install, version = "latest") {
|
|
|
6145
6583
|
...registryFlags(install)
|
|
6146
6584
|
].join(" ");
|
|
6147
6585
|
}
|
|
6586
|
+
function npmOf(ctx, windows) {
|
|
6587
|
+
const beside = ctx.node === void 0 ? void 0 : join(dirname(ctx.node), windows ? "npm.cmd" : "npm");
|
|
6588
|
+
if (beside === void 0 || !existsSync(beside)) return {
|
|
6589
|
+
path: "npm",
|
|
6590
|
+
env: ctx.env
|
|
6591
|
+
};
|
|
6592
|
+
if (windows) return {
|
|
6593
|
+
path: beside,
|
|
6594
|
+
env: ctx.env
|
|
6595
|
+
};
|
|
6596
|
+
const PATH = [dirname(beside), ctx.env.PATH].filter(Boolean).join(delimiter);
|
|
6597
|
+
return {
|
|
6598
|
+
path: beside,
|
|
6599
|
+
env: {
|
|
6600
|
+
...ctx.env,
|
|
6601
|
+
PATH
|
|
6602
|
+
}
|
|
6603
|
+
};
|
|
6604
|
+
}
|
|
6148
6605
|
function spawnNpm(args, ctx, signal) {
|
|
6149
|
-
const
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
windowsHide: true,
|
|
6156
|
-
stdio: [
|
|
6157
|
-
"ignore",
|
|
6158
|
-
"pipe",
|
|
6159
|
-
"pipe"
|
|
6160
|
-
],
|
|
6161
|
-
detached: signal === null && !windows,
|
|
6162
|
-
signal: signal ?? void 0
|
|
6163
|
-
});
|
|
6164
|
-
let stdout = "";
|
|
6165
|
-
let stderr = "";
|
|
6166
|
-
child.stdout.setEncoding("utf8").on("data", (chunk) => {
|
|
6167
|
-
stdout += chunk;
|
|
6168
|
-
});
|
|
6169
|
-
child.stderr.setEncoding("utf8").on("data", (chunk) => {
|
|
6170
|
-
stderr += chunk;
|
|
6171
|
-
});
|
|
6172
|
-
child.on("error", reject);
|
|
6173
|
-
child.on("close", (exitCode) => resolve({
|
|
6174
|
-
exitCode,
|
|
6175
|
-
stdout,
|
|
6176
|
-
stderr
|
|
6177
|
-
}));
|
|
6606
|
+
const npm = npmOf(ctx, process.platform === "win32");
|
|
6607
|
+
return spawnChild(npm.path, args, {
|
|
6608
|
+
cwd: process.cwd(),
|
|
6609
|
+
env: npm.env,
|
|
6610
|
+
signal: signal ?? new AbortController().signal,
|
|
6611
|
+
detached: signal === null
|
|
6178
6612
|
});
|
|
6179
6613
|
}
|
|
6180
6614
|
function tail$1(stderr) {
|
|
6181
|
-
const lines = lastLines(stderr, STDERR_TAIL_LINES
|
|
6615
|
+
const lines = lastLines(stderr, STDERR_TAIL_LINES);
|
|
6182
6616
|
return lines === "" ? "" : `\n${lines}`;
|
|
6183
6617
|
}
|
|
6184
6618
|
function failureOf(call, answer, ctx) {
|
|
@@ -6326,7 +6760,10 @@ const CONFIRMATION_REQUIRED = "CONFIRMATION_REQUIRED";
|
|
|
6326
6760
|
const CONFIRMATION_MISMATCH = "CONFIRMATION_MISMATCH";
|
|
6327
6761
|
function checkConfirmation({ invocation, commandLine, given }, expected) {
|
|
6328
6762
|
if (given === expected) return;
|
|
6329
|
-
const hint = `to confirm, run \`${
|
|
6763
|
+
const hint = `to confirm, run \`${commandLineOf(invocation, {
|
|
6764
|
+
remove: [CONFIRM_FLAG.flag],
|
|
6765
|
+
add: [CONFIRM_FLAG.flag, expected]
|
|
6766
|
+
})}\``;
|
|
6330
6767
|
if (given === void 0) throw new UsageError({
|
|
6331
6768
|
code: CONFIRMATION_REQUIRED,
|
|
6332
6769
|
message: `\`${commandLine}\` is destructive and needs ${CONFIRM_FLAG.flag}`,
|
|
@@ -6347,51 +6784,95 @@ function checkCost({ invocation, commandLine, yes }, cost) {
|
|
|
6347
6784
|
throw new CliError({
|
|
6348
6785
|
code: NOT_CONFIRMED,
|
|
6349
6786
|
message: `\`${commandLine}\` needs ${YES_FLAG.flag}: ${cost}`,
|
|
6350
|
-
hint: `to approve the cost, run \`${
|
|
6787
|
+
hint: `to approve the cost, run \`${commandLineOf(invocation, { add: [YES_FLAG.flag] })}\``
|
|
6351
6788
|
});
|
|
6352
6789
|
}
|
|
6353
6790
|
//#endregion
|
|
6354
6791
|
//#region ../agent-cli/dist/agent.js
|
|
6355
|
-
const
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
"
|
|
6360
|
-
"
|
|
6361
|
-
"
|
|
6792
|
+
const AGENT_NAME = /^[a-zA-Z0-9_-]+$/u;
|
|
6793
|
+
const isSet = (name) => (env) => (env[name] ?? "") !== "";
|
|
6794
|
+
const equals = (name, value) => (env) => env[name] === value;
|
|
6795
|
+
const MARKERS = [
|
|
6796
|
+
(env) => AGENT_NAME.test(env.AI_AGENT ?? ""),
|
|
6797
|
+
equals("AGENT", "amp"),
|
|
6798
|
+
isSet("CODEX_SANDBOX"),
|
|
6799
|
+
isSet("CODEX_CI"),
|
|
6800
|
+
isSet("CODEX_THREAD_ID"),
|
|
6801
|
+
isSet("GEMINI_CLI"),
|
|
6802
|
+
isSet("COPILOT_CLI"),
|
|
6803
|
+
isSet("OPENCODE"),
|
|
6804
|
+
isSet("ANTIGRAVITY_AGENT"),
|
|
6805
|
+
isSet("AUGMENT_AGENT"),
|
|
6806
|
+
isSet("REPL_ID"),
|
|
6807
|
+
isSet("CLAUDE_CODE_IS_COWORK"),
|
|
6808
|
+
isSet("CLAUDECODE"),
|
|
6809
|
+
isSet("CLAUDE_CODE"),
|
|
6810
|
+
isSet("CURSOR_TRACE_ID"),
|
|
6811
|
+
isSet("CURSOR_AGENT"),
|
|
6812
|
+
equals("CURSOR_EXTENSION_HOST_ROLE", "agent-exec"),
|
|
6813
|
+
equals("TERM_PROGRAM", "kiro"),
|
|
6814
|
+
(env) => ["/.pi/agent", "\\.pi\\agent"].some((dir) => (env.PATH ?? "").includes(dir)),
|
|
6815
|
+
isSet("GOOSE_PROVIDER")
|
|
6362
6816
|
];
|
|
6363
|
-
/**
|
|
6817
|
+
/**
|
|
6818
|
+
* Whether a Coding agent, not a person, is running the Agent CLI. Some Coding agents run commands
|
|
6819
|
+
* in a PTY, so a TTY alone doesn't mean a person is watching.
|
|
6820
|
+
*/
|
|
6364
6821
|
function isAgent(env) {
|
|
6365
|
-
return
|
|
6822
|
+
return MARKERS.some((marker) => marker(env));
|
|
6366
6823
|
}
|
|
6367
6824
|
//#endregion
|
|
6368
6825
|
//#region ../agent-cli/dist/errno.js
|
|
6369
6826
|
const PERMISSION_DENIED = "PERMISSION_DENIED";
|
|
6370
6827
|
const DISK_FULL = "DISK_FULL";
|
|
6371
6828
|
const NOT_FOUND = "NOT_FOUND";
|
|
6372
|
-
|
|
6373
|
-
|
|
6829
|
+
const ALREADY_EXISTS = "ALREADY_EXISTS";
|
|
6830
|
+
const NOT_A_FILE = "NOT_A_FILE";
|
|
6831
|
+
function permissionHint({ path, access, callerLine, env, platform }) {
|
|
6832
|
+
if (platform === "win32") return `a program may hold ${path} open: close it, then run the same command again`;
|
|
6833
|
+
if (!isAgent(env)) return `check the permissions of ${path} and its folder`;
|
|
6834
|
+
return `your sandbox may block it: ask your user to run \`! ${callerLine}\`, or ${access === "read" ? `to allow reading ${path} in the sandbox` : `to allow ${path} in the sandbox's write list`}`;
|
|
6835
|
+
}
|
|
6836
|
+
function fileErrorOf(scope) {
|
|
6837
|
+
return (error, at) => classifyErrno(error, {
|
|
6838
|
+
...at,
|
|
6839
|
+
...scope
|
|
6840
|
+
});
|
|
6374
6841
|
}
|
|
6375
|
-
/** The error a file system failure on `path` stands for; any other error comes back unchanged. */
|
|
6376
6842
|
function classifyErrno(error, context) {
|
|
6377
6843
|
const { path } = context;
|
|
6378
6844
|
switch (errnoOf(error)) {
|
|
6379
6845
|
case "EACCES":
|
|
6380
|
-
case "EPERM":
|
|
6846
|
+
case "EPERM":
|
|
6847
|
+
case "EROFS":
|
|
6848
|
+
case "EBUSY": return new CliError({
|
|
6381
6849
|
code: PERMISSION_DENIED,
|
|
6382
6850
|
message: `permission denied: ${path}`,
|
|
6383
6851
|
hint: permissionHint(context)
|
|
6384
6852
|
}, { cause: error });
|
|
6385
|
-
case "ENOSPC":
|
|
6853
|
+
case "ENOSPC":
|
|
6854
|
+
case "EDQUOT": return new CliError({
|
|
6386
6855
|
code: DISK_FULL,
|
|
6387
6856
|
message: `no space left on the disk holding ${path}`,
|
|
6388
6857
|
hint: "free space on that disk, then run the same command again"
|
|
6389
6858
|
}, { cause: error });
|
|
6390
|
-
case "ENOENT":
|
|
6859
|
+
case "ENOENT":
|
|
6860
|
+
case "ENOTDIR":
|
|
6861
|
+
case "ENAMETOOLONG": return new CliError({
|
|
6391
6862
|
code: NOT_FOUND,
|
|
6392
6863
|
message: `not found: ${path}`,
|
|
6393
6864
|
hint: `check that ${path} and its folder exist`
|
|
6394
6865
|
}, { cause: error });
|
|
6866
|
+
case "EEXIST": return new CliError({
|
|
6867
|
+
code: ALREADY_EXISTS,
|
|
6868
|
+
message: `already exists: ${path}`,
|
|
6869
|
+
hint: `pass another path, or remove ${path}`
|
|
6870
|
+
}, { cause: error });
|
|
6871
|
+
case "EISDIR": return new CliError({
|
|
6872
|
+
code: NOT_A_FILE,
|
|
6873
|
+
message: `not a file: ${path} is a folder`,
|
|
6874
|
+
hint: `pass the path of a file, not of the folder ${path}`
|
|
6875
|
+
}, { cause: error });
|
|
6395
6876
|
default: return error;
|
|
6396
6877
|
}
|
|
6397
6878
|
}
|
|
@@ -6480,7 +6961,7 @@ var RunControl = class {
|
|
|
6480
6961
|
else outer?.addEventListener("abort", this.#onOuterAbort, { once: true });
|
|
6481
6962
|
if (runDeadline !== void 0) {
|
|
6482
6963
|
const { ms, hint } = runDeadline;
|
|
6483
|
-
after(clock, ms, this.#disposed.signal, () => this.#controller.abort(deadlineError(commandLine, ms, hint)));
|
|
6964
|
+
after(clock, ms, this.#disposed.signal, () => this.#controller.abort(deadlineError(commandLine, ms, hint())));
|
|
6484
6965
|
}
|
|
6485
6966
|
}
|
|
6486
6967
|
deadline(ms) {
|
|
@@ -6512,7 +6993,7 @@ var RunControl = class {
|
|
|
6512
6993
|
return value;
|
|
6513
6994
|
} finally {
|
|
6514
6995
|
await this.#stepsDone();
|
|
6515
|
-
this
|
|
6996
|
+
this.close();
|
|
6516
6997
|
}
|
|
6517
6998
|
}
|
|
6518
6999
|
/**
|
|
@@ -6541,13 +7022,192 @@ var RunControl = class {
|
|
|
6541
7022
|
async #stepsDone() {
|
|
6542
7023
|
while (this.#steps.size > 0) await Promise.all(this.#steps.keys());
|
|
6543
7024
|
}
|
|
6544
|
-
|
|
7025
|
+
/** Stops the run's timers and its hold on the caller's signal, for a run that never settles. */
|
|
7026
|
+
close() {
|
|
6545
7027
|
this.#graceCancel.abort();
|
|
6546
7028
|
this.#disposed.abort();
|
|
6547
7029
|
this.#outer?.removeEventListener("abort", this.#onOuterAbort);
|
|
6548
7030
|
}
|
|
6549
7031
|
};
|
|
6550
7032
|
//#endregion
|
|
7033
|
+
//#region ../agent-cli/dist/operator.js
|
|
7034
|
+
const NEEDS_OPERATOR = "NEEDS_OPERATOR";
|
|
7035
|
+
/** Fails with `NEEDS_OPERATOR` when a Coding agent runs an Operator Command. */
|
|
7036
|
+
function checkOperator({ operator, commandLine }, env, callerLine) {
|
|
7037
|
+
if (!operator || !isAgent(env)) return;
|
|
7038
|
+
throw new CliError({
|
|
7039
|
+
code: NEEDS_OPERATOR,
|
|
7040
|
+
message: `\`${commandLine}\` must be run by a person at a terminal, not a Coding agent`,
|
|
7041
|
+
hint: `ask the operator to type: ! ${callerLine}`
|
|
7042
|
+
});
|
|
7043
|
+
}
|
|
7044
|
+
//#endregion
|
|
7045
|
+
//#region ../agent-cli/dist/files.js
|
|
7046
|
+
const TEMP_FILE = /^\..+\.agent-cli-(\d+)\.tmp$/;
|
|
7047
|
+
/** Where the Runtime writes `path` before moving it into place; a dead writer's is swept. */
|
|
7048
|
+
function tempPathOf(path) {
|
|
7049
|
+
return join(dirname(path), `.${basename(path)}.agent-cli-${process.pid}.tmp`);
|
|
7050
|
+
}
|
|
7051
|
+
function isAlive(pid) {
|
|
7052
|
+
try {
|
|
7053
|
+
process.kill(pid, 0);
|
|
7054
|
+
return true;
|
|
7055
|
+
} catch (error) {
|
|
7056
|
+
return errnoOf(error) === "EPERM";
|
|
7057
|
+
}
|
|
7058
|
+
}
|
|
7059
|
+
async function sweep(folder) {
|
|
7060
|
+
const dead = (await readdir(folder)).filter((name) => {
|
|
7061
|
+
const pid = TEMP_FILE.exec(name)?.[1];
|
|
7062
|
+
return pid !== void 0 && !isAlive(Number(pid));
|
|
7063
|
+
});
|
|
7064
|
+
await Promise.all(dead.map((name) => rm(join(folder, name), { force: true })));
|
|
7065
|
+
}
|
|
7066
|
+
/** The file a symlink at `path` points to, so a replacing write keeps the link. */
|
|
7067
|
+
async function targetOf$1(path) {
|
|
7068
|
+
try {
|
|
7069
|
+
return await realpath(path);
|
|
7070
|
+
} catch (error) {
|
|
7071
|
+
if (isMissingFile(error)) return path;
|
|
7072
|
+
throw error;
|
|
7073
|
+
}
|
|
7074
|
+
}
|
|
7075
|
+
async function writeWithMode(path, data, mode) {
|
|
7076
|
+
if (mode === void 0) {
|
|
7077
|
+
await writeFile(path, data);
|
|
7078
|
+
return;
|
|
7079
|
+
}
|
|
7080
|
+
await writeFile(path, data, { mode });
|
|
7081
|
+
await chmod(path, mode);
|
|
7082
|
+
}
|
|
7083
|
+
/** What `link` answers on a file system without hard links, such as exFAT. */
|
|
7084
|
+
const NO_HARD_LINKS = /* @__PURE__ */ new Set([
|
|
7085
|
+
"EPERM",
|
|
7086
|
+
"ENOTSUP",
|
|
7087
|
+
"EXDEV"
|
|
7088
|
+
]);
|
|
7089
|
+
/** A link fails atomically when `path` is taken, so no reader ever sees half a file there. */
|
|
7090
|
+
async function linkNew(temp, path, data, mode) {
|
|
7091
|
+
try {
|
|
7092
|
+
await link(temp, path);
|
|
7093
|
+
} catch (error) {
|
|
7094
|
+
if (!NO_HARD_LINKS.has(errnoOf(error))) throw error;
|
|
7095
|
+
await createNew(path, data, mode);
|
|
7096
|
+
}
|
|
7097
|
+
}
|
|
7098
|
+
/** A file this call created and could not finish is removed, so a rerun does not find half of it. */
|
|
7099
|
+
async function createNew(path, data, mode) {
|
|
7100
|
+
const handle = await open(path, "wx", mode);
|
|
7101
|
+
try {
|
|
7102
|
+
await handle.writeFile(data);
|
|
7103
|
+
if (mode !== void 0) await handle.chmod(mode);
|
|
7104
|
+
} catch (error) {
|
|
7105
|
+
await handle.close();
|
|
7106
|
+
await rm(path, { force: true });
|
|
7107
|
+
throw error;
|
|
7108
|
+
}
|
|
7109
|
+
await handle.close();
|
|
7110
|
+
}
|
|
7111
|
+
const RENAME_ATTEMPTS = 10;
|
|
7112
|
+
const RENAME_BACKOFF_MS = 10;
|
|
7113
|
+
const HELD_BY_ANOTHER_PROGRAM = /* @__PURE__ */ new Set(["EPERM", "EBUSY"]);
|
|
7114
|
+
async function renameRetrying(from, to) {
|
|
7115
|
+
for (let attempt = 1;; attempt++) try {
|
|
7116
|
+
await rename(from, to);
|
|
7117
|
+
return;
|
|
7118
|
+
} catch (error) {
|
|
7119
|
+
if (!(process.platform === "win32" && HELD_BY_ANOTHER_PROGRAM.has(errnoOf(error))) || attempt === RENAME_ATTEMPTS) throw error;
|
|
7120
|
+
await setTimeout$1(attempt * RENAME_BACKOFF_MS);
|
|
7121
|
+
}
|
|
7122
|
+
}
|
|
7123
|
+
/** Real files for one run: the first write to each folder sweeps the temp files of dead writers. */
|
|
7124
|
+
function realFiles() {
|
|
7125
|
+
const swept = /* @__PURE__ */ new Set();
|
|
7126
|
+
return {
|
|
7127
|
+
exists: async (path) => {
|
|
7128
|
+
try {
|
|
7129
|
+
await access(path);
|
|
7130
|
+
return true;
|
|
7131
|
+
} catch (error) {
|
|
7132
|
+
if (isNothingThere(error)) return false;
|
|
7133
|
+
throw error;
|
|
7134
|
+
}
|
|
7135
|
+
},
|
|
7136
|
+
write: async (path, data, options = {}) => {
|
|
7137
|
+
await mkdir(dirname(path), { recursive: true });
|
|
7138
|
+
const target = options.exclusive === true ? path : await targetOf$1(path);
|
|
7139
|
+
const folder = dirname(target);
|
|
7140
|
+
if (!swept.has(folder)) {
|
|
7141
|
+
await sweep(folder);
|
|
7142
|
+
swept.add(folder);
|
|
7143
|
+
}
|
|
7144
|
+
const temp = tempPathOf(target);
|
|
7145
|
+
try {
|
|
7146
|
+
await writeWithMode(temp, data, options.mode);
|
|
7147
|
+
if (options.exclusive === true) {
|
|
7148
|
+
await linkNew(temp, target, data, options.mode);
|
|
7149
|
+
await rm(temp);
|
|
7150
|
+
} else await renameRetrying(temp, target);
|
|
7151
|
+
} catch (error) {
|
|
7152
|
+
await rm(temp, { force: true });
|
|
7153
|
+
throw error;
|
|
7154
|
+
}
|
|
7155
|
+
},
|
|
7156
|
+
read: (path) => readFile(path),
|
|
7157
|
+
list: (folder) => readdir(folder),
|
|
7158
|
+
remove: (path) => rm(path, {
|
|
7159
|
+
recursive: true,
|
|
7160
|
+
force: true
|
|
7161
|
+
}),
|
|
7162
|
+
mkdir: async (path, options) => {
|
|
7163
|
+
if (options?.exclusive !== true) {
|
|
7164
|
+
await mkdir(path, { recursive: true });
|
|
7165
|
+
return;
|
|
7166
|
+
}
|
|
7167
|
+
await mkdir(dirname(path), { recursive: true });
|
|
7168
|
+
await mkdir(path);
|
|
7169
|
+
},
|
|
7170
|
+
stat: async (path) => {
|
|
7171
|
+
try {
|
|
7172
|
+
const { size, dev, ino } = await stat(path, { bigint: true });
|
|
7173
|
+
return {
|
|
7174
|
+
size: Number(size),
|
|
7175
|
+
id: `${dev}:${ino}`
|
|
7176
|
+
};
|
|
7177
|
+
} catch (error) {
|
|
7178
|
+
if (isNothingThere(error)) return void 0;
|
|
7179
|
+
throw error;
|
|
7180
|
+
}
|
|
7181
|
+
}
|
|
7182
|
+
};
|
|
7183
|
+
}
|
|
7184
|
+
/**
|
|
7185
|
+
* `files` resolving paths against `cwd`, its failures classified by errno; `list` drops the
|
|
7186
|
+
* Runtime's temp files and sorts.
|
|
7187
|
+
*/
|
|
7188
|
+
function classifiedFiles(files, { cwd, fileError }) {
|
|
7189
|
+
async function at(access, path, work) {
|
|
7190
|
+
const target = resolve(cwd, path);
|
|
7191
|
+
try {
|
|
7192
|
+
return await work(target);
|
|
7193
|
+
} catch (error) {
|
|
7194
|
+
throw fileError(error, {
|
|
7195
|
+
path: target,
|
|
7196
|
+
access
|
|
7197
|
+
});
|
|
7198
|
+
}
|
|
7199
|
+
}
|
|
7200
|
+
return {
|
|
7201
|
+
exists: (path) => at("read", path, (target) => files.exists(target)),
|
|
7202
|
+
write: (path, data, options) => at("write", path, (target) => files.write(target, data, options)),
|
|
7203
|
+
read: (path) => at("read", path, (target) => files.read(target)),
|
|
7204
|
+
list: (folder) => at("read", folder, async (target) => (await files.list(target)).filter((name) => !TEMP_FILE.test(name)).sort()),
|
|
7205
|
+
remove: (path) => at("write", path, (target) => files.remove(target)),
|
|
7206
|
+
mkdir: (path, options) => at("write", path, (target) => files.mkdir(target, options)),
|
|
7207
|
+
stat: (path) => at("read", path, (target) => files.stat(target))
|
|
7208
|
+
};
|
|
7209
|
+
}
|
|
7210
|
+
//#endregion
|
|
6551
7211
|
//#region ../agent-cli/dist/outputs.js
|
|
6552
7212
|
const OUTPUT_EXISTS = "OUTPUT_EXISTS";
|
|
6553
7213
|
/** Refuses a run that would overwrite existing outputs unless the caller passed `--force`. */
|
|
@@ -6560,9 +7220,62 @@ async function checkOutputs({ invocation, commandLine, force, files }, outputs)
|
|
|
6560
7220
|
throw new CliError({
|
|
6561
7221
|
code: OUTPUT_EXISTS,
|
|
6562
7222
|
message: `\`${commandLine}\` would overwrite ${existing.join(", ")}`,
|
|
6563
|
-
hint: `to replace ${them}, run \`${
|
|
7223
|
+
hint: `to replace ${them}, run \`${commandLineOf(invocation, { add: [FORCE_FLAG.flag] })}\``
|
|
6564
7224
|
});
|
|
6565
7225
|
}
|
|
7226
|
+
/** Guards the writes to declared outputs of `files`, whose paths resolve against `cwd`. */
|
|
7227
|
+
function outputsGuard(files, cwd) {
|
|
7228
|
+
const unwritten = /* @__PURE__ */ new Set();
|
|
7229
|
+
let forceLine = "";
|
|
7230
|
+
const exclusiveWrite = async (path, data, options) => {
|
|
7231
|
+
const target = resolve(cwd, path);
|
|
7232
|
+
unwritten.delete(target);
|
|
7233
|
+
try {
|
|
7234
|
+
await files.write(path, data, {
|
|
7235
|
+
...options,
|
|
7236
|
+
exclusive: true
|
|
7237
|
+
});
|
|
7238
|
+
} catch (error) {
|
|
7239
|
+
unwritten.add(target);
|
|
7240
|
+
if (!(error instanceof CliError) || error.code !== "ALREADY_EXISTS") throw error;
|
|
7241
|
+
throw new CliError({
|
|
7242
|
+
code: ALREADY_EXISTS,
|
|
7243
|
+
message: error.message,
|
|
7244
|
+
hint: `to replace it, run \`${forceLine}\``
|
|
7245
|
+
}, { cause: error });
|
|
7246
|
+
}
|
|
7247
|
+
};
|
|
7248
|
+
return {
|
|
7249
|
+
files: {
|
|
7250
|
+
...files,
|
|
7251
|
+
write: (path, data, options) => unwritten.has(resolve(cwd, path)) ? exclusiveWrite(path, data, options) : files.write(path, data, options)
|
|
7252
|
+
},
|
|
7253
|
+
guard: (outputs, line) => {
|
|
7254
|
+
forceLine = line;
|
|
7255
|
+
for (const path of outputs) unwritten.add(resolve(cwd, path));
|
|
7256
|
+
}
|
|
7257
|
+
};
|
|
7258
|
+
}
|
|
7259
|
+
/**
|
|
7260
|
+
* Creates each output folder and a temp file in it, so a sandbox denial fails before `apply`
|
|
7261
|
+
* spends anything. The temp file's name is the Runtime's, so a crashed run's leftover is swept.
|
|
7262
|
+
*/
|
|
7263
|
+
async function probeOutputs({ files, cwd, fileError }, outputs) {
|
|
7264
|
+
const folders = new Set(outputs.map((path) => dirname(resolve(cwd, path))));
|
|
7265
|
+
await Promise.all([...folders].map(async (folder) => {
|
|
7266
|
+
const probe = tempPathOf(join(folder, "outputs-probe"));
|
|
7267
|
+
try {
|
|
7268
|
+
await files.mkdir(folder);
|
|
7269
|
+
await files.write(probe, "");
|
|
7270
|
+
await files.remove(probe);
|
|
7271
|
+
} catch (error) {
|
|
7272
|
+
throw fileError(error, {
|
|
7273
|
+
path: folder,
|
|
7274
|
+
access: "write"
|
|
7275
|
+
});
|
|
7276
|
+
}
|
|
7277
|
+
}));
|
|
7278
|
+
}
|
|
6566
7279
|
//#endregion
|
|
6567
7280
|
//#region ../agent-cli/dist/project.js
|
|
6568
7281
|
const PROJECT_INVALID = "PROJECT_INVALID";
|
|
@@ -6610,145 +7323,6 @@ function projectOf(projectFile, cwd) {
|
|
|
6610
7323
|
return projectFrom(projectFile, resolve(cwd));
|
|
6611
7324
|
}
|
|
6612
7325
|
//#endregion
|
|
6613
|
-
//#region ../agent-cli/dist/tools.js
|
|
6614
|
-
const TOOL_MISSING = "TOOL_MISSING";
|
|
6615
|
-
const WINDOWS_EXTENSIONS = ".COM;.EXE;.BAT;.CMD";
|
|
6616
|
-
const NOT_EXECUTABLE = /* @__PURE__ */ new Set([
|
|
6617
|
-
"ENOENT",
|
|
6618
|
-
"ENOTDIR",
|
|
6619
|
-
"EACCES"
|
|
6620
|
-
]);
|
|
6621
|
-
function pathOf(env) {
|
|
6622
|
-
return env[Object.keys(env).find((name) => name.toUpperCase() === "PATH") ?? "PATH"] ?? "";
|
|
6623
|
-
}
|
|
6624
|
-
function extensionsOf(env) {
|
|
6625
|
-
return process.platform === "win32" ? (env.PATHEXT ?? WINDOWS_EXTENSIONS).split(";") : [""];
|
|
6626
|
-
}
|
|
6627
|
-
async function isExecutable(file) {
|
|
6628
|
-
try {
|
|
6629
|
-
await access(file, constants$1.X_OK);
|
|
6630
|
-
return true;
|
|
6631
|
-
} catch (error) {
|
|
6632
|
-
if (NOT_EXECUTABLE.has(errnoOf(error) ?? "")) return false;
|
|
6633
|
-
throw error;
|
|
6634
|
-
}
|
|
6635
|
-
}
|
|
6636
|
-
/** Where `name` is found on `PATH` from `env`, or undefined. */
|
|
6637
|
-
async function findTool(name, env) {
|
|
6638
|
-
const candidates = pathOf(env).split(delimiter).filter((folder) => folder !== "").flatMap((folder) => extensionsOf(env).map((extension) => join(folder, `${name}${extension}`)));
|
|
6639
|
-
for (const file of candidates) if (await isExecutable(file)) return file;
|
|
6640
|
-
}
|
|
6641
|
-
/** Fails with `TOOL_MISSING`, naming every missing tool at once, unless all are on `PATH`. */
|
|
6642
|
-
async function checkTools(tools, env) {
|
|
6643
|
-
const found = await Promise.all(tools.map((tool) => findTool(tool.name, env)));
|
|
6644
|
-
const missing = tools.filter((_tool, index) => found[index] === void 0);
|
|
6645
|
-
if (missing.length === 0) return;
|
|
6646
|
-
const names = missing.map(({ name }) => name).join(", ");
|
|
6647
|
-
throw new CliError({
|
|
6648
|
-
code: TOOL_MISSING,
|
|
6649
|
-
message: `${missing.length === 1 ? "a tool it runs is" : "tools it runs are"} not on PATH: ${names}`,
|
|
6650
|
-
hint: `install ${missing.length === 1 ? "it" : "them"}, then run the same command again: ${missing.map(({ install }) => install).join("; ")}`
|
|
6651
|
-
});
|
|
6652
|
-
}
|
|
6653
|
-
function toolsIn(node) {
|
|
6654
|
-
return isCommand(node) ? [...node.tools ?? []] : Object.values(node).flatMap(toolsIn);
|
|
6655
|
-
}
|
|
6656
|
-
/** One `doctor` row per distinct tool the Commands declare, with its install command as the fix. */
|
|
6657
|
-
function toolRows(commands) {
|
|
6658
|
-
return [...new Map(toolsIn(commands).map((tool) => [tool.name, tool])).values()].map(({ name, install }) => ({
|
|
6659
|
-
name,
|
|
6660
|
-
run: async (ctx) => {
|
|
6661
|
-
const file = await findTool(name, ctx.env);
|
|
6662
|
-
return file === void 0 ? {
|
|
6663
|
-
state: "problem",
|
|
6664
|
-
message: `${name} is not on PATH`,
|
|
6665
|
-
fix: install
|
|
6666
|
-
} : {
|
|
6667
|
-
state: "ok",
|
|
6668
|
-
message: `found at ${file}`
|
|
6669
|
-
};
|
|
6670
|
-
}
|
|
6671
|
-
}));
|
|
6672
|
-
}
|
|
6673
|
-
//#endregion
|
|
6674
|
-
//#region ../agent-cli/dist/spawn.js
|
|
6675
|
-
const TOOL_FAILED = "TOOL_FAILED";
|
|
6676
|
-
const STDERR_TAIL_LINES = 20;
|
|
6677
|
-
const SIGNAL_EXIT_BASE = 128;
|
|
6678
|
-
const realSpawn = (command, args, { cwd, env, signal }) => new Promise((resolve, reject) => {
|
|
6679
|
-
signal.throwIfAborted();
|
|
6680
|
-
const child = spawn(command, args, {
|
|
6681
|
-
cwd,
|
|
6682
|
-
env,
|
|
6683
|
-
stdio: [
|
|
6684
|
-
"ignore",
|
|
6685
|
-
"pipe",
|
|
6686
|
-
"pipe"
|
|
6687
|
-
]
|
|
6688
|
-
});
|
|
6689
|
-
const stdout = [];
|
|
6690
|
-
const stderr = [];
|
|
6691
|
-
child.stdout.on("data", (chunk) => stdout.push(chunk));
|
|
6692
|
-
child.stderr.on("data", (chunk) => stderr.push(chunk));
|
|
6693
|
-
const kill = () => {
|
|
6694
|
-
child.kill();
|
|
6695
|
-
};
|
|
6696
|
-
signal.addEventListener("abort", kill, { once: true });
|
|
6697
|
-
child.on("error", (error) => {
|
|
6698
|
-
signal.removeEventListener("abort", kill);
|
|
6699
|
-
reject(error);
|
|
6700
|
-
});
|
|
6701
|
-
child.on("close", (code, killedBy) => {
|
|
6702
|
-
signal.removeEventListener("abort", kill);
|
|
6703
|
-
if (signal.aborted) {
|
|
6704
|
-
reject(signal.reason);
|
|
6705
|
-
return;
|
|
6706
|
-
}
|
|
6707
|
-
resolve({
|
|
6708
|
-
stdout: Buffer.concat(stdout).toString(),
|
|
6709
|
-
stderr: Buffer.concat(stderr).toString(),
|
|
6710
|
-
exitCode: code ?? SIGNAL_EXIT_BASE + (killedBy === null ? 0 : constants.signals[killedBy])
|
|
6711
|
-
});
|
|
6712
|
-
});
|
|
6713
|
-
});
|
|
6714
|
-
function failedError(command, { exitCode, stderr }) {
|
|
6715
|
-
const tail = lastLines(stderr, STDERR_TAIL_LINES);
|
|
6716
|
-
return new CliError({
|
|
6717
|
-
code: TOOL_FAILED,
|
|
6718
|
-
message: tail === "" ? `${command} exited with ${exitCode} and wrote nothing to stderr` : `${command} exited with ${exitCode}; its stderr ends:\n${tail}`,
|
|
6719
|
-
hint: `the output of ${command} above says why it failed`
|
|
6720
|
-
});
|
|
6721
|
-
}
|
|
6722
|
-
function missingError(command, cause) {
|
|
6723
|
-
return new CliError({
|
|
6724
|
-
code: TOOL_MISSING,
|
|
6725
|
-
message: `${command} could not be started: it is not on PATH`,
|
|
6726
|
-
hint: `install ${command}, then run the same command again`
|
|
6727
|
-
}, { cause });
|
|
6728
|
-
}
|
|
6729
|
-
/** `ctx.spawn`: `spawn` bound to the run, its start failures classified by errno. */
|
|
6730
|
-
function contextSpawn(run, defaults, callerLine) {
|
|
6731
|
-
return async (command, args = [], options = {}) => {
|
|
6732
|
-
let result;
|
|
6733
|
-
try {
|
|
6734
|
-
result = await run(command, args, {
|
|
6735
|
-
cwd: options.cwd ?? defaults.cwd,
|
|
6736
|
-
env: options.env ?? defaults.env,
|
|
6737
|
-
signal: defaults.signal
|
|
6738
|
-
});
|
|
6739
|
-
} catch (error) {
|
|
6740
|
-
if (isMissingFile(error)) throw missingError(command, error);
|
|
6741
|
-
throw classifyErrno(error, {
|
|
6742
|
-
path: command,
|
|
6743
|
-
callerLine,
|
|
6744
|
-
env: defaults.env
|
|
6745
|
-
});
|
|
6746
|
-
}
|
|
6747
|
-
if (options.check === true && result.exitCode !== 0) throw failedError(command, result);
|
|
6748
|
-
return result;
|
|
6749
|
-
};
|
|
6750
|
-
}
|
|
6751
|
-
//#endregion
|
|
6752
7326
|
//#region ../agent-cli/dist/exit-classes.js
|
|
6753
7327
|
const SIGNAL_EXIT_CODES = {
|
|
6754
7328
|
SIGINT: 130,
|
|
@@ -6771,6 +7345,7 @@ function runtimeCodes() {
|
|
|
6771
7345
|
[CONFIRMATION_REQUIRED]: "caller",
|
|
6772
7346
|
[CONFIRMATION_MISMATCH]: "caller",
|
|
6773
7347
|
[NOT_CONFIRMED]: "operator",
|
|
7348
|
+
[NEEDS_OPERATOR]: "operator",
|
|
6774
7349
|
[OUTPUT_EXISTS]: "caller",
|
|
6775
7350
|
[INTERRUPTED]: "interrupted",
|
|
6776
7351
|
[DEADLINE_EXCEEDED]: "wait",
|
|
@@ -6778,6 +7353,8 @@ function runtimeCodes() {
|
|
|
6778
7353
|
[PERMISSION_DENIED]: "operator",
|
|
6779
7354
|
[DISK_FULL]: "operator",
|
|
6780
7355
|
[NOT_FOUND]: "caller",
|
|
7356
|
+
[ALREADY_EXISTS]: "caller",
|
|
7357
|
+
[NOT_A_FILE]: "caller",
|
|
6781
7358
|
[TOOL_FAILED]: "operator",
|
|
6782
7359
|
[TOOL_MISSING]: "operator",
|
|
6783
7360
|
[PROJECT_INVALID]: "operator",
|
|
@@ -6841,6 +7418,53 @@ function exitCodeOf(error, errors, stop) {
|
|
|
6841
7418
|
return exitClass === "interrupted" ? SIGNAL_EXIT_CODES[stopSignalOf(stop?.reason)] : EXIT_CODES[exitClass];
|
|
6842
7419
|
}
|
|
6843
7420
|
//#endregion
|
|
7421
|
+
//#region ../agent-cli/dist/command-spec.js
|
|
7422
|
+
/** The group's Commands and groups that help and suggestions may name: hidden Commands left out. */
|
|
7423
|
+
function visibleCommands({ commands }) {
|
|
7424
|
+
return Object.fromEntries(Object.entries(commands).filter(([, node]) => node.kind === "group" || !node.hidden));
|
|
7425
|
+
}
|
|
7426
|
+
function declaredOf(command) {
|
|
7427
|
+
if (!hasPlan(command)) return {
|
|
7428
|
+
outputs: false,
|
|
7429
|
+
force: void 0,
|
|
7430
|
+
cost: false
|
|
7431
|
+
};
|
|
7432
|
+
return {
|
|
7433
|
+
outputs: command.outputs !== void 0,
|
|
7434
|
+
force: command.force,
|
|
7435
|
+
cost: command.cost !== void 0
|
|
7436
|
+
};
|
|
7437
|
+
}
|
|
7438
|
+
function commandSpec(commandLine, command) {
|
|
7439
|
+
const list = command.rows === void 0 ? void 0 : listSpec(command.rows);
|
|
7440
|
+
return {
|
|
7441
|
+
kind: "command",
|
|
7442
|
+
commandLine,
|
|
7443
|
+
command,
|
|
7444
|
+
description: command.description,
|
|
7445
|
+
help: command.help,
|
|
7446
|
+
hidden: command.hidden === true,
|
|
7447
|
+
operator: command.operator === true,
|
|
7448
|
+
effect: command.effect,
|
|
7449
|
+
examples: command.examples,
|
|
7450
|
+
args: argFields(command.args),
|
|
7451
|
+
options: optionFields(command.options),
|
|
7452
|
+
standardFlags: standardFlagsFor(command.effect, declaredOf(command), list),
|
|
7453
|
+
list,
|
|
7454
|
+
output: list?.output ?? command.output
|
|
7455
|
+
};
|
|
7456
|
+
}
|
|
7457
|
+
function groupSpec(commandLine, commands) {
|
|
7458
|
+
return {
|
|
7459
|
+
kind: "group",
|
|
7460
|
+
commandLine,
|
|
7461
|
+
commands: Object.fromEntries(Object.entries(commands).map(([key, node]) => [key, specOf(`${commandLine} ${key}`, node)]))
|
|
7462
|
+
};
|
|
7463
|
+
}
|
|
7464
|
+
function specOf(commandLine, node) {
|
|
7465
|
+
return isCommand(node) ? commandSpec(commandLine, node) : groupSpec(commandLine, node);
|
|
7466
|
+
}
|
|
7467
|
+
//#endregion
|
|
6844
7468
|
//#region ../agent-cli/dist/help.js
|
|
6845
7469
|
function table(rows) {
|
|
6846
7470
|
const width = Math.max(...rows.map(([left]) => left.length));
|
|
@@ -6854,10 +7478,11 @@ function section(title, rows, style) {
|
|
|
6854
7478
|
];
|
|
6855
7479
|
}
|
|
6856
7480
|
function summaryOf(node) {
|
|
6857
|
-
|
|
7481
|
+
if (node.kind === "group") return `group: ${Object.keys(visibleCommands(node)).join(", ")}`;
|
|
7482
|
+
return node.operator ? `${node.description} (operator only)` : node.description;
|
|
6858
7483
|
}
|
|
6859
|
-
function commandRows(
|
|
6860
|
-
return Object.entries(
|
|
7484
|
+
function commandRows(group) {
|
|
7485
|
+
return Object.entries(visibleCommands(group)).map(([key, node]) => [key, summaryOf(node)]);
|
|
6861
7486
|
}
|
|
6862
7487
|
function lines(...parts) {
|
|
6863
7488
|
return `${parts.join("\n")}\n`;
|
|
@@ -6885,11 +7510,11 @@ function exitCodeRows(cli) {
|
|
|
6885
7510
|
}
|
|
6886
7511
|
function firstExample(node) {
|
|
6887
7512
|
if (node.kind === "command") return node.examples.slice(0, 1);
|
|
6888
|
-
return Object.values(node
|
|
7513
|
+
return Object.values(visibleCommands(node)).flatMap(firstExample).slice(0, 1);
|
|
6889
7514
|
}
|
|
6890
7515
|
function rootExamples(root) {
|
|
6891
7516
|
if (root.kind === "command") return [...root.examples];
|
|
6892
|
-
const { doctor, ...others } = root
|
|
7517
|
+
const { doctor, ...others } = visibleCommands(root);
|
|
6893
7518
|
return [...Object.values(others), ...doctor === void 0 ? [] : [doctor]].flatMap(firstExample);
|
|
6894
7519
|
}
|
|
6895
7520
|
function examplesSection(examples, style) {
|
|
@@ -6908,6 +7533,7 @@ const EFFECT_NOTES = {
|
|
|
6908
7533
|
destructive: "changes something hard to undo; show the Plan with --dry-run, run with --confirm",
|
|
6909
7534
|
serve: "changes nothing; prints its data at once, then runs until Ctrl-C, which exits 0"
|
|
6910
7535
|
};
|
|
7536
|
+
const OPERATOR_NOTE = "only a person at a terminal runs it; a Coding agent asks the operator to type it after `!`";
|
|
6911
7537
|
function choicesOf(field) {
|
|
6912
7538
|
return field.choices === void 0 ? [] : [`one of: ${field.choices.join(", ")}`];
|
|
6913
7539
|
}
|
|
@@ -6937,8 +7563,10 @@ function commandLines(spec, style, { examples }) {
|
|
|
6937
7563
|
...examples ? examplesSection(spec.examples, style) : [],
|
|
6938
7564
|
...section("Arguments", spec.args.map(argRow), style),
|
|
6939
7565
|
...section("Options", spec.options.map(optionRow), style),
|
|
7566
|
+
...spec.help === void 0 ? [] : ["", spec.help],
|
|
6940
7567
|
"",
|
|
6941
7568
|
`${style.bold("Effect:")} ${spec.effect} (${EFFECT_NOTES[spec.effect]})`,
|
|
7569
|
+
...spec.operator ? [`${style.bold("Operator Command:")} ${OPERATOR_NOTE}`] : [],
|
|
6942
7570
|
...section("Standard flags", spec.standardFlags.map(flagRow), style)
|
|
6943
7571
|
];
|
|
6944
7572
|
}
|
|
@@ -6960,7 +7588,9 @@ function commandData(spec) {
|
|
|
6960
7588
|
return {
|
|
6961
7589
|
name: spec.commandLine,
|
|
6962
7590
|
description: spec.description,
|
|
7591
|
+
help: spec.help ?? null,
|
|
6963
7592
|
effect: spec.effect,
|
|
7593
|
+
operator: spec.operator,
|
|
6964
7594
|
examples: spec.examples,
|
|
6965
7595
|
args: inputSchema(spec.command.args ?? object({})),
|
|
6966
7596
|
options: optionsSchema(spec.options),
|
|
@@ -6978,7 +7608,7 @@ function nodeData(node) {
|
|
|
6978
7608
|
function groupData(group) {
|
|
6979
7609
|
return {
|
|
6980
7610
|
name: group.commandLine,
|
|
6981
|
-
commands: Object.values(group
|
|
7611
|
+
commands: Object.values(visibleCommands(group)).map(nodeData)
|
|
6982
7612
|
};
|
|
6983
7613
|
}
|
|
6984
7614
|
function printed$1(data) {
|
|
@@ -7020,6 +7650,10 @@ function printed(value, render, { json, invocation, style, fields }) {
|
|
|
7020
7650
|
items: rows
|
|
7021
7651
|
})}\n` : `${renderRows(rows, fields)}${pageFooter(page)}`;
|
|
7022
7652
|
}
|
|
7653
|
+
/** A progress message as stderr carries it: one JSON object per line under `--json` (ADR 0006). */
|
|
7654
|
+
function progressLine(message, json) {
|
|
7655
|
+
return json ? `${JSON.stringify({ progress: message })}\n` : `${message}\n`;
|
|
7656
|
+
}
|
|
7023
7657
|
function errorText(error, format) {
|
|
7024
7658
|
const text = formatRuntimeError(error, {
|
|
7025
7659
|
...format,
|
|
@@ -7106,12 +7740,51 @@ function versionResult(cli, packageRoot) {
|
|
|
7106
7740
|
};
|
|
7107
7741
|
}
|
|
7108
7742
|
//#endregion
|
|
7743
|
+
//#region ../agent-cli/dist/skill-source.js
|
|
7744
|
+
/** The branch a release moves to the released commit, which holds the skill of that version. */
|
|
7745
|
+
const RELEASE_BRANCH = "release";
|
|
7746
|
+
const GITHUB_SHORTHAND = /^[\w.-]+\/[\w.-]+$/;
|
|
7747
|
+
const GIT_URL_PROTOCOLS = /* @__PURE__ */ new Set([
|
|
7748
|
+
"https:",
|
|
7749
|
+
"http:",
|
|
7750
|
+
"ssh:",
|
|
7751
|
+
"git:"
|
|
7752
|
+
]);
|
|
7753
|
+
const SCP_STYLE = /^[\w.-]+@[\w.-]+:[\w./-]+$/;
|
|
7754
|
+
const manifestSchema = object({ repository: union([string(), object({ url: string() })]).optional() });
|
|
7755
|
+
function sourceFromRepository(repository) {
|
|
7756
|
+
if (GITHUB_SHORTHAND.test(repository)) return repository;
|
|
7757
|
+
const url = repository.replace(/^git\+/, "");
|
|
7758
|
+
if (!(URL.canParse(url) && GIT_URL_PROTOCOLS.has(new URL(url).protocol)) && !SCP_STYLE.test(url)) return void 0;
|
|
7759
|
+
return `${url.endsWith(".git") ? url : `${url}.git`}#${RELEASE_BRANCH}`;
|
|
7760
|
+
}
|
|
7761
|
+
async function repositoryAt(packageRoot) {
|
|
7762
|
+
let manifest;
|
|
7763
|
+
try {
|
|
7764
|
+
manifest = JSON.parse(await readFile(join(packageRoot, "package.json"), "utf8"));
|
|
7765
|
+
} catch {
|
|
7766
|
+
return;
|
|
7767
|
+
}
|
|
7768
|
+
const parsed = manifestSchema.safeParse(manifest);
|
|
7769
|
+
const repository = parsed.success ? parsed.data.repository : void 0;
|
|
7770
|
+
return typeof repository === "object" ? repository.url : repository;
|
|
7771
|
+
}
|
|
7772
|
+
/** What `npx skills add` installs the CLI's skill from: the declared source, else the package's repository. */
|
|
7773
|
+
async function skillSource(declared, packageRoot) {
|
|
7774
|
+
if (declared !== void 0) return declared.source;
|
|
7775
|
+
const repository = await repositoryAt(packageRoot);
|
|
7776
|
+
return repository === void 0 ? void 0 : sourceFromRepository(repository);
|
|
7777
|
+
}
|
|
7778
|
+
//#endregion
|
|
7109
7779
|
//#region ../agent-cli/dist/skills.js
|
|
7110
7780
|
/** Where the skills CLI (`npx skills add`) puts a skill, under a project and under home. */
|
|
7111
7781
|
const SKILL_DIRS = [[".claude", "skills"], [".agents", "skills"]];
|
|
7112
7782
|
function skillUpdateCommand(cliName) {
|
|
7113
7783
|
return `npx -y skills update ${cliName}`;
|
|
7114
7784
|
}
|
|
7785
|
+
function skillAddCommand(source, cliName) {
|
|
7786
|
+
return `npx -y skills add ${source} --skill ${cliName} -g`;
|
|
7787
|
+
}
|
|
7115
7788
|
const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---/;
|
|
7116
7789
|
const METADATA_VERSION = /^metadata:[ \t]*\r?\n(?:[ \t]+.*\r?\n)*?[ \t]+version:[ \t]*["']?([^"'\s]+)["']?[ \t]*$/m;
|
|
7117
7790
|
/** The version a SKILL.md's frontmatter `metadata.version` states. */
|
|
@@ -7216,14 +7889,15 @@ function projectRow(projectFile) {
|
|
|
7216
7889
|
}
|
|
7217
7890
|
};
|
|
7218
7891
|
}
|
|
7219
|
-
function installRow(cli, bin) {
|
|
7892
|
+
function installRow(cli, { bin, node }) {
|
|
7220
7893
|
return {
|
|
7221
7894
|
name: "install",
|
|
7895
|
+
advisory: true,
|
|
7222
7896
|
run: async (ctx) => {
|
|
7223
7897
|
const { install } = cli;
|
|
7224
7898
|
if (install === void 0) return ok(`${cli.name} declares no install, so it has no \`update\``);
|
|
7225
7899
|
try {
|
|
7226
|
-
return ok(`a global npm install under ${(await globalInstallOf(bin, npmContext(cli, install, ctx))).prefix}`);
|
|
7900
|
+
return ok(`a global npm install under ${(await globalInstallOf(bin, npmContext(cli, install, ctx, node))).prefix}`);
|
|
7227
7901
|
} catch (error) {
|
|
7228
7902
|
if (error instanceof CliError && error.code === "NOT_GLOBAL_INSTALL") return {
|
|
7229
7903
|
state: "problem",
|
|
@@ -7235,13 +7909,14 @@ function installRow(cli, bin) {
|
|
|
7235
7909
|
}
|
|
7236
7910
|
};
|
|
7237
7911
|
}
|
|
7238
|
-
function registryRow(cli) {
|
|
7912
|
+
function registryRow(cli, node) {
|
|
7239
7913
|
return {
|
|
7240
7914
|
name: "registry",
|
|
7915
|
+
advisory: true,
|
|
7241
7916
|
run: async (ctx) => {
|
|
7242
7917
|
const { install } = cli;
|
|
7243
7918
|
if (install === void 0) return ok(`${cli.name} declares no registry to compare this build with`);
|
|
7244
|
-
const latest = await latestVersion(npmContext(cli, install, ctx));
|
|
7919
|
+
const latest = await latestVersion(npmContext(cli, install, ctx, node));
|
|
7245
7920
|
const standing = standingOf(cli.version, latest);
|
|
7246
7921
|
const head = `${install.registry} has ${latest} as latest: this build`;
|
|
7247
7922
|
if (standing === "behind") return {
|
|
@@ -7272,7 +7947,15 @@ function skillRow(cli) {
|
|
|
7272
7947
|
name: "skill",
|
|
7273
7948
|
run: async (ctx) => {
|
|
7274
7949
|
const copies = await skillCopies(cli.name, cli.version, ctx.cwd, ctx.env);
|
|
7275
|
-
if (copies.length === 0)
|
|
7950
|
+
if (copies.length === 0) {
|
|
7951
|
+
const message = `no copy of the ${cli.name} skill is installed`;
|
|
7952
|
+
const source = await skillSource(cli.skill, ctx.packageRoot);
|
|
7953
|
+
return source === void 0 ? ok(message) : {
|
|
7954
|
+
state: "ok",
|
|
7955
|
+
message,
|
|
7956
|
+
fix: skillAddCommand(source, cli.name)
|
|
7957
|
+
};
|
|
7958
|
+
}
|
|
7276
7959
|
const fix = skillFix(cli, copies);
|
|
7277
7960
|
const message = copies.map(describeCopy).join("; ");
|
|
7278
7961
|
return fix === void 0 ? ok(message) : {
|
|
@@ -7284,15 +7967,15 @@ function skillRow(cli) {
|
|
|
7284
7967
|
};
|
|
7285
7968
|
}
|
|
7286
7969
|
/** Every row `doctor` reports, in order: the fixed rows around the CLI's own and its tools'. */
|
|
7287
|
-
function doctorChecks(cli,
|
|
7970
|
+
function doctorChecks(cli, launch) {
|
|
7288
7971
|
return [
|
|
7289
7972
|
buildRow(cli),
|
|
7290
7973
|
nodeRow(cli),
|
|
7291
7974
|
...cli.project === void 0 ? [] : [projectRow(cli.project)],
|
|
7292
7975
|
...cli.doctor ?? [],
|
|
7293
|
-
...toolRows(cli.commands),
|
|
7294
|
-
installRow(cli,
|
|
7295
|
-
registryRow(cli),
|
|
7976
|
+
...toolRows(cli.tools ?? [], cli.commands),
|
|
7977
|
+
installRow(cli, launch),
|
|
7978
|
+
registryRow(cli, launch.node),
|
|
7296
7979
|
skillRow(cli)
|
|
7297
7980
|
];
|
|
7298
7981
|
}
|
|
@@ -7305,9 +7988,14 @@ const MIN_LABEL_WIDTH = 8;
|
|
|
7305
7988
|
const reportSchema = object({
|
|
7306
7989
|
rows: array(object({
|
|
7307
7990
|
check: string(),
|
|
7308
|
-
state: _enum([
|
|
7991
|
+
state: _enum([
|
|
7992
|
+
"ok",
|
|
7993
|
+
"problem",
|
|
7994
|
+
"skipped"
|
|
7995
|
+
]),
|
|
7309
7996
|
message: string(),
|
|
7310
|
-
fix: string().optional()
|
|
7997
|
+
fix: string().optional(),
|
|
7998
|
+
code: string().optional()
|
|
7311
7999
|
})),
|
|
7312
8000
|
next: array(string())
|
|
7313
8001
|
});
|
|
@@ -7318,23 +8006,25 @@ function problemOf(check, error, { signal, deadline, ms }) {
|
|
|
7318
8006
|
};
|
|
7319
8007
|
if (error instanceof CliError) return {
|
|
7320
8008
|
state: "problem",
|
|
7321
|
-
message: `${error.message}; ${error.hint}
|
|
8009
|
+
message: `${error.message}; ${error.hint}`,
|
|
8010
|
+
code: error.code
|
|
7322
8011
|
};
|
|
7323
8012
|
return {
|
|
7324
8013
|
state: "problem",
|
|
7325
8014
|
message: `the ${check.name} row hit a bug: ${messageOf(error)}`
|
|
7326
8015
|
};
|
|
7327
8016
|
}
|
|
8017
|
+
function withSignal(ctx, signal) {
|
|
8018
|
+
return Object.create(ctx, { signal: { value: signal } });
|
|
8019
|
+
}
|
|
7328
8020
|
async function rowOf(check, ctx) {
|
|
7329
8021
|
const ms = check.deadlineMs ?? DEFAULT_DEADLINE_MS;
|
|
7330
8022
|
const signal = ctx.deadline(ms);
|
|
7331
8023
|
let finding;
|
|
7332
8024
|
try {
|
|
7333
|
-
finding = await Promise.race([Promise.resolve().then(() => check.run(
|
|
7334
|
-
...ctx,
|
|
7335
|
-
signal
|
|
7336
|
-
})), untilAborted(signal)]);
|
|
8025
|
+
finding = await Promise.race([Promise.resolve().then(() => check.run(withSignal(ctx, signal))), untilAborted(signal)]);
|
|
7337
8026
|
} catch (error) {
|
|
8027
|
+
if (ctx.signal.aborted) return void 0;
|
|
7338
8028
|
finding = problemOf(check, error, {
|
|
7339
8029
|
signal: ctx.signal,
|
|
7340
8030
|
deadline: signal,
|
|
@@ -7360,15 +8050,16 @@ function render({ rows, next }, style) {
|
|
|
7360
8050
|
return `${check.padEnd(width)}${label}${" ".repeat(stateWidth - state.length)}${message}`;
|
|
7361
8051
|
}), ...next.map((fix) => `${"next".padEnd(width)}${fix}`)].join("\n");
|
|
7362
8052
|
}
|
|
7363
|
-
function failure(cliName, problems
|
|
7364
|
-
|
|
7365
|
-
code: DOCTOR_PROBLEMS,
|
|
7366
|
-
message: `${cliName} doctor found
|
|
7367
|
-
hint:
|
|
7368
|
-
});
|
|
8053
|
+
function failure(cliName, problems) {
|
|
8054
|
+
const errors = problems.map(({ check, message, fix, code }) => new CliError({
|
|
8055
|
+
code: code ?? "DOCTOR_PROBLEMS",
|
|
8056
|
+
message: `${cliName} doctor found a problem in ${check}: ${message}`,
|
|
8057
|
+
hint: fix === void 0 ? "the row says what is wrong" : `run ${fix}, then run doctor again`
|
|
8058
|
+
}));
|
|
8059
|
+
return new AggregateError(errors);
|
|
7369
8060
|
}
|
|
7370
8061
|
/** The built-in `doctor`: the fixed rows around the CLI's own, each under its own deadline. */
|
|
7371
|
-
function doctorCommand(cli,
|
|
8062
|
+
function doctorCommand(cli, launch) {
|
|
7372
8063
|
return defineCommand$1({
|
|
7373
8064
|
name: "doctor",
|
|
7374
8065
|
description: "check the setup and say what fixes each problem",
|
|
@@ -7382,17 +8073,20 @@ function doctorCommand(cli, bin) {
|
|
|
7382
8073
|
effect: "read",
|
|
7383
8074
|
output: reportSchema,
|
|
7384
8075
|
run: async (_input, ctx) => {
|
|
7385
|
-
const checked = await Promise.all(doctorChecks(cli,
|
|
7386
|
-
ctx.signal.throwIfAborted();
|
|
8076
|
+
const checked = (await Promise.all(doctorChecks(cli, launch).map((check) => rowOf(check, ctx)))).filter((row) => row !== void 0);
|
|
7387
8077
|
const rows = checked.map(({ row }) => row);
|
|
7388
8078
|
const report = {
|
|
7389
8079
|
rows,
|
|
7390
8080
|
next: nextOf(rows)
|
|
7391
8081
|
};
|
|
7392
|
-
|
|
8082
|
+
if (ctx.signal.aborted) {
|
|
8083
|
+
ctx.deliver(report);
|
|
8084
|
+
ctx.signal.throwIfAborted();
|
|
8085
|
+
}
|
|
8086
|
+
const problems = checked.filter(({ row, advisory }) => row.state === "problem" && !advisory).map(({ row }) => row);
|
|
7393
8087
|
if (problems.length > 0) {
|
|
7394
8088
|
ctx.deliver(report);
|
|
7395
|
-
throw failure(cli.name, problems
|
|
8089
|
+
throw failure(cli.name, problems);
|
|
7396
8090
|
}
|
|
7397
8091
|
return report;
|
|
7398
8092
|
},
|
|
@@ -7471,7 +8165,7 @@ function interruptedAfterInstall(plan) {
|
|
|
7471
8165
|
});
|
|
7472
8166
|
}
|
|
7473
8167
|
/** The built-in `update`, for a CLI installed globally with npm. */
|
|
7474
|
-
function updateCommand(cli, install, bin) {
|
|
8168
|
+
function updateCommand(cli, install, { bin, node }) {
|
|
7475
8169
|
return defineCommand$1({
|
|
7476
8170
|
name: "update",
|
|
7477
8171
|
description: "install the latest version of this CLI from its registry",
|
|
@@ -7485,7 +8179,7 @@ function updateCommand(cli, install, bin) {
|
|
|
7485
8179
|
effect: "write",
|
|
7486
8180
|
output: updateSchema,
|
|
7487
8181
|
plan: async (_input, ctx) => {
|
|
7488
|
-
const npm = npmContext(cli, install, ctx);
|
|
8182
|
+
const npm = npmContext(cli, install, ctx, node);
|
|
7489
8183
|
const copy = await globalInstallOf(bin, npm);
|
|
7490
8184
|
return {
|
|
7491
8185
|
package: install.package,
|
|
@@ -7506,7 +8200,7 @@ function updateCommand(cli, install, bin) {
|
|
|
7506
8200
|
};
|
|
7507
8201
|
ctx.signal.throwIfAborted();
|
|
7508
8202
|
ctx.progress(`installing ${plan.package}@${latest} with the npm under ${prefix}…`);
|
|
7509
|
-
await ctx.runToEnd(`installing ${plan.package}@${latest}`, () => installGlobally(latest, npmContext(cli, install, ctx)));
|
|
8203
|
+
await ctx.runToEnd(`installing ${plan.package}@${latest}`, () => installGlobally(latest, npmContext(cli, install, ctx, node)));
|
|
7510
8204
|
const update = {
|
|
7511
8205
|
from,
|
|
7512
8206
|
latest,
|
|
@@ -7530,10 +8224,10 @@ function updateCommand(cli, install, bin) {
|
|
|
7530
8224
|
//#endregion
|
|
7531
8225
|
//#region ../agent-cli/dist/built-ins.js
|
|
7532
8226
|
/** The Commands the Runtime adds to a multi-Command CLI: `update` only when it declares an install. */
|
|
7533
|
-
function builtInCommands(cli,
|
|
8227
|
+
function builtInCommands(cli, launch) {
|
|
7534
8228
|
return {
|
|
7535
|
-
doctor: doctorCommand(cli,
|
|
7536
|
-
...cli.install === void 0 ? {} : { update: updateCommand(cli, cli.install,
|
|
8229
|
+
doctor: doctorCommand(cli, launch),
|
|
8230
|
+
...cli.install === void 0 ? {} : { update: updateCommand(cli, cli.install, launch) }
|
|
7537
8231
|
};
|
|
7538
8232
|
}
|
|
7539
8233
|
//#endregion
|
|
@@ -7546,7 +8240,10 @@ function defineCli$1(cli) {
|
|
|
7546
8240
|
checkOwnCodes(cli);
|
|
7547
8241
|
if (cli.commands === void 0) return cli;
|
|
7548
8242
|
const { commands } = cli;
|
|
7549
|
-
const taken = Object.keys(builtInCommands(cli,
|
|
8243
|
+
const taken = Object.keys(builtInCommands(cli, {
|
|
8244
|
+
bin: void 0,
|
|
8245
|
+
node: void 0
|
|
8246
|
+
})).filter((name) => commands[name] !== void 0);
|
|
7550
8247
|
if (taken.length > 0) throw new Error(`${cli.name} defines ${taken.join(", ")}, a built-in Command it cannot replace`);
|
|
7551
8248
|
return cli;
|
|
7552
8249
|
}
|
|
@@ -7574,41 +8271,6 @@ function cliError(_table, code, init, options) {
|
|
|
7574
8271
|
}, options);
|
|
7575
8272
|
}
|
|
7576
8273
|
//#endregion
|
|
7577
|
-
//#region ../agent-cli/dist/command-spec.js
|
|
7578
|
-
function declaredOf(command) {
|
|
7579
|
-
const planned = command.effect === "write" || command.effect === "destructive";
|
|
7580
|
-
return {
|
|
7581
|
-
outputs: planned && command.outputs !== void 0,
|
|
7582
|
-
cost: planned && command.cost !== void 0
|
|
7583
|
-
};
|
|
7584
|
-
}
|
|
7585
|
-
function commandSpec(commandLine, command) {
|
|
7586
|
-
const list = command.rows === void 0 ? void 0 : listSpec(command.rows);
|
|
7587
|
-
return {
|
|
7588
|
-
kind: "command",
|
|
7589
|
-
commandLine,
|
|
7590
|
-
command,
|
|
7591
|
-
description: command.description,
|
|
7592
|
-
effect: command.effect,
|
|
7593
|
-
examples: command.examples,
|
|
7594
|
-
args: argFields(command.args),
|
|
7595
|
-
options: optionFields(command.options),
|
|
7596
|
-
standardFlags: standardFlagsFor(command.effect, declaredOf(command), list),
|
|
7597
|
-
list,
|
|
7598
|
-
output: list?.output ?? command.output
|
|
7599
|
-
};
|
|
7600
|
-
}
|
|
7601
|
-
function groupSpec(commandLine, commands) {
|
|
7602
|
-
return {
|
|
7603
|
-
kind: "group",
|
|
7604
|
-
commandLine,
|
|
7605
|
-
commands: Object.fromEntries(Object.entries(commands).map(([key, node]) => [key, specOf(`${commandLine} ${key}`, node)]))
|
|
7606
|
-
};
|
|
7607
|
-
}
|
|
7608
|
-
function specOf(commandLine, node) {
|
|
7609
|
-
return isCommand(node) ? commandSpec(commandLine, node) : groupSpec(commandLine, node);
|
|
7610
|
-
}
|
|
7611
|
-
//#endregion
|
|
7612
8274
|
//#region ../agent-cli/dist/execute.js
|
|
7613
8275
|
function outcomeOf(value, render) {
|
|
7614
8276
|
return {
|
|
@@ -7641,7 +8303,7 @@ function dryRunOutcome(command, plan) {
|
|
|
7641
8303
|
].join("\n")
|
|
7642
8304
|
};
|
|
7643
8305
|
}
|
|
7644
|
-
async function execute(command, input, ctx, { dryRun, confirm, yes,
|
|
8306
|
+
async function execute(command, input, ctx, { dryRun, confirm, yes, page, invocation, commandLine, started, files, guardOutputs }) {
|
|
7645
8307
|
await checkTools(command.tools ?? [], ctx.env);
|
|
7646
8308
|
if (command.rows !== void 0) return outcomeOf(await command.run({
|
|
7647
8309
|
...input,
|
|
@@ -7654,12 +8316,13 @@ async function execute(command, input, ctx, { dryRun, confirm, yes, force, page,
|
|
|
7654
8316
|
}
|
|
7655
8317
|
const plan = await command.plan(input, ctx);
|
|
7656
8318
|
if (dryRun) return dryRunOutcome(command, plan);
|
|
8319
|
+
const outputs = command.outputs?.(plan);
|
|
7657
8320
|
await checkOutputs({
|
|
7658
8321
|
invocation,
|
|
7659
8322
|
commandLine,
|
|
7660
|
-
force,
|
|
8323
|
+
force: ctx.force,
|
|
7661
8324
|
files: ctx.files
|
|
7662
|
-
},
|
|
8325
|
+
}, outputs);
|
|
7663
8326
|
checkCost({
|
|
7664
8327
|
invocation,
|
|
7665
8328
|
commandLine,
|
|
@@ -7670,58 +8333,15 @@ async function execute(command, input, ctx, { dryRun, confirm, yes, force, page,
|
|
|
7670
8333
|
commandLine,
|
|
7671
8334
|
given: confirm
|
|
7672
8335
|
}, command.confirm(plan));
|
|
7673
|
-
|
|
7674
|
-
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
|
|
7679
|
-
|
|
7680
|
-
}
|
|
7681
|
-
function isAlive(pid) {
|
|
7682
|
-
try {
|
|
7683
|
-
process.kill(pid, 0);
|
|
7684
|
-
return true;
|
|
7685
|
-
} catch (error) {
|
|
7686
|
-
return errnoOf(error) === "EPERM";
|
|
8336
|
+
if (outputs !== void 0) {
|
|
8337
|
+
await probeOutputs({
|
|
8338
|
+
files,
|
|
8339
|
+
cwd: ctx.cwd,
|
|
8340
|
+
fileError: ctx.fileError
|
|
8341
|
+
}, outputs);
|
|
8342
|
+
if (!ctx.force) guardOutputs(outputs, ctx.commandLine({ add: [FORCE_FLAG.flag] }));
|
|
7687
8343
|
}
|
|
7688
|
-
|
|
7689
|
-
async function sweep(folder) {
|
|
7690
|
-
const dead = (await readdir(folder)).filter((name) => {
|
|
7691
|
-
const pid = TEMP_FILE.exec(name)?.[1];
|
|
7692
|
-
return pid !== void 0 && !isAlive(Number(pid));
|
|
7693
|
-
});
|
|
7694
|
-
await Promise.all(dead.map((name) => rm(join(folder, name), { force: true })));
|
|
7695
|
-
}
|
|
7696
|
-
/** Real files for one run: the first write to each folder sweeps the temp files of dead writers. */
|
|
7697
|
-
function realFiles() {
|
|
7698
|
-
const swept = /* @__PURE__ */ new Set();
|
|
7699
|
-
return {
|
|
7700
|
-
exists: async (path) => {
|
|
7701
|
-
try {
|
|
7702
|
-
await access(path);
|
|
7703
|
-
return true;
|
|
7704
|
-
} catch (error) {
|
|
7705
|
-
if (isMissingFile(error)) return false;
|
|
7706
|
-
throw error;
|
|
7707
|
-
}
|
|
7708
|
-
},
|
|
7709
|
-
write: async (path, data) => {
|
|
7710
|
-
const folder = dirname(path);
|
|
7711
|
-
if (!swept.has(folder)) {
|
|
7712
|
-
await sweep(folder);
|
|
7713
|
-
swept.add(folder);
|
|
7714
|
-
}
|
|
7715
|
-
const temp = tempPathOf(path);
|
|
7716
|
-
try {
|
|
7717
|
-
await writeFile(temp, data);
|
|
7718
|
-
await rename(temp, path);
|
|
7719
|
-
} catch (error) {
|
|
7720
|
-
await rm(temp, { force: true });
|
|
7721
|
-
throw error;
|
|
7722
|
-
}
|
|
7723
|
-
}
|
|
7724
|
-
};
|
|
8344
|
+
return outcomeOf(await command.apply(plan, ctx), (data, style) => command.render(data, style));
|
|
7725
8345
|
}
|
|
7726
8346
|
//#endregion
|
|
7727
8347
|
//#region ../agent-cli/dist/package-root.js
|
|
@@ -7780,88 +8400,6 @@ function closestFlag(flag, flags) {
|
|
|
7780
8400
|
return closest.length === 1 ? closest[0] : void 0;
|
|
7781
8401
|
}
|
|
7782
8402
|
//#endregion
|
|
7783
|
-
//#region ../agent-cli/dist/tokenize.js
|
|
7784
|
-
const NEGATIVE_NUMBER = /^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/;
|
|
7785
|
-
function isOptionLike(word) {
|
|
7786
|
-
return word !== void 0 && word.length > 1 && word[0] === "-" && !NEGATIVE_NUMBER.test(word);
|
|
7787
|
-
}
|
|
7788
|
-
function parseArgsOptions(known) {
|
|
7789
|
-
return Object.fromEntries(known.map(({ flag, takes }) => [flag.slice(2), { type: takes === "value" ? "string" : "boolean" }]));
|
|
7790
|
-
}
|
|
7791
|
-
function flagItem(token, { flag, takes }, words) {
|
|
7792
|
-
if (takes !== "optional value" || token.inlineValue === true) return {
|
|
7793
|
-
kind: "flag",
|
|
7794
|
-
flag,
|
|
7795
|
-
value: token.value ?? true
|
|
7796
|
-
};
|
|
7797
|
-
const took = token.index + 1;
|
|
7798
|
-
const next = words[took];
|
|
7799
|
-
return next === void 0 || isOptionLike(next) ? {
|
|
7800
|
-
kind: "flag",
|
|
7801
|
-
flag,
|
|
7802
|
-
value: true
|
|
7803
|
-
} : {
|
|
7804
|
-
kind: "flag",
|
|
7805
|
-
flag,
|
|
7806
|
-
value: next,
|
|
7807
|
-
took
|
|
7808
|
-
};
|
|
7809
|
-
}
|
|
7810
|
-
function itemOf(token, words, byFlag) {
|
|
7811
|
-
const word = words[token.index] ?? "";
|
|
7812
|
-
if (token.kind === "option-terminator") return { kind: "end" };
|
|
7813
|
-
if (token.kind === "positional" || NEGATIVE_NUMBER.test(word)) return {
|
|
7814
|
-
kind: "operand",
|
|
7815
|
-
value: word
|
|
7816
|
-
};
|
|
7817
|
-
const flag = byFlag.get(token.rawName);
|
|
7818
|
-
return flag === void 0 || flag.takes === "nothing" && token.inlineValue === true ? {
|
|
7819
|
-
kind: "unknown option",
|
|
7820
|
-
word
|
|
7821
|
-
} : flagItem(token, flag, words);
|
|
7822
|
-
}
|
|
7823
|
-
/** Splits a Command's words into operands, unknown options and the values of known flags. */
|
|
7824
|
-
function tokenize(words, known) {
|
|
7825
|
-
const byFlag = new Map(known.map((flag) => [flag.flag, flag]));
|
|
7826
|
-
const { tokens } = parseArgs({
|
|
7827
|
-
args: [...words],
|
|
7828
|
-
options: parseArgsOptions(known),
|
|
7829
|
-
strict: false,
|
|
7830
|
-
allowPositionals: true,
|
|
7831
|
-
tokens: true
|
|
7832
|
-
});
|
|
7833
|
-
const operands = [];
|
|
7834
|
-
const unknownOptions = [];
|
|
7835
|
-
const values = /* @__PURE__ */ new Map();
|
|
7836
|
-
const done = /* @__PURE__ */ new Set();
|
|
7837
|
-
let literal = false;
|
|
7838
|
-
let afterUnknownOption = false;
|
|
7839
|
-
for (const token of tokens) {
|
|
7840
|
-
if (done.has(token.index)) continue;
|
|
7841
|
-
done.add(token.index);
|
|
7842
|
-
const item = itemOf(token, words, byFlag);
|
|
7843
|
-
if (item.kind === "end") literal = true;
|
|
7844
|
-
else if (item.kind === "operand") {
|
|
7845
|
-
operands.push({
|
|
7846
|
-
value: item.value,
|
|
7847
|
-
afterUnknownOption: !literal && afterUnknownOption
|
|
7848
|
-
});
|
|
7849
|
-
afterUnknownOption = false;
|
|
7850
|
-
} else if (item.kind === "unknown option") {
|
|
7851
|
-
unknownOptions.push(item.word);
|
|
7852
|
-
afterUnknownOption = true;
|
|
7853
|
-
} else {
|
|
7854
|
-
values.set(item.flag, item.value);
|
|
7855
|
-
if (item.took !== void 0) done.add(item.took);
|
|
7856
|
-
}
|
|
7857
|
-
}
|
|
7858
|
-
return {
|
|
7859
|
-
operands,
|
|
7860
|
-
unknownOptions,
|
|
7861
|
-
values
|
|
7862
|
-
};
|
|
7863
|
-
}
|
|
7864
|
-
//#endregion
|
|
7865
8403
|
//#region ../agent-cli/dist/parse-input.js
|
|
7866
8404
|
const NO_INPUT = object({});
|
|
7867
8405
|
function knownFlags(spec) {
|
|
@@ -7889,28 +8427,46 @@ function unknownOptionsOf(words, candidates) {
|
|
|
7889
8427
|
};
|
|
7890
8428
|
});
|
|
7891
8429
|
}
|
|
7892
|
-
function optionValue(field,
|
|
8430
|
+
function optionValue(field, all) {
|
|
8431
|
+
if (field.variadic) return variadicValue(field, (all ?? []).filter((value) => value !== true));
|
|
8432
|
+
const raw = all?.[all.length - 1];
|
|
7893
8433
|
return field.type === "boolean" && raw === true && field.label === `--no-${field.name}` ? false : raw;
|
|
7894
8434
|
}
|
|
7895
8435
|
function converted(field, raw) {
|
|
8436
|
+
if (Array.isArray(raw)) return raw.map((element) => converted(field, element));
|
|
7896
8437
|
if (field.type !== "number" || typeof raw !== "string" || raw.trim() === "") return raw;
|
|
7897
8438
|
const number = Number(raw);
|
|
7898
8439
|
return Number.isNaN(number) ? raw : number;
|
|
7899
8440
|
}
|
|
8441
|
+
function variadicValue(field, values) {
|
|
8442
|
+
return values.length === 0 && !field.required ? void 0 : values;
|
|
8443
|
+
}
|
|
7900
8444
|
function parse(schema, values) {
|
|
7901
8445
|
const input = Object.fromEntries([...values].filter(([, raw]) => raw !== void 0).map(([field, raw]) => [field.key, converted(field, raw)]));
|
|
7902
8446
|
return schema.safeParse(input);
|
|
7903
8447
|
}
|
|
7904
|
-
function issueLines(result, values, howToPass, reported) {
|
|
8448
|
+
function issueLines(result, values, { howToPass, arrayIssueLine, reported = [], fromStdin }) {
|
|
7905
8449
|
if (result.success) return [];
|
|
7906
8450
|
return result.error.issues.flatMap((issue) => {
|
|
7907
8451
|
const field = [...values.keys()].find((candidate) => candidate.key === issue.path[0]);
|
|
7908
8452
|
if (field === void 0) return [` ${issue.message}`];
|
|
7909
8453
|
if (reported.includes(field)) return [];
|
|
7910
8454
|
const raw = values.get(field);
|
|
7911
|
-
|
|
8455
|
+
if (raw === void 0) return [` ${field.label}: required, ${howToPass(field)}`];
|
|
8456
|
+
if (field === fromStdin) return [` ${field.label} from stdin: ${issue.message}`];
|
|
8457
|
+
return Array.isArray(raw) ? [arrayIssueLine(field, raw, issue)] : [` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`];
|
|
7912
8458
|
});
|
|
7913
8459
|
}
|
|
8460
|
+
function flagValuesIssueLine(field, raw, issue) {
|
|
8461
|
+
const [, element] = issue.path;
|
|
8462
|
+
if (typeof element === "number") return ` ${field.label} ${JSON.stringify(raw[element])}: ${issue.message}`;
|
|
8463
|
+
return raw.length === 0 ? ` ${field.label}: ${issue.message}, pass ${field.usage}` : ` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`;
|
|
8464
|
+
}
|
|
8465
|
+
function operandsIssueLine(field, raw, issue, first) {
|
|
8466
|
+
const [, element] = issue.path;
|
|
8467
|
+
if (typeof element === "number") return ` ${field.label} ${JSON.stringify(raw[element])} (argument ${first + element}): ${issue.message}`;
|
|
8468
|
+
return raw.length === 0 ? ` ${field.label}: ${issue.message}, pass them as arguments from ${first}` : ` ${field.label} ${JSON.stringify(raw)}: ${issue.message}`;
|
|
8469
|
+
}
|
|
7914
8470
|
function unknownLine({ flag, suggestion }) {
|
|
7915
8471
|
return ` unknown option '${flag}'${suggestion === void 0 ? "" : ` (did you mean ${suggestion}?)`}`;
|
|
7916
8472
|
}
|
|
@@ -7927,15 +8483,36 @@ function invalidInput(commandLine, invocation, unknown, otherLines) {
|
|
|
7927
8483
|
hint: correctable ? `did you mean \`${commandLineRenaming(invocation, renames)}\`?` : `run \`${commandLine} --help\` to see the expected input`
|
|
7928
8484
|
});
|
|
7929
8485
|
}
|
|
7930
|
-
function
|
|
8486
|
+
async function stdinTextOf(spec, operands, read) {
|
|
8487
|
+
const index = spec.args.findIndex((field) => field.stdin);
|
|
8488
|
+
const field = spec.args[index];
|
|
8489
|
+
if (field === void 0 || operands[index]?.value !== "-") return void 0;
|
|
8490
|
+
return {
|
|
8491
|
+
field,
|
|
8492
|
+
text: await read(field)
|
|
8493
|
+
};
|
|
8494
|
+
}
|
|
8495
|
+
async function parseInput(spec, words, invocation, readStdin) {
|
|
7931
8496
|
const { command, args: argFields, options: optionFields } = spec;
|
|
7932
8497
|
const pageFields = spec.list?.pageFields ?? [];
|
|
7933
8498
|
const known = knownFlags(spec);
|
|
7934
|
-
const { operands, unknownOptions, values } = tokenize(words, known);
|
|
8499
|
+
const { operands, unknownOptions, values, occurrences } = tokenize(words, known);
|
|
8500
|
+
const stdin = await stdinTextOf(spec, operands, readStdin);
|
|
7935
8501
|
if (values.get(CONFIRM_FLAG.flag) === true) throw invalidInputError(spec.commandLine, `option '${CONFIRM_FLAG.usage}' argument missing`);
|
|
7936
|
-
const missing = [...optionFields, ...pageFields].filter((field) => field.type !== "boolean" && values.get(field.label) === true);
|
|
7937
|
-
const
|
|
7938
|
-
|
|
8502
|
+
const missing = [...optionFields, ...pageFields].filter((field) => field.type !== "boolean" && (field.variadic ? occurrences.get(field.label)?.includes(true) : values.get(field.label) === true));
|
|
8503
|
+
const argValue = (field, index) => {
|
|
8504
|
+
if (field === stdin?.field) return stdin.text;
|
|
8505
|
+
if (!field.variadic) return operands[index]?.value;
|
|
8506
|
+
return variadicValue(field, operands.slice(index).filter((operand) => !operand.afterUnknownOption).map((operand) => operand.value));
|
|
8507
|
+
};
|
|
8508
|
+
const argValues = new Map(argFields.map((field, index) => [field, argValue(field, index)]));
|
|
8509
|
+
const extraOperands = argFields.some((field) => field.variadic) ? [] : operands.slice(argFields.length);
|
|
8510
|
+
const valuesOf = (fields) => new Map(fields.map((field) => [field, missing.includes(field) ? void 0 : optionValue(field, occurrences.get(field.label))]));
|
|
8511
|
+
const flagWording = {
|
|
8512
|
+
howToPass: (field) => `pass ${field.usage}`,
|
|
8513
|
+
arrayIssueLine: flagValuesIssueLine,
|
|
8514
|
+
reported: missing
|
|
8515
|
+
};
|
|
7939
8516
|
const optionValues = valuesOf(optionFields);
|
|
7940
8517
|
const pageValues = valuesOf(pageFields);
|
|
7941
8518
|
const args = parse(command.args ?? NO_INPUT, argValues);
|
|
@@ -7944,10 +8521,14 @@ function parseInput(spec, words, invocation) {
|
|
|
7944
8521
|
const unknown = unknownOptionsOf(unknownOptions, candidateFlags(known));
|
|
7945
8522
|
const otherLines = [
|
|
7946
8523
|
...missing.map((field) => ` ${field.label}: missing value, pass ${field.usage}`),
|
|
7947
|
-
...
|
|
7948
|
-
...issueLines(args, argValues,
|
|
7949
|
-
|
|
7950
|
-
|
|
8524
|
+
...extraOperands.filter((operand) => !operand.afterUnknownOption).map((operand) => ` unexpected argument ${JSON.stringify(operand.value)}`),
|
|
8525
|
+
...issueLines(args, argValues, {
|
|
8526
|
+
howToPass: (field) => `pass it as argument ${argFields.indexOf(field) + 1}`,
|
|
8527
|
+
arrayIssueLine: (field, raw, issue) => operandsIssueLine(field, raw, issue, argFields.indexOf(field) + 1),
|
|
8528
|
+
fromStdin: stdin?.field
|
|
8529
|
+
}),
|
|
8530
|
+
...issueLines(options, optionValues, flagWording),
|
|
8531
|
+
...issueLines(page, pageValues, flagWording)
|
|
7951
8532
|
];
|
|
7952
8533
|
if (unknown.length === 0 && otherLines.length === 0 && args.success && options.success && page.success) return {
|
|
7953
8534
|
input: {
|
|
@@ -7961,9 +8542,12 @@ function parseInput(spec, words, invocation) {
|
|
|
7961
8542
|
if (only !== void 0 && unknown.length === 1 && otherLines.length === 0) throw unknownOptionError(spec.commandLine, invocation, only.flag, only.suggestion === void 0 ? [] : [only.suggestion]);
|
|
7962
8543
|
throw invalidInput(spec.commandLine, invocation, unknown, otherLines);
|
|
7963
8544
|
}
|
|
7964
|
-
/**
|
|
7965
|
-
|
|
7966
|
-
|
|
8545
|
+
/**
|
|
8546
|
+
* The validated input and Standard flag values of the routed Command, or one usage error; the arg
|
|
8547
|
+
* given `-` takes its text from `readStdin`.
|
|
8548
|
+
*/
|
|
8549
|
+
async function parseCommand({ spec, words, json }, invocation, readStdin) {
|
|
8550
|
+
const { input, page, values } = await parseInput(spec, words, invocation, readStdin);
|
|
7967
8551
|
const confirm = values.get(CONFIRM_FLAG.flag);
|
|
7968
8552
|
return {
|
|
7969
8553
|
input,
|
|
@@ -8034,7 +8618,7 @@ function walk(node, words, json, invocation) {
|
|
|
8034
8618
|
return unknownCommand(node, first, json);
|
|
8035
8619
|
}
|
|
8036
8620
|
function unknownCommand(group, name, json) {
|
|
8037
|
-
const suggestions = closestNames(name, Object.keys(group
|
|
8621
|
+
const suggestions = closestNames(name, Object.keys(visibleCommands(group)));
|
|
8038
8622
|
return {
|
|
8039
8623
|
kind: "usage error",
|
|
8040
8624
|
error: unknownCommandError(group.commandLine, name, suggestions),
|
|
@@ -8059,23 +8643,28 @@ function dotenvPath(cliName, env) {
|
|
|
8059
8643
|
const config = env.XDG_CONFIG_HOME || join(env.HOME || homedir(), ".config");
|
|
8060
8644
|
return join(config, cliName, ".env");
|
|
8061
8645
|
}
|
|
8062
|
-
function readDotenv(path) {
|
|
8646
|
+
function readDotenv(path, fileError) {
|
|
8647
|
+
let text;
|
|
8063
8648
|
try {
|
|
8064
|
-
|
|
8649
|
+
text = readFileSync(path, "utf8");
|
|
8065
8650
|
} catch (error) {
|
|
8066
8651
|
if (isMissingFile(error)) return {};
|
|
8067
|
-
throw error
|
|
8652
|
+
throw fileError(error, {
|
|
8653
|
+
path,
|
|
8654
|
+
access: "read"
|
|
8655
|
+
});
|
|
8068
8656
|
}
|
|
8657
|
+
return parseEnv(text);
|
|
8069
8658
|
}
|
|
8070
8659
|
/** Looks `name` up in the env, then in `$XDG_CONFIG_HOME/<cli>/.env`; an empty value counts as unset. */
|
|
8071
|
-
function secretOf(cliName, env, name) {
|
|
8660
|
+
function secretOf({ cliName, env, fileError }, name) {
|
|
8072
8661
|
const fromEnv = env[name];
|
|
8073
8662
|
if (fromEnv) return {
|
|
8074
8663
|
value: fromEnv,
|
|
8075
8664
|
origin: { kind: "env" }
|
|
8076
8665
|
};
|
|
8077
8666
|
const path = dotenvPath(cliName, env);
|
|
8078
|
-
const fromFile = readDotenv(path)[name];
|
|
8667
|
+
const fromFile = readDotenv(path, fileError)[name];
|
|
8079
8668
|
return fromFile ? {
|
|
8080
8669
|
value: fromFile,
|
|
8081
8670
|
origin: {
|
|
@@ -8109,10 +8698,9 @@ async function prepare(folder, cutoff, target) {
|
|
|
8109
8698
|
await mkdir(folder, { recursive: true });
|
|
8110
8699
|
await pruneOld(folder, cutoff);
|
|
8111
8700
|
} catch (error) {
|
|
8112
|
-
throw
|
|
8701
|
+
throw target.fileError(error, {
|
|
8113
8702
|
path: folder,
|
|
8114
|
-
|
|
8115
|
-
env: target.env
|
|
8703
|
+
access: "write"
|
|
8116
8704
|
});
|
|
8117
8705
|
}
|
|
8118
8706
|
}
|
|
@@ -8168,51 +8756,22 @@ function styleFor(env, stdoutIsTTY) {
|
|
|
8168
8756
|
}
|
|
8169
8757
|
//#endregion
|
|
8170
8758
|
//#region ../agent-cli/dist/run-cli.js
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
return {
|
|
8174
|
-
exists: async (path) => {
|
|
8175
|
-
const target = resolve(base.cwd, path);
|
|
8176
|
-
try {
|
|
8177
|
-
return await files.exists(target);
|
|
8178
|
-
} catch (error) {
|
|
8179
|
-
throw classifyErrno(error, {
|
|
8180
|
-
path: target,
|
|
8181
|
-
callerLine,
|
|
8182
|
-
env: base.env
|
|
8183
|
-
});
|
|
8184
|
-
}
|
|
8185
|
-
},
|
|
8186
|
-
write: async (path, data) => {
|
|
8187
|
-
const target = resolve(base.cwd, path);
|
|
8188
|
-
try {
|
|
8189
|
-
await files.write(target, data);
|
|
8190
|
-
} catch (error) {
|
|
8191
|
-
throw classifyErrno(error, {
|
|
8192
|
-
path: target,
|
|
8193
|
-
callerLine,
|
|
8194
|
-
env: base.env
|
|
8195
|
-
});
|
|
8196
|
-
}
|
|
8197
|
-
}
|
|
8198
|
-
};
|
|
8759
|
+
function stdinNeverEndedHint(callerLine) {
|
|
8760
|
+
return `stdin never ended: pipe the text into \`${callerLine}\`, or redirect a file into it`;
|
|
8199
8761
|
}
|
|
8200
|
-
async function runCommand(routed, { base, writeStdout, signal, format: baseFormat, ports, clock, files, spawn, projectFile }) {
|
|
8762
|
+
async function runCommand(routed, { base, writeStdout, signal, format: baseFormat, ports, clock, files, spawn, projectFile, stdin, platform }) {
|
|
8201
8763
|
const { command, commandLine } = routed.spec;
|
|
8764
|
+
const invocation = {
|
|
8765
|
+
...baseFormat.invocation,
|
|
8766
|
+
flags: knownFlags(routed.spec)
|
|
8767
|
+
};
|
|
8202
8768
|
const format = {
|
|
8203
8769
|
...baseFormat,
|
|
8204
|
-
json: routed.json
|
|
8770
|
+
json: routed.json,
|
|
8771
|
+
invocation
|
|
8205
8772
|
};
|
|
8206
|
-
const
|
|
8207
|
-
let
|
|
8208
|
-
let project;
|
|
8209
|
-
try {
|
|
8210
|
-
parsed = parseCommand(routed, invocation);
|
|
8211
|
-
project = projectFile === void 0 ? void 0 : projectOf(projectFile, base.cwd);
|
|
8212
|
-
} catch (error) {
|
|
8213
|
-
return errorResult(error, format);
|
|
8214
|
-
}
|
|
8215
|
-
const { input, flags } = parsed;
|
|
8773
|
+
const typedLine = (change) => commandLineOf(invocation, change);
|
|
8774
|
+
let resumeHint;
|
|
8216
8775
|
const control = new RunControl({
|
|
8217
8776
|
commandLine,
|
|
8218
8777
|
outer: signal,
|
|
@@ -8220,35 +8779,62 @@ async function runCommand(routed, { base, writeStdout, signal, format: baseForma
|
|
|
8220
8779
|
progress: base.progress,
|
|
8221
8780
|
runDeadline: command.deadline === void 0 ? void 0 : {
|
|
8222
8781
|
ms: command.deadline.ms,
|
|
8223
|
-
hint:
|
|
8782
|
+
hint: () => resumeHint ?? stdinNeverEndedHint(typedLine())
|
|
8224
8783
|
}
|
|
8225
8784
|
});
|
|
8785
|
+
let parsed;
|
|
8786
|
+
let project;
|
|
8787
|
+
try {
|
|
8788
|
+
checkOperator(routed.spec, base.env, typedLine());
|
|
8789
|
+
parsed = await parseCommand(routed, invocation, (field) => {
|
|
8790
|
+
if (isTerminal(stdin)) base.progress(readingLine(field.name, platform));
|
|
8791
|
+
return readStdin(stdin, control.signal);
|
|
8792
|
+
});
|
|
8793
|
+
project = projectFile === void 0 ? void 0 : projectOf(projectFile, base.cwd);
|
|
8794
|
+
} catch (error) {
|
|
8795
|
+
control.close();
|
|
8796
|
+
return errorResult(error, format);
|
|
8797
|
+
}
|
|
8798
|
+
const { input, flags } = parsed;
|
|
8799
|
+
resumeHint = command.deadline?.resume(input, typedLine);
|
|
8226
8800
|
let delivered;
|
|
8227
|
-
const
|
|
8228
|
-
const
|
|
8801
|
+
const { fileError } = base;
|
|
8802
|
+
const outputs = outputsGuard(classifiedFiles(files, {
|
|
8803
|
+
cwd: base.cwd,
|
|
8804
|
+
fileError
|
|
8805
|
+
}), base.cwd);
|
|
8229
8806
|
const spill = spillTo({
|
|
8230
8807
|
cliName: format.cliName,
|
|
8231
8808
|
commandName: command.name,
|
|
8232
8809
|
env: base.env,
|
|
8233
8810
|
clock,
|
|
8234
|
-
files:
|
|
8235
|
-
|
|
8811
|
+
files: outputs.files,
|
|
8812
|
+
fileError
|
|
8236
8813
|
});
|
|
8237
|
-
const
|
|
8814
|
+
const portsBase = {
|
|
8238
8815
|
...base,
|
|
8239
8816
|
signal: control.signal,
|
|
8240
|
-
deadline: (ms) => control.deadline(ms),
|
|
8241
|
-
runToEnd: (name, work) => control.runToEnd(name, work),
|
|
8242
|
-
ports: ports(),
|
|
8243
8817
|
clock,
|
|
8244
|
-
files:
|
|
8818
|
+
files: outputs.files,
|
|
8245
8819
|
spawn: contextSpawn(spawn, {
|
|
8246
8820
|
cwd: base.cwd,
|
|
8247
8821
|
env: base.env,
|
|
8248
|
-
signal: control.signal
|
|
8249
|
-
|
|
8822
|
+
signal: control.signal,
|
|
8823
|
+
progress: base.progress
|
|
8824
|
+
}, fileError)
|
|
8825
|
+
};
|
|
8826
|
+
const builtPorts = once(() => ports(portsBase));
|
|
8827
|
+
const ctx = {
|
|
8828
|
+
...portsBase,
|
|
8829
|
+
deadline: (ms) => control.deadline(ms),
|
|
8830
|
+
runToEnd: (name, work) => control.runToEnd(name, work),
|
|
8831
|
+
get ports() {
|
|
8832
|
+
return builtPorts();
|
|
8833
|
+
},
|
|
8250
8834
|
project,
|
|
8251
|
-
|
|
8835
|
+
force: flags.force,
|
|
8836
|
+
commandLine: typedLine,
|
|
8837
|
+
poll: (check, { intervalMs, signal: stop }) => poll(clock, check, intervalMs, stop === void 0 ? control.signal : AbortSignal.any([control.signal, stop])),
|
|
8252
8838
|
deliver: (data) => {
|
|
8253
8839
|
delivered = deliveredOutcome(command, data);
|
|
8254
8840
|
}
|
|
@@ -8262,14 +8848,15 @@ async function runCommand(routed, { base, writeStdout, signal, format: baseForma
|
|
|
8262
8848
|
dryRun: flags.dryRun,
|
|
8263
8849
|
confirm: flags.confirm,
|
|
8264
8850
|
yes: flags.yes,
|
|
8265
|
-
force: flags.force,
|
|
8266
8851
|
page: flags.page,
|
|
8267
8852
|
invocation,
|
|
8268
8853
|
commandLine,
|
|
8269
8854
|
started: async (outcome) => {
|
|
8270
8855
|
writeStdout(await startedOutput(outcome, format, spill));
|
|
8271
8856
|
served = true;
|
|
8272
|
-
}
|
|
8857
|
+
},
|
|
8858
|
+
files,
|
|
8859
|
+
guardOutputs: outputs.guard
|
|
8273
8860
|
}))
|
|
8274
8861
|
};
|
|
8275
8862
|
} catch (error) {
|
|
@@ -8285,29 +8872,78 @@ async function runCommand(routed, { base, writeStdout, signal, format: baseForma
|
|
|
8285
8872
|
fields: flags.fields
|
|
8286
8873
|
}, spill);
|
|
8287
8874
|
}
|
|
8875
|
+
/** `build` runs on the first call; later calls give its value or throw its error again. */
|
|
8876
|
+
function once(build) {
|
|
8877
|
+
let outcome;
|
|
8878
|
+
return () => {
|
|
8879
|
+
if (outcome === void 0) try {
|
|
8880
|
+
outcome = {
|
|
8881
|
+
ok: true,
|
|
8882
|
+
value: build()
|
|
8883
|
+
};
|
|
8884
|
+
} catch (error) {
|
|
8885
|
+
outcome = {
|
|
8886
|
+
ok: false,
|
|
8887
|
+
error
|
|
8888
|
+
};
|
|
8889
|
+
}
|
|
8890
|
+
if (outcome.ok) return outcome.value;
|
|
8891
|
+
throw outcome.error;
|
|
8892
|
+
};
|
|
8893
|
+
}
|
|
8894
|
+
function selfOf(name, bin) {
|
|
8895
|
+
return bin === void 0 ? [name] : [
|
|
8896
|
+
process.execPath,
|
|
8897
|
+
...process.execArgv,
|
|
8898
|
+
bin
|
|
8899
|
+
];
|
|
8900
|
+
}
|
|
8288
8901
|
function portsOf(cli, replacement) {
|
|
8289
8902
|
if (replacement !== void 0) return () => replacement;
|
|
8290
8903
|
return cli.ports ?? (() => ({}));
|
|
8291
8904
|
}
|
|
8292
|
-
|
|
8905
|
+
function stopLine(notice, json) {
|
|
8906
|
+
return json ? progressLine(notice, true) : `\n${notice}\n`;
|
|
8907
|
+
}
|
|
8908
|
+
/** Calls `onStop` if `signal` aborts while `work` runs. */
|
|
8909
|
+
async function whileStopping(signal, onStop, work) {
|
|
8910
|
+
if (signal === void 0 || onStop === void 0) return work();
|
|
8911
|
+
signal.addEventListener("abort", onStop, { once: true });
|
|
8912
|
+
try {
|
|
8913
|
+
return await work();
|
|
8914
|
+
} finally {
|
|
8915
|
+
signal.removeEventListener("abort", onStop);
|
|
8916
|
+
}
|
|
8917
|
+
}
|
|
8918
|
+
async function runWithProgress(cli, argv, options, write, stopNotice) {
|
|
8293
8919
|
const format = {
|
|
8294
8920
|
cliName: cli.name,
|
|
8295
8921
|
env: options.env,
|
|
8296
8922
|
style: styleFor(options.env, options.stdoutIsTTY === true),
|
|
8297
8923
|
invocation: {
|
|
8298
8924
|
cliName: cli.name,
|
|
8299
|
-
argv
|
|
8925
|
+
argv,
|
|
8926
|
+
flags: []
|
|
8300
8927
|
},
|
|
8301
8928
|
json: false,
|
|
8302
8929
|
errors: cli.errors ?? {},
|
|
8303
8930
|
stop: options.signal
|
|
8304
8931
|
};
|
|
8305
|
-
const builtIns = cli.commands === void 0 ? {} : builtInCommands(cli,
|
|
8932
|
+
const builtIns = cli.commands === void 0 ? {} : builtInCommands(cli, {
|
|
8933
|
+
bin: options.bin,
|
|
8934
|
+
node: options.node
|
|
8935
|
+
});
|
|
8306
8936
|
const root = cli.commands === void 0 ? commandSpec(cli.name, cli.command) : groupSpec(cli.name, {
|
|
8307
8937
|
...cli.commands,
|
|
8308
8938
|
...builtIns
|
|
8309
8939
|
});
|
|
8310
8940
|
const routed = route(root, format.invocation);
|
|
8941
|
+
const platform = options.platform ?? process.platform;
|
|
8942
|
+
const fileError = fileErrorOf({
|
|
8943
|
+
callerLine: commandLineOf(format.invocation),
|
|
8944
|
+
env: options.env,
|
|
8945
|
+
platform
|
|
8946
|
+
});
|
|
8311
8947
|
const misused = (node) => isAgent(options.env) ? {
|
|
8312
8948
|
...format,
|
|
8313
8949
|
usageHelp: textHelp(node, root, cli, format.style)
|
|
@@ -8322,13 +8958,21 @@ async function runWithProgress(cli, argv, options, write) {
|
|
|
8322
8958
|
...misused(routed.node),
|
|
8323
8959
|
json: routed.json
|
|
8324
8960
|
});
|
|
8325
|
-
case "command": return runCommand(routed, {
|
|
8961
|
+
case "command": return whileStopping(options.signal, stopNotice === void 0 ? void 0 : () => write.stderr(stopLine(stopNotice, routed.json)), () => runCommand(routed, {
|
|
8326
8962
|
base: {
|
|
8327
8963
|
cwd: options.cwd,
|
|
8328
8964
|
env: options.env,
|
|
8329
8965
|
packageRoot: packageRootOf(options.bin, options.cwd),
|
|
8330
|
-
progress: (message) => write.stderr(
|
|
8331
|
-
secret: (name) => secretOf(
|
|
8966
|
+
progress: (message) => write.stderr(progressLine(message, routed.json)),
|
|
8967
|
+
secret: (name) => secretOf({
|
|
8968
|
+
cliName: cli.name,
|
|
8969
|
+
env: options.env,
|
|
8970
|
+
fileError
|
|
8971
|
+
}, name),
|
|
8972
|
+
fileError,
|
|
8973
|
+
version: cli.version,
|
|
8974
|
+
build: cli.build,
|
|
8975
|
+
self: selfOf(cli.name, options.bin)
|
|
8332
8976
|
},
|
|
8333
8977
|
writeStdout: (text) => write.stdout(text),
|
|
8334
8978
|
signal: options.signal,
|
|
@@ -8337,8 +8981,10 @@ async function runWithProgress(cli, argv, options, write) {
|
|
|
8337
8981
|
clock: options.clock ?? realClock,
|
|
8338
8982
|
files: options.files ?? realFiles(),
|
|
8339
8983
|
spawn: options.spawn ?? realSpawn,
|
|
8340
|
-
projectFile: Object.values(builtIns).includes(routed.spec.command) ? void 0 : cli.project
|
|
8341
|
-
|
|
8984
|
+
projectFile: Object.values(builtIns).includes(routed.spec.command) ? void 0 : cli.project,
|
|
8985
|
+
stdin: options.stdin ?? "",
|
|
8986
|
+
platform
|
|
8987
|
+
}));
|
|
8342
8988
|
}
|
|
8343
8989
|
}
|
|
8344
8990
|
//#endregion
|
|
@@ -8350,7 +8996,6 @@ async function runProcess(cli) {
|
|
|
8350
8996
|
const stop = new AbortController();
|
|
8351
8997
|
const onSignal = (signal) => {
|
|
8352
8998
|
if (stop.signal.aborted) process.exit(SIGNAL_EXIT_CODES[signal]);
|
|
8353
|
-
process.stderr.write("\nstopping… (Ctrl-C again to quit now)\n");
|
|
8354
8999
|
stop.abort(signal);
|
|
8355
9000
|
};
|
|
8356
9001
|
process.on("SIGINT", onSignal);
|
|
@@ -8361,11 +9006,13 @@ async function runProcess(cli) {
|
|
|
8361
9006
|
cwd: process.cwd(),
|
|
8362
9007
|
stdoutIsTTY: process.stdout.isTTY === true,
|
|
8363
9008
|
signal: stop.signal,
|
|
8364
|
-
bin: process.argv[1]
|
|
9009
|
+
bin: process.argv[1],
|
|
9010
|
+
node: process.execPath,
|
|
9011
|
+
stdin: process.stdin
|
|
8365
9012
|
}, {
|
|
8366
9013
|
stdout: (text) => process.stdout.write(text),
|
|
8367
9014
|
stderr: (text) => process.stderr.write(text)
|
|
8368
|
-
});
|
|
9015
|
+
}, "stopping… (Ctrl-C again to quit now)");
|
|
8369
9016
|
await written(process.stdout, result.stdout);
|
|
8370
9017
|
await written(process.stderr, result.stderr);
|
|
8371
9018
|
process.exitCode = result.exitCode;
|
|
@@ -8378,9 +9025,9 @@ async function runProcess(cli) {
|
|
|
8378
9025
|
//#endregion
|
|
8379
9026
|
//#region src/build.ts
|
|
8380
9027
|
const build = {
|
|
8381
|
-
"sha": "
|
|
9028
|
+
"sha": "c325cae",
|
|
8382
9029
|
"dirty": false,
|
|
8383
|
-
"builtAt": "2026-10-
|
|
9030
|
+
"builtAt": "2026-10-19T14:33:32.022Z"
|
|
8384
9031
|
};
|
|
8385
9032
|
//#endregion
|
|
8386
9033
|
//#region src/steps.ts
|
|
@@ -8509,7 +9156,7 @@ async function writeTemplate(root, files, values) {
|
|
|
8509
9156
|
}
|
|
8510
9157
|
//#endregion
|
|
8511
9158
|
//#region src/version.ts
|
|
8512
|
-
const version = "0.
|
|
9159
|
+
const version = "0.5.0";
|
|
8513
9160
|
//#endregion
|
|
8514
9161
|
//#region src/create.ts
|
|
8515
9162
|
const { defineCommand } = agentCli();
|