dockai 0.2.2

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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -0
  3. package/dist/api.js +17 -0
  4. package/dist/api.js.map +1 -0
  5. package/dist/commands/claude.js +301 -0
  6. package/dist/commands/claude.js.map +1 -0
  7. package/dist/commands/connect.js +55 -0
  8. package/dist/commands/connect.js.map +1 -0
  9. package/dist/commands/deploy.js +98 -0
  10. package/dist/commands/deploy.js.map +1 -0
  11. package/dist/commands/login.js +103 -0
  12. package/dist/commands/login.js.map +1 -0
  13. package/dist/commands/logout.js +10 -0
  14. package/dist/commands/logout.js.map +1 -0
  15. package/dist/commands/logs.js +26 -0
  16. package/dist/commands/logs.js.map +1 -0
  17. package/dist/commands/open.js +26 -0
  18. package/dist/commands/open.js.map +1 -0
  19. package/dist/commands/paste.js +63 -0
  20. package/dist/commands/paste.js.map +1 -0
  21. package/dist/commands/projects.js +31 -0
  22. package/dist/commands/projects.js.map +1 -0
  23. package/dist/commands/proxy.js +55 -0
  24. package/dist/commands/proxy.js.map +1 -0
  25. package/dist/commands/push.js +53 -0
  26. package/dist/commands/push.js.map +1 -0
  27. package/dist/commands/sessions.js +330 -0
  28. package/dist/commands/sessions.js.map +1 -0
  29. package/dist/commands/ssh-config.js +138 -0
  30. package/dist/commands/ssh-config.js.map +1 -0
  31. package/dist/commands/start-stop.js +37 -0
  32. package/dist/commands/start-stop.js.map +1 -0
  33. package/dist/commands/status.js +38 -0
  34. package/dist/commands/status.js.map +1 -0
  35. package/dist/commands/whoami.js +27 -0
  36. package/dist/commands/whoami.js.map +1 -0
  37. package/dist/config.js +34 -0
  38. package/dist/config.js.map +1 -0
  39. package/dist/index.js +154 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/lib/client-tools.js +175 -0
  42. package/dist/lib/client-tools.js.map +1 -0
  43. package/dist/lib/pick-project.js +176 -0
  44. package/dist/lib/pick-project.js.map +1 -0
  45. package/dist/lib/remote.js +161 -0
  46. package/dist/lib/remote.js.map +1 -0
  47. package/dist/terminal.js +80 -0
  48. package/dist/terminal.js.map +1 -0
  49. package/dist/version.js +17 -0
  50. package/dist/version.js.map +1 -0
  51. package/package.json +52 -0
