@kaynooo/cli-docker 0.2.0 → 0.4.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/README.md +7 -1
- package/dist/dc-cli.js +14 -3
- package/dist/dlog-cli.js +1164 -0
- package/dist/dx-cli.js +103 -57
- package/dist/sf-cli.js +1339 -0
- package/package.json +10 -5
- package/src/dlog-cli.ts +8 -0
- package/src/dlog.ts +179 -0
- package/src/dx.ts +5 -5
- package/src/picker.ts +15 -45
- package/src/sf-cli.ts +8 -0
- package/src/sf.ts +368 -0
- package/src/stack.ts +19 -5
- package/src/history.ts +0 -48
package/dist/dx-cli.js
CHANGED
|
@@ -349,6 +349,9 @@ function optionRows(options, colors = paint(process3.stdout)) {
|
|
|
349
349
|
|
|
350
350
|
// ../kit/src/text.ts
|
|
351
351
|
var ANSI = new RegExp(`${String.fromCharCode(27)}\\[[\\d;?]*[a-z]`, "gi");
|
|
352
|
+
function stripAnsi(text) {
|
|
353
|
+
return text.replace(ANSI, "");
|
|
354
|
+
}
|
|
352
355
|
function distance(a, b) {
|
|
353
356
|
let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
|
|
354
357
|
for (const [i, left] of [...a].entries()) {
|
|
@@ -745,34 +748,86 @@ var {Glob } = globalThis.Bun;
|
|
|
745
748
|
var SESSION_FILES = new Glob("*.json");
|
|
746
749
|
var ACCOUNT_DIRS = new Glob("*/sessions");
|
|
747
750
|
// package.json
|
|
748
|
-
var version = "0.
|
|
751
|
+
var version = "0.4.0";
|
|
749
752
|
|
|
750
753
|
// src/dx.ts
|
|
751
754
|
import process10 from "process";
|
|
752
755
|
|
|
753
|
-
// src/
|
|
756
|
+
// ../kit/src/fzf.ts
|
|
754
757
|
import { existsSync, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
|
|
755
758
|
import { homedir as homedir2 } from "os";
|
|
756
759
|
import { dirname as dirname2, join as join2 } from "path";
|
|
757
760
|
import process8 from "process";
|
|
758
761
|
var REMEMBERED = 20;
|
|
759
|
-
function
|
|
760
|
-
|
|
762
|
+
function table(rows) {
|
|
763
|
+
const widths = rows[0]?.cells.map((_, index) => Math.max(...rows.map((row) => Bun.stringWidth(row.cells[index])))) ?? [];
|
|
764
|
+
return rows.map((row) => [
|
|
765
|
+
...row.hidden,
|
|
766
|
+
...row.cells.map((cell, index) => index === row.cells.length - 1 ? cell.trimEnd() : `${cell}${" ".repeat(widths[index] + 1 - Bun.stringWidth(cell))}`)
|
|
767
|
+
].join("\t"));
|
|
768
|
+
}
|
|
769
|
+
function fzf(rows, options) {
|
|
770
|
+
const hidden = options.hidden ?? rows[0]?.hidden.length ?? 0;
|
|
771
|
+
const proc = Bun.spawnSync([
|
|
772
|
+
"fzf",
|
|
773
|
+
"--prompt",
|
|
774
|
+
options.prompt,
|
|
775
|
+
...options.header === undefined ? [] : ["--header", options.header],
|
|
776
|
+
...(options.expect ?? []).length > 0 ? ["--expect", (options.expect ?? []).join(",")] : [],
|
|
777
|
+
"--ansi",
|
|
778
|
+
"--reverse",
|
|
779
|
+
"--height",
|
|
780
|
+
options.height ?? "100%",
|
|
781
|
+
"--delimiter",
|
|
782
|
+
"\t",
|
|
783
|
+
"--with-nth",
|
|
784
|
+
`${hidden + 1}..`,
|
|
785
|
+
"--nth",
|
|
786
|
+
`1..${options.searched}`,
|
|
787
|
+
"--tabstop",
|
|
788
|
+
"1",
|
|
789
|
+
"--tiebreak",
|
|
790
|
+
"chunk,index",
|
|
791
|
+
...options.preview === undefined ? [] : ["--preview", options.preview, "--preview-window", "down,40%"],
|
|
792
|
+
...(options.bind ?? []).flatMap((bind) => ["--bind", bind]),
|
|
793
|
+
...options.query === true ? ["--print-query"] : []
|
|
794
|
+
], {
|
|
795
|
+
stdin: new TextEncoder().encode(table(rows).join(`
|
|
796
|
+
`)),
|
|
797
|
+
stdout: "pipe",
|
|
798
|
+
stderr: "inherit"
|
|
799
|
+
});
|
|
800
|
+
return picked(proc.stdout.toString(), hidden, options);
|
|
801
|
+
}
|
|
802
|
+
function picked(output, hidden, options) {
|
|
803
|
+
const lines = output.split(`
|
|
804
|
+
`);
|
|
805
|
+
const query = options.query === true ? lines.shift() : "";
|
|
806
|
+
const [key, line] = (options.expect ?? []).length > 0 ? [lines[0], lines[1]] : ["", lines[0]];
|
|
807
|
+
if (line !== undefined && line !== "")
|
|
808
|
+
return { key, hidden: line.split("\t").slice(0, hidden), query };
|
|
809
|
+
return options.query === true && key !== "" ? { key, hidden: [], query } : undefined;
|
|
810
|
+
}
|
|
811
|
+
function heightFor(count) {
|
|
812
|
+
return String(Math.max(15, Math.ceil((count + 4) / 0.6)));
|
|
813
|
+
}
|
|
814
|
+
function historyFile(name) {
|
|
815
|
+
return join2(process8.env.XDG_CACHE_HOME ?? join2(homedir2(), ".cache"), name, "history.json");
|
|
761
816
|
}
|
|
762
|
-
function history() {
|
|
817
|
+
function history(name) {
|
|
763
818
|
try {
|
|
764
|
-
const file = historyFile();
|
|
819
|
+
const file = historyFile(name);
|
|
765
820
|
return existsSync(file) ? JSON.parse(readFileSync(file, "utf-8")) : {};
|
|
766
821
|
} catch {
|
|
767
822
|
return {};
|
|
768
823
|
}
|
|
769
824
|
}
|
|
770
|
-
function runs() {
|
|
771
|
-
return history()[process8.cwd()] ?? [];
|
|
825
|
+
function runs(name) {
|
|
826
|
+
return history(name)[process8.cwd()] ?? [];
|
|
772
827
|
}
|
|
773
|
-
function record(run) {
|
|
774
|
-
const all = history();
|
|
775
|
-
const file = historyFile();
|
|
828
|
+
function record(name, run) {
|
|
829
|
+
const all = history(name);
|
|
830
|
+
const file = historyFile(name);
|
|
776
831
|
all[process8.cwd()] = [run, ...(all[process8.cwd()] ?? []).filter((earlier) => earlier.id !== run.id)].slice(0, REMEMBERED);
|
|
777
832
|
mkdirSync2(dirname2(file), { recursive: true });
|
|
778
833
|
writeFileSync(file, JSON.stringify(all));
|
|
@@ -782,6 +837,19 @@ function byRecency(items, previous, idOf) {
|
|
|
782
837
|
const recent = items.filter((item) => rank.has(idOf(item))).sort((a, b) => rank.get(idOf(a)) - rank.get(idOf(b)));
|
|
783
838
|
return [...recent, ...items.filter((item) => !rank.has(idOf(item)))];
|
|
784
839
|
}
|
|
840
|
+
function word(arg) {
|
|
841
|
+
if (typeof arg === "string")
|
|
842
|
+
return `=${arg}`;
|
|
843
|
+
return "given" in arg ? `+${arg.given}` : `?${arg.ask}`;
|
|
844
|
+
}
|
|
845
|
+
function emit(mode, typed, recorded, command) {
|
|
846
|
+
const words = command.map(word);
|
|
847
|
+
console.log([mode, typed, recorded, ...words].join(`
|
|
848
|
+
`));
|
|
849
|
+
}
|
|
850
|
+
function list(rows) {
|
|
851
|
+
console.log(JSON.stringify(rows));
|
|
852
|
+
}
|
|
785
853
|
|
|
786
854
|
// src/picker.ts
|
|
787
855
|
import process9 from "process";
|
|
@@ -863,9 +931,17 @@ async function recordedNearby() {
|
|
|
863
931
|
const dirs = new Set([...up("."), ...children()].map((dir) => resolve(dir)));
|
|
864
932
|
return (await labels()).filter((stack) => dirs.has(stack.workdir));
|
|
865
933
|
}
|
|
866
|
-
async function
|
|
934
|
+
async function attempt(stack, args) {
|
|
867
935
|
const proc = Bun.spawn([...stack.list.argv, ...args], { cwd: stack.list.cwd, env: stack.list.env, stdout: "pipe", stderr: "pipe" });
|
|
868
|
-
|
|
936
|
+
const [text, stderr, code] = await Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text(), proc.exited]);
|
|
937
|
+
if (code === 0)
|
|
938
|
+
return { text, error: undefined };
|
|
939
|
+
const last = stderr.trim().split(`
|
|
940
|
+
`).at(-1) ?? "";
|
|
941
|
+
return { text: "", error: last === "" ? `exit ${code}` : last };
|
|
942
|
+
}
|
|
943
|
+
async function output(stack, args) {
|
|
944
|
+
return (await attempt(stack, args)).text;
|
|
869
945
|
}
|
|
870
946
|
function containers(text) {
|
|
871
947
|
const trimmed = text.trim();
|
|
@@ -955,47 +1031,17 @@ function row(service) {
|
|
|
955
1031
|
cells: [dir === "." ? name : `${colors.dim(`${dir}/`)}${name}`, colors[stateColor(service.state)](service.state), colors.cyan(service.ports), colors.dim(service.image)]
|
|
956
1032
|
};
|
|
957
1033
|
}
|
|
958
|
-
function table(rows) {
|
|
959
|
-
const widths = rows[0]?.cells.map((_, index) => Math.max(...rows.map((each) => Bun.stringWidth(each.cells[index])))) ?? [];
|
|
960
|
-
return rows.map((each) => [
|
|
961
|
-
...each.hidden,
|
|
962
|
-
...each.cells.map((cell, index) => index === each.cells.length - 1 ? cell.trimEnd() : `${cell}${" ".repeat(widths[index] + 1 - Bun.stringWidth(cell))}`)
|
|
963
|
-
].join("\t")).join(`
|
|
964
|
-
`);
|
|
965
|
-
}
|
|
966
1034
|
function pickService(services) {
|
|
967
|
-
const
|
|
968
|
-
"
|
|
969
|
-
"
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
"--height",
|
|
978
|
-
String(Math.max(15, Math.ceil((services.length + 4) / 0.6))),
|
|
979
|
-
"--delimiter",
|
|
980
|
-
"\t",
|
|
981
|
-
"--with-nth",
|
|
982
|
-
"5..",
|
|
983
|
-
"--nth",
|
|
984
|
-
"1",
|
|
985
|
-
"--tabstop",
|
|
986
|
-
"1",
|
|
987
|
-
"--tiebreak",
|
|
988
|
-
"chunk,index",
|
|
989
|
-
"--preview",
|
|
990
|
-
`${process9.execPath} ${process9.argv[1]} --show {1} {2} {4}`,
|
|
991
|
-
"--preview-window",
|
|
992
|
-
"down,40%"
|
|
993
|
-
], { stdin: new TextEncoder().encode(table(services.map(row))), stdout: "pipe", stderr: "inherit" });
|
|
994
|
-
const [pressed = "", line] = proc.stdout.toString().split(`
|
|
995
|
-
`);
|
|
996
|
-
const keyed = line?.split("\t")[2];
|
|
997
|
-
const service = services.find((candidate) => key(candidate) === keyed);
|
|
998
|
-
return service === undefined ? undefined : { service, key: pressed };
|
|
1035
|
+
const picked = fzf(services.map(row), {
|
|
1036
|
+
prompt: "dx> ",
|
|
1037
|
+
header: "enter shell or up, ctrl-l logs, ctrl-r restart, ctrl-x stop, ctrl-b rebuild",
|
|
1038
|
+
expect: Object.keys(KEYS),
|
|
1039
|
+
searched: 1,
|
|
1040
|
+
height: heightFor(services.length),
|
|
1041
|
+
preview: `${process9.execPath} ${process9.argv[1]} --show {1} {2} {4}`
|
|
1042
|
+
});
|
|
1043
|
+
const service = services.find((candidate) => key(candidate) === picked?.hidden[2]);
|
|
1044
|
+
return picked === undefined || service === undefined ? undefined : { service, key: picked.key };
|
|
999
1045
|
}
|
|
1000
1046
|
|
|
1001
1047
|
// src/dx.ts
|
|
@@ -1031,7 +1077,7 @@ function find(services, named) {
|
|
|
1031
1077
|
return fail(`no service named ${named}${nearest === undefined ? "" : `, did you mean ${nearest}?`}`, 1);
|
|
1032
1078
|
}
|
|
1033
1079
|
function listed2(services) {
|
|
1034
|
-
return byRecency(services, runs(), key).map((service) => ({
|
|
1080
|
+
return byRecency(services, runs("dx"), key).map((service) => ({
|
|
1035
1081
|
label: key(service),
|
|
1036
1082
|
hint: [service.state, service.ports, service.image].filter(Boolean).join(" \xB7 "),
|
|
1037
1083
|
typed: key(service),
|
|
@@ -1091,13 +1137,13 @@ async function dx(args) {
|
|
|
1091
1137
|
console.log(table2(services));
|
|
1092
1138
|
return 0;
|
|
1093
1139
|
}
|
|
1094
|
-
const picked = pickService(byRecency(services, runs(), key));
|
|
1140
|
+
const picked = pickService(byRecency(services, runs("dx"), key));
|
|
1095
1141
|
if (picked === undefined)
|
|
1096
1142
|
return 1;
|
|
1097
1143
|
service = picked.service;
|
|
1098
1144
|
action = KEYS[picked.key];
|
|
1099
1145
|
} else if (named === "-") {
|
|
1100
|
-
const last = runs()[0];
|
|
1146
|
+
const last = runs("dx")[0];
|
|
1101
1147
|
service = last && services.find((candidate) => key(candidate) === last.id);
|
|
1102
1148
|
if (service === undefined)
|
|
1103
1149
|
fail(last ? `${last.id} is gone` : "nothing done here yet", 1);
|
|
@@ -1110,7 +1156,7 @@ async function dx(args) {
|
|
|
1110
1156
|
}
|
|
1111
1157
|
const chosen = action ?? defaultAction(service);
|
|
1112
1158
|
const command = await commandFor(service, chosen);
|
|
1113
|
-
record({ id: key(service), args: [chosen] });
|
|
1159
|
+
record("dx", { id: key(service), args: [chosen] });
|
|
1114
1160
|
if (emit) {
|
|
1115
1161
|
console.log(["run", action === undefined ? key(service) : `${key(service)} ${action}`, "", ...command.map((word) => `=${word}`)].join(`
|
|
1116
1162
|
`));
|