dockai 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +292 -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 +92 -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 +104 -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
package/dist/index.js ADDED
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { loginCommand } from "./commands/login.js";
4
+ import { logoutCommand } from "./commands/logout.js";
5
+ import { whoamiCommand } from "./commands/whoami.js";
6
+ import { projectsCommand } from "./commands/projects.js";
7
+ import { startCommand, stopCommand } from "./commands/start-stop.js";
8
+ import { connectCommand } from "./commands/connect.js";
9
+ import { logsCommand } from "./commands/logs.js";
10
+ import { openCommand } from "./commands/open.js";
11
+ import { statusCommand } from "./commands/status.js";
12
+ import { proxyCommand } from "./commands/proxy.js";
13
+ import { sshConfigCommand, codeCommand } from "./commands/ssh-config.js";
14
+ import { claudeCommand } from "./commands/claude.js";
15
+ import { pushCommand } from "./commands/push.js";
16
+ import { sessionsPushCommand, sessionsListCommand, sessionsResumeCommand, sessionsHandoffCommand } from "./commands/sessions.js";
17
+ import { deployCommand } from "./commands/deploy.js";
18
+ import { ensureSlug } from "./lib/pick-project.js";
19
+ import { pasteCommand } from "./commands/paste.js";
20
+ import { CLI_VERSION } from "./version.js";
21
+ const program = new Command();
22
+ program
23
+ .name("dockai")
24
+ .description("CLI for DockAI — self-hosted Claude Code session manager")
25
+ .version(CLI_VERSION)
26
+ // Lets `dockai claude <slug> --resume x -r` hand every flag after the slug to
27
+ // claude untouched, without a `--` separator.
28
+ .enablePositionalOptions();
29
+ program
30
+ .command("login")
31
+ .description("Authenticate with the DockAI server")
32
+ .option("-s, --server <url>", "Server URL")
33
+ .option("--no-version-check", "Skip the server version check")
34
+ .action(loginCommand);
35
+ program
36
+ .command("logout")
37
+ .description("Clear the saved API token")
38
+ .action(logoutCommand);
39
+ program
40
+ .command("whoami")
41
+ .description("Show the currently logged-in account")
42
+ .action(whoamiCommand);
43
+ program
44
+ .command("projects")
45
+ .description("List all projects with status")
46
+ .action(projectsCommand);
47
+ program
48
+ .command("start <slug>")
49
+ .description("Start a project")
50
+ .action(startCommand);
51
+ program
52
+ .command("stop <slug>")
53
+ .description("Stop a project")
54
+ .action(stopCommand);
55
+ program
56
+ .command("connect <slug>")
57
+ .description("Connect to a worker container terminal")
58
+ .option("--claude", "Drop into interactive Claude session")
59
+ .option("--ssh", "Connect via SSH instead of WebSocket")
60
+ .action(connectCommand);
61
+ program
62
+ .command("logs <slug>")
63
+ .description("Fetch project logs")
64
+ .option("-t, --tail <lines>", "Number of lines", "100")
65
+ .action(logsCommand);
66
+ program
67
+ .command("open <slug>")
68
+ .description("Open the Claude.ai session URL in browser")
69
+ .action(openCommand);
70
+ program
71
+ .command("ssh-config")
72
+ .description("Print an ssh config block so `ssh dockai-<slug>` works from anywhere")
73
+ .option("--print", "Print only the block, for appending to ~/.ssh/config")
74
+ .action(sshConfigCommand);
75
+ program
76
+ .command("code <slug>")
77
+ .description("Open the project in local VS Code over the SSH tunnel")
78
+ .action(codeCommand);
79
+ program
80
+ .command("claude <slug> [claudeArgs...]")
81
+ .description("Run Claude Code inside the project's worker, in tmux — joining the conversation your phone is on when there is one. -r / --resume <id|title> picks among the project's conversations; other flags after the project name go to claude: dockai claude app --permission-mode bypassPermissions")
82
+ // No default here: an unset session is what lets the command join the
83
+ // conversation the phone is on; naming one is an explicit choice.
84
+ .option("-s, --session <name>", "tmux session to attach to or create (before the project name; default claude-cli)")
85
+ .option("--no-tmux", "Skip tmux — the session ends when you disconnect (before the project name)")
86
+ .option("--no-chrome", "Don't forward this machine's Claude in Chrome bridge into the worker (before the project name)")
87
+ .option("--no-client", "Don't offer this machine's files and clipboard to the session (before the project name)")
88
+ .option("--root <dir>", "Directory the session may read from on this machine; repeatable (default: the current directory)", (v, prev) => [...(prev ?? []), v], [])
89
+ .option("--allow-run", "Let the session run commands on this machine (each run is logged here); the project's own setting is the default")
90
+ .option("--no-allow-run", "Refuse commands on this machine even if the project allows them by default")
91
+ .passThroughOptions()
92
+ .action((slug, claudeArgs, options) => claudeCommand(slug, options, claudeArgs));
93
+ program
94
+ .command("push <slug> <paths...>")
95
+ .description("Copy local files into the project's workspace — the .env and scripts a clone doesn't carry")
96
+ .option("--keep-existing", "Leave files that already exist on the worker untouched")
97
+ .action(pushCommand);
98
+ const sessions = program
99
+ .command("sessions")
100
+ .description("Move Claude Code sessions from this machine into a project");
101
+ sessions
102
+ .command("list <slug>")
103
+ .description("Conversations on the worker, with ids and whether each is live on the phone")
104
+ .action(sessionsListCommand);
105
+ sessions
106
+ .command("resume <slug> <session>")
107
+ .description("Open a conversation by id, id prefix or name — in a terminal here, or on the phone with --remote")
108
+ .option("--remote", "Register it with Remote Control through DockAI instead of opening a terminal")
109
+ .action(sessionsResumeCommand);
110
+ sessions
111
+ .command("handoff <slug> <ref>")
112
+ .description("Continue a conversation in a new one bound to the project's environment: the dialogue is written to .dockai/handoff/ and you send one message in the new conversation")
113
+ .option("--turns <n>", "How many of the most recent turns to carry (default 200, max 5000)")
114
+ .option("--title <title>", "Title for the new conversation (default: the old one's)")
115
+ .option("--file-only", "Write the hand-off file without creating a conversation, to send the message in one that already exists")
116
+ .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 an interactive Remote Control conversation — on the phone and joinable with dockai claude — instead of a server-bound one")
118
+ .action(sessionsHandoffCommand);
119
+ sessions
120
+ .command("push <slug>")
121
+ .description("Copy this directory's Claude sessions and memory into the project, with paths rewritten to the workspace")
122
+ .option("--from <dir>", "Local project directory whose sessions to push (default: current directory)")
123
+ .option("--latest <n>", "Only the n most recently used sessions")
124
+ .option("--session <id...>", "Only these sessions (id or unique prefix); repeatable")
125
+ .option("--overwrite", "Replace sessions that already exist on the worker")
126
+ .option("--remote", "Then resume each pushed session in the worker with Remote Control, so it appears in the Claude app and claude.ai/code")
127
+ .option("--dry-run", "Show what would be pushed without sending anything")
128
+ .action(sessionsPushCommand);
129
+ program
130
+ .command("paste <slug>")
131
+ .description("Paste the image on your clipboard into a running dockai claude session (macOS)")
132
+ .option("-s, --session <name>", "tmux session to type into", "claude-cli")
133
+ .action(pasteCommand);
134
+ program
135
+ .command("deploy [target]")
136
+ .description("Redeploy DockAI itself, or a named deploy target (Admin → System): pull the latest images and recreate the stack (admin)")
137
+ .option("--no-wait", "Return right after starting instead of following the deploy")
138
+ .action(deployCommand);
139
+ program
140
+ .command("proxy <host>")
141
+ .description("SSH ProxyCommand transport (used by ssh, not run directly)")
142
+ .action(proxyCommand);
143
+ program
144
+ .command("status")
145
+ .description("Show server status and project overview")
146
+ .action(statusCommand);
147
+ // Commands that take a project first: ask for it when it was left out.
148
+ let argv = process.argv;
149
+ argv = await ensureSlug(argv, ["claude"], { flags: ["--no-tmux", "--tmux", "--no-chrome", "--chrome", "--no-client", "--allow-run", "--no-allow-run"], valued: ["-s", "--session", "--root"] });
150
+ for (const path of [["push"], ["paste"], ["sessions", "list"], ["sessions", "resume"], ["sessions", "push"]]) {
151
+ argv = await ensureSlug(argv, path);
152
+ }
153
+ await program.parseAsync(argv);
154
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,175 @@
1
+ import { createServer } from "node:net";
2
+ import { execFile, spawn } from "node:child_process";
3
+ import { promises as fs } from "node:fs";
4
+ import { hostname, platform, tmpdir } from "node:os";
5
+ import path from "node:path";
6
+ /**
7
+ * The "client tools" a `dockai claude` session can use on this machine —
8
+ * served on a loopback port that the ssh tunnel forwards into the worker as
9
+ * 127.0.0.1:47800, where the worker's `dockai` MCP server calls it once per
10
+ * tool call (worker/mcp/index.mjs).
11
+ *
12
+ * One JSON request per connection: {op, args} → {ok, data} | {ok:false, error}.
13
+ * Everything file-shaped is confined to the allowed roots (default: the
14
+ * directory `dockai claude` was run in); `run` only when explicitly allowed.
15
+ */
16
+ export const CLIENT_REMOTE_PORT = 47800;
17
+ /** In the worker's home: the port the most recent `dockai claude` forwarded its client tools to. */
18
+ export const CLIENT_PORT_FILE = ".dockai-client-port";
19
+ const MAX_TEXT = 1024 * 1024;
20
+ const MAX_FETCH = 50 * 1024 * 1024;
21
+ async function resolveInRoots(p, roots) {
22
+ const target = p ? (path.isAbsolute(p) ? p : path.resolve(roots[0], p)) : roots[0];
23
+ const real = await fs.realpath(target).catch(() => { throw new Error(`not found: ${target}`); });
24
+ for (const root of roots) {
25
+ const r = await fs.realpath(root).catch(() => root);
26
+ if (real === r || real.startsWith(r + path.sep))
27
+ return real;
28
+ }
29
+ throw new Error(`${target} is outside the allowed roots (${roots.join(", ")}). Start dockai claude with --root <dir> to allow more.`);
30
+ }
31
+ function tarDir(dir) {
32
+ return new Promise((resolve, reject) => {
33
+ const chunks = [];
34
+ const child = spawn("tar", ["-czf", "-", "--exclude=node_modules", "--exclude=.git", "-C", path.dirname(dir), path.basename(dir)], {
35
+ env: { ...process.env, COPYFILE_DISABLE: "1" },
36
+ });
37
+ let size = 0;
38
+ child.stdout.on("data", (d) => { size += d.length; if (size > MAX_FETCH) {
39
+ child.kill();
40
+ reject(new Error("directory exceeds 50 MB compressed — fetch a subfolder"));
41
+ } chunks.push(d); });
42
+ child.on("error", reject);
43
+ child.on("close", (code) => (code === 0 ? resolve(Buffer.concat(chunks)) : reject(new Error(`tar exited ${code}`))));
44
+ });
45
+ }
46
+ async function countFiles(dir) {
47
+ let n = 0;
48
+ for (const e of await fs.readdir(dir, { withFileTypes: true })) {
49
+ if (e.name === "node_modules" || e.name === ".git")
50
+ continue;
51
+ n += e.isDirectory() ? await countFiles(path.join(dir, e.name)) : 1;
52
+ }
53
+ return n;
54
+ }
55
+ async function clipboard() {
56
+ if (platform() === "darwin") {
57
+ const png = path.join(tmpdir(), `dockai-clip-${Date.now()}.png`);
58
+ const script = [
59
+ `set f to POSIX file "${png}"`,
60
+ "try",
61
+ " set h to open for access f with write permission",
62
+ " write (the clipboard as «class PNGf») to h",
63
+ " close access h",
64
+ "on error",
65
+ ' error "no image"',
66
+ "end try",
67
+ ].join("\n");
68
+ const ok = await new Promise((resolve) => execFile("osascript", ["-e", script], (err) => resolve(!err)));
69
+ if (ok) {
70
+ const b = await fs.readFile(png);
71
+ await fs.unlink(png).catch(() => { });
72
+ return { type: "image", base64: b.toString("base64") };
73
+ }
74
+ const text = await new Promise((resolve, reject) => execFile("pbpaste", (err, out) => (err ? reject(err) : resolve(out))));
75
+ return { type: "text", text };
76
+ }
77
+ if (platform() === "win32") {
78
+ const text = await new Promise((resolve, reject) => execFile("powershell", ["-NoProfile", "-Command", "Get-Clipboard"], (err, out) => (err ? reject(err) : resolve(out))));
79
+ return { type: "text", text };
80
+ }
81
+ const text = await new Promise((resolve, reject) => execFile("xclip", ["-selection", "clipboard", "-o"], (err, out) => (err ? reject(new Error("no clipboard tool (xclip) on this machine")) : resolve(out))));
82
+ return { type: "text", text };
83
+ }
84
+ async function handle(op, args, opts) {
85
+ switch (op) {
86
+ case "info":
87
+ return { host: hostname(), platform: platform(), roots: opts.roots, allowRun: opts.allowRun };
88
+ case "list": {
89
+ const dir = await resolveInRoots(args.path, opts.roots);
90
+ const entries = await fs.readdir(dir, { withFileTypes: true });
91
+ const out = [];
92
+ for (const e of entries.slice(0, 500)) {
93
+ const st = e.isFile() ? await fs.stat(path.join(dir, e.name)).catch(() => null) : null;
94
+ out.push({ name: e.name, type: e.isDirectory() ? "dir" : "file", size: st?.size });
95
+ }
96
+ return { path: dir, entries: out };
97
+ }
98
+ case "read": {
99
+ const file = await resolveInRoots(args.path, opts.roots);
100
+ const st = await fs.stat(file);
101
+ if (!st.isFile())
102
+ throw new Error(`${file} is not a file`);
103
+ if (st.size > MAX_TEXT)
104
+ throw new Error(`${file} is ${st.size} bytes; read is capped at 1 MB — use client_fetch`);
105
+ return { text: await fs.readFile(file, "utf8") };
106
+ }
107
+ case "fetch": {
108
+ const p = await resolveInRoots(args.path, opts.roots);
109
+ const st = await fs.stat(p);
110
+ if (st.isDirectory()) {
111
+ const tgz = await tarDir(p);
112
+ return { kind: "dir", name: path.basename(p), files: await countFiles(p), base64: tgz.toString("base64") };
113
+ }
114
+ if (st.size > MAX_FETCH)
115
+ throw new Error(`${p} is ${st.size} bytes; fetch is capped at 50 MB`);
116
+ return { kind: "file", name: path.basename(p), size: st.size, base64: (await fs.readFile(p)).toString("base64") };
117
+ }
118
+ case "clipboard":
119
+ return clipboard();
120
+ case "run": {
121
+ if (!opts.allowRun)
122
+ throw new Error("running commands on this machine is off — start dockai claude with --allow-run to allow it");
123
+ const cwd = args.cwd ? await resolveInRoots(args.cwd, opts.roots) : opts.roots[0];
124
+ return new Promise((resolve) => {
125
+ let output = "";
126
+ const shell = platform() === "win32" ? ["powershell", ["-NoProfile", "-Command", String(args.command)]] : ["sh", ["-c", String(args.command)]];
127
+ const child = spawn(shell[0], [...shell[1]], { cwd, env: process.env });
128
+ const cap = (d) => { if (output.length < 100_000)
129
+ output += d.toString(); };
130
+ child.stdout.on("data", cap);
131
+ child.stderr.on("data", cap);
132
+ const timer = setTimeout(() => { child.kill(); output += "\n[killed after 60s]"; }, 60_000);
133
+ child.on("close", (code) => { clearTimeout(timer); resolve({ code, output }); });
134
+ });
135
+ }
136
+ default:
137
+ throw new Error(`unknown op ${op}`);
138
+ }
139
+ }
140
+ /** Serve the client tools on a random loopback port; returns it. */
141
+ export function startClientTools(opts) {
142
+ const server = createServer((sock) => {
143
+ let buf = "";
144
+ sock.on("data", async (d) => {
145
+ buf += d.toString();
146
+ const nl = buf.indexOf("\n");
147
+ if (nl < 0)
148
+ return;
149
+ let req;
150
+ try {
151
+ req = JSON.parse(buf.slice(0, nl));
152
+ }
153
+ catch {
154
+ sock.end(JSON.stringify({ ok: false, error: "bad request" }));
155
+ return;
156
+ }
157
+ try {
158
+ const data = await handle(req.op, req.args ?? {}, opts);
159
+ sock.end(JSON.stringify({ ok: true, data }));
160
+ }
161
+ catch (err) {
162
+ sock.end(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }));
163
+ }
164
+ });
165
+ sock.on("error", () => { });
166
+ });
167
+ return new Promise((resolve, reject) => {
168
+ server.on("error", reject);
169
+ server.listen(0, "127.0.0.1", () => {
170
+ const addr = server.address();
171
+ resolve({ port: typeof addr === "object" && addr ? addr.port : 0, server });
172
+ });
173
+ });
174
+ }
175
+ //# sourceMappingURL=client-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-tools.js","sourceRoot":"","sources":["../../src/lib/client-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,176 @@
1
+ import { emitKeypressEvents } from "node:readline";
2
+ import { createApiClient } from "../api.js";
3
+ import { getToken } from "../config.js";
4
+ import { resetTerminal } from "./remote.js";
5
+ /**
6
+ * Ask which project, when a command that needs one was given none.
7
+ *
8
+ * Only when there is a terminal to ask in: a script that forgets the slug
9
+ * should fail, not hang on a prompt nobody sees.
10
+ */
11
+ export async function pickProject() {
12
+ if (!getToken()) {
13
+ console.error("Not logged in. Run `dockai login` first.");
14
+ process.exit(1);
15
+ }
16
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
17
+ console.error("Missing project. Pass its slug: dockai <command> <slug>");
18
+ process.exit(1);
19
+ }
20
+ // A previous session that died under the TUI can leave mouse reporting on,
21
+ // which would type escape codes over the picker.
22
+ resetTerminal();
23
+ // Raw mode from the start: an arrow pressed while the list is still being
24
+ // fetched would otherwise echo as ^[[B into the terminal.
25
+ process.stdin.setRawMode(true);
26
+ process.stdin.resume();
27
+ // Raw mode also means the terminal no longer turns Ctrl-C into SIGINT, so
28
+ // honour it by hand while the list is loading — a slow network must not
29
+ // leave the user with a blank, unkillable prompt.
30
+ const onCtrlC = (d) => { if (d.includes(0x03)) {
31
+ process.stdout.write("\x1b[?25h\n");
32
+ process.exit(130);
33
+ } };
34
+ process.stdin.on("data", onCtrlC);
35
+ process.stdout.write("\x1b[?25l\x1b[2mLoading projects…\x1b[0m");
36
+ const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), 15000));
37
+ let projects;
38
+ try {
39
+ projects = (await Promise.race([createApiClient().project.list.query(), timeout]));
40
+ }
41
+ catch (err) {
42
+ process.stdout.write("\r\x1b[K\x1b[?25h");
43
+ process.stdin.setRawMode(false);
44
+ console.error(err instanceof Error && err.message === "timeout"
45
+ ? "DockAI did not answer within 15s. Check your connection, or pass the slug: dockai <command> <slug>"
46
+ : `Could not list projects: ${err instanceof Error ? err.message : err}`);
47
+ process.exit(1);
48
+ }
49
+ process.stdin.off("data", onCtrlC);
50
+ process.stdout.write("\r\x1b[K");
51
+ if (!projects.length) {
52
+ console.error("No projects yet.");
53
+ process.exit(1);
54
+ }
55
+ // Running first — that is almost always the one being reached for.
56
+ projects.sort((a, b) => Number(b.status === "RUNNING") - Number(a.status === "RUNNING") || a.name.localeCompare(b.name));
57
+ const chosen = await selectFromList("Which project?", projects.map((p) => ({ label: describe(p), value: p })));
58
+ if (!chosen) {
59
+ console.error("No project chosen.");
60
+ process.exit(1);
61
+ }
62
+ return chosen.slug;
63
+ }
64
+ const DIM = "\x1b[2m";
65
+ const RESET_DIM = "\x1b[22m";
66
+ /**
67
+ * One row per project: what it is, whether it is up, whether Claude is busy
68
+ * in it, and which branch and account it works with — the things that decide
69
+ * which one to attach to.
70
+ */
71
+ export function describe(p) {
72
+ const state = p.status === "RUNNING"
73
+ ? (p.claudeStatus === "working" ? "\x1b[33mworking\x1b[39m" : "\x1b[32mrunning\x1b[39m")
74
+ : `${DIM}${p.status.toLowerCase()}${RESET_DIM}`;
75
+ const branch = p.githubRepoUrl && p.githubBranch ? p.githubBranch.slice(0, 14) : "";
76
+ const account = p.claudeAccount?.label ? `${DIM}· ${p.claudeAccount.label}${RESET_DIM}` : "";
77
+ return [
78
+ p.name.slice(0, 26).padEnd(28),
79
+ `${DIM}${p.slug.slice(0, 22).padEnd(24)}${RESET_DIM}`,
80
+ pad(state, 9),
81
+ `${DIM}${branch.padEnd(15)}${RESET_DIM}`,
82
+ account,
83
+ ].join("");
84
+ }
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
+ /**
93
+ * Insert a prompted slug into argv when the command's slug position is empty
94
+ * or holds a flag — so `dockai claude --resume x` still means "ask me which
95
+ * project, then pass --resume x to claude".
96
+ */
97
+ export async function ensureSlug(argv, commandPath, opts = {}) {
98
+ const start = 2; // node, script
99
+ for (let i = 0; i < commandPath.length; i++) {
100
+ if (argv[start + i] !== commandPath[i])
101
+ return argv;
102
+ }
103
+ // Skip the command's own options (which come before the project name), so
104
+ // `dockai claude --no-tmux app` and `dockai claude -s work app` still find
105
+ // the slug. Anything else starting with "-" is a flag for the far end.
106
+ let pos = start + commandPath.length;
107
+ for (;;) {
108
+ const tok = argv[pos];
109
+ if (tok && opts.valued?.includes(tok))
110
+ pos += 2;
111
+ else if (tok && opts.flags?.includes(tok))
112
+ pos += 1;
113
+ else
114
+ break;
115
+ }
116
+ const current = argv[pos];
117
+ if (current && !current.startsWith("-"))
118
+ return argv;
119
+ const slug = await pickProject();
120
+ return [...argv.slice(0, pos), slug, ...argv.slice(pos)];
121
+ }
122
+ /**
123
+ * Arrow-key list selection on a TTY: ↑/↓ or j/k to move, Enter to choose,
124
+ * a digit to jump, Esc or Ctrl-C to cancel. Redraws in place.
125
+ */
126
+ export function selectFromList(title, items) {
127
+ return new Promise((resolve) => {
128
+ let index = 0;
129
+ const out = process.stdout;
130
+ const render = (first = false) => {
131
+ if (!first)
132
+ out.write(`\x1b[${items.length + 1}A`); // back to the title line
133
+ out.write(`${title}\x1b[K\n`);
134
+ items.forEach((it, i) => {
135
+ const on = i === index;
136
+ out.write(`${on ? "\x1b[36m❯" : " "} ${it.label}\x1b[0m\x1b[K\n`);
137
+ });
138
+ };
139
+ const finish = (value) => {
140
+ out.write("\x1b[?25h");
141
+ process.stdin.setRawMode(false);
142
+ process.stdin.pause();
143
+ process.stdin.off("keypress", onKey);
144
+ resolve(value);
145
+ };
146
+ const onKey = (str, key) => {
147
+ if (key.ctrl && key.name === "c") {
148
+ finish(null);
149
+ return;
150
+ }
151
+ if (key.name === "escape") {
152
+ finish(null);
153
+ return;
154
+ }
155
+ if (key.name === "return") {
156
+ finish(items[index].value);
157
+ return;
158
+ }
159
+ if (key.name === "up" || str === "k")
160
+ index = (index - 1 + items.length) % items.length;
161
+ else if (key.name === "down" || str === "j")
162
+ index = (index + 1) % items.length;
163
+ else if (/^[1-9]$/.test(str) && Number(str) <= items.length)
164
+ index = Number(str) - 1;
165
+ else
166
+ return;
167
+ render();
168
+ };
169
+ emitKeypressEvents(process.stdin);
170
+ process.stdin.setRawMode(true);
171
+ process.stdin.resume();
172
+ process.stdin.on("keypress", onKey);
173
+ render(true);
174
+ });
175
+ }
176
+ //# sourceMappingURL=pick-project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pick-project.js","sourceRoot":"","sources":["../../src/lib/pick-project.ts"],"names":[],"mappings":"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"}