dockai 0.2.2 → 0.2.4
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 +42 -22
- package/dist/commands/__tests__/claude-default.test.js +25 -0
- package/dist/commands/__tests__/claude-default.test.js.map +1 -0
- package/dist/commands/accounts.js +186 -0
- package/dist/commands/accounts.js.map +1 -0
- package/dist/commands/claude.js +32 -10
- package/dist/commands/claude.js.map +1 -1
- package/dist/commands/connect.js +6 -1
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/deploy.js +2 -2
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/login.js +26 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logs.js +10 -6
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/open.js +11 -12
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/projects.js +14 -6
- package/dist/commands/projects.js.map +1 -1
- package/dist/commands/start-stop.js +8 -10
- package/dist/commands/start-stop.js.map +1 -1
- package/dist/commands/status.js +5 -2
- package/dist/commands/status.js.map +1 -1
- package/dist/index.js +51 -22
- package/dist/index.js.map +1 -1
- package/dist/lib/__tests__/accounts.test.js +40 -0
- package/dist/lib/__tests__/accounts.test.js.map +1 -0
- package/dist/lib/__tests__/fail.test.js +33 -0
- package/dist/lib/__tests__/fail.test.js.map +1 -0
- package/dist/lib/__tests__/remote.test.js +81 -0
- package/dist/lib/__tests__/remote.test.js.map +1 -0
- package/dist/lib/accounts.js +90 -0
- package/dist/lib/accounts.js.map +1 -0
- package/dist/lib/fail.js +48 -0
- package/dist/lib/fail.js.map +1 -0
- package/dist/lib/pick-project.js +7 -0
- package/dist/lib/pick-project.js.map +1 -1
- package/dist/lib/remote.js +11 -2
- package/dist/lib/remote.js.map +1 -1
- package/dist/terminal.js +11 -6
- package/dist/terminal.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAY,EACZ,OAA0B;IAE1B,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,6DAA6D;IAC7D,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,OAAO,CAAC,KAAK,CAAC,wCAAwC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEtC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAc,CAAC;QAC/D,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAChC,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAErE,CAAC;QACF,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,EAAE,0BAA0B,CAAC,CAAC;IACxC,CAAC;AACH,CAAC"}
|
package/dist/commands/open.js
CHANGED
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
import open from "open";
|
|
2
2
|
import { createApiClient } from "../api.js";
|
|
3
|
+
import { getServerUrl } from "../config.js";
|
|
4
|
+
import { fail, noSuchProject } from "../lib/fail.js";
|
|
3
5
|
export async function openCommand(slug) {
|
|
4
6
|
const api = createApiClient();
|
|
5
7
|
try {
|
|
6
8
|
const projects = (await api.project.list.query());
|
|
7
9
|
const project = projects.find((p) => p.slug === slug);
|
|
8
10
|
if (!project) {
|
|
9
|
-
|
|
10
|
-
process.exit(1);
|
|
11
|
-
}
|
|
12
|
-
if (project.container?.sessionUrl) {
|
|
13
|
-
console.log(`Opening ${project.container.sessionUrl}...`);
|
|
14
|
-
await open(project.container.sessionUrl);
|
|
15
|
-
}
|
|
16
|
-
else {
|
|
17
|
-
console.log("No active session URL. Is the project running?");
|
|
11
|
+
noSuchProject(slug, projects);
|
|
18
12
|
}
|
|
13
|
+
// This used to read `container.sessionUrl`, a column nothing in the
|
|
14
|
+
// server ever writes — so it answered "No active session URL. Is the
|
|
15
|
+
// project running?" on a running project, every time (audit 6 §3). What
|
|
16
|
+
// a person means by `dockai open <slug>` is the project's page.
|
|
17
|
+
const url = `${getServerUrl().replace(/\/$/, "")}/projects/${project.slug}`;
|
|
18
|
+
console.log(`Opening ${url}`);
|
|
19
|
+
await open(url);
|
|
19
20
|
}
|
|
20
21
|
catch (err) {
|
|
21
|
-
|
|
22
|
-
console.error("Failed:", msg);
|
|
23
|
-
process.exit(1);
|
|
22
|
+
fail(err);
|
|
24
23
|
}
|
|
25
24
|
}
|
|
26
25
|
//# sourceMappingURL=open.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY;IAC5C,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAc,CAAC;QAC/D,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAChC,CAAC;QAED,oEAAoE;QACpE,qEAAqE;QACrE,wEAAwE;QACxE,gEAAgE;QAChE,MAAM,GAAG,GAAG,GAAG,YAAY,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5E,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC;QAC9B,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createApiClient } from "../api.js";
|
|
2
|
+
import { fail } from "../lib/fail.js";
|
|
2
3
|
const statusIcons = {
|
|
3
4
|
RUNNING: "\x1b[32m●\x1b[0m",
|
|
4
5
|
STARTING: "\x1b[33m◐\x1b[0m",
|
|
@@ -6,10 +7,17 @@ const statusIcons = {
|
|
|
6
7
|
ERROR: "\x1b[31m●\x1b[0m",
|
|
7
8
|
STOPPED: "\x1b[90m○\x1b[0m",
|
|
8
9
|
};
|
|
9
|
-
export async function projectsCommand() {
|
|
10
|
+
export async function projectsCommand(options = {}) {
|
|
10
11
|
const api = createApiClient();
|
|
11
12
|
try {
|
|
12
13
|
const projects = (await api.project.list.query());
|
|
14
|
+
// The list was unparsable for scripting except by stripping ANSI, which
|
|
15
|
+
// is the kind of thing a person writes once and then maintains for ever
|
|
16
|
+
// (audit 6 §17).
|
|
17
|
+
if (options.json) {
|
|
18
|
+
console.log(JSON.stringify(projects.map((p) => ({ name: p.name, slug: p.slug, status: p.status })), null, 2));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
13
21
|
if (!projects.length) {
|
|
14
22
|
console.log("No projects found. Create one in the dashboard.");
|
|
15
23
|
return;
|
|
@@ -17,15 +25,15 @@ export async function projectsCommand() {
|
|
|
17
25
|
console.log("\nProjects:\n");
|
|
18
26
|
for (const p of projects) {
|
|
19
27
|
const icon = statusIcons[p.status] || "?";
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
// `container.sessionUrl` is a column nothing in the server writes, so
|
|
29
|
+
// this suffix never appeared (audit 6 §3, the same dead field `open`
|
|
30
|
+
// was reading).
|
|
31
|
+
console.log(` ${icon} ${p.name} (${p.slug}) [${p.status}]`);
|
|
22
32
|
}
|
|
23
33
|
console.log();
|
|
24
34
|
}
|
|
25
35
|
catch (err) {
|
|
26
|
-
|
|
27
|
-
console.error("Failed to list projects:", msg);
|
|
28
|
-
process.exit(1);
|
|
36
|
+
fail(err, "Could not list your projects");
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
39
|
//# sourceMappingURL=projects.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/commands/projects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/commands/projects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtC,MAAM,WAAW,GAA2B;IAC1C,OAAO,EAAE,kBAAkB;IAC3B,QAAQ,EAAE,kBAAkB;IAC5B,QAAQ,EAAE,kBAAkB;IAC5B,KAAK,EAAE,kBAAkB;IACzB,OAAO,EAAE,kBAAkB;CAC5B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAO,GAAuB,EAAE;IACpE,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAc,CAAC;QAE/D,wEAAwE;QACxE,wEAAwE;QACxE,iBAAiB;QACjB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC9G,OAAO;QACT,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;YAC/D,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAC7B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC;YAC1C,sEAAsE;YACtE,qEAAqE;YACrE,gBAAgB;YAChB,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,EAAE,8BAA8B,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC"}
|
|
@@ -1,37 +1,35 @@
|
|
|
1
1
|
import { createApiClient } from "../api.js";
|
|
2
|
+
import { fail, noSuchProject } from "../lib/fail.js";
|
|
2
3
|
async function findProject(api, slug) {
|
|
3
4
|
const projects = (await api.project.list.query());
|
|
4
5
|
const project = projects.find((p) => p.slug === slug);
|
|
5
6
|
if (!project) {
|
|
6
|
-
|
|
7
|
-
process.exit(1);
|
|
7
|
+
noSuchProject(slug, projects);
|
|
8
8
|
}
|
|
9
9
|
return project;
|
|
10
10
|
}
|
|
11
11
|
export async function startCommand(slug) {
|
|
12
12
|
const api = createApiClient();
|
|
13
|
-
|
|
13
|
+
// Inside the try: `findProject` is an API call, and with the server down it
|
|
14
|
+
// threw a raw `TRPCClientError` straight to the terminal (audit 6 §9).
|
|
14
15
|
try {
|
|
16
|
+
const project = await findProject(api, slug);
|
|
15
17
|
await api.project.start.mutate({ id: project.id });
|
|
16
18
|
console.log(`Starting ${project.name}...`);
|
|
17
19
|
}
|
|
18
20
|
catch (err) {
|
|
19
|
-
|
|
20
|
-
console.error("Failed to start:", msg);
|
|
21
|
-
process.exit(1);
|
|
21
|
+
fail(err, "Could not start it");
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
export async function stopCommand(slug) {
|
|
25
25
|
const api = createApiClient();
|
|
26
|
-
const project = await findProject(api, slug);
|
|
27
26
|
try {
|
|
27
|
+
const project = await findProject(api, slug);
|
|
28
28
|
await api.project.stop.mutate({ id: project.id });
|
|
29
29
|
console.log(`Stopping ${project.name}...`);
|
|
30
30
|
}
|
|
31
31
|
catch (err) {
|
|
32
|
-
|
|
33
|
-
console.error("Failed to stop:", msg);
|
|
34
|
-
process.exit(1);
|
|
32
|
+
fail(err, "Could not stop it");
|
|
35
33
|
}
|
|
36
34
|
}
|
|
37
35
|
//# sourceMappingURL=start-stop.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start-stop.js","sourceRoot":"","sources":["../../src/commands/start-stop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgC,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"start-stop.js","sourceRoot":"","sources":["../../src/commands/start-stop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgC,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAErD,KAAK,UAAU,WAAW,CAAC,GAAc,EAAE,IAAY;IACrD,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAc,CAAC;IAC/D,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,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY;IAC7C,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,4EAA4E;IAC5E,uEAAuE;IACvE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC7C,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY;IAC5C,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC7C,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QAClD,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;IACjC,CAAC;AACH,CAAC"}
|
package/dist/commands/status.js
CHANGED
|
@@ -14,11 +14,14 @@ export async function statusCommand() {
|
|
|
14
14
|
catch {
|
|
15
15
|
console.log(`\nServer: ${serverUrl}`);
|
|
16
16
|
console.log(`Status: \x1b[31munreachable\x1b[0m\n`);
|
|
17
|
-
|
|
17
|
+
// Exit non-zero, or `dockai status` cannot be used as a health check —
|
|
18
|
+
// it reported success for an unreachable server and for a missing login
|
|
19
|
+
// alike (audit 6 §17).
|
|
20
|
+
process.exit(1);
|
|
18
21
|
}
|
|
19
22
|
if (!token) {
|
|
20
23
|
console.log("\nNot logged in. Run 'dockai login' first.\n");
|
|
21
|
-
|
|
24
|
+
process.exit(1);
|
|
22
25
|
}
|
|
23
26
|
try {
|
|
24
27
|
const projects = (await api.project.list.query());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,SAAS,aAAa,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA0C,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,aAAa,SAAS,EAAE,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,CAAC,MAAM,SAAS,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,aAAa,SAAS,EAAE,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACpD,OAAO;
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEtD,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAE9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,SAAS,aAAa,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA0C,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,aAAa,SAAS,EAAE,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,CAAC,MAAM,SAAS,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,aAAa,SAAS,EAAE,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACpD,uEAAuE;QACvE,wEAAwE;QACxE,uBAAuB;QACvB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAc,CAAC;QAC/D,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,eAAe,QAAQ,CAAC,MAAM,WAAW,OAAO,YAAY,CAAC,CAAC;IAC5E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACxD,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;QAC/D,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,+BAA+B,GAAG,IAAI,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -17,15 +17,29 @@ import { sessionsPushCommand, sessionsListCommand, sessionsResumeCommand, sessio
|
|
|
17
17
|
import { deployCommand } from "./commands/deploy.js";
|
|
18
18
|
import { ensureSlug } from "./lib/pick-project.js";
|
|
19
19
|
import { pasteCommand } from "./commands/paste.js";
|
|
20
|
+
import { accountsCommand, accountsLoginCommand } from "./commands/accounts.js";
|
|
20
21
|
import { CLI_VERSION } from "./version.js";
|
|
21
22
|
const program = new Command();
|
|
22
23
|
program
|
|
23
24
|
.name("dockai")
|
|
24
|
-
.description("CLI for DockAI — self-hosted Claude Code
|
|
25
|
+
.description("CLI for DockAI — self-hosted Claude Code workers")
|
|
25
26
|
.version(CLI_VERSION)
|
|
26
27
|
// Lets `dockai claude <slug> --resume x -r` hand every flag after the slug to
|
|
27
28
|
// claude untouched, without a `--` separator.
|
|
28
|
-
.enablePositionalOptions()
|
|
29
|
+
.enablePositionalOptions()
|
|
30
|
+
// There were no examples anywhere, and the three flag rules a person cannot
|
|
31
|
+
// guess live in four different command descriptions (audit 6 §17).
|
|
32
|
+
.addHelpText("after", `
|
|
33
|
+
Examples:
|
|
34
|
+
$ dockai login set the server and token, once per laptop
|
|
35
|
+
$ dockai projects --json machine-readable, for scripts
|
|
36
|
+
$ dockai claude app Claude Code in the "app" worker, in tmux
|
|
37
|
+
$ dockai claude app --permission-mode bypassPermissions
|
|
38
|
+
flags AFTER the project name go to claude
|
|
39
|
+
$ dockai claude -s scratch app flags BEFORE it are dockai's own
|
|
40
|
+
$ ssh dockai-app the same worker as a plain ssh host
|
|
41
|
+
$ dockai status exits non-zero if the server is unreachable
|
|
42
|
+
`);
|
|
29
43
|
program
|
|
30
44
|
.command("login")
|
|
31
45
|
.description("Authenticate with the DockAI server")
|
|
@@ -43,6 +57,7 @@ program
|
|
|
43
57
|
program
|
|
44
58
|
.command("projects")
|
|
45
59
|
.description("List all projects with status")
|
|
60
|
+
.option("--json", "Print the raw list, for scripts")
|
|
46
61
|
.action(projectsCommand);
|
|
47
62
|
program
|
|
48
63
|
.command("start <slug>")
|
|
@@ -54,8 +69,8 @@ program
|
|
|
54
69
|
.action(stopCommand);
|
|
55
70
|
program
|
|
56
71
|
.command("connect <slug>")
|
|
57
|
-
.description("
|
|
58
|
-
.option("--claude", "
|
|
72
|
+
.description("Open a terminal in the project's worker")
|
|
73
|
+
.option("--claude", "Open Claude instead of a shell")
|
|
59
74
|
.option("--ssh", "Connect via SSH instead of WebSocket")
|
|
60
75
|
.action(connectCommand);
|
|
61
76
|
program
|
|
@@ -65,7 +80,7 @@ program
|
|
|
65
80
|
.action(logsCommand);
|
|
66
81
|
program
|
|
67
82
|
.command("open <slug>")
|
|
68
|
-
.description("Open the
|
|
83
|
+
.description("Open the conversation's claude.ai URL in a browser")
|
|
69
84
|
.action(openCommand);
|
|
70
85
|
program
|
|
71
86
|
.command("ssh-config")
|
|
@@ -78,15 +93,15 @@ program
|
|
|
78
93
|
.action(codeCommand);
|
|
79
94
|
program
|
|
80
95
|
.command("claude <slug> [claudeArgs...]")
|
|
81
|
-
.description("Run Claude Code inside the project's worker, in tmux
|
|
96
|
+
.description("Run Claude Code inside the project's worker, in tmux. At a terminal it asks: a new conversation, or which one to join. --resume <id|title> goes straight to one; other flags after the project name go to claude: dockai claude app --permission-mode bypassPermissions")
|
|
82
97
|
// No default here: an unset session is what lets the command join the
|
|
83
98
|
// conversation the phone is on; naming one is an explicit choice.
|
|
84
99
|
.option("-s, --session <name>", "tmux session to attach to or create (before the project name; default claude-cli)")
|
|
85
100
|
.option("--no-tmux", "Skip tmux — the session ends when you disconnect (before the project name)")
|
|
86
|
-
.option("--no-chrome", "Don't forward this
|
|
87
|
-
.option("--no-client", "Don't offer this
|
|
88
|
-
.option("--root <dir>", "Directory the
|
|
89
|
-
.option("--allow-run", "Let the
|
|
101
|
+
.option("--no-chrome", "Don't forward this laptop's Claude in Chrome bridge into the worker (before the project name)")
|
|
102
|
+
.option("--no-client", "Don't offer this laptop's files and clipboard to the conversation (before the project name)")
|
|
103
|
+
.option("--root <dir>", "Directory the conversation may read from on this laptop; repeatable (default: the current directory)", (v, prev) => [...(prev ?? []), v], [])
|
|
104
|
+
.option("--allow-run", "Let the conversation run commands on this laptop (each run is logged here); the project's own setting is the default")
|
|
90
105
|
.option("--no-allow-run", "Refuse commands on this machine even if the project allows them by default")
|
|
91
106
|
.passThroughOptions()
|
|
92
107
|
.action((slug, claudeArgs, options) => claudeCommand(slug, options, claudeArgs));
|
|
@@ -95,16 +110,28 @@ program
|
|
|
95
110
|
.description("Copy local files into the project's workspace — the .env and scripts a clone doesn't carry")
|
|
96
111
|
.option("--keep-existing", "Leave files that already exist on the worker untouched")
|
|
97
112
|
.action(pushCommand);
|
|
113
|
+
const accounts = program
|
|
114
|
+
.command("accounts")
|
|
115
|
+
.description("Your Claude accounts: signed in or not, plan, and usage (session and weekly windows)")
|
|
116
|
+
.action(accountsCommand);
|
|
117
|
+
accounts
|
|
118
|
+
.command("login [name]")
|
|
119
|
+
.description("Sign a Claude account in with this computer's browser — the same sign-in as the dashboard's")
|
|
120
|
+
.action(accountsLoginCommand);
|
|
121
|
+
program
|
|
122
|
+
.command("usage")
|
|
123
|
+
.description("Claude usage per account — the same as `dockai accounts`")
|
|
124
|
+
.action(accountsCommand);
|
|
98
125
|
const sessions = program
|
|
99
126
|
.command("sessions")
|
|
100
|
-
.description("Move
|
|
127
|
+
.description("Move this laptop's Claude conversations into a project");
|
|
101
128
|
sessions
|
|
102
129
|
.command("list <slug>")
|
|
103
|
-
.description("Conversations on the worker, with ids and whether each is live
|
|
130
|
+
.description("Conversations on the worker, with ids and whether each is live")
|
|
104
131
|
.action(sessionsListCommand);
|
|
105
132
|
sessions
|
|
106
133
|
.command("resume <slug> <session>")
|
|
107
|
-
.description("Open a conversation by id, id prefix or name — in a terminal here, or
|
|
134
|
+
.description("Open a conversation by id, id prefix or name — in a terminal here, or in the Claude app with --remote")
|
|
108
135
|
.option("--remote", "Register it with Remote Control through DockAI instead of opening a terminal")
|
|
109
136
|
.action(sessionsResumeCommand);
|
|
110
137
|
sessions
|
|
@@ -114,21 +141,21 @@ sessions
|
|
|
114
141
|
.option("--title <title>", "Title for the new conversation (default: the old one's)")
|
|
115
142
|
.option("--file-only", "Write the hand-off file without creating a conversation, to send the message in one that already exists")
|
|
116
143
|
.option("--into <id>", "Continue in this existing conversation instead of creating one: a cse_… id (environment) or a local id with --terminal")
|
|
117
|
-
.option("--terminal", "Continue in
|
|
144
|
+
.option("--terminal", "Continue in a terminal conversation — in the Claude app and joinable with dockai claude — instead of an app-only one")
|
|
118
145
|
.action(sessionsHandoffCommand);
|
|
119
146
|
sessions
|
|
120
147
|
.command("push <slug>")
|
|
121
|
-
.description("Copy this directory's Claude
|
|
122
|
-
.option("--from <dir>", "Local project directory whose
|
|
123
|
-
.option("--latest <n>", "Only the n most recently used
|
|
124
|
-
.option("--session <id...>", "Only these
|
|
125
|
-
.option("--overwrite", "Replace
|
|
126
|
-
.option("--remote", "Then
|
|
148
|
+
.description("Copy this directory's Claude conversations and memory into the project, with paths rewritten to the workspace")
|
|
149
|
+
.option("--from <dir>", "Local project directory whose conversations to push (default: current directory)")
|
|
150
|
+
.option("--latest <n>", "Only the n most recently used conversations")
|
|
151
|
+
.option("--session <id...>", "Only these conversations (id or unique prefix); repeatable")
|
|
152
|
+
.option("--overwrite", "Replace conversations that already exist on the worker")
|
|
153
|
+
.option("--remote", "Then register each pushed conversation with Remote Control, so it appears in the Claude app")
|
|
127
154
|
.option("--dry-run", "Show what would be pushed without sending anything")
|
|
128
155
|
.action(sessionsPushCommand);
|
|
129
156
|
program
|
|
130
157
|
.command("paste <slug>")
|
|
131
|
-
.description("Paste the image on your clipboard into a running dockai claude
|
|
158
|
+
.description("Paste the image on your clipboard into a running dockai claude conversation (macOS)")
|
|
132
159
|
.option("-s, --session <name>", "tmux session to type into", "claude-cli")
|
|
133
160
|
.action(pasteCommand);
|
|
134
161
|
program
|
|
@@ -147,7 +174,9 @@ program
|
|
|
147
174
|
// Commands that take a project first: ask for it when it was left out.
|
|
148
175
|
let argv = process.argv;
|
|
149
176
|
argv = await ensureSlug(argv, ["claude"], { flags: ["--no-tmux", "--tmux", "--no-chrome", "--chrome", "--no-client", "--allow-run", "--no-allow-run"], valued: ["-s", "--session", "--root"] });
|
|
150
|
-
|
|
177
|
+
// `sessions handoff` was missing from this list, so it alone asked for a slug
|
|
178
|
+
// differently from its three siblings (audit 6 §17).
|
|
179
|
+
for (const path of [["push"], ["paste"], ["sessions", "list"], ["sessions", "resume"], ["sessions", "push"], ["sessions", "handoff"]]) {
|
|
151
180
|
argv = await ensureSlug(argv, path);
|
|
152
181
|
}
|
|
153
182
|
await program.parseAsync(argv);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACjI,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { accountState, findAccount, findLoginUrl, planLabel, usageLine } from "../accounts.js";
|
|
3
|
+
const accounts = [
|
|
4
|
+
{ id: "cmA", label: "FrogJump", isValid: true },
|
|
5
|
+
{ id: "cmB", label: "Personal", isValid: false, hasSdkToken: true },
|
|
6
|
+
{ id: "cmC", label: "Personal old", isValid: false },
|
|
7
|
+
];
|
|
8
|
+
describe("dockai accounts", () => {
|
|
9
|
+
it("says the dashboard's three states", () => {
|
|
10
|
+
expect(accounts.map(accountState)).toEqual(["signed in", "token only", "not signed in"]);
|
|
11
|
+
});
|
|
12
|
+
it("never prints a raw tier", () => {
|
|
13
|
+
expect(planLabel("default_claude_max_20x")).toBe("Max 20x");
|
|
14
|
+
expect(planLabel(null)).toBeNull();
|
|
15
|
+
expect(planLabel("default_claude_ultra_plus")).toBe("ultra plus");
|
|
16
|
+
});
|
|
17
|
+
it("prints the windows, and says why when there are none", () => {
|
|
18
|
+
expect(usageLine({ fiveHour: { utilization: 2.4, resetsIn: "4h 8m" }, sevenDay: { utilization: 90, resetsIn: "1d 8h" }, scoped: [{ name: "Fable", utilization: 83 }], source: "api" }, true))
|
|
19
|
+
.toBe("session 2% (resets in 4h 8m) · weekly 90% (resets in 1d 8h) · Fable 83%");
|
|
20
|
+
expect(usageLine(null, false)).toMatch(/start a project/);
|
|
21
|
+
expect(usageLine({ fiveHour: null, sevenDay: null, source: "error", error: "Rate limited" }, true)).toBe("usage: Rate limited");
|
|
22
|
+
});
|
|
23
|
+
it("finds an account by id, exact name or unique prefix, and refuses to guess", () => {
|
|
24
|
+
expect(findAccount(accounts, "cmB")).toMatchObject({ label: "Personal" });
|
|
25
|
+
expect(findAccount(accounts, "personal")).toMatchObject({ label: "Personal" });
|
|
26
|
+
expect(findAccount(accounts, "frog")).toMatchObject({ label: "FrogJump" });
|
|
27
|
+
expect(findAccount(accounts, "pers")).toMatch(/matches 2 accounts/);
|
|
28
|
+
expect(findAccount(accounts, "nope")).toMatch(/No Claude account matches/);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe("the sign-in link in claude auth login's output", () => {
|
|
32
|
+
it("is found across a wrap and escape codes", () => {
|
|
33
|
+
const out = "Browser didn't open? Use the url below to sign in:\r\n\r\n\u001b[1mhttps://claude.ai/oauth/authorize?code=true&client_id=abc\r\n&state=xyz\u001b[22m \r\n";
|
|
34
|
+
expect(findLoginUrl(out)).toBe("https://claude.ai/oauth/authorize?code=true&client_id=abc&state=xyz");
|
|
35
|
+
});
|
|
36
|
+
it("is null until it has arrived", () => {
|
|
37
|
+
expect(findLoginUrl("Opening browser to sign in…")).toBeNull();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=accounts.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/accounts.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
vi.mock("../../config.js", () => ({ getServerUrl: () => "https://dockai.example.com" }));
|
|
3
|
+
const { explain } = await import("../fail.js");
|
|
4
|
+
/**
|
|
5
|
+
* One sentence, never a stack.
|
|
6
|
+
*
|
|
7
|
+
* `start`, `stop` and `ssh-config` called the API outside their `try`, so a
|
|
8
|
+
* server that was down printed twelve lines of `node_modules` paths and an
|
|
9
|
+
* undici frame — while `dockai projects`, in the same situation, printed one
|
|
10
|
+
* sentence. Four more commands let a bare `UNAUTHORIZED` reach the screen as
|
|
11
|
+
* their entire output (audit 6 §9).
|
|
12
|
+
*/
|
|
13
|
+
describe("explain", () => {
|
|
14
|
+
it("names the server when it cannot be reached", () => {
|
|
15
|
+
const msg = explain(new Error("fetch failed"));
|
|
16
|
+
expect(msg).toContain("dockai.example.com");
|
|
17
|
+
expect(msg).toMatch(/dockai login/);
|
|
18
|
+
});
|
|
19
|
+
it("says what a rejected token is, not its code", () => {
|
|
20
|
+
expect(explain(new Error("UNAUTHORIZED"))).toMatch(/token was rejected/i);
|
|
21
|
+
expect(explain(new Error("UNAUTHORIZED"))).not.toMatch(/UNAUTHORIZED/);
|
|
22
|
+
});
|
|
23
|
+
it("keeps a tRPC message written for a person", () => {
|
|
24
|
+
expect(explain(new Error("Start the project first"))).toBe("Start the project first");
|
|
25
|
+
});
|
|
26
|
+
it("drops the stack, which is what used to be the output", () => {
|
|
27
|
+
const err = new Error("TRPCClientError: fetch failed\n\n at node:internal/deps/undici/undici:15157:13\n at process.processTicksAndRejections");
|
|
28
|
+
const msg = explain(err);
|
|
29
|
+
expect(msg, "a node_modules frame reached the terminal").not.toMatch(/node:internal|at process/);
|
|
30
|
+
expect(msg.split("\n").length).toBeLessThanOrEqual(3);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=fail.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fail.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/fail.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAElD,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,4BAA4B,EAAE,CAAC,CAAC,CAAC;AAEzF,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;AAE/C;;;;;;;;GAQG;AACH,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;QAC1E,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,GAAG,GAAG,IAAI,KAAK,CACnB,6HAA6H,CAC9H,CAAC;QACF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,CAAC,GAAG,EAAE,2CAA2C,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;QACjG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import { sq, dq } from "../remote.js";
|
|
4
|
+
/**
|
|
5
|
+
* The quoting that carries a command across two shells.
|
|
6
|
+
*
|
|
7
|
+
* `dockai claude <slug>` builds one string that ssh hands to `sh -c`, which
|
|
8
|
+
* hands part of it to tmux, which hands that to `sh -c` again. CLAUDE.md §7
|
|
9
|
+
* says these are "verified against `$VAR`, quotes, backticks, and directories
|
|
10
|
+
* containing spaces — change `sq`/`dq` only with an equivalent test". There
|
|
11
|
+
* was no test: `pnpm -r test:run` skipped this package entirely, because it
|
|
12
|
+
* had no `test:run`, so no failure was possible in the one part of the repo
|
|
13
|
+
* that ships to npm (audit 5 §8.2).
|
|
14
|
+
*
|
|
15
|
+
* These run a real `/bin/sh`. Asserting the escaped string looks right is
|
|
16
|
+
* asserting a guess about a shell; asking the shell is the contract.
|
|
17
|
+
*/
|
|
18
|
+
const HOSTILE = [
|
|
19
|
+
"plain",
|
|
20
|
+
"with spaces",
|
|
21
|
+
"$HOME",
|
|
22
|
+
"${HOME}",
|
|
23
|
+
"`id`",
|
|
24
|
+
"$(id)",
|
|
25
|
+
'double"quote',
|
|
26
|
+
"single'quote",
|
|
27
|
+
"back\\slash",
|
|
28
|
+
"semi;colon && echo pwned",
|
|
29
|
+
"new\nline",
|
|
30
|
+
"tab\there",
|
|
31
|
+
"a|b&c<d>e*f?g[h]i{j}k",
|
|
32
|
+
"emoji 🐸 and accents ñáü",
|
|
33
|
+
];
|
|
34
|
+
/** What `sh -c <script>` prints on stdout, exactly. */
|
|
35
|
+
const shell = (script) => execFileSync("/bin/sh", ["-c", script], { encoding: "utf8" });
|
|
36
|
+
describe("sq — POSIX single-quote", () => {
|
|
37
|
+
it.each(HOSTILE)("survives one shell unchanged: %j", (value) => {
|
|
38
|
+
expect(shell(`printf %s ${sq(value)}`)).toBe(value);
|
|
39
|
+
});
|
|
40
|
+
it("is what makes a workspace path with a space work", () => {
|
|
41
|
+
// The real call site: `cd ${sq(workspace)} && exec …`
|
|
42
|
+
expect(shell(`cd ${sq("/tmp")} && printf %s "$PWD"`)).toBe("/tmp");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe("dq — survives one round of double-quoted expansion", () => {
|
|
46
|
+
it.each(HOSTILE)("survives being inside double quotes: %j", (value) => {
|
|
47
|
+
expect(shell(`printf %s ${dq(value)}`)).toBe(value);
|
|
48
|
+
});
|
|
49
|
+
it("carries a whole command through the outer shell to the inner one", () => {
|
|
50
|
+
// The real call site: `tmux new-session … ${dq(claudeCmd)}`, where tmux
|
|
51
|
+
// runs the result through a shell of its own.
|
|
52
|
+
const inner = `printf %s ${sq("it survived $HOME `id`")}`;
|
|
53
|
+
expect(shell(`sh -c ${dq(inner)}`)).toBe("it survived $HOME `id`");
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
/**
|
|
57
|
+
* `--help` reaches Commander.
|
|
58
|
+
*
|
|
59
|
+
* `ensureSlug` runs before `program.parseAsync` and treated `--help` as a
|
|
60
|
+
* missing project: logged out, `dockai claude --help` answered *"Not logged
|
|
61
|
+
* in. Run `dockai login` first."* and exited 1; logged in, it opened an
|
|
62
|
+
* interactive picker. Five commands, including the flagship one and the four
|
|
63
|
+
* with the subtlest flag rules — among them the rule a person cannot guess,
|
|
64
|
+
* that flags *after* the project name go to `claude` untouched, documented in
|
|
65
|
+
* the help you could not print (audit 6 §3).
|
|
66
|
+
*/
|
|
67
|
+
describe("ensureSlug", () => {
|
|
68
|
+
it("leaves --help alone instead of asking which project", async () => {
|
|
69
|
+
const { ensureSlug } = await import("../pick-project.js");
|
|
70
|
+
for (const argv of [
|
|
71
|
+
["node", "dockai", "claude", "--help"],
|
|
72
|
+
["node", "dockai", "claude", "-h"],
|
|
73
|
+
["node", "dockai", "push", "--help"],
|
|
74
|
+
]) {
|
|
75
|
+
// Returns untouched, and — the half that matters — never reaches the
|
|
76
|
+
// network, so this resolves with no server and no token.
|
|
77
|
+
await expect(ensureSlug([...argv], [argv[2]])).resolves.toEqual(argv);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
//# sourceMappingURL=remote.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/remote.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAEtC;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,GAAG;IACd,OAAO;IACP,aAAa;IACb,OAAO;IACP,SAAS;IACT,MAAM;IACN,OAAO;IACP,cAAc;IACd,cAAc;IACd,aAAa;IACb,0BAA0B;IAC1B,WAAW;IACX,WAAW;IACX,uBAAuB;IACvB,0BAA0B;CAC3B,CAAC;AAEF,uDAAuD;AACvD,MAAM,KAAK,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;AAEhG,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,kCAAkC,EAAE,CAAC,KAAK,EAAE,EAAE;QAC7D,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,sDAAsD;QACtD,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oDAAoD,EAAE,GAAG,EAAE;IAClE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,yCAAyC,EAAE,CAAC,KAAK,EAAE,EAAE;QACpE,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,wEAAwE;QACxE,8CAA8C;QAC9C,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC,wBAAwB,CAAC,EAAE,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH;;;;;;;;;;GAUG;AACH,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAC1D,KAAK,MAAM,IAAI,IAAI;YACjB,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;YACtC,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC;YAClC,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACrC,EAAE,CAAC;YACF,qEAAqE;YACrE,yDAAyD;YACzD,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACxE,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|