codeam-cli 2.13.0 → 2.14.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.
- package/CHANGELOG.md +15 -0
- package/dist/index.js +325 -33
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,21 @@ All notable changes to `codeam-cli` are documented here.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [2.13.0] — 2026-05-16
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Forward CODEAM_VERCEL_BYPASS as x-vercel-protection-bypass
|
|
12
|
+
|
|
13
|
+
### CI
|
|
14
|
+
|
|
15
|
+
- **deps:** Cap @types/node major in CLI dependabot config
|
|
16
|
+
|
|
17
|
+
### Chore
|
|
18
|
+
|
|
19
|
+
- **deps:** Bump gradle-wrapper in /apps/jetbrains-plugin (#32)
|
|
20
|
+
- **deps:** Bump org.jetbrains.intellij.platform (#29)
|
|
21
|
+
|
|
7
22
|
## [2.12.17] — 2026-05-16
|
|
8
23
|
|
|
9
24
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -1018,7 +1018,7 @@ var require_unixTerminal = __commonJS({
|
|
|
1018
1018
|
var terminal_1 = require_terminal();
|
|
1019
1019
|
var utils_1 = require_utils();
|
|
1020
1020
|
var native = utils_1.loadNativeModule("pty");
|
|
1021
|
-
var
|
|
1021
|
+
var pty2 = native.module;
|
|
1022
1022
|
var helperPath = native.dir + "/spawn-helper";
|
|
1023
1023
|
helperPath = path23.resolve(__dirname, helperPath);
|
|
1024
1024
|
helperPath = helperPath.replace("app.asar", "app.asar.unpacked");
|
|
@@ -1076,7 +1076,7 @@ var require_unixTerminal = __commonJS({
|
|
|
1076
1076
|
}
|
|
1077
1077
|
_this.emit("exit", code, signal);
|
|
1078
1078
|
};
|
|
1079
|
-
var term =
|
|
1079
|
+
var term = pty2.fork(file, args2, parsedEnv, cwd, _this._cols, _this._rows, uid, gid, encoding === "utf8", helperPath, onexit);
|
|
1080
1080
|
_this._socket = new tty.ReadStream(term.fd);
|
|
1081
1081
|
if (encoding !== null) {
|
|
1082
1082
|
_this._socket.setEncoding(encoding);
|
|
@@ -1164,7 +1164,7 @@ var require_unixTerminal = __commonJS({
|
|
|
1164
1164
|
var cols = opt.cols || terminal_1.DEFAULT_COLS;
|
|
1165
1165
|
var rows = opt.rows || terminal_1.DEFAULT_ROWS;
|
|
1166
1166
|
var encoding = opt.encoding === void 0 ? "utf8" : opt.encoding;
|
|
1167
|
-
var term =
|
|
1167
|
+
var term = pty2.open(cols, rows);
|
|
1168
1168
|
self._master = new tty.ReadStream(term.master);
|
|
1169
1169
|
if (encoding !== null) {
|
|
1170
1170
|
self._master.setEncoding(encoding);
|
|
@@ -1215,10 +1215,10 @@ var require_unixTerminal = __commonJS({
|
|
|
1215
1215
|
*/
|
|
1216
1216
|
get: function() {
|
|
1217
1217
|
if (process.platform === "darwin") {
|
|
1218
|
-
var title =
|
|
1218
|
+
var title = pty2.process(this._fd);
|
|
1219
1219
|
return title !== "kernel_task" ? title : this._file;
|
|
1220
1220
|
}
|
|
1221
|
-
return
|
|
1221
|
+
return pty2.process(this._fd, this._pty) || this._file;
|
|
1222
1222
|
},
|
|
1223
1223
|
enumerable: false,
|
|
1224
1224
|
configurable: true
|
|
@@ -1227,7 +1227,7 @@ var require_unixTerminal = __commonJS({
|
|
|
1227
1227
|
if (cols <= 0 || rows <= 0 || isNaN(cols) || isNaN(rows) || cols === Infinity || rows === Infinity) {
|
|
1228
1228
|
throw new Error("resizing must be done using positive cols and rows");
|
|
1229
1229
|
}
|
|
1230
|
-
|
|
1230
|
+
pty2.resize(this._fd, cols, rows);
|
|
1231
1231
|
this._cols = cols;
|
|
1232
1232
|
this._rows = rows;
|
|
1233
1233
|
};
|
|
@@ -1313,10 +1313,10 @@ var require_lib = __commonJS({
|
|
|
1313
1313
|
} else {
|
|
1314
1314
|
terminalCtor = require_unixTerminal().UnixTerminal;
|
|
1315
1315
|
}
|
|
1316
|
-
function
|
|
1316
|
+
function spawn12(file, args2, opt) {
|
|
1317
1317
|
return new terminalCtor(file, args2, opt);
|
|
1318
1318
|
}
|
|
1319
|
-
exports2.spawn =
|
|
1319
|
+
exports2.spawn = spawn12;
|
|
1320
1320
|
function fork(file, args2, opt) {
|
|
1321
1321
|
return new terminalCtor(file, args2, opt);
|
|
1322
1322
|
}
|
|
@@ -1689,7 +1689,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
1689
1689
|
// package.json
|
|
1690
1690
|
var package_default = {
|
|
1691
1691
|
name: "codeam-cli",
|
|
1692
|
-
version: "2.
|
|
1692
|
+
version: "2.14.0",
|
|
1693
1693
|
description: "Remote control Claude Code (and other AI coding agents) from your mobile phone. Pair your device, send prompts, stream responses in real-time, and approve commands \u2014 from anywhere.",
|
|
1694
1694
|
type: "commonjs",
|
|
1695
1695
|
main: "dist/index.js",
|
|
@@ -6789,6 +6789,31 @@ var OutputService = class _OutputService {
|
|
|
6789
6789
|
this.dispose();
|
|
6790
6790
|
}
|
|
6791
6791
|
}
|
|
6792
|
+
/**
|
|
6793
|
+
* Push a terminal-data chunk for the IDE-integrated terminal
|
|
6794
|
+
* panel. Distinct from chat output: `type: 'terminal_data'`
|
|
6795
|
+
* lets the host filter the SSE stream by terminal session id.
|
|
6796
|
+
* `done: false` because terminal sessions are long-lived — the
|
|
6797
|
+
* `terminal_close` command emits the final chunk separately.
|
|
6798
|
+
*/
|
|
6799
|
+
async sendTerminalChunk(terminalSessionId, data) {
|
|
6800
|
+
await this.emitter.send({
|
|
6801
|
+
type: "terminal_data",
|
|
6802
|
+
terminalSessionId,
|
|
6803
|
+
data,
|
|
6804
|
+
done: false
|
|
6805
|
+
});
|
|
6806
|
+
}
|
|
6807
|
+
/** Final chunk for a terminal session — fires when the PTY
|
|
6808
|
+
* exits, so the host can update UI (badge "exit 0", etc). */
|
|
6809
|
+
async sendTerminalExit(terminalSessionId, exitCode) {
|
|
6810
|
+
await this.emitter.send({
|
|
6811
|
+
type: "terminal_exit",
|
|
6812
|
+
terminalSessionId,
|
|
6813
|
+
exitCode,
|
|
6814
|
+
done: true
|
|
6815
|
+
});
|
|
6816
|
+
}
|
|
6792
6817
|
stopPoll() {
|
|
6793
6818
|
if (this.pollTimer) {
|
|
6794
6819
|
clearInterval(this.pollTimer);
|
|
@@ -7287,7 +7312,7 @@ var HistoryService = class _HistoryService {
|
|
|
7287
7312
|
} catch {
|
|
7288
7313
|
return;
|
|
7289
7314
|
}
|
|
7290
|
-
const
|
|
7315
|
+
const sessions3 = [];
|
|
7291
7316
|
for (const entry of entries) {
|
|
7292
7317
|
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
|
|
7293
7318
|
const id = path14.basename(entry.name, ".jsonl");
|
|
@@ -7317,11 +7342,11 @@ var HistoryService = class _HistoryService {
|
|
|
7317
7342
|
}
|
|
7318
7343
|
} catch {
|
|
7319
7344
|
}
|
|
7320
|
-
if (summary)
|
|
7345
|
+
if (summary) sessions3.push({ id, summary, timestamp: mtime });
|
|
7321
7346
|
}
|
|
7322
|
-
if (
|
|
7323
|
-
|
|
7324
|
-
await post("/api/sessions/claude-sessions", { pluginId: this.pluginId, sessions:
|
|
7347
|
+
if (sessions3.length === 0) return;
|
|
7348
|
+
sessions3.sort((a, b) => b.timestamp - a.timestamp);
|
|
7349
|
+
await post("/api/sessions/claude-sessions", { pluginId: this.pluginId, sessions: sessions3 });
|
|
7325
7350
|
}
|
|
7326
7351
|
/**
|
|
7327
7352
|
* Read a specific session's full conversation and POST it to the API in batches.
|
|
@@ -7464,7 +7489,7 @@ function buildKeepAlive(ctx) {
|
|
|
7464
7489
|
var fs14 = __toESM(require("fs"));
|
|
7465
7490
|
var os13 = __toESM(require("os"));
|
|
7466
7491
|
var path17 = __toESM(require("path"));
|
|
7467
|
-
var
|
|
7492
|
+
var import_crypto2 = require("crypto");
|
|
7468
7493
|
var import_child_process8 = require("child_process");
|
|
7469
7494
|
|
|
7470
7495
|
// src/lib/payload.ts
|
|
@@ -7494,7 +7519,26 @@ var startCommandSchema = import_zod2.z.object({
|
|
|
7494
7519
|
message: import_zod2.z.string().max(8e3).optional(),
|
|
7495
7520
|
paths: import_zod2.z.array(import_zod2.z.string().max(4096)).optional(),
|
|
7496
7521
|
side: import_zod2.z.enum(["ours", "theirs"]).optional(),
|
|
7497
|
-
limit: import_zod2.z.number().int().min(1).max(500).optional()
|
|
7522
|
+
limit: import_zod2.z.number().int().min(1).max(500).optional(),
|
|
7523
|
+
// search_files options. `query` is the haystack/needle string,
|
|
7524
|
+
// declared above for list_files. The rest mirror VS Code's
|
|
7525
|
+
// search panel toggles + the @codeam/ide-core SearchOptions
|
|
7526
|
+
// contract.
|
|
7527
|
+
caseSensitive: import_zod2.z.boolean().optional(),
|
|
7528
|
+
wholeWord: import_zod2.z.boolean().optional(),
|
|
7529
|
+
regex: import_zod2.z.boolean().optional(),
|
|
7530
|
+
include: import_zod2.z.array(import_zod2.z.string().max(512)).max(64).optional(),
|
|
7531
|
+
exclude: import_zod2.z.array(import_zod2.z.string().max(512)).max(64).optional(),
|
|
7532
|
+
maxResults: import_zod2.z.number().int().min(1).max(500).optional(),
|
|
7533
|
+
// terminal_open / _write / _resize / _close. `sessionId` is the
|
|
7534
|
+
// opaque uuid returned by `terminal_open` and required by every
|
|
7535
|
+
// subsequent op. `data` carries keystrokes (any UTF-8 string).
|
|
7536
|
+
// `cwd` lets the host pin the spawn directory.
|
|
7537
|
+
sessionId: import_zod2.z.string().min(1).max(128).optional(),
|
|
7538
|
+
data: import_zod2.z.string().max(64 * 1024).optional(),
|
|
7539
|
+
cwd: import_zod2.z.string().max(4096).optional(),
|
|
7540
|
+
cols: import_zod2.z.number().int().min(1).max(500).optional(),
|
|
7541
|
+
rows: import_zod2.z.number().int().min(1).max(200).optional()
|
|
7498
7542
|
});
|
|
7499
7543
|
function parsePayload(schema, raw) {
|
|
7500
7544
|
const result = schema.safeParse(raw);
|
|
@@ -7852,13 +7896,19 @@ async function gitDiffStaged(file, cwd) {
|
|
|
7852
7896
|
return { diff: r.stdout.slice(0, MAX_DIFF_BYTES), truncated };
|
|
7853
7897
|
}
|
|
7854
7898
|
async function gitLog(limit = 30, cwd) {
|
|
7855
|
-
const
|
|
7856
|
-
const fmt =
|
|
7899
|
+
const SEP = "";
|
|
7900
|
+
const fmt = `%H${SEP}%s${SEP}%an${SEP}%ct${SEP}%D`;
|
|
7857
7901
|
const r = await git(["log", `-n${Math.min(limit, 200)}`, `--pretty=format:${fmt}`], cwd);
|
|
7858
7902
|
if (r.code !== 0) return { commits: [], error: r.stderr.trim() };
|
|
7859
7903
|
const commits = r.stdout.split("\n").filter(Boolean).map((line) => {
|
|
7860
|
-
const [
|
|
7861
|
-
return {
|
|
7904
|
+
const [sha, subject, author, ts, refs] = line.split(SEP);
|
|
7905
|
+
return {
|
|
7906
|
+
sha: sha ?? "",
|
|
7907
|
+
subject: subject ?? "",
|
|
7908
|
+
author: author ?? "",
|
|
7909
|
+
timestamp: parseInt(ts ?? "0", 10) * 1e3,
|
|
7910
|
+
refs: (refs ?? "").split(",").map((s) => s.trim().replace(/^HEAD -> /, "")).filter((s) => s.length > 0)
|
|
7911
|
+
};
|
|
7862
7912
|
});
|
|
7863
7913
|
return { commits };
|
|
7864
7914
|
}
|
|
@@ -7897,12 +7947,189 @@ async function gitResolve(file, side, cwd) {
|
|
|
7897
7947
|
if (add.code !== 0) return { error: add.stderr.trim() || "git add (resolve) failed" };
|
|
7898
7948
|
return { ok: true };
|
|
7899
7949
|
}
|
|
7950
|
+
var MAX_SEARCH_HITS = 500;
|
|
7951
|
+
var MAX_SEARCH_BYTES = 256 * 1024;
|
|
7952
|
+
async function searchFiles(opts) {
|
|
7953
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
7954
|
+
const cap = Math.min(opts.maxResults ?? MAX_SEARCH_HITS, MAX_SEARCH_HITS);
|
|
7955
|
+
if (!opts.query.trim()) return { hits: [], total: 0, truncated: false };
|
|
7956
|
+
const args2 = ["grep", "-n", "--column", "-I"];
|
|
7957
|
+
if (!opts.caseSensitive) args2.push("-i");
|
|
7958
|
+
if (opts.wholeWord) args2.push("-w");
|
|
7959
|
+
if (opts.regex) args2.push("-E");
|
|
7960
|
+
else args2.push("-F");
|
|
7961
|
+
args2.push(opts.query);
|
|
7962
|
+
if (opts.include && opts.include.length > 0) {
|
|
7963
|
+
args2.push("--");
|
|
7964
|
+
for (const p2 of opts.include) args2.push(p2);
|
|
7965
|
+
} else if (opts.exclude && opts.exclude.length > 0) {
|
|
7966
|
+
args2.push("--");
|
|
7967
|
+
args2.push(".");
|
|
7968
|
+
}
|
|
7969
|
+
for (const p2 of opts.exclude ?? []) args2.push(`:!${p2}`);
|
|
7970
|
+
const r = await git(args2, cwd);
|
|
7971
|
+
if (r.code !== 0 && r.code !== 1) {
|
|
7972
|
+
return jsSearchFiles(opts, cwd, cap);
|
|
7973
|
+
}
|
|
7974
|
+
const hits = [];
|
|
7975
|
+
const lines = r.stdout.split("\n");
|
|
7976
|
+
let truncated = false;
|
|
7977
|
+
let byteBudget = MAX_SEARCH_BYTES;
|
|
7978
|
+
for (const line of lines) {
|
|
7979
|
+
if (!line) continue;
|
|
7980
|
+
if (hits.length >= cap) {
|
|
7981
|
+
truncated = true;
|
|
7982
|
+
break;
|
|
7983
|
+
}
|
|
7984
|
+
if (byteBudget <= 0) {
|
|
7985
|
+
truncated = true;
|
|
7986
|
+
break;
|
|
7987
|
+
}
|
|
7988
|
+
byteBudget -= line.length;
|
|
7989
|
+
const m = line.match(/^([^]+?):(\d+):(\d+):(.*)$/);
|
|
7990
|
+
if (!m) continue;
|
|
7991
|
+
const filePath = m[1] ?? "";
|
|
7992
|
+
const lineNo = parseInt(m[2] ?? "0", 10);
|
|
7993
|
+
const col = parseInt(m[3] ?? "1", 10);
|
|
7994
|
+
const text = (m[4] ?? "").slice(0, 400);
|
|
7995
|
+
if (!filePath) continue;
|
|
7996
|
+
hits.push({
|
|
7997
|
+
path: filePath,
|
|
7998
|
+
line: lineNo,
|
|
7999
|
+
column: col,
|
|
8000
|
+
text,
|
|
8001
|
+
matchLength: opts.query.length
|
|
8002
|
+
});
|
|
8003
|
+
}
|
|
8004
|
+
return { hits, total: hits.length, truncated };
|
|
8005
|
+
}
|
|
8006
|
+
async function jsSearchFiles(opts, cwd, cap) {
|
|
8007
|
+
const files = await listProjectFiles({ cwd, cap: 2e3 });
|
|
8008
|
+
const hits = [];
|
|
8009
|
+
const needle = opts.caseSensitive ? opts.query : opts.query.toLowerCase();
|
|
8010
|
+
let truncated = files.truncated;
|
|
8011
|
+
for (const f of files.files) {
|
|
8012
|
+
if (hits.length >= cap) {
|
|
8013
|
+
truncated = true;
|
|
8014
|
+
break;
|
|
8015
|
+
}
|
|
8016
|
+
let content = "";
|
|
8017
|
+
try {
|
|
8018
|
+
content = await fs13.readFile(path16.join(cwd, f.path), "utf8");
|
|
8019
|
+
} catch {
|
|
8020
|
+
continue;
|
|
8021
|
+
}
|
|
8022
|
+
const lines = content.split("\n");
|
|
8023
|
+
for (let i = 0; i < lines.length && hits.length < cap; i++) {
|
|
8024
|
+
const line = lines[i] ?? "";
|
|
8025
|
+
const hay = opts.caseSensitive ? line : line.toLowerCase();
|
|
8026
|
+
const idx = hay.indexOf(needle);
|
|
8027
|
+
if (idx === -1) continue;
|
|
8028
|
+
hits.push({
|
|
8029
|
+
path: f.path,
|
|
8030
|
+
line: i + 1,
|
|
8031
|
+
column: idx + 1,
|
|
8032
|
+
text: line.slice(0, 400),
|
|
8033
|
+
matchLength: opts.query.length
|
|
8034
|
+
});
|
|
8035
|
+
}
|
|
8036
|
+
}
|
|
8037
|
+
return { hits, total: hits.length, truncated };
|
|
8038
|
+
}
|
|
8039
|
+
|
|
8040
|
+
// src/services/terminal-ops.service.ts
|
|
8041
|
+
var import_crypto = require("crypto");
|
|
8042
|
+
var pty = __toESM(require_lib());
|
|
8043
|
+
var MAX_CONCURRENT_SESSIONS = 4;
|
|
8044
|
+
var sessions = /* @__PURE__ */ new Map();
|
|
8045
|
+
var onDataHandler = null;
|
|
8046
|
+
var onExitHandler = null;
|
|
8047
|
+
function registerTerminalHandlers(opts) {
|
|
8048
|
+
onDataHandler = opts.onData;
|
|
8049
|
+
onExitHandler = opts.onExit;
|
|
8050
|
+
}
|
|
8051
|
+
function defaultShell() {
|
|
8052
|
+
if (process.platform === "win32") {
|
|
8053
|
+
return process.env.COMSPEC ?? "powershell.exe";
|
|
8054
|
+
}
|
|
8055
|
+
return process.env.SHELL ?? "/bin/bash";
|
|
8056
|
+
}
|
|
8057
|
+
function openTerminal(opts) {
|
|
8058
|
+
if (sessions.size >= MAX_CONCURRENT_SESSIONS) {
|
|
8059
|
+
return { error: `Too many open terminals (max ${MAX_CONCURRENT_SESSIONS})` };
|
|
8060
|
+
}
|
|
8061
|
+
const shell = opts.shell ?? defaultShell();
|
|
8062
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
8063
|
+
const env = {
|
|
8064
|
+
...process.env,
|
|
8065
|
+
TERM: "xterm-256color",
|
|
8066
|
+
COLORTERM: "truecolor"
|
|
8067
|
+
};
|
|
8068
|
+
env.FORCE_COLOR = "1";
|
|
8069
|
+
try {
|
|
8070
|
+
const term = pty.spawn(shell, [], {
|
|
8071
|
+
name: "xterm-256color",
|
|
8072
|
+
cols: Math.max(1, Math.min(opts.cols ?? 80, 500)),
|
|
8073
|
+
rows: Math.max(1, Math.min(opts.rows ?? 24, 200)),
|
|
8074
|
+
cwd,
|
|
8075
|
+
env,
|
|
8076
|
+
// Windows-specific: ConPTY is the default on Win 10 1809+
|
|
8077
|
+
// and is what we want. node-pty falls back to winpty
|
|
8078
|
+
// automatically on older builds.
|
|
8079
|
+
useConpty: process.platform === "win32" ? true : void 0
|
|
8080
|
+
});
|
|
8081
|
+
const id = (0, import_crypto.randomUUID)();
|
|
8082
|
+
const dataListener = term.onData((data) => {
|
|
8083
|
+
onDataHandler?.({ sessionId: id, data });
|
|
8084
|
+
});
|
|
8085
|
+
const exitListener = term.onExit(({ exitCode }) => {
|
|
8086
|
+
onExitHandler?.({ sessionId: id, exitCode });
|
|
8087
|
+
sessions.delete(id);
|
|
8088
|
+
});
|
|
8089
|
+
sessions.set(id, { id, pty: term, dataListener, exitListener });
|
|
8090
|
+
return { sessionId: id };
|
|
8091
|
+
} catch (e) {
|
|
8092
|
+
return { error: e instanceof Error ? e.message : "spawn failed" };
|
|
8093
|
+
}
|
|
8094
|
+
}
|
|
8095
|
+
function writeTerminal(sessionId, data) {
|
|
8096
|
+
const s = sessions.get(sessionId);
|
|
8097
|
+
if (!s) return { ok: false, error: "No such session" };
|
|
8098
|
+
try {
|
|
8099
|
+
s.pty.write(data);
|
|
8100
|
+
return { ok: true };
|
|
8101
|
+
} catch (e) {
|
|
8102
|
+
return { ok: false, error: e instanceof Error ? e.message : "write failed" };
|
|
8103
|
+
}
|
|
8104
|
+
}
|
|
8105
|
+
function resizeTerminal(sessionId, cols, rows) {
|
|
8106
|
+
const s = sessions.get(sessionId);
|
|
8107
|
+
if (!s) return { ok: false, error: "No such session" };
|
|
8108
|
+
try {
|
|
8109
|
+
s.pty.resize(Math.max(1, Math.min(cols, 500)), Math.max(1, Math.min(rows, 200)));
|
|
8110
|
+
return { ok: true };
|
|
8111
|
+
} catch (e) {
|
|
8112
|
+
return { ok: false, error: e instanceof Error ? e.message : "resize failed" };
|
|
8113
|
+
}
|
|
8114
|
+
}
|
|
8115
|
+
function closeTerminal(sessionId) {
|
|
8116
|
+
const s = sessions.get(sessionId);
|
|
8117
|
+
if (!s) return { ok: true };
|
|
8118
|
+
try {
|
|
8119
|
+
s.dataListener.dispose();
|
|
8120
|
+
s.exitListener.dispose();
|
|
8121
|
+
s.pty.kill();
|
|
8122
|
+
} catch {
|
|
8123
|
+
}
|
|
8124
|
+
sessions.delete(sessionId);
|
|
8125
|
+
return { ok: true };
|
|
8126
|
+
}
|
|
7900
8127
|
|
|
7901
8128
|
// src/commands/start/handlers.ts
|
|
7902
8129
|
function saveFilesTemp(files) {
|
|
7903
8130
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
7904
8131
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
7905
|
-
const tmpPath = path17.join(os13.tmpdir(), `codeam-${(0,
|
|
8132
|
+
const tmpPath = path17.join(os13.tmpdir(), `codeam-${(0, import_crypto2.randomUUID)()}-${safeName}`);
|
|
7906
8133
|
fs14.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
7907
8134
|
return tmpPath;
|
|
7908
8135
|
});
|
|
@@ -8077,7 +8304,7 @@ var shutdownSession = async (ctx, cmd) => {
|
|
|
8077
8304
|
ctx.relay.stop();
|
|
8078
8305
|
process.exit(0);
|
|
8079
8306
|
};
|
|
8080
|
-
var
|
|
8307
|
+
var readFile3 = async (ctx, cmd, parsed) => {
|
|
8081
8308
|
if (!parsed.path) {
|
|
8082
8309
|
await ctx.relay.sendResult(cmd.id, "failed", { error: "Missing path" });
|
|
8083
8310
|
return;
|
|
@@ -8097,6 +8324,58 @@ var listFiles = async (ctx, cmd, parsed) => {
|
|
|
8097
8324
|
const result = await listProjectFiles({ query: parsed.query });
|
|
8098
8325
|
await ctx.relay.sendResult(cmd.id, "completed", result);
|
|
8099
8326
|
};
|
|
8327
|
+
var terminalOpenH = async (ctx, cmd, parsed) => {
|
|
8328
|
+
const r = openTerminal({
|
|
8329
|
+
cols: typeof parsed.cols === "number" ? parsed.cols : void 0,
|
|
8330
|
+
rows: typeof parsed.rows === "number" ? parsed.rows : void 0,
|
|
8331
|
+
cwd: typeof parsed.cwd === "string" ? parsed.cwd : void 0
|
|
8332
|
+
});
|
|
8333
|
+
if ("error" in r) {
|
|
8334
|
+
await ctx.relay.sendResult(cmd.id, "failed", { error: r.error });
|
|
8335
|
+
return;
|
|
8336
|
+
}
|
|
8337
|
+
await ctx.relay.sendResult(cmd.id, "completed", r);
|
|
8338
|
+
};
|
|
8339
|
+
var terminalWriteH = async (ctx, cmd, parsed) => {
|
|
8340
|
+
if (typeof parsed.sessionId !== "string" || typeof parsed.data !== "string") {
|
|
8341
|
+
await ctx.relay.sendResult(cmd.id, "failed", { error: "Missing sessionId or data" });
|
|
8342
|
+
return;
|
|
8343
|
+
}
|
|
8344
|
+
const r = writeTerminal(parsed.sessionId, parsed.data);
|
|
8345
|
+
await ctx.relay.sendResult(cmd.id, r.ok ? "completed" : "failed", r);
|
|
8346
|
+
};
|
|
8347
|
+
var terminalResizeH = async (ctx, cmd, parsed) => {
|
|
8348
|
+
if (typeof parsed.sessionId !== "string" || typeof parsed.cols !== "number" || typeof parsed.rows !== "number") {
|
|
8349
|
+
await ctx.relay.sendResult(cmd.id, "failed", { error: "Missing sessionId / cols / rows" });
|
|
8350
|
+
return;
|
|
8351
|
+
}
|
|
8352
|
+
const r = resizeTerminal(parsed.sessionId, parsed.cols, parsed.rows);
|
|
8353
|
+
await ctx.relay.sendResult(cmd.id, r.ok ? "completed" : "failed", r);
|
|
8354
|
+
};
|
|
8355
|
+
var terminalCloseH = async (ctx, cmd, parsed) => {
|
|
8356
|
+
if (typeof parsed.sessionId !== "string") {
|
|
8357
|
+
await ctx.relay.sendResult(cmd.id, "failed", { error: "Missing sessionId" });
|
|
8358
|
+
return;
|
|
8359
|
+
}
|
|
8360
|
+
const r = closeTerminal(parsed.sessionId);
|
|
8361
|
+
await ctx.relay.sendResult(cmd.id, "completed", r);
|
|
8362
|
+
};
|
|
8363
|
+
var searchFilesH = async (ctx, cmd, parsed) => {
|
|
8364
|
+
if (!parsed.query || typeof parsed.query !== "string") {
|
|
8365
|
+
await ctx.relay.sendResult(cmd.id, "failed", { error: "Missing query" });
|
|
8366
|
+
return;
|
|
8367
|
+
}
|
|
8368
|
+
const result = await searchFiles({
|
|
8369
|
+
query: parsed.query,
|
|
8370
|
+
caseSensitive: parsed.caseSensitive,
|
|
8371
|
+
wholeWord: parsed.wholeWord,
|
|
8372
|
+
regex: parsed.regex,
|
|
8373
|
+
include: Array.isArray(parsed.include) ? parsed.include : void 0,
|
|
8374
|
+
exclude: Array.isArray(parsed.exclude) ? parsed.exclude : void 0,
|
|
8375
|
+
maxResults: typeof parsed.maxResults === "number" ? parsed.maxResults : void 0
|
|
8376
|
+
});
|
|
8377
|
+
await ctx.relay.sendResult(cmd.id, "completed", result);
|
|
8378
|
+
};
|
|
8100
8379
|
var gitStatusH = async (ctx, cmd) => {
|
|
8101
8380
|
const result = await gitStatus();
|
|
8102
8381
|
await ctx.relay.sendResult(cmd.id, "completed", result);
|
|
@@ -8152,9 +8431,14 @@ var handlers = {
|
|
|
8152
8431
|
set_keep_alive: setKeepAlive,
|
|
8153
8432
|
session_terminated: sessionTerminated,
|
|
8154
8433
|
shutdown_session: shutdownSession,
|
|
8155
|
-
read_file:
|
|
8434
|
+
read_file: readFile3,
|
|
8156
8435
|
write_file: writeFile2,
|
|
8157
8436
|
list_files: listFiles,
|
|
8437
|
+
search_files: searchFilesH,
|
|
8438
|
+
terminal_open: terminalOpenH,
|
|
8439
|
+
terminal_write: terminalWriteH,
|
|
8440
|
+
terminal_resize: terminalResizeH,
|
|
8441
|
+
terminal_close: terminalCloseH,
|
|
8158
8442
|
git_status: gitStatusH,
|
|
8159
8443
|
git_diff: gitDiffH,
|
|
8160
8444
|
git_diff_staged: gitDiffStagedH,
|
|
@@ -8256,6 +8540,14 @@ async function start(requestedAgent) {
|
|
|
8256
8540
|
await dispatchCommand(ctx, cmd);
|
|
8257
8541
|
}, runtime.meta);
|
|
8258
8542
|
ctx.relay = relay;
|
|
8543
|
+
registerTerminalHandlers({
|
|
8544
|
+
onData: ({ sessionId, data }) => {
|
|
8545
|
+
void outputSvc.sendTerminalChunk(sessionId, data);
|
|
8546
|
+
},
|
|
8547
|
+
onExit: ({ sessionId, exitCode }) => {
|
|
8548
|
+
void outputSvc.sendTerminalExit(sessionId, exitCode);
|
|
8549
|
+
}
|
|
8550
|
+
});
|
|
8259
8551
|
function sigintHandler() {
|
|
8260
8552
|
claude.kill();
|
|
8261
8553
|
outputSvc.dispose();
|
|
@@ -8274,7 +8566,7 @@ async function start(requestedAgent) {
|
|
|
8274
8566
|
}
|
|
8275
8567
|
|
|
8276
8568
|
// src/commands/pair.ts
|
|
8277
|
-
var
|
|
8569
|
+
var import_crypto3 = require("crypto");
|
|
8278
8570
|
var import_picocolors3 = __toESM(require("picocolors"));
|
|
8279
8571
|
|
|
8280
8572
|
// src/ui/prompts.ts
|
|
@@ -8283,10 +8575,10 @@ async function confirmAction(message) {
|
|
|
8283
8575
|
if (q(result)) return false;
|
|
8284
8576
|
return result;
|
|
8285
8577
|
}
|
|
8286
|
-
async function selectSession(
|
|
8578
|
+
async function selectSession(sessions3, activeId) {
|
|
8287
8579
|
const result = await _t({
|
|
8288
8580
|
message: "Select active session:",
|
|
8289
|
-
options:
|
|
8581
|
+
options: sessions3.map((s) => ({
|
|
8290
8582
|
value: s.id,
|
|
8291
8583
|
label: `${s.userName} ${s.plan}`,
|
|
8292
8584
|
hint: s.id === activeId ? "active" : `paired ${new Date(s.pairedAt).toLocaleDateString()}`
|
|
@@ -8337,7 +8629,7 @@ async function pair(args2 = []) {
|
|
|
8337
8629
|
const flagAgent = parseAgentFlag(args2);
|
|
8338
8630
|
const agentId = flagAgent ?? await promptForAgent(config.preferredAgent ?? "claude");
|
|
8339
8631
|
showIntro();
|
|
8340
|
-
const pluginId = (0,
|
|
8632
|
+
const pluginId = (0, import_crypto3.randomUUID)();
|
|
8341
8633
|
const spin = dist_exports.spinner();
|
|
8342
8634
|
spin.start("Requesting pairing code...");
|
|
8343
8635
|
const result = await requestCode(pluginId);
|
|
@@ -8393,7 +8685,7 @@ async function pair(args2 = []) {
|
|
|
8393
8685
|
// src/commands/pair-auto.ts
|
|
8394
8686
|
var fs15 = __toESM(require("fs"));
|
|
8395
8687
|
var os14 = __toESM(require("os"));
|
|
8396
|
-
var
|
|
8688
|
+
var import_crypto4 = require("crypto");
|
|
8397
8689
|
var API_BASE5 = process.env.CODEAM_API_URL ?? "https://codeagent-mobile-api.vercel.app";
|
|
8398
8690
|
function fail(msg) {
|
|
8399
8691
|
console.error(`
|
|
@@ -8455,7 +8747,7 @@ async function claim(token, pluginId) {
|
|
|
8455
8747
|
}
|
|
8456
8748
|
async function pairAuto(args2) {
|
|
8457
8749
|
const token = readTokenFromArgs(args2);
|
|
8458
|
-
const pluginId = (0,
|
|
8750
|
+
const pluginId = (0, import_crypto4.randomUUID)();
|
|
8459
8751
|
console.log(" Claiming pairing token\u2026");
|
|
8460
8752
|
const claimed = await claim(token, pluginId);
|
|
8461
8753
|
if (!isKnownAgentId(claimed.agent)) {
|
|
@@ -8480,7 +8772,7 @@ async function pairAuto(args2) {
|
|
|
8480
8772
|
|
|
8481
8773
|
// src/commands/sessions.ts
|
|
8482
8774
|
var import_picocolors4 = __toESM(require("picocolors"));
|
|
8483
|
-
async function
|
|
8775
|
+
async function sessions2(args2) {
|
|
8484
8776
|
const [sub, id] = args2;
|
|
8485
8777
|
if (sub === "switch") return switchSession();
|
|
8486
8778
|
if (sub === "delete") {
|
|
@@ -10525,7 +10817,7 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
10525
10817
|
// src/commands/version.ts
|
|
10526
10818
|
var import_picocolors11 = __toESM(require("picocolors"));
|
|
10527
10819
|
function version() {
|
|
10528
|
-
const v = true ? "2.
|
|
10820
|
+
const v = true ? "2.14.0" : "unknown";
|
|
10529
10821
|
console.log(`${import_picocolors11.default.bold("codeam-cli")} ${import_picocolors11.default.cyan(v)}`);
|
|
10530
10822
|
}
|
|
10531
10823
|
|
|
@@ -10664,7 +10956,7 @@ function checkForUpdates() {
|
|
|
10664
10956
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
10665
10957
|
if (process.env.CI) return;
|
|
10666
10958
|
if (!process.stdout.isTTY) return;
|
|
10667
|
-
const current = true ? "2.
|
|
10959
|
+
const current = true ? "2.14.0" : null;
|
|
10668
10960
|
if (!current) return;
|
|
10669
10961
|
const cache = readCache();
|
|
10670
10962
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -10697,7 +10989,7 @@ async function main() {
|
|
|
10697
10989
|
case "pair-auto":
|
|
10698
10990
|
return pairAuto(args);
|
|
10699
10991
|
case "sessions":
|
|
10700
|
-
return
|
|
10992
|
+
return sessions2(args);
|
|
10701
10993
|
case "status":
|
|
10702
10994
|
return status();
|
|
10703
10995
|
case "logout":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"description": "Remote control Claude Code (and other AI coding agents) from your mobile phone. Pair your device, send prompts, stream responses in real-time, and approve commands — from anywhere.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "dist/index.js",
|