@kaynooo/cli-doctor 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-bin.js +118 -26
- package/dist/cli.js +110 -16
- package/package.json +2 -2
package/dist/cli-bin.js
CHANGED
|
@@ -481,7 +481,6 @@ var DASHES = /^-+/;
|
|
|
481
481
|
function jsonOption(holds) {
|
|
482
482
|
return { type: "boolean", description: holds === undefined ? "print JSON" : `print JSON: ${holds}` };
|
|
483
483
|
}
|
|
484
|
-
|
|
485
484
|
class Exit extends Error {
|
|
486
485
|
code;
|
|
487
486
|
hint;
|
|
@@ -1480,6 +1479,28 @@ var BASH_FUNCTION = `__kaynooo_cli_complete() {
|
|
|
1480
1479
|
done
|
|
1481
1480
|
COMPREPLY+=($(compgen -W "$words" -- "$cur"))
|
|
1482
1481
|
}`;
|
|
1482
|
+
var ZSH_FUNCTION = `__kaynooo_cli_complete() {
|
|
1483
|
+
local line
|
|
1484
|
+
local -a described plain
|
|
1485
|
+
for line in \${(f)"$("\${words[1]}" __complete "\${(@)words[2,CURRENT]}" 2>/dev/null)"}; do
|
|
1486
|
+
if [[ $line == __files__ ]]; then
|
|
1487
|
+
_files
|
|
1488
|
+
elif [[ $line == *$'\\t'* ]]; then
|
|
1489
|
+
described+=("\${\${line%%$'\\t'*}//:/\\\\:}:\${line#*$'\\t'}")
|
|
1490
|
+
else
|
|
1491
|
+
plain+=("$line")
|
|
1492
|
+
fi
|
|
1493
|
+
done
|
|
1494
|
+
(( \${#described} )) && _describe -V value described
|
|
1495
|
+
(( \${#plain} )) && compadd -- "\${plain[@]}"
|
|
1496
|
+
return 0
|
|
1497
|
+
}`;
|
|
1498
|
+
function zshScript(bins) {
|
|
1499
|
+
return `# Generated by \`cli completions zsh\`
|
|
1500
|
+
${ZSH_FUNCTION}
|
|
1501
|
+
compdef __kaynooo_cli_complete ${bins.join(" ")}
|
|
1502
|
+
`;
|
|
1503
|
+
}
|
|
1483
1504
|
function bashScript(bins) {
|
|
1484
1505
|
return `# Generated by \`cli completions bash\`
|
|
1485
1506
|
${BASH_FUNCTION}
|
|
@@ -1578,13 +1599,68 @@ import process16 from "process";
|
|
|
1578
1599
|
|
|
1579
1600
|
// ../kit/src/prompt.ts
|
|
1580
1601
|
import process15 from "process";
|
|
1581
|
-
|
|
1582
|
-
|
|
1602
|
+
|
|
1603
|
+
// ../kit/src/picker/score.ts
|
|
1604
|
+
var BOUNDARY_AFTER = new Set([" ", "/", "-", "_", ".", ":", "\\", "(", "[", ",", "\t"]);
|
|
1605
|
+
var NONE = Number.NEGATIVE_INFINITY;
|
|
1606
|
+
|
|
1607
|
+
// ../kit/src/picker/state.ts
|
|
1608
|
+
var IS_CONTROL = /[\x00-\x1F\x7F-\x9F]/;
|
|
1609
|
+
var PASTE_START = "\x1B[200~";
|
|
1610
|
+
var PASTE_END = "\x1B[201~";
|
|
1611
|
+
var KEY_SEQUENCES = /\x1B\[[0-9;]*[A-Z~]|\x1BO[A-Z]|\x1B[\s\S]|[\s\S]/gu;
|
|
1612
|
+
var KEYS = {
|
|
1613
|
+
"\x1B[A": "up",
|
|
1614
|
+
"\x1BOA": "up",
|
|
1615
|
+
"\x10": "up",
|
|
1616
|
+
"\x1B[B": "down",
|
|
1617
|
+
"\x1BOB": "down",
|
|
1618
|
+
"\x0E": "down",
|
|
1619
|
+
"\x1B[5~": "pageup",
|
|
1620
|
+
"\x1B[6~": "pagedown",
|
|
1621
|
+
"\x1B[H": "home",
|
|
1622
|
+
"\x1B[1~": "home",
|
|
1623
|
+
"\x1BOH": "home",
|
|
1624
|
+
"\x1B[F": "end",
|
|
1625
|
+
"\x1B[4~": "end",
|
|
1626
|
+
"\x1BOF": "end",
|
|
1627
|
+
"\r": "enter",
|
|
1628
|
+
"\n": "enter",
|
|
1629
|
+
"\x03": "cancel",
|
|
1630
|
+
"\x1B": "cancel",
|
|
1631
|
+
"\x7F": "erase",
|
|
1632
|
+
"\b": "erase",
|
|
1633
|
+
"\x15": "clear",
|
|
1634
|
+
"\x17": "word",
|
|
1635
|
+
"\t": "tab",
|
|
1636
|
+
"\x1F": "help",
|
|
1637
|
+
"\x1BOP": "help",
|
|
1638
|
+
"\x1B[11~": "help"
|
|
1639
|
+
};
|
|
1640
|
+
function parseKeys(input, paste = { active: false }, ctrls = []) {
|
|
1641
|
+
const codes = new Map(ctrls.map((name) => [String.fromCharCode(name.codePointAt(name.length - 1) - 96), name]));
|
|
1642
|
+
return (input.match(KEY_SEQUENCES) ?? []).flatMap((sequence) => {
|
|
1643
|
+
const named = codes.get(sequence);
|
|
1644
|
+
const key = named === undefined ? KEYS[sequence] : { ctrl: named };
|
|
1645
|
+
if (sequence === PASTE_START || sequence === PASTE_END) {
|
|
1646
|
+
paste.active = sequence === PASTE_START;
|
|
1647
|
+
return [];
|
|
1648
|
+
}
|
|
1649
|
+
if (paste.active && (sequence === "\r" || sequence === `
|
|
1650
|
+
`))
|
|
1651
|
+
return [];
|
|
1652
|
+
if (key !== undefined)
|
|
1653
|
+
return [key];
|
|
1654
|
+
return IS_CONTROL.test(sequence) || sequence.startsWith("\x1B") ? [] : [{ text: sequence }];
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
// ../kit/src/prompt.ts
|
|
1583
1659
|
var WORDS = /\s+/;
|
|
1584
1660
|
var MAX_ROWS = 10;
|
|
1585
|
-
var
|
|
1586
|
-
function readKeys(input) {
|
|
1587
|
-
return (input
|
|
1661
|
+
var PROMPT_KEYS = new Set(["up", "down", "pageup", "pagedown", "home", "end", "enter", "cancel", "erase"]);
|
|
1662
|
+
function readKeys(input, paste = { active: false }) {
|
|
1663
|
+
return parseKeys(input, paste).filter((key) => typeof key === "object" ? "text" in key : PROMPT_KEYS.has(key));
|
|
1588
1664
|
}
|
|
1589
1665
|
function flip(checked, value) {
|
|
1590
1666
|
const next = new Set(checked);
|
|
@@ -1683,6 +1759,12 @@ class List {
|
|
|
1683
1759
|
this.cursor = (this.cursor + (key === "up" ? this.matches.length - 1 : 1)) % this.matches.length;
|
|
1684
1760
|
return;
|
|
1685
1761
|
}
|
|
1762
|
+
if (key === "home" || key === "end" || key === "pageup" || key === "pagedown") {
|
|
1763
|
+
const last = this.matches.length - 1;
|
|
1764
|
+
const to = { home: 0, end: last, pageup: this.cursor - MAX_ROWS, pagedown: this.cursor + MAX_ROWS }[key];
|
|
1765
|
+
this.cursor = Math.max(0, Math.min(last, to));
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1686
1768
|
if (key === "erase")
|
|
1687
1769
|
this.filter([...this.query].slice(0, -1).join(""));
|
|
1688
1770
|
else if (typeof key === "object")
|
|
@@ -1724,22 +1806,29 @@ async function ask(question, { hint, terminal = process15 }, render, press) {
|
|
|
1724
1806
|
if (!isInteractive(terminal))
|
|
1725
1807
|
fail(`cannot ask "${question}" off a terminal`, 2, hint);
|
|
1726
1808
|
const colors = paint(stderr);
|
|
1727
|
-
let drawn =
|
|
1809
|
+
let drawn = [];
|
|
1810
|
+
let current = "asking";
|
|
1728
1811
|
let outcome;
|
|
1812
|
+
const columns = () => stderr.columns || 80;
|
|
1729
1813
|
const draw = (state) => {
|
|
1730
|
-
const frame = render(colors, state, { columns:
|
|
1731
|
-
|
|
1814
|
+
const frame = render(colors, state, { columns: columns(), rows: stderr.rows || 24 });
|
|
1815
|
+
const rows = drawn.reduce((sum, line) => sum + Math.max(1, Math.ceil(Bun.stringWidth(line) / columns())), 0);
|
|
1816
|
+
stderr.write(`${rows > 1 ? `\x1B[${rows - 1}A` : ""}\r\x1B[0J${frame.join(`
|
|
1732
1817
|
`)}`);
|
|
1733
|
-
drawn = frame
|
|
1818
|
+
drawn = frame;
|
|
1819
|
+
current = state;
|
|
1734
1820
|
};
|
|
1821
|
+
const redraw = () => draw(current);
|
|
1822
|
+
const paste = { active: false };
|
|
1735
1823
|
try {
|
|
1824
|
+
stderr.on?.("resize", redraw);
|
|
1736
1825
|
stdin.setRawMode(true);
|
|
1737
1826
|
stdin.resume();
|
|
1738
|
-
stderr.write("\x1B[?25l");
|
|
1827
|
+
stderr.write("\x1B[?25l\x1B[?2004h");
|
|
1739
1828
|
draw("asking");
|
|
1740
1829
|
return await new Promise((resolve) => {
|
|
1741
1830
|
function onData(data) {
|
|
1742
|
-
for (const key of readKeys(data.toString())) {
|
|
1831
|
+
for (const key of readKeys(data.toString(), paste)) {
|
|
1743
1832
|
const pressed = press(key);
|
|
1744
1833
|
if (pressed !== undefined) {
|
|
1745
1834
|
settle(pressed);
|
|
@@ -1761,9 +1850,10 @@ async function ask(question, { hint, terminal = process15 }, render, press) {
|
|
|
1761
1850
|
stdin.on("end", onEnd);
|
|
1762
1851
|
});
|
|
1763
1852
|
} finally {
|
|
1853
|
+
stderr.off?.("resize", redraw);
|
|
1764
1854
|
draw(outcome ?? "cancel");
|
|
1765
1855
|
stderr.write(`
|
|
1766
|
-
\x1B[?25h`);
|
|
1856
|
+
\x1B[?25h\x1B[?2004l`);
|
|
1767
1857
|
stdin.setRawMode(false);
|
|
1768
1858
|
stdin.pause();
|
|
1769
1859
|
}
|
|
@@ -1854,7 +1944,7 @@ async function install(host, options, recheck, choosing = ask2) {
|
|
|
1854
1944
|
console.log("everything is installed");
|
|
1855
1945
|
return 0;
|
|
1856
1946
|
}
|
|
1857
|
-
if (pool.length === 0 && options.names.length > 0) {
|
|
1947
|
+
if (pool.length === 0 && (options.names.length > 0 || !isInteractive())) {
|
|
1858
1948
|
console.log("everything is installed");
|
|
1859
1949
|
return 0;
|
|
1860
1950
|
}
|
|
@@ -1917,10 +2007,14 @@ async function install(host, options, recheck, choosing = ask2) {
|
|
|
1917
2007
|
return 1;
|
|
1918
2008
|
}
|
|
1919
2009
|
}
|
|
1920
|
-
if (removing.plugin && host.which("claude")
|
|
2010
|
+
if (removing.plugin && host.which("claude") === null) {
|
|
2011
|
+
console.error(`${yellow("not run")} ${PLUGIN_UNINSTALL.join(" ")}: claude is not on PATH`);
|
|
2012
|
+
} else if (removing.plugin) {
|
|
1921
2013
|
const ran = await host.run(PLUGIN_UNINSTALL);
|
|
1922
|
-
if (ran.code !== 0)
|
|
2014
|
+
if (ran.code !== 0) {
|
|
1923
2015
|
console.error(`${red("failed")} ${PLUGIN_UNINSTALL.join(" ")}: exit ${ran.code}: ${firstLine(ran.stderr || ran.stdout)}`);
|
|
2016
|
+
return 1;
|
|
2017
|
+
}
|
|
1924
2018
|
}
|
|
1925
2019
|
console.log(`
|
|
1926
2020
|
after the install:`);
|
|
@@ -2045,26 +2139,24 @@ async function list(args, host = hostHere()) {
|
|
|
2045
2139
|
print2(listed);
|
|
2046
2140
|
return 0;
|
|
2047
2141
|
}
|
|
2048
|
-
var COMPLETIONS_USAGE = `cli completions <fish|bash> [--install] [--dir <folder>]: shell completions for every installed bin of the @kaynooo/cli-* packages
|
|
2142
|
+
var COMPLETIONS_USAGE = `cli completions <fish|bash|zsh> [--install] [--dir <folder>]: shell completions for every installed bin of the @kaynooo/cli-* packages
|
|
2049
2143
|
|
|
2050
2144
|
Each bin completes itself through \`<bin> __complete\`; this writes the glue a shell needs per bin.
|
|
2051
2145
|
fish: without --install the files print on stdout, with it they go to ~/.cache/fish/kaynooo-cli (or $XDG_CACHE_HOME), one <bin>.fish each, the stale ones this command wrote taken out. That folder has to be in fish_complete_path, first so a completion fish ships for the same name does not win: \`set -p fish_complete_path ~/.cache/fish/kaynooo-cli\`.
|
|
2052
2146
|
bash: one script on stdout, sourced from ~/.bashrc with \`source <(cli completions bash)\`; --install and --dir are fish's.
|
|
2053
|
-
zsh:
|
|
2147
|
+
zsh: one script on stdout like bash's, after compinit in ~/.zshrc: \`autoload -U +X compinit && compinit\`, then \`source <(cli completions zsh)\` (written without zsh at hand to run it, so untested).`;
|
|
2054
2148
|
var COMPLETIONS_OPTIONS = {
|
|
2055
2149
|
install: { type: "boolean", description: "write the files to the folder instead of printing them" },
|
|
2056
2150
|
dir: { type: "string", short: "d", description: "the folder to write to, instead of ~/.cache/fish/kaynooo-cli" }
|
|
2057
2151
|
};
|
|
2058
2152
|
async function completions(args, host = hostHere()) {
|
|
2059
|
-
const { values, positionals } = parse(args, COMPLETIONS_USAGE, COMPLETIONS_OPTIONS, { positionals: ["<shell>"], exits: [[0, "it printed or wrote them"], [2, "a usage error or a shell without a script"]], candidates: { "<shell>": () => ["fish", "bash"] }, examples: ["cli completions fish", ["cli completions fish --install", "write one file per bin"], ["source <(cli completions bash)", "in ~/.bashrc"]] });
|
|
2060
|
-
if (positionals[0]
|
|
2061
|
-
badUsage("
|
|
2062
|
-
if (positionals[0]
|
|
2063
|
-
badUsage("completions exist for fish and bash: cli completions fish");
|
|
2064
|
-
if (positionals[0] === "bash") {
|
|
2153
|
+
const { values, positionals } = parse(args, COMPLETIONS_USAGE, COMPLETIONS_OPTIONS, { positionals: ["<shell>"], exits: [[0, "it printed or wrote them"], [2, "a usage error or a shell without a script"]], candidates: { "<shell>": () => ["fish", "bash", "zsh"] }, examples: ["cli completions fish", ["cli completions fish --install", "write one file per bin"], ["source <(cli completions bash)", "in ~/.bashrc"], ["source <(cli completions zsh)", "in ~/.zshrc after compinit"]] });
|
|
2154
|
+
if (positionals[0] !== "fish" && positionals[0] !== "bash" && positionals[0] !== "zsh")
|
|
2155
|
+
badUsage("completions exist for fish, bash and zsh: cli completions fish");
|
|
2156
|
+
if (positionals[0] === "bash" || positionals[0] === "zsh") {
|
|
2065
2157
|
if (values.install === true || values.dir !== undefined)
|
|
2066
|
-
badUsage(
|
|
2067
|
-
console.log(bashScript(installedBins(host)).trimEnd());
|
|
2158
|
+
badUsage(`--install and --dir are for fish: source the ${positionals[0]} script instead`);
|
|
2159
|
+
console.log((positionals[0] === "zsh" ? zshScript : bashScript)(installedBins(host)).trimEnd());
|
|
2068
2160
|
return 0;
|
|
2069
2161
|
}
|
|
2070
2162
|
if (values.install !== true) {
|
package/dist/cli.js
CHANGED
|
@@ -481,7 +481,6 @@ var DASHES = /^-+/;
|
|
|
481
481
|
function jsonOption(holds) {
|
|
482
482
|
return { type: "boolean", description: holds === undefined ? "print JSON" : `print JSON: ${holds}` };
|
|
483
483
|
}
|
|
484
|
-
|
|
485
484
|
class Exit extends Error {
|
|
486
485
|
code;
|
|
487
486
|
hint;
|
|
@@ -1318,6 +1317,28 @@ var BASH_FUNCTION = `__kaynooo_cli_complete() {
|
|
|
1318
1317
|
done
|
|
1319
1318
|
COMPREPLY+=($(compgen -W "$words" -- "$cur"))
|
|
1320
1319
|
}`;
|
|
1320
|
+
var ZSH_FUNCTION = `__kaynooo_cli_complete() {
|
|
1321
|
+
local line
|
|
1322
|
+
local -a described plain
|
|
1323
|
+
for line in \${(f)"$("\${words[1]}" __complete "\${(@)words[2,CURRENT]}" 2>/dev/null)"}; do
|
|
1324
|
+
if [[ $line == __files__ ]]; then
|
|
1325
|
+
_files
|
|
1326
|
+
elif [[ $line == *$'\\t'* ]]; then
|
|
1327
|
+
described+=("\${\${line%%$'\\t'*}//:/\\\\:}:\${line#*$'\\t'}")
|
|
1328
|
+
else
|
|
1329
|
+
plain+=("$line")
|
|
1330
|
+
fi
|
|
1331
|
+
done
|
|
1332
|
+
(( \${#described} )) && _describe -V value described
|
|
1333
|
+
(( \${#plain} )) && compadd -- "\${plain[@]}"
|
|
1334
|
+
return 0
|
|
1335
|
+
}`;
|
|
1336
|
+
function zshScript(bins) {
|
|
1337
|
+
return `# Generated by \`cli completions zsh\`
|
|
1338
|
+
${ZSH_FUNCTION}
|
|
1339
|
+
compdef __kaynooo_cli_complete ${bins.join(" ")}
|
|
1340
|
+
`;
|
|
1341
|
+
}
|
|
1321
1342
|
function bashScript(bins) {
|
|
1322
1343
|
return `# Generated by \`cli completions bash\`
|
|
1323
1344
|
${BASH_FUNCTION}
|
|
@@ -1576,13 +1597,68 @@ import process16 from "process";
|
|
|
1576
1597
|
|
|
1577
1598
|
// ../kit/src/prompt.ts
|
|
1578
1599
|
import process15 from "process";
|
|
1579
|
-
|
|
1580
|
-
|
|
1600
|
+
|
|
1601
|
+
// ../kit/src/picker/score.ts
|
|
1602
|
+
var BOUNDARY_AFTER = new Set([" ", "/", "-", "_", ".", ":", "\\", "(", "[", ",", "\t"]);
|
|
1603
|
+
var NONE = Number.NEGATIVE_INFINITY;
|
|
1604
|
+
|
|
1605
|
+
// ../kit/src/picker/state.ts
|
|
1606
|
+
var IS_CONTROL = /[\x00-\x1F\x7F-\x9F]/;
|
|
1607
|
+
var PASTE_START = "\x1B[200~";
|
|
1608
|
+
var PASTE_END = "\x1B[201~";
|
|
1609
|
+
var KEY_SEQUENCES = /\x1B\[[0-9;]*[A-Z~]|\x1BO[A-Z]|\x1B[\s\S]|[\s\S]/gu;
|
|
1610
|
+
var KEYS = {
|
|
1611
|
+
"\x1B[A": "up",
|
|
1612
|
+
"\x1BOA": "up",
|
|
1613
|
+
"\x10": "up",
|
|
1614
|
+
"\x1B[B": "down",
|
|
1615
|
+
"\x1BOB": "down",
|
|
1616
|
+
"\x0E": "down",
|
|
1617
|
+
"\x1B[5~": "pageup",
|
|
1618
|
+
"\x1B[6~": "pagedown",
|
|
1619
|
+
"\x1B[H": "home",
|
|
1620
|
+
"\x1B[1~": "home",
|
|
1621
|
+
"\x1BOH": "home",
|
|
1622
|
+
"\x1B[F": "end",
|
|
1623
|
+
"\x1B[4~": "end",
|
|
1624
|
+
"\x1BOF": "end",
|
|
1625
|
+
"\r": "enter",
|
|
1626
|
+
"\n": "enter",
|
|
1627
|
+
"\x03": "cancel",
|
|
1628
|
+
"\x1B": "cancel",
|
|
1629
|
+
"\x7F": "erase",
|
|
1630
|
+
"\b": "erase",
|
|
1631
|
+
"\x15": "clear",
|
|
1632
|
+
"\x17": "word",
|
|
1633
|
+
"\t": "tab",
|
|
1634
|
+
"\x1F": "help",
|
|
1635
|
+
"\x1BOP": "help",
|
|
1636
|
+
"\x1B[11~": "help"
|
|
1637
|
+
};
|
|
1638
|
+
function parseKeys(input, paste = { active: false }, ctrls = []) {
|
|
1639
|
+
const codes = new Map(ctrls.map((name) => [String.fromCharCode(name.codePointAt(name.length - 1) - 96), name]));
|
|
1640
|
+
return (input.match(KEY_SEQUENCES) ?? []).flatMap((sequence) => {
|
|
1641
|
+
const named = codes.get(sequence);
|
|
1642
|
+
const key = named === undefined ? KEYS[sequence] : { ctrl: named };
|
|
1643
|
+
if (sequence === PASTE_START || sequence === PASTE_END) {
|
|
1644
|
+
paste.active = sequence === PASTE_START;
|
|
1645
|
+
return [];
|
|
1646
|
+
}
|
|
1647
|
+
if (paste.active && (sequence === "\r" || sequence === `
|
|
1648
|
+
`))
|
|
1649
|
+
return [];
|
|
1650
|
+
if (key !== undefined)
|
|
1651
|
+
return [key];
|
|
1652
|
+
return IS_CONTROL.test(sequence) || sequence.startsWith("\x1B") ? [] : [{ text: sequence }];
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
// ../kit/src/prompt.ts
|
|
1581
1657
|
var WORDS = /\s+/;
|
|
1582
1658
|
var MAX_ROWS = 10;
|
|
1583
|
-
var
|
|
1584
|
-
function readKeys(input) {
|
|
1585
|
-
return (input
|
|
1659
|
+
var PROMPT_KEYS = new Set(["up", "down", "pageup", "pagedown", "home", "end", "enter", "cancel", "erase"]);
|
|
1660
|
+
function readKeys(input, paste = { active: false }) {
|
|
1661
|
+
return parseKeys(input, paste).filter((key) => typeof key === "object" ? "text" in key : PROMPT_KEYS.has(key));
|
|
1586
1662
|
}
|
|
1587
1663
|
function flip(checked, value) {
|
|
1588
1664
|
const next = new Set(checked);
|
|
@@ -1681,6 +1757,12 @@ class List {
|
|
|
1681
1757
|
this.cursor = (this.cursor + (key === "up" ? this.matches.length - 1 : 1)) % this.matches.length;
|
|
1682
1758
|
return;
|
|
1683
1759
|
}
|
|
1760
|
+
if (key === "home" || key === "end" || key === "pageup" || key === "pagedown") {
|
|
1761
|
+
const last = this.matches.length - 1;
|
|
1762
|
+
const to = { home: 0, end: last, pageup: this.cursor - MAX_ROWS, pagedown: this.cursor + MAX_ROWS }[key];
|
|
1763
|
+
this.cursor = Math.max(0, Math.min(last, to));
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1684
1766
|
if (key === "erase")
|
|
1685
1767
|
this.filter([...this.query].slice(0, -1).join(""));
|
|
1686
1768
|
else if (typeof key === "object")
|
|
@@ -1722,22 +1804,29 @@ async function ask(question, { hint, terminal = process15 }, render, press) {
|
|
|
1722
1804
|
if (!isInteractive(terminal))
|
|
1723
1805
|
fail(`cannot ask "${question}" off a terminal`, 2, hint);
|
|
1724
1806
|
const colors = paint(stderr);
|
|
1725
|
-
let drawn =
|
|
1807
|
+
let drawn = [];
|
|
1808
|
+
let current = "asking";
|
|
1726
1809
|
let outcome;
|
|
1810
|
+
const columns = () => stderr.columns || 80;
|
|
1727
1811
|
const draw = (state) => {
|
|
1728
|
-
const frame = render(colors, state, { columns:
|
|
1729
|
-
|
|
1812
|
+
const frame = render(colors, state, { columns: columns(), rows: stderr.rows || 24 });
|
|
1813
|
+
const rows = drawn.reduce((sum, line) => sum + Math.max(1, Math.ceil(Bun.stringWidth(line) / columns())), 0);
|
|
1814
|
+
stderr.write(`${rows > 1 ? `\x1B[${rows - 1}A` : ""}\r\x1B[0J${frame.join(`
|
|
1730
1815
|
`)}`);
|
|
1731
|
-
drawn = frame
|
|
1816
|
+
drawn = frame;
|
|
1817
|
+
current = state;
|
|
1732
1818
|
};
|
|
1819
|
+
const redraw = () => draw(current);
|
|
1820
|
+
const paste = { active: false };
|
|
1733
1821
|
try {
|
|
1822
|
+
stderr.on?.("resize", redraw);
|
|
1734
1823
|
stdin.setRawMode(true);
|
|
1735
1824
|
stdin.resume();
|
|
1736
|
-
stderr.write("\x1B[?25l");
|
|
1825
|
+
stderr.write("\x1B[?25l\x1B[?2004h");
|
|
1737
1826
|
draw("asking");
|
|
1738
1827
|
return await new Promise((resolve) => {
|
|
1739
1828
|
function onData(data) {
|
|
1740
|
-
for (const key of readKeys(data.toString())) {
|
|
1829
|
+
for (const key of readKeys(data.toString(), paste)) {
|
|
1741
1830
|
const pressed = press(key);
|
|
1742
1831
|
if (pressed !== undefined) {
|
|
1743
1832
|
settle(pressed);
|
|
@@ -1759,9 +1848,10 @@ async function ask(question, { hint, terminal = process15 }, render, press) {
|
|
|
1759
1848
|
stdin.on("end", onEnd);
|
|
1760
1849
|
});
|
|
1761
1850
|
} finally {
|
|
1851
|
+
stderr.off?.("resize", redraw);
|
|
1762
1852
|
draw(outcome ?? "cancel");
|
|
1763
1853
|
stderr.write(`
|
|
1764
|
-
\x1B[?25h`);
|
|
1854
|
+
\x1B[?25h\x1B[?2004l`);
|
|
1765
1855
|
stdin.setRawMode(false);
|
|
1766
1856
|
stdin.pause();
|
|
1767
1857
|
}
|
|
@@ -1852,7 +1942,7 @@ async function install(host, options, recheck, choosing = ask2) {
|
|
|
1852
1942
|
console.log("everything is installed");
|
|
1853
1943
|
return 0;
|
|
1854
1944
|
}
|
|
1855
|
-
if (pool.length === 0 && options.names.length > 0) {
|
|
1945
|
+
if (pool.length === 0 && (options.names.length > 0 || !isInteractive())) {
|
|
1856
1946
|
console.log("everything is installed");
|
|
1857
1947
|
return 0;
|
|
1858
1948
|
}
|
|
@@ -1915,10 +2005,14 @@ async function install(host, options, recheck, choosing = ask2) {
|
|
|
1915
2005
|
return 1;
|
|
1916
2006
|
}
|
|
1917
2007
|
}
|
|
1918
|
-
if (removing.plugin && host.which("claude")
|
|
2008
|
+
if (removing.plugin && host.which("claude") === null) {
|
|
2009
|
+
console.error(`${yellow("not run")} ${PLUGIN_UNINSTALL.join(" ")}: claude is not on PATH`);
|
|
2010
|
+
} else if (removing.plugin) {
|
|
1919
2011
|
const ran = await host.run(PLUGIN_UNINSTALL);
|
|
1920
|
-
if (ran.code !== 0)
|
|
2012
|
+
if (ran.code !== 0) {
|
|
1921
2013
|
console.error(`${red("failed")} ${PLUGIN_UNINSTALL.join(" ")}: exit ${ran.code}: ${firstLine(ran.stderr || ran.stdout)}`);
|
|
2014
|
+
return 1;
|
|
2015
|
+
}
|
|
1922
2016
|
}
|
|
1923
2017
|
console.log(`
|
|
1924
2018
|
after the install:`);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaynooo/cli-doctor",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.12.0",
|
|
5
5
|
"description": "doctor: checks the @kaynooo/cli-* install of a host: each bin's version against the registry, tea's login to Forgejo, the Claude Code hooks and the Bun floor; cli list: every bin in one line, read from its own help.",
|
|
6
6
|
"author": "Kaynooo <contact@kaynooo.fr>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -37,6 +37,6 @@
|
|
|
37
37
|
"doctor": "$npm_execpath src/cli.ts"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@kaynooo/cli-kit": "0.
|
|
40
|
+
"@kaynooo/cli-kit": "0.25.0"
|
|
41
41
|
}
|
|
42
42
|
}
|