@kaynooo/cli-docker 0.7.0 → 0.8.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/dc-cli.js +3 -3
- package/dist/dlog-cli.js +3 -3
- package/dist/dx-cli.js +68 -8
- package/dist/sf-cli.js +86 -20
- package/package.json +3 -3
- package/src/stack.ts +2 -3
package/dist/dc-cli.js
CHANGED
|
@@ -627,7 +627,6 @@ var DASHES = /^-+/;
|
|
|
627
627
|
function jsonOption(holds) {
|
|
628
628
|
return { type: "boolean", description: holds === undefined ? "print JSON" : `print JSON: ${holds}` };
|
|
629
629
|
}
|
|
630
|
-
|
|
631
630
|
class Exit extends Error {
|
|
632
631
|
code;
|
|
633
632
|
hint;
|
|
@@ -1032,6 +1031,8 @@ function composeError({ code, stderr }) {
|
|
|
1032
1031
|
`).at(-1) ?? "";
|
|
1033
1032
|
return last === "" ? `exit ${code}` : last;
|
|
1034
1033
|
}
|
|
1034
|
+
// ../kit/src/folders.ts
|
|
1035
|
+
var SKIPPED_FOLDERS = new Set(["node_modules", "vendor", "dist", "build", "target", "coverage", "venv", "__pycache__"]);
|
|
1035
1036
|
// ../kit/src/secrets.ts
|
|
1036
1037
|
var SECRET_PART = /token|secret|passw|credential|private|dsn|apikey|accesskey|key$/i;
|
|
1037
1038
|
var SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "session", "jwt", "ssn", "iban", "card", "cvv", "otp"]);
|
|
@@ -1404,13 +1405,12 @@ class Redactor {
|
|
|
1404
1405
|
var LABEL_FORMAT = ["project", "project.config_files", "project.environment_file", "project.working_dir"].map((label) => `{{.Label "com.docker.compose.${label}"}}`).join("\t");
|
|
1405
1406
|
var COMPOSE_FILE_VAR = /^\s*(?:export\s+)?COMPOSE_FILE\s*=\s*\S/m;
|
|
1406
1407
|
var COMPOSE_FILES = ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"];
|
|
1407
|
-
var SKIPPED2 = new Set(["node_modules", "vendor", "dist", "build", "target", "venv", "__pycache__"]);
|
|
1408
1408
|
var ACTIONS = ["shell", "logs", "restart", "up", "stop", "build"];
|
|
1409
1409
|
function from(dir, command) {
|
|
1410
1410
|
return dir === "." ? command : ["env", "-C", dir, ...command];
|
|
1411
1411
|
}
|
|
1412
1412
|
function children(dir = ".") {
|
|
1413
|
-
return readdirSync(dir, { withFileTypes: true }).filter((child) => child.isDirectory() && !child.name.startsWith(".") && !
|
|
1413
|
+
return readdirSync(dir, { withFileTypes: true }).filter((child) => child.isDirectory() && !child.name.startsWith(".") && !SKIPPED_FOLDERS.has(child.name)).map((child) => child.name).sort();
|
|
1414
1414
|
}
|
|
1415
1415
|
function up(dir) {
|
|
1416
1416
|
const dirs = [];
|
package/dist/dlog-cli.js
CHANGED
|
@@ -627,7 +627,6 @@ var DASHES = /^-+/;
|
|
|
627
627
|
function jsonOption(holds) {
|
|
628
628
|
return { type: "boolean", description: holds === undefined ? "print JSON" : `print JSON: ${holds}` };
|
|
629
629
|
}
|
|
630
|
-
|
|
631
630
|
class Exit extends Error {
|
|
632
631
|
code;
|
|
633
632
|
hint;
|
|
@@ -1032,6 +1031,8 @@ function composeError({ code, stderr }) {
|
|
|
1032
1031
|
`).at(-1) ?? "";
|
|
1033
1032
|
return last === "" ? `exit ${code}` : last;
|
|
1034
1033
|
}
|
|
1034
|
+
// ../kit/src/folders.ts
|
|
1035
|
+
var SKIPPED_FOLDERS = new Set(["node_modules", "vendor", "dist", "build", "target", "coverage", "venv", "__pycache__"]);
|
|
1035
1036
|
// ../kit/src/secrets.ts
|
|
1036
1037
|
var SECRET_PART = /token|secret|passw|credential|private|dsn|apikey|accesskey|key$/i;
|
|
1037
1038
|
var SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "session", "jwt", "ssn", "iban", "card", "cvv", "otp"]);
|
|
@@ -1404,13 +1405,12 @@ class Redactor {
|
|
|
1404
1405
|
var LABEL_FORMAT = ["project", "project.config_files", "project.environment_file", "project.working_dir"].map((label) => `{{.Label "com.docker.compose.${label}"}}`).join("\t");
|
|
1405
1406
|
var COMPOSE_FILE_VAR = /^\s*(?:export\s+)?COMPOSE_FILE\s*=\s*\S/m;
|
|
1406
1407
|
var COMPOSE_FILES = ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"];
|
|
1407
|
-
var SKIPPED2 = new Set(["node_modules", "vendor", "dist", "build", "target", "venv", "__pycache__"]);
|
|
1408
1408
|
var ACTIONS = ["shell", "logs", "restart", "up", "stop", "build"];
|
|
1409
1409
|
function from(dir, command) {
|
|
1410
1410
|
return dir === "." ? command : ["env", "-C", dir, ...command];
|
|
1411
1411
|
}
|
|
1412
1412
|
function children(dir = ".") {
|
|
1413
|
-
return readdirSync(dir, { withFileTypes: true }).filter((child) => child.isDirectory() && !child.name.startsWith(".") && !
|
|
1413
|
+
return readdirSync(dir, { withFileTypes: true }).filter((child) => child.isDirectory() && !child.name.startsWith(".") && !SKIPPED_FOLDERS.has(child.name)).map((child) => child.name).sort();
|
|
1414
1414
|
}
|
|
1415
1415
|
function up(dir) {
|
|
1416
1416
|
const dirs = [];
|
package/dist/dx-cli.js
CHANGED
|
@@ -627,7 +627,6 @@ var DASHES = /^-+/;
|
|
|
627
627
|
function jsonOption(holds) {
|
|
628
628
|
return { type: "boolean", description: holds === undefined ? "print JSON" : `print JSON: ${holds}` };
|
|
629
629
|
}
|
|
630
|
-
|
|
631
630
|
class Exit extends Error {
|
|
632
631
|
code;
|
|
633
632
|
hint;
|
|
@@ -1032,6 +1031,8 @@ function composeError({ code, stderr }) {
|
|
|
1032
1031
|
`).at(-1) ?? "";
|
|
1033
1032
|
return last === "" ? `exit ${code}` : last;
|
|
1034
1033
|
}
|
|
1034
|
+
// ../kit/src/folders.ts
|
|
1035
|
+
var SKIPPED_FOLDERS = new Set(["node_modules", "vendor", "dist", "build", "target", "coverage", "venv", "__pycache__"]);
|
|
1035
1036
|
// ../kit/src/secrets.ts
|
|
1036
1037
|
var SECRET_PART = /token|secret|passw|credential|private|dsn|apikey|accesskey|key$/i;
|
|
1037
1038
|
var SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "session", "jwt", "ssn", "iban", "card", "cvv", "otp"]);
|
|
@@ -1503,6 +1504,14 @@ var KEYS = {
|
|
|
1503
1504
|
"\x1B[B": "down",
|
|
1504
1505
|
"\x1BOB": "down",
|
|
1505
1506
|
"\x0E": "down",
|
|
1507
|
+
"\x1B[5~": "pageup",
|
|
1508
|
+
"\x1B[6~": "pagedown",
|
|
1509
|
+
"\x1B[H": "home",
|
|
1510
|
+
"\x1B[1~": "home",
|
|
1511
|
+
"\x1BOH": "home",
|
|
1512
|
+
"\x1B[F": "end",
|
|
1513
|
+
"\x1B[4~": "end",
|
|
1514
|
+
"\x1BOF": "end",
|
|
1506
1515
|
"\r": "enter",
|
|
1507
1516
|
"\n": "enter",
|
|
1508
1517
|
"\x03": "cancel",
|
|
@@ -1511,7 +1520,10 @@ var KEYS = {
|
|
|
1511
1520
|
"\b": "erase",
|
|
1512
1521
|
"\x15": "clear",
|
|
1513
1522
|
"\x17": "word",
|
|
1514
|
-
"\t": "tab"
|
|
1523
|
+
"\t": "tab",
|
|
1524
|
+
"\x1F": "help",
|
|
1525
|
+
"\x1BOP": "help",
|
|
1526
|
+
"\x1B[11~": "help"
|
|
1515
1527
|
};
|
|
1516
1528
|
var CTRL_KEY = /^ctrl-[abd-gkln-z]$/;
|
|
1517
1529
|
function repeat(value, count) {
|
|
@@ -1581,7 +1593,7 @@ function parseKeys(input, paste = { active: false }, ctrls = []) {
|
|
|
1581
1593
|
});
|
|
1582
1594
|
}
|
|
1583
1595
|
function createState(rows, { multi = false, prompt = "> ", query = "", header = "", expect = [], searched = Number.POSITIVE_INFINITY } = {}) {
|
|
1584
|
-
const state = { rows: [], items: [], styles: [], searchable: [], searched, header, expect, key: "", status: "", query, matches: [], cursor: 0, marked: new Set, multi, prompt, done: undefined };
|
|
1596
|
+
const state = { rows: [], items: [], styles: [], searchable: [], searched, header, expect, key: "", status: "", query, matches: [], cursor: 0, help: false, page: 10, marked: new Set, multi, prompt, done: undefined };
|
|
1585
1597
|
return withRows(state, rows);
|
|
1586
1598
|
}
|
|
1587
1599
|
function withRows(state, rows, header = state.header) {
|
|
@@ -1603,6 +1615,8 @@ function highlighted(state) {
|
|
|
1603
1615
|
function press(state, key) {
|
|
1604
1616
|
if (state.done !== undefined)
|
|
1605
1617
|
return state;
|
|
1618
|
+
if (state.help)
|
|
1619
|
+
return { ...state, help: false };
|
|
1606
1620
|
if (typeof key === "object") {
|
|
1607
1621
|
if ("text" in key)
|
|
1608
1622
|
return withQuery(state, state.query + key.text);
|
|
@@ -1613,8 +1627,18 @@ function press(state, key) {
|
|
|
1613
1627
|
return move(state, -1);
|
|
1614
1628
|
case "down":
|
|
1615
1629
|
return move(state, 1);
|
|
1630
|
+
case "pageup":
|
|
1631
|
+
return move(state, -state.page);
|
|
1632
|
+
case "pagedown":
|
|
1633
|
+
return move(state, state.page);
|
|
1634
|
+
case "home":
|
|
1635
|
+
return move(state, -state.matches.length);
|
|
1636
|
+
case "end":
|
|
1637
|
+
return move(state, state.matches.length);
|
|
1616
1638
|
case "cancel":
|
|
1617
1639
|
return { ...state, done: "cancel" };
|
|
1640
|
+
case "help":
|
|
1641
|
+
return { ...state, help: true };
|
|
1618
1642
|
case "erase":
|
|
1619
1643
|
return withQuery(state, [...state.query].slice(0, -1).join(""));
|
|
1620
1644
|
case "clear":
|
|
@@ -1794,7 +1818,18 @@ function fitStyled(line, width, plain = identity) {
|
|
|
1794
1818
|
function caretColumn(state, layout) {
|
|
1795
1819
|
return Math.min(layout.listWidth, Bun.stringWidth(state.prompt) + Bun.stringWidth(state.query) + 1);
|
|
1796
1820
|
}
|
|
1821
|
+
function helpLines(state, layout, theme) {
|
|
1822
|
+
const lines = [
|
|
1823
|
+
"type to filter, up, down, ctrl-p, ctrl-n, pgup, pgdn, home, end move",
|
|
1824
|
+
`enter picks${state.multi ? ", tab marks" : ""}, ctrl-u clears the query, ctrl-w a word, esc or ctrl-c cancels`,
|
|
1825
|
+
...state.expect.length > 0 ? [`${state.expect.join(", ")} end the pick as this command asks`] : []
|
|
1826
|
+
];
|
|
1827
|
+
const title = "keys, any key closes this help";
|
|
1828
|
+
return [{ text: theme.accent(title), width: title.length }, ...lines.map((line) => fit(` ${line}`, layout.listWidth, theme.label))];
|
|
1829
|
+
}
|
|
1797
1830
|
function listLines(state, layout, theme) {
|
|
1831
|
+
if (state.help)
|
|
1832
|
+
return helpLines(state, layout, theme);
|
|
1798
1833
|
const header = state.header === "" ? [] : state.header.split(`
|
|
1799
1834
|
`).map((line) => fitStyled(line, layout.listWidth, theme.label));
|
|
1800
1835
|
const rows = Math.max(1, layout.listHeight - 2 - header.length);
|
|
@@ -1803,7 +1838,8 @@ function listLines(state, layout, theme) {
|
|
|
1803
1838
|
const marks = (state.marked.size > 0 ? ` (${state.marked.size} marked)` : "") + (state.status === "" ? "" : ` ${state.status}`);
|
|
1804
1839
|
const promptWidth = Bun.stringWidth(state.prompt);
|
|
1805
1840
|
const query = fit(state.query, Math.max(1, layout.listWidth - promptWidth), identity);
|
|
1806
|
-
const
|
|
1841
|
+
const place = state.matches.length > rows ? ` (${state.cursor + 1} of ${state.matches.length})` : "";
|
|
1842
|
+
const count = fit(` ${state.matches.length}/${state.items.length}${place}${marks}`, layout.listWidth, theme.label);
|
|
1807
1843
|
const lines = [{ text: theme.accent(state.prompt) + query.text, width: promptWidth + query.width }, count, ...header];
|
|
1808
1844
|
if (state.matches.length === 0)
|
|
1809
1845
|
lines.push(fit(" no match", layout.listWidth, theme.label));
|
|
@@ -1830,6 +1866,7 @@ function render(state, layout, theme, preview = []) {
|
|
|
1830
1866
|
|
|
1831
1867
|
// ../kit/src/picker/terminal.ts
|
|
1832
1868
|
var PREVIEW_DELAY_MS = 120;
|
|
1869
|
+
var ESCAPE_WAIT_MS = 30;
|
|
1833
1870
|
var OPEN = { ctrl: "open" };
|
|
1834
1871
|
var HIDE_CURSOR = "\x1B[?25l";
|
|
1835
1872
|
var SHOW_CURSOR = "\x1B[?25h";
|
|
@@ -1885,20 +1922,29 @@ async function select(rows, settings, terminal = openTerminal()) {
|
|
|
1885
1922
|
let shownLine;
|
|
1886
1923
|
let finish;
|
|
1887
1924
|
let restored = false;
|
|
1925
|
+
let escape;
|
|
1926
|
+
let caret;
|
|
1888
1927
|
function draw(clear = false) {
|
|
1889
1928
|
if (restored)
|
|
1890
1929
|
return;
|
|
1891
1930
|
const layout = layoutFor({ columns: terminal.columns, rows: terminal.rows }, settings.height, settings.preview !== undefined, settings.previewPosition);
|
|
1892
1931
|
let frame = HIDE_CURSOR;
|
|
1893
1932
|
if (reserved !== layout.height || clear) {
|
|
1933
|
+
frame += clear && caret !== undefined ? up(Math.floor((caret - 1) / terminal.columns)) : "";
|
|
1894
1934
|
frame += CLEAR_BELOW + `
|
|
1895
1935
|
`.repeat(layout.height - 1) + up(layout.height - 1);
|
|
1896
1936
|
reserved = layout.height;
|
|
1897
1937
|
}
|
|
1938
|
+
caret = caretColumn(state, layout);
|
|
1898
1939
|
frame += `\r${render(state, layout, theme, preview).map((line) => `\x1B[2K${line}`).join(`
|
|
1899
|
-
`)}${up(layout.height - 1)}\r\x1B[${
|
|
1940
|
+
`)}${up(layout.height - 1)}\r\x1B[${caret}G${SHOW_CURSOR}`;
|
|
1900
1941
|
terminal.write(frame);
|
|
1901
1942
|
}
|
|
1943
|
+
function pageSize() {
|
|
1944
|
+
const headerLines = state.header === "" ? 0 : state.header.split(`
|
|
1945
|
+
`).length;
|
|
1946
|
+
return Math.max(1, layoutFor({ columns: terminal.columns, rows: terminal.rows }, settings.height, settings.preview !== undefined, settings.previewPosition).listHeight - 2 - headerLines);
|
|
1947
|
+
}
|
|
1902
1948
|
function refreshPreview() {
|
|
1903
1949
|
const at = highlighted(state);
|
|
1904
1950
|
if (settings.preview === undefined || at === shownLine)
|
|
@@ -1928,6 +1974,7 @@ async function select(rows, settings, terminal = openTerminal()) {
|
|
|
1928
1974
|
return;
|
|
1929
1975
|
restored = true;
|
|
1930
1976
|
clearTimeout(previewTimer);
|
|
1977
|
+
clearTimeout(escape);
|
|
1931
1978
|
previewing.abort();
|
|
1932
1979
|
terminal.write(`${CLEAR_BELOW}${PASTE_OFF}${SHOW_CURSOR}`);
|
|
1933
1980
|
terminal.close();
|
|
@@ -1966,7 +2013,7 @@ async function select(rows, settings, terminal = openTerminal()) {
|
|
|
1966
2013
|
if (key === OPEN || typeof key === "object" && "ctrl" in key && key.ctrl === reload?.key)
|
|
1967
2014
|
await reloadRows();
|
|
1968
2015
|
else
|
|
1969
|
-
state = press(state, key);
|
|
2016
|
+
state = press({ ...state, page: pageSize() }, key);
|
|
1970
2017
|
}
|
|
1971
2018
|
} finally {
|
|
1972
2019
|
draining = false;
|
|
@@ -1979,6 +2026,20 @@ async function select(rows, settings, terminal = openTerminal()) {
|
|
|
1979
2026
|
draw();
|
|
1980
2027
|
}
|
|
1981
2028
|
function onChunk(chunk) {
|
|
2029
|
+
if (escape !== undefined) {
|
|
2030
|
+
clearTimeout(escape);
|
|
2031
|
+
escape = undefined;
|
|
2032
|
+
chunk = `\x1B${chunk}`;
|
|
2033
|
+
} else if (chunk === "\x1B") {
|
|
2034
|
+
escape = setTimeout(() => {
|
|
2035
|
+
escape = undefined;
|
|
2036
|
+
takeKeys("\x1B");
|
|
2037
|
+
}, ESCAPE_WAIT_MS);
|
|
2038
|
+
return;
|
|
2039
|
+
}
|
|
2040
|
+
takeKeys(chunk);
|
|
2041
|
+
}
|
|
2042
|
+
function takeKeys(chunk) {
|
|
1982
2043
|
const keys = parseKeys(chunk, paste, [...settings.expect ?? [], ...reload?.key === undefined ? [] : [reload.key]]);
|
|
1983
2044
|
if (busy && keys.includes("cancel")) {
|
|
1984
2045
|
stop();
|
|
@@ -2092,13 +2153,12 @@ import { dirname as dirname6, join as join8, relative, resolve as resolve3 } fro
|
|
|
2092
2153
|
var LABEL_FORMAT = ["project", "project.config_files", "project.environment_file", "project.working_dir"].map((label) => `{{.Label "com.docker.compose.${label}"}}`).join("\t");
|
|
2093
2154
|
var COMPOSE_FILE_VAR = /^\s*(?:export\s+)?COMPOSE_FILE\s*=\s*\S/m;
|
|
2094
2155
|
var COMPOSE_FILES = ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"];
|
|
2095
|
-
var SKIPPED2 = new Set(["node_modules", "vendor", "dist", "build", "target", "venv", "__pycache__"]);
|
|
2096
2156
|
var ACTIONS = ["shell", "logs", "restart", "up", "stop", "build"];
|
|
2097
2157
|
function from(dir, command) {
|
|
2098
2158
|
return dir === "." ? command : ["env", "-C", dir, ...command];
|
|
2099
2159
|
}
|
|
2100
2160
|
function children(dir = ".") {
|
|
2101
|
-
return readdirSync(dir, { withFileTypes: true }).filter((child) => child.isDirectory() && !child.name.startsWith(".") && !
|
|
2161
|
+
return readdirSync(dir, { withFileTypes: true }).filter((child) => child.isDirectory() && !child.name.startsWith(".") && !SKIPPED_FOLDERS.has(child.name)).map((child) => child.name).sort();
|
|
2102
2162
|
}
|
|
2103
2163
|
function up2(dir) {
|
|
2104
2164
|
const dirs = [];
|
package/dist/sf-cli.js
CHANGED
|
@@ -627,7 +627,6 @@ var DASHES = /^-+/;
|
|
|
627
627
|
function jsonOption(holds) {
|
|
628
628
|
return { type: "boolean", description: holds === undefined ? "print JSON" : `print JSON: ${holds}` };
|
|
629
629
|
}
|
|
630
|
-
|
|
631
630
|
class Exit extends Error {
|
|
632
631
|
code;
|
|
633
632
|
hint;
|
|
@@ -1032,6 +1031,8 @@ function composeError({ code, stderr }) {
|
|
|
1032
1031
|
`).at(-1) ?? "";
|
|
1033
1032
|
return last === "" ? `exit ${code}` : last;
|
|
1034
1033
|
}
|
|
1034
|
+
// ../kit/src/folders.ts
|
|
1035
|
+
var SKIPPED_FOLDERS = new Set(["node_modules", "vendor", "dist", "build", "target", "coverage", "venv", "__pycache__"]);
|
|
1035
1036
|
// ../kit/src/secrets.ts
|
|
1036
1037
|
var SECRET_PART = /token|secret|passw|credential|private|dsn|apikey|accesskey|key$/i;
|
|
1037
1038
|
var SECRET_WORDS = new Set(["key", "pass", "pwd", "auth", "salt", "cookie", "session", "jwt", "ssn", "iban", "card", "cvv", "otp"]);
|
|
@@ -1156,6 +1157,14 @@ var KEYS = {
|
|
|
1156
1157
|
"\x1B[B": "down",
|
|
1157
1158
|
"\x1BOB": "down",
|
|
1158
1159
|
"\x0E": "down",
|
|
1160
|
+
"\x1B[5~": "pageup",
|
|
1161
|
+
"\x1B[6~": "pagedown",
|
|
1162
|
+
"\x1B[H": "home",
|
|
1163
|
+
"\x1B[1~": "home",
|
|
1164
|
+
"\x1BOH": "home",
|
|
1165
|
+
"\x1B[F": "end",
|
|
1166
|
+
"\x1B[4~": "end",
|
|
1167
|
+
"\x1BOF": "end",
|
|
1159
1168
|
"\r": "enter",
|
|
1160
1169
|
"\n": "enter",
|
|
1161
1170
|
"\x03": "cancel",
|
|
@@ -1164,7 +1173,10 @@ var KEYS = {
|
|
|
1164
1173
|
"\b": "erase",
|
|
1165
1174
|
"\x15": "clear",
|
|
1166
1175
|
"\x17": "word",
|
|
1167
|
-
"\t": "tab"
|
|
1176
|
+
"\t": "tab",
|
|
1177
|
+
"\x1F": "help",
|
|
1178
|
+
"\x1BOP": "help",
|
|
1179
|
+
"\x1B[11~": "help"
|
|
1168
1180
|
};
|
|
1169
1181
|
var CTRL_KEY = /^ctrl-[abd-gkln-z]$/;
|
|
1170
1182
|
function repeat(value, count) {
|
|
@@ -1234,7 +1246,7 @@ function parseKeys(input, paste = { active: false }, ctrls = []) {
|
|
|
1234
1246
|
});
|
|
1235
1247
|
}
|
|
1236
1248
|
function createState(rows, { multi = false, prompt = "> ", query = "", header = "", expect = [], searched = Number.POSITIVE_INFINITY } = {}) {
|
|
1237
|
-
const state = { rows: [], items: [], styles: [], searchable: [], searched, header, expect, key: "", status: "", query, matches: [], cursor: 0, marked: new Set, multi, prompt, done: undefined };
|
|
1249
|
+
const state = { rows: [], items: [], styles: [], searchable: [], searched, header, expect, key: "", status: "", query, matches: [], cursor: 0, help: false, page: 10, marked: new Set, multi, prompt, done: undefined };
|
|
1238
1250
|
return withRows(state, rows);
|
|
1239
1251
|
}
|
|
1240
1252
|
function withRows(state, rows, header = state.header) {
|
|
@@ -1256,6 +1268,8 @@ function highlighted(state) {
|
|
|
1256
1268
|
function press(state, key) {
|
|
1257
1269
|
if (state.done !== undefined)
|
|
1258
1270
|
return state;
|
|
1271
|
+
if (state.help)
|
|
1272
|
+
return { ...state, help: false };
|
|
1259
1273
|
if (typeof key === "object") {
|
|
1260
1274
|
if ("text" in key)
|
|
1261
1275
|
return withQuery(state, state.query + key.text);
|
|
@@ -1266,8 +1280,18 @@ function press(state, key) {
|
|
|
1266
1280
|
return move(state, -1);
|
|
1267
1281
|
case "down":
|
|
1268
1282
|
return move(state, 1);
|
|
1283
|
+
case "pageup":
|
|
1284
|
+
return move(state, -state.page);
|
|
1285
|
+
case "pagedown":
|
|
1286
|
+
return move(state, state.page);
|
|
1287
|
+
case "home":
|
|
1288
|
+
return move(state, -state.matches.length);
|
|
1289
|
+
case "end":
|
|
1290
|
+
return move(state, state.matches.length);
|
|
1269
1291
|
case "cancel":
|
|
1270
1292
|
return { ...state, done: "cancel" };
|
|
1293
|
+
case "help":
|
|
1294
|
+
return { ...state, help: true };
|
|
1271
1295
|
case "erase":
|
|
1272
1296
|
return withQuery(state, [...state.query].slice(0, -1).join(""));
|
|
1273
1297
|
case "clear":
|
|
@@ -1447,7 +1471,18 @@ function fitStyled(line, width, plain = identity) {
|
|
|
1447
1471
|
function caretColumn(state, layout) {
|
|
1448
1472
|
return Math.min(layout.listWidth, Bun.stringWidth(state.prompt) + Bun.stringWidth(state.query) + 1);
|
|
1449
1473
|
}
|
|
1474
|
+
function helpLines(state, layout, theme) {
|
|
1475
|
+
const lines = [
|
|
1476
|
+
"type to filter, up, down, ctrl-p, ctrl-n, pgup, pgdn, home, end move",
|
|
1477
|
+
`enter picks${state.multi ? ", tab marks" : ""}, ctrl-u clears the query, ctrl-w a word, esc or ctrl-c cancels`,
|
|
1478
|
+
...state.expect.length > 0 ? [`${state.expect.join(", ")} end the pick as this command asks`] : []
|
|
1479
|
+
];
|
|
1480
|
+
const title = "keys, any key closes this help";
|
|
1481
|
+
return [{ text: theme.accent(title), width: title.length }, ...lines.map((line) => fit(` ${line}`, layout.listWidth, theme.label))];
|
|
1482
|
+
}
|
|
1450
1483
|
function listLines(state, layout, theme) {
|
|
1484
|
+
if (state.help)
|
|
1485
|
+
return helpLines(state, layout, theme);
|
|
1451
1486
|
const header = state.header === "" ? [] : state.header.split(`
|
|
1452
1487
|
`).map((line) => fitStyled(line, layout.listWidth, theme.label));
|
|
1453
1488
|
const rows = Math.max(1, layout.listHeight - 2 - header.length);
|
|
@@ -1456,7 +1491,8 @@ function listLines(state, layout, theme) {
|
|
|
1456
1491
|
const marks = (state.marked.size > 0 ? ` (${state.marked.size} marked)` : "") + (state.status === "" ? "" : ` ${state.status}`);
|
|
1457
1492
|
const promptWidth = Bun.stringWidth(state.prompt);
|
|
1458
1493
|
const query = fit(state.query, Math.max(1, layout.listWidth - promptWidth), identity);
|
|
1459
|
-
const
|
|
1494
|
+
const place = state.matches.length > rows ? ` (${state.cursor + 1} of ${state.matches.length})` : "";
|
|
1495
|
+
const count = fit(` ${state.matches.length}/${state.items.length}${place}${marks}`, layout.listWidth, theme.label);
|
|
1460
1496
|
const lines = [{ text: theme.accent(state.prompt) + query.text, width: promptWidth + query.width }, count, ...header];
|
|
1461
1497
|
if (state.matches.length === 0)
|
|
1462
1498
|
lines.push(fit(" no match", layout.listWidth, theme.label));
|
|
@@ -1483,6 +1519,7 @@ function render(state, layout, theme, preview = []) {
|
|
|
1483
1519
|
|
|
1484
1520
|
// ../kit/src/picker/terminal.ts
|
|
1485
1521
|
var PREVIEW_DELAY_MS = 120;
|
|
1522
|
+
var ESCAPE_WAIT_MS = 30;
|
|
1486
1523
|
var OPEN = { ctrl: "open" };
|
|
1487
1524
|
var HIDE_CURSOR = "\x1B[?25l";
|
|
1488
1525
|
var SHOW_CURSOR = "\x1B[?25h";
|
|
@@ -1538,20 +1575,29 @@ async function select(rows, settings, terminal = openTerminal()) {
|
|
|
1538
1575
|
let shownLine;
|
|
1539
1576
|
let finish;
|
|
1540
1577
|
let restored = false;
|
|
1578
|
+
let escape;
|
|
1579
|
+
let caret;
|
|
1541
1580
|
function draw(clear = false) {
|
|
1542
1581
|
if (restored)
|
|
1543
1582
|
return;
|
|
1544
1583
|
const layout = layoutFor({ columns: terminal.columns, rows: terminal.rows }, settings.height, settings.preview !== undefined, settings.previewPosition);
|
|
1545
1584
|
let frame = HIDE_CURSOR;
|
|
1546
1585
|
if (reserved !== layout.height || clear) {
|
|
1586
|
+
frame += clear && caret !== undefined ? up(Math.floor((caret - 1) / terminal.columns)) : "";
|
|
1547
1587
|
frame += CLEAR_BELOW + `
|
|
1548
1588
|
`.repeat(layout.height - 1) + up(layout.height - 1);
|
|
1549
1589
|
reserved = layout.height;
|
|
1550
1590
|
}
|
|
1591
|
+
caret = caretColumn(state, layout);
|
|
1551
1592
|
frame += `\r${render(state, layout, theme, preview).map((line) => `\x1B[2K${line}`).join(`
|
|
1552
|
-
`)}${up(layout.height - 1)}\r\x1B[${
|
|
1593
|
+
`)}${up(layout.height - 1)}\r\x1B[${caret}G${SHOW_CURSOR}`;
|
|
1553
1594
|
terminal.write(frame);
|
|
1554
1595
|
}
|
|
1596
|
+
function pageSize() {
|
|
1597
|
+
const headerLines = state.header === "" ? 0 : state.header.split(`
|
|
1598
|
+
`).length;
|
|
1599
|
+
return Math.max(1, layoutFor({ columns: terminal.columns, rows: terminal.rows }, settings.height, settings.preview !== undefined, settings.previewPosition).listHeight - 2 - headerLines);
|
|
1600
|
+
}
|
|
1555
1601
|
function refreshPreview() {
|
|
1556
1602
|
const at = highlighted(state);
|
|
1557
1603
|
if (settings.preview === undefined || at === shownLine)
|
|
@@ -1581,6 +1627,7 @@ async function select(rows, settings, terminal = openTerminal()) {
|
|
|
1581
1627
|
return;
|
|
1582
1628
|
restored = true;
|
|
1583
1629
|
clearTimeout(previewTimer);
|
|
1630
|
+
clearTimeout(escape);
|
|
1584
1631
|
previewing.abort();
|
|
1585
1632
|
terminal.write(`${CLEAR_BELOW}${PASTE_OFF}${SHOW_CURSOR}`);
|
|
1586
1633
|
terminal.close();
|
|
@@ -1619,7 +1666,7 @@ async function select(rows, settings, terminal = openTerminal()) {
|
|
|
1619
1666
|
if (key === OPEN || typeof key === "object" && "ctrl" in key && key.ctrl === reload?.key)
|
|
1620
1667
|
await reloadRows();
|
|
1621
1668
|
else
|
|
1622
|
-
state = press(state, key);
|
|
1669
|
+
state = press({ ...state, page: pageSize() }, key);
|
|
1623
1670
|
}
|
|
1624
1671
|
} finally {
|
|
1625
1672
|
draining = false;
|
|
@@ -1632,6 +1679,20 @@ async function select(rows, settings, terminal = openTerminal()) {
|
|
|
1632
1679
|
draw();
|
|
1633
1680
|
}
|
|
1634
1681
|
function onChunk(chunk) {
|
|
1682
|
+
if (escape !== undefined) {
|
|
1683
|
+
clearTimeout(escape);
|
|
1684
|
+
escape = undefined;
|
|
1685
|
+
chunk = `\x1B${chunk}`;
|
|
1686
|
+
} else if (chunk === "\x1B") {
|
|
1687
|
+
escape = setTimeout(() => {
|
|
1688
|
+
escape = undefined;
|
|
1689
|
+
takeKeys("\x1B");
|
|
1690
|
+
}, ESCAPE_WAIT_MS);
|
|
1691
|
+
return;
|
|
1692
|
+
}
|
|
1693
|
+
takeKeys(chunk);
|
|
1694
|
+
}
|
|
1695
|
+
function takeKeys(chunk) {
|
|
1635
1696
|
const keys = parseKeys(chunk, paste, [...settings.expect ?? [], ...reload?.key === undefined ? [] : [reload.key]]);
|
|
1636
1697
|
if (busy && keys.includes("cancel")) {
|
|
1637
1698
|
stop();
|
|
@@ -1738,11 +1799,9 @@ function list(rows) {
|
|
|
1738
1799
|
|
|
1739
1800
|
// ../kit/src/prompt.ts
|
|
1740
1801
|
import process16 from "process";
|
|
1741
|
-
var
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
function readKeys(input) {
|
|
1745
|
-
return (input.match(KEY_SEQUENCES2) ?? []).flatMap((sequence) => KEYS2[sequence] ?? (CONTROL3.test(sequence) ? [] : [{ text: sequence }]));
|
|
1802
|
+
var PROMPT_KEYS = new Set(["up", "down", "pageup", "pagedown", "home", "end", "enter", "cancel", "erase"]);
|
|
1803
|
+
function readKeys(input, paste = { active: false }) {
|
|
1804
|
+
return parseKeys(input, paste).filter((key) => typeof key === "object" ? "text" in key : PROMPT_KEYS.has(key));
|
|
1746
1805
|
}
|
|
1747
1806
|
async function input2(question, { default: fallback, mask = false, validate, ...settings } = {}) {
|
|
1748
1807
|
let value = "";
|
|
@@ -1781,22 +1840,29 @@ async function ask(question, { hint, terminal = process16 }, render, press) {
|
|
|
1781
1840
|
if (!isInteractive(terminal))
|
|
1782
1841
|
fail(`cannot ask "${question}" off a terminal`, 2, hint);
|
|
1783
1842
|
const colors = paint(stderr);
|
|
1784
|
-
let drawn =
|
|
1843
|
+
let drawn = [];
|
|
1844
|
+
let current = "asking";
|
|
1785
1845
|
let outcome;
|
|
1846
|
+
const columns = () => stderr.columns || 80;
|
|
1786
1847
|
const draw = (state) => {
|
|
1787
|
-
const frame = render(colors, state, { columns:
|
|
1788
|
-
|
|
1848
|
+
const frame = render(colors, state, { columns: columns(), rows: stderr.rows || 24 });
|
|
1849
|
+
const rows = drawn.reduce((sum, line) => sum + Math.max(1, Math.ceil(Bun.stringWidth(line) / columns())), 0);
|
|
1850
|
+
stderr.write(`${rows > 1 ? `\x1B[${rows - 1}A` : ""}\r\x1B[0J${frame.join(`
|
|
1789
1851
|
`)}`);
|
|
1790
|
-
drawn = frame
|
|
1852
|
+
drawn = frame;
|
|
1853
|
+
current = state;
|
|
1791
1854
|
};
|
|
1855
|
+
const redraw = () => draw(current);
|
|
1856
|
+
const paste = { active: false };
|
|
1792
1857
|
try {
|
|
1858
|
+
stderr.on?.("resize", redraw);
|
|
1793
1859
|
stdin.setRawMode(true);
|
|
1794
1860
|
stdin.resume();
|
|
1795
|
-
stderr.write("\x1B[?25l");
|
|
1861
|
+
stderr.write("\x1B[?25l\x1B[?2004h");
|
|
1796
1862
|
draw("asking");
|
|
1797
1863
|
return await new Promise((resolve) => {
|
|
1798
1864
|
function onData(data) {
|
|
1799
|
-
for (const key of readKeys(data.toString())) {
|
|
1865
|
+
for (const key of readKeys(data.toString(), paste)) {
|
|
1800
1866
|
const pressed = press(key);
|
|
1801
1867
|
if (pressed !== undefined) {
|
|
1802
1868
|
settle(pressed);
|
|
@@ -1818,9 +1884,10 @@ async function ask(question, { hint, terminal = process16 }, render, press) {
|
|
|
1818
1884
|
stdin.on("end", onEnd);
|
|
1819
1885
|
});
|
|
1820
1886
|
} finally {
|
|
1887
|
+
stderr.off?.("resize", redraw);
|
|
1821
1888
|
draw(outcome ?? "cancel");
|
|
1822
1889
|
stderr.write(`
|
|
1823
|
-
\x1B[?25h`);
|
|
1890
|
+
\x1B[?25h\x1B[?2004l`);
|
|
1824
1891
|
stdin.setRawMode(false);
|
|
1825
1892
|
stdin.pause();
|
|
1826
1893
|
}
|
|
@@ -2184,13 +2251,12 @@ class Redactor {
|
|
|
2184
2251
|
var LABEL_FORMAT = ["project", "project.config_files", "project.environment_file", "project.working_dir"].map((label) => `{{.Label "com.docker.compose.${label}"}}`).join("\t");
|
|
2185
2252
|
var COMPOSE_FILE_VAR = /^\s*(?:export\s+)?COMPOSE_FILE\s*=\s*\S/m;
|
|
2186
2253
|
var COMPOSE_FILES = ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"];
|
|
2187
|
-
var SKIPPED2 = new Set(["node_modules", "vendor", "dist", "build", "target", "venv", "__pycache__"]);
|
|
2188
2254
|
var ACTIONS = ["shell", "logs", "restart", "up", "stop", "build"];
|
|
2189
2255
|
function from(dir, command) {
|
|
2190
2256
|
return dir === "." ? command : ["env", "-C", dir, ...command];
|
|
2191
2257
|
}
|
|
2192
2258
|
function children(dir = ".") {
|
|
2193
|
-
return readdirSync(dir, { withFileTypes: true }).filter((child) => child.isDirectory() && !child.name.startsWith(".") && !
|
|
2259
|
+
return readdirSync(dir, { withFileTypes: true }).filter((child) => child.isDirectory() && !child.name.startsWith(".") && !SKIPPED_FOLDERS.has(child.name)).map((child) => child.name).sort();
|
|
2194
2260
|
}
|
|
2195
2261
|
function up2(dir) {
|
|
2196
2262
|
const dirs = [];
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaynooo/cli-docker",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"description": "dc, dx, dlog and sf: docker compose on the stack found here, including one only its containers tell of, a compose service's shell, logs, restart, stop or rebuild, every service's health and recent errors in one call, and a Symfony console command picked and run.",
|
|
6
6
|
"author": "Kaynooo <contact@kaynooo.fr>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"sf": "$npm_execpath src/sf-cli.ts"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@kaynooo/cli-env": "0.
|
|
41
|
-
"@kaynooo/cli-kit": "0.
|
|
40
|
+
"@kaynooo/cli-env": "0.12.0",
|
|
41
|
+
"@kaynooo/cli-kit": "0.26.0"
|
|
42
42
|
}
|
|
43
43
|
}
|
package/src/stack.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
|
3
3
|
import { dirname, join, relative, resolve } from 'node:path'
|
|
4
4
|
import { loadKnown } from '@kaynooo/cli-env/files'
|
|
5
5
|
import { Redactor } from '@kaynooo/cli-env/redactor'
|
|
6
|
-
import { captureOutput, composeError } from '@kaynooo/cli-kit'
|
|
6
|
+
import { captureOutput, composeError, SKIPPED_FOLDERS } from '@kaynooo/cli-kit'
|
|
7
7
|
|
|
8
8
|
/** How to reach one compose project: the command a user runs, and the one this package lists it with. */
|
|
9
9
|
export interface Stack {
|
|
@@ -54,7 +54,6 @@ export interface Container {
|
|
|
54
54
|
const LABEL_FORMAT = ['project', 'project.config_files', 'project.environment_file', 'project.working_dir'].map(label => `{{.Label "com.docker.compose.${label}"}}`).join('\t')
|
|
55
55
|
const COMPOSE_FILE_VAR = /^\s*(?:export\s+)?COMPOSE_FILE\s*=\s*\S/m
|
|
56
56
|
const COMPOSE_FILES = ['compose.yaml', 'compose.yml', 'docker-compose.yaml', 'docker-compose.yml']
|
|
57
|
-
const SKIPPED = new Set(['node_modules', 'vendor', 'dist', 'build', 'target', 'venv', '__pycache__'])
|
|
58
57
|
|
|
59
58
|
export const ACTIONS: Action[] = ['shell', 'logs', 'restart', 'up', 'stop', 'build']
|
|
60
59
|
|
|
@@ -66,7 +65,7 @@ export function from(dir: string, command: string[]): string[] {
|
|
|
66
65
|
/** The direct child folders, hidden and built ones aside. */
|
|
67
66
|
export function children(dir = '.'): string[] {
|
|
68
67
|
return readdirSync(dir, { withFileTypes: true })
|
|
69
|
-
.filter(child => child.isDirectory() && !child.name.startsWith('.') && !
|
|
68
|
+
.filter(child => child.isDirectory() && !child.name.startsWith('.') && !SKIPPED_FOLDERS.has(child.name))
|
|
70
69
|
.map(child => child.name)
|
|
71
70
|
.sort()
|
|
72
71
|
}
|