@@ -0,0 +1,161 @@
1
+ import { spawn } from "node:child_process";
2
+ import { readdirSync } from "node:fs";
3
+ import { userInfo } from "node:os";
4
+ import { createApiClient } from "../api.js";
5
+ import { getToken } from "../config.js";
6
+ /** POSIX single-quote — safe for anything, including quotes themselves. */
7
+ export function sq(s) {
8
+ return `'${s.replace(/'/g, `'\\''`)}'`;
9
+ }
10
+ /** Wrap a command so it survives one round of double-quoted expansion. */
11
+ export function dq(s) {
12
+ return `"${s.replace(/([\\$`"])/g, "\\$1")}"`;
13
+ }
14
+ /** The ssh host `dockai ssh-config` registers for a project. */
15
+ export function sshHost(slug) {
16
+ return `dockai-${slug}`;
17
+ }
18
+ /** Where the project's code lives inside the worker. */
19
+ export function workspaceDir(slug) {
20
+ return `/workspace/${slug}`;
21
+ }
22
+ /**
23
+ * Fail early with a readable reason.
24
+ *
25
+ * Without this the failure surfaces as an ssh error, because ProxyCommand's
26
+ * stderr is easy to miss behind ssh's own "Connection closed" message.
27
+ */
28
+ export async function assertRunning(slug) {
29
+ if (!getToken()) {
30
+ console.error("Not logged in. Run `dockai login` first.");
31
+ process.exit(1);
32
+ }
33
+ let projects;
34
+ try {
35
+ projects = (await createApiClient().project.list.query());
36
+ }
37
+ catch {
38
+ return; // Server unreachable — let ssh produce the error instead.
39
+ }
40
+ const project = projects.find((p) => p.slug === slug);
41
+ if (!project) {
42
+ const known = projects.map((p) => p.slug).join(", ");
43
+ console.error(`No project "${slug}".${known ? ` Known projects: ${known}` : ""}`);
44
+ process.exit(1);
45
+ }
46
+ if (project.status !== "RUNNING") {
47
+ console.error(`Project "${slug}" is ${project.status.toLowerCase()}. Start it with:`);
48
+ console.error(` dockai start ${slug}`);
49
+ process.exit(1);
50
+ }
51
+ }
52
+ /** What to print when ssh itself failed (exit 255) rather than the far end. */
53
+ export function explainSshFailure(slug) {
54
+ console.error("");
55
+ console.error(`Could not reach ${sshHost(slug)}. Is the ssh config block installed?`);
56
+ console.error(" dockai ssh-config --print >> ~/.ssh/config");
57
+ console.error("");
58
+ console.error("If it is, re-run it — the ProxyCommand hardcodes the path");
59
+ console.error("to this CLI, so moving or reinstalling dockai breaks it.");
60
+ }
61
+ /**
62
+ * Stream a local tree into a directory on the worker.
63
+ *
64
+ * tar over ssh rather than scp: a single connection through the ProxyCommand
65
+ * tunnel, modification times preserved (Claude picks `--continue` by them),
66
+ * and GNU tar on the far end can leave existing files alone. rsync would be
67
+ * the obvious tool, but the worker image does not ship it, and `scp -r`
68
+ * cannot skip what is already there.
69
+ *
70
+ * COPYFILE_DISABLE stops macOS bsdtar from adding `._*` AppleDouble entries
71
+ * for extended attributes, and --no-xattrs stops it encoding the attributes
72
+ * themselves as pax headers, which GNU tar on the worker reports line by
73
+ * line ("Ignoring unknown extended header keyword") for every file.
74
+ *
75
+ * Resolves with the exit status: 0 on success, 255 when ssh itself failed.
76
+ */
77
+ export function pushTree(slug, opts) {
78
+ const remote = `mkdir -p ${sq(opts.remoteDir)} && ` +
79
+ `tar -C ${sq(opts.remoteDir)} -x${opts.overwrite ? "" : " --skip-old-files"} -f -`;
80
+ const local = `COPYFILE_DISABLE=1 tar --no-xattrs -C ${sq(opts.cwd)} -cf - ${opts.paths.map(sq).join(" ")}`;
81
+ // bash, not sh: pipefail is what makes a local tar failure visible.
82
+ const script = `set -o pipefail; ${local} | ssh ${sq(sshHost(slug))} ${sq(remote)}`;
83
+ const child = spawn("bash", ["-c", script], { stdio: ["ignore", "inherit", "inherit"] });
84
+ return new Promise((resolve) => {
85
+ child.on("error", () => resolve(255));
86
+ child.on("close", (code) => resolve(code ?? 1));
87
+ });
88
+ }
89
+ /** Run a command on the worker over ssh and capture its output. */
90
+ export function runRemote(slug, command) {
91
+ const child = spawn("ssh", ["-o", "BatchMode=yes", sshHost(slug), command], { stdio: ["ignore", "pipe", "inherit"] });
92
+ let stdout = "";
93
+ child.stdout.on("data", (d) => { stdout += d.toString(); });
94
+ return new Promise((resolve) => {
95
+ child.on("error", () => resolve({ code: 255, stdout }));
96
+ child.on("close", (code) => resolve({ code: code ?? 1, stdout }));
97
+ });
98
+ }
99
+ /**
100
+ * Put the terminal back the way a full-screen program leaves it when it exits
101
+ * cleanly. When the tunnel dies under Claude's TUI (a deploy restarts the
102
+ * orchestrator, the network drops) nothing sends the "off" sequences, and the
103
+ * shell is left with mouse reporting on — every pointer move types
104
+ * `35;43;29M` into the prompt. Harmless to send when nothing was on.
105
+ */
106
+ export function resetTerminal() {
107
+ if (!process.stdout.isTTY)
108
+ return;
109
+ process.stdout.write("\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l" + // mouse reporting, all flavours
110
+ "\x1b[?2004l" + // bracketed paste
111
+ // No "leave alternate screen" (?1049l): Claude's TUI renders inline and
112
+ // never enters it, and on a terminal that is not in it the sequence
113
+ // restores a stale saved cursor, so the next output lands mid-scrollback.
114
+ "\x1b[?25h" + // cursor
115
+ "\x1b[0m");
116
+ }
117
+ /** True once the API answers again — polled after a dropped tunnel. */
118
+ export async function apiReachable() {
119
+ try {
120
+ await createApiClient().project.list.query();
121
+ return true;
122
+ }
123
+ catch {
124
+ return false;
125
+ }
126
+ }
127
+ /** Where the Claude in Chrome native host listens, on this machine. */
128
+ export const BROWSER_BRIDGE_REMOTE_DIR = "/tmp/claude-mcp-browser-bridge-claude";
129
+ /**
130
+ * The Chrome extension's native host (launched by Chrome, on the laptop)
131
+ * listens on a Unix socket per host process; the CLI's browser tools connect
132
+ * to whatever sockets sit in this directory. Forwarding those sockets over
133
+ * the ssh tunnel is all it takes for Claude inside a worker to drive the
134
+ * laptop's Chrome — verified 2026-09-14. Sockets of dead hosts are skipped.
135
+ */
136
+ export function localBrowserBridgeSockets() {
137
+ const dir = `/tmp/claude-mcp-browser-bridge-${userInfo().username}`;
138
+ let names;
139
+ try {
140
+ names = readdirSync(dir);
141
+ }
142
+ catch {
143
+ return [];
144
+ }
145
+ return names
146
+ .filter((n) => n.endsWith(".sock"))
147
+ .filter((n) => {
148
+ const pid = Number(n.slice(0, -5));
149
+ if (!Number.isInteger(pid))
150
+ return true;
151
+ try {
152
+ process.kill(pid, 0);
153
+ return true;
154
+ }
155
+ catch {
156
+ return false;
157
+ }
158
+ })
159
+ .map((n) => `${dir}/${n}`);
160
+ }
161
+ //# sourceMappingURL=remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/lib/remote.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import { WebSocket } from "ws";
2
+ import { getServerUrl, getToken } from "./config.js";
3
+ /**
4
+ * Opens a raw TTY WebSocket connection to the worker container.
5
+ * Pipes local stdin/stdout through the WebSocket.
6
+ */
7
+ export async function connectTerminal(slug, options = {}) {
8
+ const serverUrl = getServerUrl();
9
+ const token = getToken();
10
+ // Build WebSocket URL
11
+ const wsBase = serverUrl.replace(/^http/, "ws");
12
+ const wsUrl = `${wsBase}/api/ws/terminal/${slug}`;
13
+ return new Promise((resolve, reject) => {
14
+ const ws = new WebSocket(wsUrl, {
15
+ headers: token ? { Authorization: `Bearer ${token}` } : {},
16
+ });
17
+ ws.binaryType = "arraybuffer";
18
+ ws.on("open", () => {
19
+ // Put terminal in raw mode
20
+ if (process.stdin.isTTY) {
21
+ process.stdin.setRawMode(true);
22
+ }
23
+ process.stdin.resume();
24
+ // Send initial resize
25
+ const cols = process.stdout.columns || 80;
26
+ const rows = process.stdout.rows || 24;
27
+ ws.send(JSON.stringify({ type: "resize", cols, rows }));
28
+ // If claude mode, send mode control message
29
+ if (options.claude) {
30
+ ws.send(JSON.stringify({ type: "mode", value: "claude" }));
31
+ }
32
+ // stdin → WebSocket
33
+ process.stdin.on("data", (data) => {
34
+ if (ws.readyState === WebSocket.OPEN) {
35
+ ws.send(data);
36
+ }
37
+ });
38
+ // Handle terminal resize
39
+ process.stdout.on("resize", () => {
40
+ if (ws.readyState === WebSocket.OPEN) {
41
+ ws.send(JSON.stringify({
42
+ type: "resize",
43
+ cols: process.stdout.columns,
44
+ rows: process.stdout.rows,
45
+ }));
46
+ }
47
+ });
48
+ });
49
+ ws.on("message", (data) => {
50
+ if (data instanceof ArrayBuffer) {
51
+ process.stdout.write(Buffer.from(data));
52
+ }
53
+ else if (Buffer.isBuffer(data)) {
54
+ process.stdout.write(data);
55
+ }
56
+ else {
57
+ process.stdout.write(String(data));
58
+ }
59
+ });
60
+ ws.on("close", (code) => {
61
+ // Restore terminal
62
+ if (process.stdin.isTTY) {
63
+ process.stdin.setRawMode(false);
64
+ }
65
+ process.stdin.pause();
66
+ if (code !== 1000) {
67
+ console.error(`\nConnection closed (code: ${code})`);
68
+ }
69
+ resolve();
70
+ });
71
+ ws.on("error", (err) => {
72
+ if (process.stdin.isTTY) {
73
+ process.stdin.setRawMode(false);
74
+ }
75
+ process.stdin.pause();
76
+ reject(new Error(`WebSocket error: ${err.message}`));
77
+ });
78
+ });
79
+ }
80
+ //# sourceMappingURL=terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * CLI version. Kept in sync with apps/cli/package.json by the release workflow.
3
+ * Hardcoded so it works whether the CLI is run via npx, global install, or local link.
4
+ */
5
+ export const CLI_VERSION = "0.2.2";
6
+ export function compareSemver(a, b) {
7
+ const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
8
+ const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
9
+ for (let i = 0; i < 3; i++) {
10
+ const da = pa[i] ?? 0;
11
+ const db = pb[i] ?? 0;
12
+ if (da !== db)
13
+ return da - db;
14
+ }
15
+ return 0;
16
+ }
17
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC;AAEnC,MAAM,UAAU,aAAa,CAAC,CAAS,EAAE,CAAS;IAChD,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACzD,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,GAAG,EAAE,CAAC;IAChC,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "dockai",
3
+ "version": "0.2.2",
4
+ "description": "CLI for DockAI — self-hosted Claude Code session manager",
5
+ "license": "MIT",
6
+ "author": "Pol Amoros",
7
+ "homepage": "https://github.com/polamoros/DockAI",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/polamoros/DockAI.git",
11
+ "directory": "apps/cli"
12
+ },
13
+ "keywords": [
14
+ "claude",
15
+ "claude-code",
16
+ "dockai",
17
+ "docker",
18
+ "cli",
19
+ "remote",
20
+ "ssh",
21
+ "terminal"
22
+ ],
23
+ "engines": {
24
+ "node": ">=20"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md"
29
+ ],
30
+ "type": "module",
31
+ "bin": {
32
+ "dockai": "./dist/index.js"
33
+ },
34
+ "dependencies": {
35
+ "@trpc/client": "^11.18.0",
36
+ "commander": "^15.0.0",
37
+ "open": "^11.0.0",
38
+ "superjson": "^2.2.6",
39
+ "ws": "^8.21.3"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.19.15",
43
+ "@types/ws": "^8.18.1",
44
+ "tsx": "^4.23.11",
45
+ "typescript": "^7.0.2"
46
+ },
47
+ "scripts": {
48
+ "dev": "tsx src/index.ts",
49
+ "build": "tsc",
50
+ "typecheck": "tsc --noEmit"
51
+ }
52
+ }