dockai 0.2.4 → 0.2.6
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 +15 -3
- package/dist/commands/claude.js +3 -5
- package/dist/commands/claude.js.map +1 -1
- package/dist/commands/completion.js +129 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/doctor.js +159 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/logs.js +33 -2
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/sessions.js +6 -14
- package/dist/commands/sessions.js.map +1 -1
- package/dist/commands/ssh-config.js +10 -0
- package/dist/commands/ssh-config.js.map +1 -1
- package/dist/commands/start-stop.js +32 -0
- package/dist/commands/start-stop.js.map +1 -1
- package/dist/index.js +29 -8
- package/dist/index.js.map +1 -1
- package/dist/lib/__tests__/doctor.test.js +41 -0
- package/dist/lib/__tests__/doctor.test.js.map +1 -0
- package/dist/lib/__tests__/git-remote.test.js +26 -0
- package/dist/lib/__tests__/git-remote.test.js.map +1 -0
- package/dist/lib/__tests__/recent.test.js +49 -0
- package/dist/lib/__tests__/recent.test.js.map +1 -0
- package/dist/lib/__tests__/select.test.js +50 -0
- package/dist/lib/__tests__/select.test.js.map +1 -0
- package/dist/lib/follow.js +32 -0
- package/dist/lib/follow.js.map +1 -0
- package/dist/lib/format.js +71 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/git-remote.js +42 -0
- package/dist/lib/git-remote.js.map +1 -0
- package/dist/lib/pick-project.js +19 -66
- package/dist/lib/pick-project.js.map +1 -1
- package/dist/lib/recent.js +63 -0
- package/dist/lib/recent.js.map +1 -0
- package/dist/lib/remote.js +21 -0
- package/dist/lib/remote.js.map +1 -1
- package/dist/lib/select.js +148 -0
- package/dist/lib/select.js.map +1 -0
- package/dist/lib/update-check.js +92 -0
- package/dist/lib/update-check.js.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/lib/pick-project.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { emitKeypressEvents } from "node:readline";
|
|
2
1
|
import { createApiClient } from "../api.js";
|
|
3
2
|
import { getToken } from "../config.js";
|
|
4
3
|
import { resetTerminal } from "./remote.js";
|
|
4
|
+
import { orderForDir, readRecent, recordUse } from "./recent.js";
|
|
5
|
+
import { projectsForRemotes, remotesOf } from "./git-remote.js";
|
|
6
|
+
import { pad, selectFromList } from "./select.js";
|
|
5
7
|
/**
|
|
6
8
|
* Ask which project, when a command that needs one was given none.
|
|
7
9
|
*
|
|
@@ -52,17 +54,25 @@ export async function pickProject() {
|
|
|
52
54
|
console.error("No projects yet.");
|
|
53
55
|
process.exit(1);
|
|
54
56
|
}
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
// The project this folder is a checkout of, then what was used from here,
|
|
58
|
+
// the first pre-selected and taken on its own after a few seconds; then
|
|
59
|
+
// running, then by name.
|
|
60
|
+
const dir = process.cwd();
|
|
61
|
+
const { ordered, usedHere } = orderForDir(projects, readRecent(), dir, projectsForRemotes(projects, remotesOf(dir)));
|
|
62
|
+
const chosen = await selectFromList("Which project?", ordered.map((p) => ({ label: describe(p), value: p })), {
|
|
63
|
+
autoSelectAfter: usedHere > 0 ? AUTO_SELECT_SECONDS : undefined,
|
|
64
|
+
autoLabel: ordered[0]?.name,
|
|
65
|
+
});
|
|
58
66
|
if (!chosen) {
|
|
59
67
|
console.error("No project chosen.");
|
|
60
68
|
process.exit(1);
|
|
61
69
|
}
|
|
70
|
+
recordUse(dir, chosen.slug);
|
|
62
71
|
return chosen.slug;
|
|
63
72
|
}
|
|
64
73
|
const DIM = "\x1b[2m";
|
|
65
74
|
const RESET_DIM = "\x1b[22m";
|
|
75
|
+
const AUTO_SELECT_SECONDS = 5;
|
|
66
76
|
/**
|
|
67
77
|
* One row per project: what it is, whether it is up, whether Claude is busy
|
|
68
78
|
* in it, and which branch and account it works with — the things that decide
|
|
@@ -82,13 +92,6 @@ export function describe(p) {
|
|
|
82
92
|
account,
|
|
83
93
|
].join("");
|
|
84
94
|
}
|
|
85
|
-
/** padEnd that measures the visible text, not the escape codes. */
|
|
86
|
-
function pad(s, width) {
|
|
87
|
-
return s + " ".repeat(Math.max(0, width - visibleLength(s)));
|
|
88
|
-
}
|
|
89
|
-
function visibleLength(s) {
|
|
90
|
-
return s.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
91
|
-
}
|
|
92
95
|
/**
|
|
93
96
|
* Insert a prompted slug into argv when the command's slug position is empty
|
|
94
97
|
* or holds a flag — so `dockai claude --resume x` still means "ask me which
|
|
@@ -114,8 +117,11 @@ export async function ensureSlug(argv, commandPath, opts = {}) {
|
|
|
114
117
|
break;
|
|
115
118
|
}
|
|
116
119
|
const current = argv[pos];
|
|
117
|
-
if (current && !current.startsWith("-"))
|
|
120
|
+
if (current && !current.startsWith("-")) {
|
|
121
|
+
// Named outright: still the project used from this folder.
|
|
122
|
+
recordUse(process.cwd(), current);
|
|
118
123
|
return argv;
|
|
124
|
+
}
|
|
119
125
|
// `--help` is not a missing project. This pre-pass runs before Commander
|
|
120
126
|
// parses, so `dockai claude --help` asked the *server* for a project list
|
|
121
127
|
// and answered "Not logged in. Run `dockai login` first." — on the flagship
|
|
@@ -126,58 +132,5 @@ export async function ensureSlug(argv, commandPath, opts = {}) {
|
|
|
126
132
|
const slug = await pickProject();
|
|
127
133
|
return [...argv.slice(0, pos), slug, ...argv.slice(pos)];
|
|
128
134
|
}
|
|
129
|
-
|
|
130
|
-
* Arrow-key list selection on a TTY: ↑/↓ or j/k to move, Enter to choose,
|
|
131
|
-
* a digit to jump, Esc or Ctrl-C to cancel. Redraws in place.
|
|
132
|
-
*/
|
|
133
|
-
export function selectFromList(title, items) {
|
|
134
|
-
return new Promise((resolve) => {
|
|
135
|
-
let index = 0;
|
|
136
|
-
const out = process.stdout;
|
|
137
|
-
const render = (first = false) => {
|
|
138
|
-
if (!first)
|
|
139
|
-
out.write(`\x1b[${items.length + 1}A`); // back to the title line
|
|
140
|
-
out.write(`${title}\x1b[K\n`);
|
|
141
|
-
items.forEach((it, i) => {
|
|
142
|
-
const on = i === index;
|
|
143
|
-
out.write(`${on ? "\x1b[36m❯" : " "} ${it.label}\x1b[0m\x1b[K\n`);
|
|
144
|
-
});
|
|
145
|
-
};
|
|
146
|
-
const finish = (value) => {
|
|
147
|
-
out.write("\x1b[?25h");
|
|
148
|
-
process.stdin.setRawMode(false);
|
|
149
|
-
process.stdin.pause();
|
|
150
|
-
process.stdin.off("keypress", onKey);
|
|
151
|
-
resolve(value);
|
|
152
|
-
};
|
|
153
|
-
const onKey = (str, key) => {
|
|
154
|
-
if (key.ctrl && key.name === "c") {
|
|
155
|
-
finish(null);
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
if (key.name === "escape") {
|
|
159
|
-
finish(null);
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
if (key.name === "return") {
|
|
163
|
-
finish(items[index].value);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (key.name === "up" || str === "k")
|
|
167
|
-
index = (index - 1 + items.length) % items.length;
|
|
168
|
-
else if (key.name === "down" || str === "j")
|
|
169
|
-
index = (index + 1) % items.length;
|
|
170
|
-
else if (/^[1-9]$/.test(str) && Number(str) <= items.length)
|
|
171
|
-
index = Number(str) - 1;
|
|
172
|
-
else
|
|
173
|
-
return;
|
|
174
|
-
render();
|
|
175
|
-
};
|
|
176
|
-
emitKeypressEvents(process.stdin);
|
|
177
|
-
process.stdin.setRawMode(true);
|
|
178
|
-
process.stdin.resume();
|
|
179
|
-
process.stdin.on("keypress", onKey);
|
|
180
|
-
render(true);
|
|
181
|
-
});
|
|
182
|
-
}
|
|
135
|
+
export { selectFromList } from "./select.js";
|
|
183
136
|
//# sourceMappingURL=pick-project.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pick-project.js","sourceRoot":"","sources":["../../src/lib/pick-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"pick-project.js","sourceRoot":"","sources":["../../src/lib/pick-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClD,OAAO,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;QACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,2EAA2E;IAC3E,iDAAiD;IACjD,aAAa,EAAE,CAAC;IAChB,0EAA0E;IAC1E,0DAA0D;IAC1D,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IACvB,0EAA0E;IAC1E,wEAAwE;IACxE,kDAAkD;IAClD,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC,CAAC,CAAC,CAAC;IACrH,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACjE,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACzG,IAAI,QAAmB,CAAC;IACxB,IAAI,CAAC;QACH,QAAQ,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC,CAAc,CAAC;IAClG,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAC1C,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS;YAC7D,CAAC,CAAC,oGAAoG;YACtG,CAAC,CAAC,4BAA4B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACrB,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,0EAA0E;IAC1E,wEAAwE;IACxE,yBAAyB;IACzB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,WAAW,CAAC,QAAQ,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,kBAAkB,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE;QAC5G,eAAe,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS;QAC/D,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI;KAC5B,CAAC,CAAC;IACH,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,MAAM,GAAG,GAAG,SAAS,CAAC;AACtB,MAAM,SAAS,GAAG,UAAU,CAAC;AAC7B,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,CAAU;IACjC,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,KAAK,SAAS;QAClC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,yBAAyB,CAAC;QACxF,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,GAAG,SAAS,EAAE,CAAC;IAClD,MAAM,MAAM,GAAG,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACpF,MAAM,OAAO,GAAG,CAAC,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,KAAK,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7F,OAAO;QACL,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9B,GAAG,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE;QACrD,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QACb,GAAG,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE;QACxC,OAAO;KACR,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACb,CAAC;AAGD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAc,EACd,WAAqB,EACrB,IAAI,GAA4C,EAAE;IAElD,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,eAAe;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IACtD,CAAC;IACD,0EAA0E;IAC1E,2EAA2E;IAC3E,uEAAuE;IACvE,IAAI,GAAG,GAAG,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC;IACrC,SAAS,CAAC;QACR,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC;YAAE,GAAG,IAAI,CAAC,CAAC;aAC3C,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC;YAAE,GAAG,IAAI,CAAC,CAAC;;YAC/C,MAAM;IACb,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxC,2DAA2D;QAC3D,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,yEAAyE;IACzE,0EAA0E;IAC1E,4EAA4E;IAC5E,sEAAsE;IACtE,uEAAuE;IACvE,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3E,MAAM,IAAI,GAAG,MAAM,WAAW,EAAE,CAAC;IACjC,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const FILE = path.join(homedir(), ".config", "dockai", "recent.json");
|
|
5
|
+
const PER_DIR = 10;
|
|
6
|
+
const DIRS = 200;
|
|
7
|
+
export function readRecent(file = FILE) {
|
|
8
|
+
try {
|
|
9
|
+
return existsSync(file) ? JSON.parse(readFileSync(file, "utf8")) : {};
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** The record with `slug` moved to the front for `dir`, bounded both ways. */
|
|
16
|
+
export function withUse(recent, dir, slug, at) {
|
|
17
|
+
const list = [{ slug, at }, ...(recent[dir] ?? []).filter((e) => e.slug !== slug)].slice(0, PER_DIR);
|
|
18
|
+
const next = { ...recent, [dir]: list };
|
|
19
|
+
const dirs = Object.keys(next);
|
|
20
|
+
if (dirs.length > DIRS) {
|
|
21
|
+
// Drop the directories used longest ago.
|
|
22
|
+
const newest = (d) => next[d][0]?.at ?? 0;
|
|
23
|
+
for (const d of dirs.sort((a, b) => newest(a) - newest(b)).slice(0, dirs.length - DIRS))
|
|
24
|
+
delete next[d];
|
|
25
|
+
}
|
|
26
|
+
return next;
|
|
27
|
+
}
|
|
28
|
+
/** Best-effort: a read-only home must not stop the command. */
|
|
29
|
+
export function recordUse(dir, slug, file = FILE) {
|
|
30
|
+
try {
|
|
31
|
+
const next = withUse(readRecent(file), dir, slug, Date.now());
|
|
32
|
+
mkdirSync(path.dirname(file), { recursive: true });
|
|
33
|
+
writeFileSync(file, JSON.stringify(next));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
/* not worth failing a command over */
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Order for the picker: the projects used from `dir`, most recent first;
|
|
41
|
+
* then those whose repository this folder is a checkout of (`fromGit`); then
|
|
42
|
+
* running before the rest; then by name. Returns how many at the top belong
|
|
43
|
+
* to this folder by either route, so the caller knows whether there is one to
|
|
44
|
+
* pre-select.
|
|
45
|
+
*
|
|
46
|
+
* History outranks the git match: what was last chosen here is the answer
|
|
47
|
+
* the person gave, and the remote only guesses — it is the default for a
|
|
48
|
+
* folder with no history yet (asked for in that order, 2026-09-23).
|
|
49
|
+
*/
|
|
50
|
+
export function orderForDir(projects, recent, dir, fromGit = []) {
|
|
51
|
+
const used = (recent[dir] ?? []).map((e) => e.slug);
|
|
52
|
+
const ranked = [...used, ...fromGit.filter((slug) => !used.includes(slug))];
|
|
53
|
+
const rank = new Map(ranked.map((slug, i) => [slug, i]));
|
|
54
|
+
const ordered = [...projects].sort((a, b) => {
|
|
55
|
+
const ra = rank.get(a.slug) ?? Infinity;
|
|
56
|
+
const rb = rank.get(b.slug) ?? Infinity;
|
|
57
|
+
if (ra !== rb)
|
|
58
|
+
return ra - rb;
|
|
59
|
+
return Number(b.status === "RUNNING") - Number(a.status === "RUNNING") || a.name.localeCompare(b.name);
|
|
60
|
+
});
|
|
61
|
+
return { ordered, usedHere: ordered.filter((p) => rank.has(p.slug)).length };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=recent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recent.js","sourceRoot":"","sources":["../../src/lib/recent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAY7B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AACtE,MAAM,OAAO,GAAG,EAAE,CAAC;AACnB,MAAM,IAAI,GAAG,GAAG,CAAC;AAEjB,MAAM,UAAU,UAAU,CAAC,IAAI,GAAG,IAAI;IACpC,IAAI,CAAC;QACH,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IACpF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,OAAO,CAAC,MAAc,EAAE,GAAW,EAAE,IAAY,EAAE,EAAU;IAC3E,MAAM,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACrG,MAAM,IAAI,GAAW,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC;IAChD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;QACvB,yCAAyC;QACzC,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAClD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1G,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,IAAY,EAAE,IAAI,GAAG,IAAI;IAC9D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAC9D,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,sCAAsC;IACxC,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CACzB,QAAa,EAAE,MAAc,EAAE,GAAW,EAAE,OAAO,GAAa,EAAE;IAElE,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC1C,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;QACxC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;QACxC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,GAAG,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACzG,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;AAC/E,CAAC"}
|
package/dist/lib/remote.js
CHANGED
|
@@ -53,6 +53,27 @@ export async function assertRunning(slug) {
|
|
|
53
53
|
process.exit(1);
|
|
54
54
|
}
|
|
55
55
|
if (project.status !== "RUNNING") {
|
|
56
|
+
// At a terminal, offer to start it rather than print the command to type
|
|
57
|
+
// and stop — the answer is nearly always yes.
|
|
58
|
+
if (project.status === "STOPPED" && process.stdin.isTTY && process.stdout.isTTY) {
|
|
59
|
+
const { createInterface } = await import("node:readline/promises");
|
|
60
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
61
|
+
const answer = (await rl.question(`${project.name} is stopped. Start it now? [Y/n] `)).trim().toLowerCase();
|
|
62
|
+
rl.close();
|
|
63
|
+
if (answer === "" || answer === "y" || answer === "yes") {
|
|
64
|
+
const { startAndWait } = await import("../commands/start-stop.js");
|
|
65
|
+
try {
|
|
66
|
+
if (await startAndWait(createApiClient(), project))
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
fail(err, "Could not start it");
|
|
71
|
+
}
|
|
72
|
+
console.error(`It did not come up in time. \`dockai projects\` shows how it is doing; the dashboard's Logs tab says why.`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
56
77
|
console.error(`Project "${slug}" is ${project.status.toLowerCase()}. Start it with:`);
|
|
57
78
|
console.error(` dockai start ${slug}`);
|
|
58
79
|
process.exit(1);
|
package/dist/lib/remote.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/lib/remote.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/lib/remote.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,2EAA2E;AAC3E,MAAM,UAAU,EAAE,CAAC,CAAS;IAC1B,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AACzC,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,EAAE,CAAC,CAAS;IAC1B,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC;AAChD,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,UAAU,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,cAAc,IAAI,EAAE,CAAC;AAC9B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY;IAC9C,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,QAAmB,CAAC;IACxB,IAAI,CAAC;QACH,QAAQ,GAAG,CAAC,MAAM,eAAe,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAc,CAAC;IACzE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,wEAAwE;QACxE,sEAAsE;QACtE,wEAAwE;QACxE,qEAAqE;QACrE,qCAAqC;QACrC,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,wCAAwC,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAClE,OAAO,CAAC,6DAA6D;IACvE,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACtD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrD,OAAO,CAAC,KAAK,CAAC,eAAe,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,oBAAoB,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACjC,yEAAyE;QACzE,8CAA8C;QAC9C,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAChF,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;YACnE,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAC7E,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,mCAAmC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC5G,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACxD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;gBACnE,IAAI,CAAC;oBACH,IAAI,MAAM,YAAY,CAAC,eAAe,EAAE,EAAE,OAAO,CAAC;wBAAE,OAAO;gBAC7D,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;gBAClC,CAAC;gBACD,OAAO,CAAC,KAAK,CAAC,2GAA2G,CAAC,CAAC;gBAC3H,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,YAAY,IAAI,QAAQ,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;QACtF,OAAO,CAAC,KAAK,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,mBAAmB,OAAO,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;IACtF,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAC9D,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC3E,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,QAAQ,CACtB,IAAY,EACZ,IAA6E;IAE7E,MAAM,MAAM,GACV,YAAY,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM;QACpC,UAAU,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,mBAAmB,OAAO,CAAC;IACrF,MAAM,KAAK,GAAG,yCAAyC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAC5G,oEAAoE;IACpE,MAAM,MAAM,GAAG,oBAAoB,KAAK,UAAU,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;IACpF,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;IACzF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QACtC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,OAAe;IACrD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;IACtH,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,MAAM,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QACxD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO;IAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,8CAA8C,GAAG,gCAAgC;QACjF,aAAa,GAAG,kBAAkB;QAClC,wEAAwE;QACxE,oEAAoE;QACpE,0EAA0E;QAC1E,WAAW,GAAG,SAAS;QACvB,SAAS,CACV,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,CAAC;QACH,MAAM,eAAe,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,uEAAuE;AACvE,MAAM,CAAC,MAAM,yBAAyB,GAAG,uCAAuC,CAAC;AAEjF;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB;IACvC,MAAM,GAAG,GAAG,kCAAkC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC;IACpE,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QAAC,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC;IAAC,CAAC;IACtD,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;SAClC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACZ,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,CAAC;YAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YAAC,OAAO,IAAI,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,KAAK,CAAC;QAAC,CAAC;IACpE,CAAC,CAAC;SACD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { emitKeypressEvents } from "node:readline";
|
|
2
|
+
const DIM = "\x1b[2m";
|
|
3
|
+
const RESET_DIM = "\x1b[22m";
|
|
4
|
+
/** The text a person sees: escape codes stripped. */
|
|
5
|
+
export function visibleText(s) {
|
|
6
|
+
// eslint-disable-next-line no-control-regex
|
|
7
|
+
return s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
8
|
+
}
|
|
9
|
+
/** padEnd that measures the visible text, not the escape codes. */
|
|
10
|
+
export function pad(s, width) {
|
|
11
|
+
return s + " ".repeat(Math.max(0, width - visibleText(s).length));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The items whose visible label holds every word typed, in any order and any
|
|
15
|
+
* case — "wed as" finds "Wedding Assistant".
|
|
16
|
+
*/
|
|
17
|
+
export function filterItems(items, query) {
|
|
18
|
+
const words = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
19
|
+
if (!words.length)
|
|
20
|
+
return items;
|
|
21
|
+
return items.filter((it) => {
|
|
22
|
+
const text = visibleText(it.label).toLowerCase();
|
|
23
|
+
return words.every((w) => text.includes(w));
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/** Which slice of a long list to draw so the selection stays in view. */
|
|
27
|
+
export function windowFor(total, index, height) {
|
|
28
|
+
if (total <= height)
|
|
29
|
+
return { start: 0, end: total };
|
|
30
|
+
const start = Math.min(Math.max(0, index - Math.floor(height / 2)), total - height);
|
|
31
|
+
return { start, end: start + height };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Arrow-key list selection on a TTY. ↑/↓ move, typing filters (every word,
|
|
35
|
+
* any order), Backspace un-types, Enter chooses, Esc clears the filter and
|
|
36
|
+
* then cancels, Ctrl-C cancels. Redraws in place, and a list taller than the
|
|
37
|
+
* terminal scrolls.
|
|
38
|
+
*
|
|
39
|
+
* `autoSelectAfter` takes the pre-selected first item after that many
|
|
40
|
+
* seconds, counting down on the title line; any key stops the countdown.
|
|
41
|
+
*
|
|
42
|
+
* j/k used to move too; typing filters now, so the letters are text.
|
|
43
|
+
*/
|
|
44
|
+
export function selectFromList(title, items, opts = {}) {
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
let index = 0;
|
|
47
|
+
let query = "";
|
|
48
|
+
let drawn = 0;
|
|
49
|
+
let remaining = opts.autoSelectAfter ?? 0;
|
|
50
|
+
let timer = null;
|
|
51
|
+
const out = process.stdout;
|
|
52
|
+
const shown = () => filterItems(items, query);
|
|
53
|
+
const render = () => {
|
|
54
|
+
const list = shown();
|
|
55
|
+
if (index >= list.length)
|
|
56
|
+
index = Math.max(0, list.length - 1);
|
|
57
|
+
const height = Math.max(3, (out.rows || 24) - 3);
|
|
58
|
+
const { start, end } = windowFor(list.length, index, height);
|
|
59
|
+
const hint = timer
|
|
60
|
+
? `${DIM}Enter to choose · ${remaining}s to ${opts.autoLabel ?? "the first"}${RESET_DIM}`
|
|
61
|
+
: query
|
|
62
|
+
? `${DIM}filter:${RESET_DIM} ${query}${DIM} (Esc clears)${RESET_DIM}`
|
|
63
|
+
: `${DIM}type to filter${RESET_DIM}`;
|
|
64
|
+
const lines = [`${title} ${hint}`];
|
|
65
|
+
if (!list.length)
|
|
66
|
+
lines.push(` ${DIM}nothing matches "${query}"${RESET_DIM}`);
|
|
67
|
+
if (start > 0)
|
|
68
|
+
lines.push(` ${DIM}↑ ${start} more${RESET_DIM}`);
|
|
69
|
+
for (let i = start; i < end; i++) {
|
|
70
|
+
lines.push(`${i === index ? "\x1b[36m❯" : " "} ${list[i].label}\x1b[0m`);
|
|
71
|
+
}
|
|
72
|
+
if (end < list.length)
|
|
73
|
+
lines.push(` ${DIM}↓ ${list.length - end} more${RESET_DIM}`);
|
|
74
|
+
// Back to where the last frame began, clear everything below, redraw:
|
|
75
|
+
// the frame's height changes as the filter narrows the list.
|
|
76
|
+
if (drawn)
|
|
77
|
+
out.write(`\x1b[${drawn}A\r`);
|
|
78
|
+
out.write("\x1b[J" + lines.map((l) => `${l}\x1b[K`).join("\n") + "\n");
|
|
79
|
+
drawn = lines.length;
|
|
80
|
+
};
|
|
81
|
+
const finish = (value) => {
|
|
82
|
+
if (timer)
|
|
83
|
+
clearInterval(timer);
|
|
84
|
+
out.write("\x1b[?25h");
|
|
85
|
+
process.stdin.setRawMode(false);
|
|
86
|
+
process.stdin.pause();
|
|
87
|
+
process.stdin.off("keypress", onKey);
|
|
88
|
+
resolve(value);
|
|
89
|
+
};
|
|
90
|
+
const onKey = (str, key) => {
|
|
91
|
+
// Any key means a person is choosing: stop counting.
|
|
92
|
+
if (timer) {
|
|
93
|
+
clearInterval(timer);
|
|
94
|
+
timer = null;
|
|
95
|
+
}
|
|
96
|
+
if (key.ctrl && key.name === "c") {
|
|
97
|
+
finish(null);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const list = shown();
|
|
101
|
+
if (key.name === "escape") {
|
|
102
|
+
if (query) {
|
|
103
|
+
query = "";
|
|
104
|
+
index = 0;
|
|
105
|
+
render();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
finish(null);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (key.name === "return") {
|
|
112
|
+
if (list.length)
|
|
113
|
+
finish(list[index].value);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (key.name === "up")
|
|
117
|
+
index = list.length ? (index - 1 + list.length) % list.length : 0;
|
|
118
|
+
else if (key.name === "down")
|
|
119
|
+
index = list.length ? (index + 1) % list.length : 0;
|
|
120
|
+
else if (key.name === "backspace") {
|
|
121
|
+
query = query.slice(0, -1);
|
|
122
|
+
index = 0;
|
|
123
|
+
}
|
|
124
|
+
else if (str && !key.ctrl && !key.meta && str.length === 1 && str >= " ") {
|
|
125
|
+
query += str;
|
|
126
|
+
index = 0;
|
|
127
|
+
}
|
|
128
|
+
render();
|
|
129
|
+
};
|
|
130
|
+
emitKeypressEvents(process.stdin);
|
|
131
|
+
process.stdin.setRawMode(true);
|
|
132
|
+
process.stdin.resume();
|
|
133
|
+
process.stdin.on("keypress", onKey);
|
|
134
|
+
out.write("\x1b[?25l");
|
|
135
|
+
if (remaining > 0 && items.length > 0) {
|
|
136
|
+
timer = setInterval(() => {
|
|
137
|
+
remaining -= 1;
|
|
138
|
+
if (remaining <= 0) {
|
|
139
|
+
finish(items[0].value);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
render();
|
|
143
|
+
}, 1000);
|
|
144
|
+
}
|
|
145
|
+
render();
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/lib/select.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,GAAG,GAAG,SAAS,CAAC;AACtB,MAAM,SAAS,GAAG,UAAU,CAAC;AAE7B,qDAAqD;AACrD,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,4CAA4C;IAC5C,OAAO,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,GAAG,CAAC,CAAS,EAAE,KAAa;IAC1C,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACpE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAI,KAAyC,EAAE,KAAa;IACrF,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/D,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAChC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE;QACzB,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QACjD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,SAAS,CAAC,KAAa,EAAE,KAAa,EAAE,MAAc;IACpE,IAAI,KAAK,IAAI,MAAM;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IACrD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,CAAC;IACpF,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,GAAG,MAAM,EAAE,CAAC;AACxC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAa,EACb,KAAyC,EACzC,IAAI,GAAqD,EAAE;IAE3D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,KAAK,GAAG,EAAE,CAAC;QACf,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,SAAS,GAAG,IAAI,CAAC,eAAe,IAAI,CAAC,CAAC;QAC1C,IAAI,KAAK,GAA0C,IAAI,CAAC;QACxD,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;QAC3B,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAE9C,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,MAAM,IAAI,GAAG,KAAK,EAAE,CAAC;YACrB,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM;gBAAE,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YACjD,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;YAC7D,MAAM,IAAI,GAAG,KAAK;gBAChB,CAAC,CAAC,GAAG,GAAG,qBAAqB,SAAS,QAAQ,IAAI,CAAC,SAAS,IAAI,WAAW,GAAG,SAAS,EAAE;gBACzF,CAAC,CAAC,KAAK;oBACL,CAAC,CAAC,GAAG,GAAG,UAAU,SAAS,IAAI,KAAK,GAAG,GAAG,iBAAiB,SAAS,EAAE;oBACtE,CAAC,CAAC,GAAG,GAAG,iBAAiB,SAAS,EAAE,CAAC;YACzC,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,KAAK,IAAI,EAAE,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,oBAAoB,KAAK,IAAI,SAAS,EAAE,CAAC,CAAC;YAC/E,IAAI,KAAK,GAAG,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,KAAK,QAAQ,SAAS,EAAE,CAAC,CAAC;YACjE,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;gBACjC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;YAC3E,CAAC;YACD,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,IAAI,CAAC,MAAM,GAAG,GAAG,QAAQ,SAAS,EAAE,CAAC,CAAC;YACrF,sEAAsE;YACtE,6DAA6D;YAC7D,IAAI,KAAK;gBAAE,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC;YACzC,GAAG,CAAC,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;YACvE,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;QACvB,CAAC,CAAC;QAEF,MAAM,MAAM,GAAG,CAAC,KAAe,EAAE,EAAE;YACjC,IAAI,KAAK;gBAAE,aAAa,CAAC,KAAK,CAAC,CAAC;YAChC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YACvB,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAChC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,CAAC;QAEF,MAAM,KAAK,GAAG,CAAC,GAAuB,EAAE,GAAyE,EAAE,EAAE;YACnH,qDAAqD;YACrD,IAAI,KAAK,EAAE,CAAC;gBAAC,aAAa,CAAC,KAAK,CAAC,CAAC;gBAAC,KAAK,GAAG,IAAI,CAAC;YAAC,CAAC;YAClD,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,EAAE,CAAC;gBAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAAC,OAAO;YAAC,CAAC;YAC3D,MAAM,IAAI,GAAG,KAAK,EAAE,CAAC;YACrB,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC1B,IAAI,KAAK,EAAE,CAAC;oBAAC,KAAK,GAAG,EAAE,CAAC;oBAAC,KAAK,GAAG,CAAC,CAAC;oBAAC,MAAM,EAAE,CAAC;oBAAC,OAAO;gBAAC,CAAC;gBACvD,MAAM,CAAC,IAAI,CAAC,CAAC;gBACb,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC1B,IAAI,IAAI,CAAC,MAAM;oBAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;gBAC3C,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI;gBAAE,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;iBACpF,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;gBAAE,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;iBAC7E,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAAC,KAAK,GAAG,CAAC,CAAC;YAAC,CAAC;iBACxE,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;gBAAC,KAAK,IAAI,GAAG,CAAC;gBAAC,KAAK,GAAG,CAAC,CAAC;YAAC,CAAC;YACtG,MAAM,EAAE,CAAC;QACX,CAAC,CAAC;QAEF,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QACpC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACvB,IAAI,SAAS,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;gBACvB,SAAS,IAAI,CAAC,CAAC;gBACf,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;oBAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;oBAAC,OAAO;gBAAC,CAAC;gBACvD,MAAM,EAAE,CAAC;YACX,CAAC,EAAE,IAAI,CAAC,CAAC;QACX,CAAC;QACD,MAAM,EAAE,CAAC;IACX,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* "A newer dockai exists" — one dim line on stderr, at most once a day.
|
|
6
|
+
*
|
|
7
|
+
* A laptop ran 0.1.0 for five weeks behind a symlink into a stale checkout,
|
|
8
|
+
* with 0.2.5 on npm, and nothing said so until a feature was missing
|
|
9
|
+
* (2026-09-23). The registry is asked at most once a day, in the background,
|
|
10
|
+
* with a short deadline; the answer is kept and the line printed from it,
|
|
11
|
+
* so no command waits on the network for this.
|
|
12
|
+
*/
|
|
13
|
+
const FILE = path.join(homedir(), ".config", "dockai", "update-check.json");
|
|
14
|
+
const DAY = 86_400_000;
|
|
15
|
+
/** -1, 0 or 1, comparing dotted numeric versions; pre-release tags lose. */
|
|
16
|
+
export function compareVersions(a, b) {
|
|
17
|
+
const parse = (v) => {
|
|
18
|
+
const [core, pre] = v.replace(/^v/, "").split("-", 2);
|
|
19
|
+
return { nums: core.split(".").map((n) => Number.parseInt(n, 10) || 0), pre: pre ?? null };
|
|
20
|
+
};
|
|
21
|
+
const x = parse(a);
|
|
22
|
+
const y = parse(b);
|
|
23
|
+
for (let i = 0; i < Math.max(x.nums.length, y.nums.length); i++) {
|
|
24
|
+
const d = (x.nums[i] ?? 0) - (y.nums[i] ?? 0);
|
|
25
|
+
if (d)
|
|
26
|
+
return d > 0 ? 1 : -1;
|
|
27
|
+
}
|
|
28
|
+
if (x.pre === y.pre)
|
|
29
|
+
return 0;
|
|
30
|
+
if (x.pre === null)
|
|
31
|
+
return 1;
|
|
32
|
+
if (y.pre === null)
|
|
33
|
+
return -1;
|
|
34
|
+
return x.pre > y.pre ? 1 : -1;
|
|
35
|
+
}
|
|
36
|
+
export function updateNotice(current, latest) {
|
|
37
|
+
if (!latest || compareVersions(latest, current) <= 0)
|
|
38
|
+
return null;
|
|
39
|
+
return `\x1b[2mdockai ${latest} is available (you have ${current}) — npm i -g dockai\x1b[22m`;
|
|
40
|
+
}
|
|
41
|
+
function read(file) {
|
|
42
|
+
try {
|
|
43
|
+
return existsSync(file) ? JSON.parse(readFileSync(file, "utf8")) : null;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** The latest version on npm, or null; never throws, never waits long. */
|
|
50
|
+
export async function fetchLatest(timeoutMs = 1500) {
|
|
51
|
+
try {
|
|
52
|
+
const res = await fetch("https://registry.npmjs.org/dockai/latest", { signal: AbortSignal.timeout(timeoutMs) });
|
|
53
|
+
if (!res.ok)
|
|
54
|
+
return null;
|
|
55
|
+
const body = (await res.json());
|
|
56
|
+
return typeof body.version === "string" ? body.version : null;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Print the notice from what is known, and refresh what is known when it is
|
|
64
|
+
* a day old. Skipped where a stray line would do harm: not a terminal, the
|
|
65
|
+
* ssh ProxyCommand transport (its stderr is ssh's), completion, JSON output,
|
|
66
|
+
* or DOCKAI_NO_UPDATE_CHECK set.
|
|
67
|
+
*/
|
|
68
|
+
export function checkForUpdate(current, argv, file = FILE) {
|
|
69
|
+
if (process.env.DOCKAI_NO_UPDATE_CHECK || process.env.CI)
|
|
70
|
+
return;
|
|
71
|
+
if (!process.stderr.isTTY)
|
|
72
|
+
return;
|
|
73
|
+
const cmd = argv[2];
|
|
74
|
+
if (!cmd || cmd === "proxy" || cmd.startsWith("__") || cmd === "completion" || argv.includes("--json"))
|
|
75
|
+
return;
|
|
76
|
+
const cache = read(file);
|
|
77
|
+
const notice = updateNotice(current, cache?.latest ?? null);
|
|
78
|
+
if (notice)
|
|
79
|
+
process.stderr.write(`${notice}\n`);
|
|
80
|
+
if (cache && Date.now() - cache.checkedAt < DAY)
|
|
81
|
+
return;
|
|
82
|
+
void fetchLatest().then((latest) => {
|
|
83
|
+
try {
|
|
84
|
+
mkdirSync(path.dirname(file), { recursive: true });
|
|
85
|
+
writeFileSync(file, JSON.stringify({ checkedAt: Date.now(), latest: latest ?? cache?.latest ?? null }));
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
/* a read-only home is not a reason to fail anything */
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=update-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-check.js","sourceRoot":"","sources":["../../src/lib/update-check.ts"],"names":[],"mappings":"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"}
|
package/dist/version.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* CLI version. Kept in sync with apps/cli/package.json by the release workflow.
|
|
3
3
|
* Hardcoded so it works whether the CLI is run via npx, global install, or local link.
|
|
4
4
|
*/
|
|
5
|
-
export const CLI_VERSION = "0.2.
|
|
5
|
+
export const CLI_VERSION = "0.2.6";
|
|
6
6
|
export function compareSemver(a, b) {
|
|
7
7
|
const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
|
|
8
8
|
const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
|