dockai 0.2.4 → 0.2.5
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 +4 -0
- package/dist/lib/__tests__/recent.test.js +38 -0
- package/dist/lib/__tests__/recent.test.js.map +1 -0
- package/dist/lib/pick-project.js +41 -6
- package/dist/lib/pick-project.js.map +1 -1
- package/dist/lib/recent.js +56 -0
- package/dist/lib/recent.js.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,6 +63,10 @@ dockai proxy <host> The ProxyCommand transport (not run by hand
|
|
|
63
63
|
dockai deploy [target] Redeploy DockAI, or a named Compose stack
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
Leave the project out and it asks which one, listing first the projects used
|
|
67
|
+
from the folder you are in; the last of those is pre-selected and taken on its
|
|
68
|
+
own after 5 seconds unless you press a key.
|
|
69
|
+
|
|
66
70
|
Flags written after the project name are passed to `claude` untouched, so
|
|
67
71
|
`dockai claude app --permission-mode bypassPermissions -r` works. That is also
|
|
68
72
|
why `dockai`'s own options go before the name.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { mkdtempSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { orderForDir, readRecent, recordUse, withUse } from "../recent.js";
|
|
6
|
+
const projects = [
|
|
7
|
+
{ slug: "camper", name: "Camper 3.0", status: "RUNNING" },
|
|
8
|
+
{ slug: "dockai", name: "DockAI", status: "RUNNING" },
|
|
9
|
+
{ slug: "notestack", name: "NoteStack", status: "STOPPED" },
|
|
10
|
+
{ slug: "wedding", name: "Wedding Assistant", status: "RUNNING" },
|
|
11
|
+
];
|
|
12
|
+
describe("the project picker, per folder", () => {
|
|
13
|
+
it("lists what was used from this folder first, most recent on top", () => {
|
|
14
|
+
let recent = withUse({}, "/p/DockAI", "notestack", 1);
|
|
15
|
+
recent = withUse(recent, "/p/DockAI", "dockai", 2);
|
|
16
|
+
const { ordered, usedHere } = orderForDir(projects, recent, "/p/DockAI");
|
|
17
|
+
expect(ordered.map((p) => p.slug)).toEqual(["dockai", "notestack", "camper", "wedding"]);
|
|
18
|
+
expect(usedHere).toBe(2);
|
|
19
|
+
});
|
|
20
|
+
it("falls back to running first, then by name, in a folder with no history", () => {
|
|
21
|
+
const { ordered, usedHere } = orderForDir(projects, withUse({}, "/elsewhere", "notestack", 1), "/p/new");
|
|
22
|
+
expect(ordered.map((p) => p.slug)).toEqual(["camper", "dockai", "wedding", "notestack"]);
|
|
23
|
+
expect(usedHere).toBe(0);
|
|
24
|
+
});
|
|
25
|
+
it("moves a re-used project to the front without duplicating it", () => {
|
|
26
|
+
let recent = withUse({}, "/d", "a", 1);
|
|
27
|
+
recent = withUse(recent, "/d", "b", 2);
|
|
28
|
+
recent = withUse(recent, "/d", "a", 3);
|
|
29
|
+
expect(recent["/d"].map((e) => e.slug)).toEqual(["a", "b"]);
|
|
30
|
+
});
|
|
31
|
+
it("persists across runs, and survives a missing or broken file", () => {
|
|
32
|
+
const file = path.join(mkdtempSync(path.join(tmpdir(), "dockai-recent-")), "recent.json");
|
|
33
|
+
expect(readRecent(file)).toEqual({});
|
|
34
|
+
recordUse("/p/DockAI", "dockai", file);
|
|
35
|
+
expect(readRecent(file)["/p/DockAI"][0].slug).toBe("dockai");
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=recent.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recent.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/recent.test.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/pick-project.js
CHANGED
|
@@ -2,6 +2,7 @@ import { emitKeypressEvents } from "node:readline";
|
|
|
2
2
|
import { createApiClient } from "../api.js";
|
|
3
3
|
import { getToken } from "../config.js";
|
|
4
4
|
import { resetTerminal } from "./remote.js";
|
|
5
|
+
import { orderForDir, readRecent, recordUse } from "./recent.js";
|
|
5
6
|
/**
|
|
6
7
|
* Ask which project, when a command that needs one was given none.
|
|
7
8
|
*
|
|
@@ -52,17 +53,24 @@ export async function pickProject() {
|
|
|
52
53
|
console.error("No projects yet.");
|
|
53
54
|
process.exit(1);
|
|
54
55
|
}
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
const
|
|
56
|
+
// What was used from this folder first, the last one pre-selected and
|
|
57
|
+
// taken on its own after a few seconds; then running, then by name.
|
|
58
|
+
const dir = process.cwd();
|
|
59
|
+
const { ordered, usedHere } = orderForDir(projects, readRecent(), dir);
|
|
60
|
+
const chosen = await selectFromList("Which project?", ordered.map((p) => ({ label: describe(p), value: p })), {
|
|
61
|
+
autoSelectAfter: usedHere > 0 ? AUTO_SELECT_SECONDS : undefined,
|
|
62
|
+
autoLabel: ordered[0]?.name,
|
|
63
|
+
});
|
|
58
64
|
if (!chosen) {
|
|
59
65
|
console.error("No project chosen.");
|
|
60
66
|
process.exit(1);
|
|
61
67
|
}
|
|
68
|
+
recordUse(dir, chosen.slug);
|
|
62
69
|
return chosen.slug;
|
|
63
70
|
}
|
|
64
71
|
const DIM = "\x1b[2m";
|
|
65
72
|
const RESET_DIM = "\x1b[22m";
|
|
73
|
+
const AUTO_SELECT_SECONDS = 5;
|
|
66
74
|
/**
|
|
67
75
|
* One row per project: what it is, whether it is up, whether Claude is busy
|
|
68
76
|
* in it, and which branch and account it works with — the things that decide
|
|
@@ -114,8 +122,11 @@ export async function ensureSlug(argv, commandPath, opts = {}) {
|
|
|
114
122
|
break;
|
|
115
123
|
}
|
|
116
124
|
const current = argv[pos];
|
|
117
|
-
if (current && !current.startsWith("-"))
|
|
125
|
+
if (current && !current.startsWith("-")) {
|
|
126
|
+
// Named outright: still the project used from this folder.
|
|
127
|
+
recordUse(process.cwd(), current);
|
|
118
128
|
return argv;
|
|
129
|
+
}
|
|
119
130
|
// `--help` is not a missing project. This pre-pass runs before Commander
|
|
120
131
|
// parses, so `dockai claude --help` asked the *server* for a project list
|
|
121
132
|
// and answered "Not logged in. Run `dockai login` first." — on the flagship
|
|
@@ -129,21 +140,29 @@ export async function ensureSlug(argv, commandPath, opts = {}) {
|
|
|
129
140
|
/**
|
|
130
141
|
* Arrow-key list selection on a TTY: ↑/↓ or j/k to move, Enter to choose,
|
|
131
142
|
* a digit to jump, Esc or Ctrl-C to cancel. Redraws in place.
|
|
143
|
+
*
|
|
144
|
+
* `autoSelectAfter` takes the pre-selected first item after that many
|
|
145
|
+
* seconds, counting down on the title line; any key stops the countdown.
|
|
132
146
|
*/
|
|
133
|
-
export function selectFromList(title, items) {
|
|
147
|
+
export function selectFromList(title, items, opts = {}) {
|
|
134
148
|
return new Promise((resolve) => {
|
|
135
149
|
let index = 0;
|
|
150
|
+
let remaining = opts.autoSelectAfter ?? 0;
|
|
151
|
+
let timer = null;
|
|
136
152
|
const out = process.stdout;
|
|
137
153
|
const render = (first = false) => {
|
|
138
154
|
if (!first)
|
|
139
155
|
out.write(`\x1b[${items.length + 1}A`); // back to the title line
|
|
140
|
-
|
|
156
|
+
const countdown = timer ? ` ${DIM}Enter to choose · ${remaining}s to ${opts.autoLabel ?? "the first"}${RESET_DIM}` : "";
|
|
157
|
+
out.write(`${title}${countdown}\x1b[K\n`);
|
|
141
158
|
items.forEach((it, i) => {
|
|
142
159
|
const on = i === index;
|
|
143
160
|
out.write(`${on ? "\x1b[36m❯" : " "} ${it.label}\x1b[0m\x1b[K\n`);
|
|
144
161
|
});
|
|
145
162
|
};
|
|
146
163
|
const finish = (value) => {
|
|
164
|
+
if (timer)
|
|
165
|
+
clearInterval(timer);
|
|
147
166
|
out.write("\x1b[?25h");
|
|
148
167
|
process.stdin.setRawMode(false);
|
|
149
168
|
process.stdin.pause();
|
|
@@ -151,6 +170,12 @@ export function selectFromList(title, items) {
|
|
|
151
170
|
resolve(value);
|
|
152
171
|
};
|
|
153
172
|
const onKey = (str, key) => {
|
|
173
|
+
// Any key means a person is choosing: stop counting.
|
|
174
|
+
if (timer) {
|
|
175
|
+
clearInterval(timer);
|
|
176
|
+
timer = null;
|
|
177
|
+
render();
|
|
178
|
+
}
|
|
154
179
|
if (key.ctrl && key.name === "c") {
|
|
155
180
|
finish(null);
|
|
156
181
|
return;
|
|
@@ -177,6 +202,16 @@ export function selectFromList(title, items) {
|
|
|
177
202
|
process.stdin.setRawMode(true);
|
|
178
203
|
process.stdin.resume();
|
|
179
204
|
process.stdin.on("keypress", onKey);
|
|
205
|
+
if (remaining > 0 && items.length > 0) {
|
|
206
|
+
timer = setInterval(() => {
|
|
207
|
+
remaining -= 1;
|
|
208
|
+
if (remaining <= 0) {
|
|
209
|
+
finish(items[0].value);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
render();
|
|
213
|
+
}, 1000);
|
|
214
|
+
}
|
|
180
215
|
render(true);
|
|
181
216
|
});
|
|
182
217
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pick-project.js","sourceRoot":"","sources":["../../src/lib/pick-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"pick-project.js","sourceRoot":"","sources":["../../src/lib/pick-project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
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: projects used from `dir` first, most recent first;
|
|
41
|
+
* then running before the rest; then by name. Returns how many at the top
|
|
42
|
+
* were used here, so the caller knows whether there is a "last used" to
|
|
43
|
+
* pre-select.
|
|
44
|
+
*/
|
|
45
|
+
export function orderForDir(projects, recent, dir) {
|
|
46
|
+
const rank = new Map((recent[dir] ?? []).map((e, i) => [e.slug, i]));
|
|
47
|
+
const ordered = [...projects].sort((a, b) => {
|
|
48
|
+
const ra = rank.get(a.slug) ?? Infinity;
|
|
49
|
+
const rb = rank.get(b.slug) ?? Infinity;
|
|
50
|
+
if (ra !== rb)
|
|
51
|
+
return ra - rb;
|
|
52
|
+
return Number(b.status === "RUNNING") - Number(a.status === "RUNNING") || a.name.localeCompare(b.name);
|
|
53
|
+
});
|
|
54
|
+
return { ordered, usedHere: ordered.filter((p) => rank.has(p.slug)).length };
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=recent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recent.js","sourceRoot":"","sources":["../../src/lib/recent.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.5";
|
|
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);
|