codeam-cli 2.2.2 → 2.3.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 +12 -0
- package/dist/index.js +331 -18
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ 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.2.2] — 2026-05-02
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **clients:** Recursive suffix search for read_file (v2.2.2)
|
|
12
|
+
|
|
13
|
+
## [2.2.1] — 2026-05-02
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **cli:** Subdir fallback for read_file when CLI cwd is a monorepo parent (v2.2.1)
|
|
18
|
+
|
|
7
19
|
## [2.1.0] — 2026-04-25
|
|
8
20
|
|
|
9
21
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -87,11 +87,11 @@ var require_src = __commonJS({
|
|
|
87
87
|
});
|
|
88
88
|
|
|
89
89
|
// src/commands/start.ts
|
|
90
|
-
var
|
|
90
|
+
var fs7 = __toESM(require("fs"));
|
|
91
91
|
var os5 = __toESM(require("os"));
|
|
92
|
-
var
|
|
92
|
+
var path7 = __toESM(require("path"));
|
|
93
93
|
var import_crypto = require("crypto");
|
|
94
|
-
var
|
|
94
|
+
var import_child_process4 = require("child_process");
|
|
95
95
|
var import_picocolors2 = __toESM(require("picocolors"));
|
|
96
96
|
|
|
97
97
|
// src/config.ts
|
|
@@ -179,7 +179,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
179
179
|
// package.json
|
|
180
180
|
var package_default = {
|
|
181
181
|
name: "codeam-cli",
|
|
182
|
-
version: "2.
|
|
182
|
+
version: "2.3.0",
|
|
183
183
|
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.",
|
|
184
184
|
main: "dist/index.js",
|
|
185
185
|
bin: {
|
|
@@ -2163,7 +2163,15 @@ var startCommandSchema = import_zod2.z.object({
|
|
|
2163
2163
|
// `path` is bounded to 4096 chars (a comfortable POSIX path max) so a
|
|
2164
2164
|
// malformed payload can't blow up the disk-side validator.
|
|
2165
2165
|
path: import_zod2.z.string().min(1).max(4096).optional(),
|
|
2166
|
-
content: import_zod2.z.string().optional()
|
|
2166
|
+
content: import_zod2.z.string().optional(),
|
|
2167
|
+
// Mini-IDE / project ops. `paths` (plural, strings) is used for
|
|
2168
|
+
// git_commit's optional file selection — distinct from `files`
|
|
2169
|
+
// (FileEntry[]) used by `start_task` for attachments.
|
|
2170
|
+
query: import_zod2.z.string().max(256).optional(),
|
|
2171
|
+
message: import_zod2.z.string().max(8e3).optional(),
|
|
2172
|
+
paths: import_zod2.z.array(import_zod2.z.string().max(4096)).optional(),
|
|
2173
|
+
side: import_zod2.z.enum(["ours", "theirs"]).optional(),
|
|
2174
|
+
limit: import_zod2.z.number().int().min(1).max(500).optional()
|
|
2167
2175
|
});
|
|
2168
2176
|
function parsePayload(schema, raw) {
|
|
2169
2177
|
const result = schema.safeParse(raw);
|
|
@@ -2212,8 +2220,8 @@ function isUnder(parent, candidate) {
|
|
|
2212
2220
|
}
|
|
2213
2221
|
async function isExistingFile(absPath) {
|
|
2214
2222
|
try {
|
|
2215
|
-
const
|
|
2216
|
-
return
|
|
2223
|
+
const stat3 = await fs5.stat(absPath);
|
|
2224
|
+
return stat3.isFile();
|
|
2217
2225
|
} catch {
|
|
2218
2226
|
return false;
|
|
2219
2227
|
}
|
|
@@ -2286,9 +2294,9 @@ async function readProjectFile(rawPath) {
|
|
|
2286
2294
|
if (!abs) {
|
|
2287
2295
|
return { error: `File not found in the project tree: ${rawPath}` };
|
|
2288
2296
|
}
|
|
2289
|
-
const
|
|
2290
|
-
if (
|
|
2291
|
-
return { error: `File too large (${(
|
|
2297
|
+
const stat3 = await fs5.stat(abs);
|
|
2298
|
+
if (stat3.size > MAX_FILE_BYTES) {
|
|
2299
|
+
return { error: `File too large (${(stat3.size / 1024 / 1024).toFixed(1)} MB > ${MAX_FILE_BYTES / 1024 / 1024} MB).` };
|
|
2292
2300
|
}
|
|
2293
2301
|
const buf = await fs5.readFile(abs);
|
|
2294
2302
|
if (looksBinary(buf)) {
|
|
@@ -2318,12 +2326,261 @@ async function writeProjectFile(rawPath, content) {
|
|
|
2318
2326
|
}
|
|
2319
2327
|
}
|
|
2320
2328
|
|
|
2329
|
+
// src/services/project-ops.service.ts
|
|
2330
|
+
var import_child_process3 = require("child_process");
|
|
2331
|
+
var import_util = require("util");
|
|
2332
|
+
var fs6 = __toESM(require("fs/promises"));
|
|
2333
|
+
var path6 = __toESM(require("path"));
|
|
2334
|
+
var execFileP = (0, import_util.promisify)(import_child_process3.execFile);
|
|
2335
|
+
var PROJECT_IGNORE = /* @__PURE__ */ new Set([
|
|
2336
|
+
"node_modules",
|
|
2337
|
+
".git",
|
|
2338
|
+
".next",
|
|
2339
|
+
".expo",
|
|
2340
|
+
"dist",
|
|
2341
|
+
"build",
|
|
2342
|
+
"out",
|
|
2343
|
+
".cache",
|
|
2344
|
+
"coverage",
|
|
2345
|
+
".turbo",
|
|
2346
|
+
".parcel-cache",
|
|
2347
|
+
".idea",
|
|
2348
|
+
".vscode",
|
|
2349
|
+
".vscode-test",
|
|
2350
|
+
"ios",
|
|
2351
|
+
"android",
|
|
2352
|
+
".gradle",
|
|
2353
|
+
".cxx",
|
|
2354
|
+
".intellijPlatform",
|
|
2355
|
+
".kotlin",
|
|
2356
|
+
"tmp",
|
|
2357
|
+
"target",
|
|
2358
|
+
"venv",
|
|
2359
|
+
".venv",
|
|
2360
|
+
".mypy_cache",
|
|
2361
|
+
".pytest_cache",
|
|
2362
|
+
"__pycache__",
|
|
2363
|
+
".DS_Store"
|
|
2364
|
+
]);
|
|
2365
|
+
var MAX_TREE_FILES = 5e3;
|
|
2366
|
+
var MAX_DIFF_BYTES = 512 * 1024;
|
|
2367
|
+
var MAX_GIT_OUTPUT = 256 * 1024;
|
|
2368
|
+
async function listProjectFiles(opts = {}) {
|
|
2369
|
+
const root = opts.cwd ?? process.cwd();
|
|
2370
|
+
const cap = opts.cap ?? MAX_TREE_FILES;
|
|
2371
|
+
const q2 = (opts.query ?? "").trim().toLowerCase();
|
|
2372
|
+
const out = [];
|
|
2373
|
+
let truncated = false;
|
|
2374
|
+
async function walk(dir, depth) {
|
|
2375
|
+
if (out.length >= cap) {
|
|
2376
|
+
truncated = true;
|
|
2377
|
+
return;
|
|
2378
|
+
}
|
|
2379
|
+
let entries = [];
|
|
2380
|
+
try {
|
|
2381
|
+
entries = await fs6.readdir(dir, { withFileTypes: true });
|
|
2382
|
+
} catch {
|
|
2383
|
+
return;
|
|
2384
|
+
}
|
|
2385
|
+
for (const e of entries) {
|
|
2386
|
+
if (out.length >= cap) {
|
|
2387
|
+
truncated = true;
|
|
2388
|
+
return;
|
|
2389
|
+
}
|
|
2390
|
+
if (PROJECT_IGNORE.has(e.name)) continue;
|
|
2391
|
+
const full = path6.join(dir, e.name);
|
|
2392
|
+
if (e.isDirectory()) {
|
|
2393
|
+
if (depth >= 12) continue;
|
|
2394
|
+
await walk(full, depth + 1);
|
|
2395
|
+
} else if (e.isFile()) {
|
|
2396
|
+
const rel = path6.relative(root, full);
|
|
2397
|
+
if (q2 && !rel.toLowerCase().includes(q2) && !e.name.toLowerCase().includes(q2)) {
|
|
2398
|
+
continue;
|
|
2399
|
+
}
|
|
2400
|
+
let size = 0;
|
|
2401
|
+
try {
|
|
2402
|
+
const st3 = await fs6.stat(full);
|
|
2403
|
+
size = st3.size;
|
|
2404
|
+
} catch {
|
|
2405
|
+
}
|
|
2406
|
+
out.push({ path: rel, name: e.name, size });
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
await walk(root, 0);
|
|
2411
|
+
out.sort((a, b) => a.path.localeCompare(b.path));
|
|
2412
|
+
return { files: out, truncated, root };
|
|
2413
|
+
}
|
|
2414
|
+
async function git(args2, cwd) {
|
|
2415
|
+
try {
|
|
2416
|
+
const { stdout, stderr } = await execFileP("git", args2, {
|
|
2417
|
+
cwd: cwd ?? process.cwd(),
|
|
2418
|
+
maxBuffer: MAX_GIT_OUTPUT,
|
|
2419
|
+
timeout: 3e4
|
|
2420
|
+
});
|
|
2421
|
+
return { stdout, stderr, code: 0 };
|
|
2422
|
+
} catch (err) {
|
|
2423
|
+
const e = err;
|
|
2424
|
+
return {
|
|
2425
|
+
stdout: e.stdout ?? "",
|
|
2426
|
+
stderr: e.stderr ?? e.message ?? "git failed",
|
|
2427
|
+
code: typeof e.code === "number" ? e.code : 1
|
|
2428
|
+
};
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2431
|
+
async function gitStatus(cwd) {
|
|
2432
|
+
const root = cwd ?? process.cwd();
|
|
2433
|
+
const r = await git(["status", "--porcelain=v2", "--branch"], root);
|
|
2434
|
+
if (r.code !== 0) {
|
|
2435
|
+
return {
|
|
2436
|
+
branch: null,
|
|
2437
|
+
upstream: null,
|
|
2438
|
+
ahead: 0,
|
|
2439
|
+
behind: 0,
|
|
2440
|
+
entries: [],
|
|
2441
|
+
hasMergeInProgress: false,
|
|
2442
|
+
error: r.stderr.trim()
|
|
2443
|
+
};
|
|
2444
|
+
}
|
|
2445
|
+
const lines = r.stdout.split("\n").filter(Boolean);
|
|
2446
|
+
let branch = null;
|
|
2447
|
+
let upstream = null;
|
|
2448
|
+
let ahead = 0;
|
|
2449
|
+
let behind = 0;
|
|
2450
|
+
const entries = [];
|
|
2451
|
+
for (const line of lines) {
|
|
2452
|
+
if (line.startsWith("# branch.head ")) branch = line.slice("# branch.head ".length).trim();
|
|
2453
|
+
else if (line.startsWith("# branch.upstream ")) upstream = line.slice("# branch.upstream ".length).trim();
|
|
2454
|
+
else if (line.startsWith("# branch.ab ")) {
|
|
2455
|
+
const m = line.match(/\+(\d+)\s+-(\d+)/);
|
|
2456
|
+
if (m) {
|
|
2457
|
+
ahead = parseInt(m[1], 10);
|
|
2458
|
+
behind = parseInt(m[2], 10);
|
|
2459
|
+
}
|
|
2460
|
+
} else if (line.startsWith("1 ")) {
|
|
2461
|
+
const parts = line.split(" ");
|
|
2462
|
+
const xy = parts[1];
|
|
2463
|
+
const p2 = parts.slice(8).join(" ");
|
|
2464
|
+
entries.push({
|
|
2465
|
+
code: xy,
|
|
2466
|
+
path: p2,
|
|
2467
|
+
staged: xy[0] !== ".",
|
|
2468
|
+
conflict: false
|
|
2469
|
+
});
|
|
2470
|
+
} else if (line.startsWith("2 ")) {
|
|
2471
|
+
const parts = line.split(" ");
|
|
2472
|
+
const xy = parts[1];
|
|
2473
|
+
const tail = parts.slice(9).join(" ");
|
|
2474
|
+
const [newPath, oldPath] = tail.split(" ");
|
|
2475
|
+
entries.push({
|
|
2476
|
+
code: xy,
|
|
2477
|
+
path: newPath ?? "",
|
|
2478
|
+
oldPath: oldPath ?? void 0,
|
|
2479
|
+
staged: xy[0] !== ".",
|
|
2480
|
+
conflict: false
|
|
2481
|
+
});
|
|
2482
|
+
} else if (line.startsWith("? ")) {
|
|
2483
|
+
entries.push({
|
|
2484
|
+
code: "??",
|
|
2485
|
+
path: line.slice(2),
|
|
2486
|
+
staged: false,
|
|
2487
|
+
conflict: false
|
|
2488
|
+
});
|
|
2489
|
+
} else if (line.startsWith("u ")) {
|
|
2490
|
+
const parts = line.split(" ");
|
|
2491
|
+
const xy = parts[1];
|
|
2492
|
+
const p2 = parts.slice(10).join(" ");
|
|
2493
|
+
entries.push({
|
|
2494
|
+
code: xy,
|
|
2495
|
+
path: p2,
|
|
2496
|
+
staged: false,
|
|
2497
|
+
conflict: true
|
|
2498
|
+
});
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
let hasMergeInProgress = false;
|
|
2502
|
+
try {
|
|
2503
|
+
const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
|
|
2504
|
+
const mergeHead = path6.isAbsolute(gitDir) ? path6.join(gitDir, "MERGE_HEAD") : path6.join(root, gitDir, "MERGE_HEAD");
|
|
2505
|
+
await fs6.access(mergeHead);
|
|
2506
|
+
hasMergeInProgress = true;
|
|
2507
|
+
} catch {
|
|
2508
|
+
}
|
|
2509
|
+
return { branch, upstream, ahead, behind, entries, hasMergeInProgress };
|
|
2510
|
+
}
|
|
2511
|
+
async function gitDiff(file, cwd) {
|
|
2512
|
+
const args2 = ["diff", "--no-color", "--patch"];
|
|
2513
|
+
if (file) args2.push("--", file);
|
|
2514
|
+
const r = await git(args2, cwd);
|
|
2515
|
+
if (r.code !== 0 && !r.stdout) {
|
|
2516
|
+
return { diff: "", truncated: false, error: r.stderr.trim() };
|
|
2517
|
+
}
|
|
2518
|
+
const truncated = r.stdout.length >= MAX_DIFF_BYTES;
|
|
2519
|
+
return { diff: r.stdout.slice(0, MAX_DIFF_BYTES), truncated };
|
|
2520
|
+
}
|
|
2521
|
+
async function gitDiffStaged(file, cwd) {
|
|
2522
|
+
const args2 = ["diff", "--cached", "--no-color", "--patch"];
|
|
2523
|
+
if (file) args2.push("--", file);
|
|
2524
|
+
const r = await git(args2, cwd);
|
|
2525
|
+
if (r.code !== 0 && !r.stdout) {
|
|
2526
|
+
return { diff: "", truncated: false, error: r.stderr.trim() };
|
|
2527
|
+
}
|
|
2528
|
+
const truncated = r.stdout.length >= MAX_DIFF_BYTES;
|
|
2529
|
+
return { diff: r.stdout.slice(0, MAX_DIFF_BYTES), truncated };
|
|
2530
|
+
}
|
|
2531
|
+
async function gitLog(limit = 30, cwd) {
|
|
2532
|
+
const sep2 = "";
|
|
2533
|
+
const fmt = ["%H", "%h", "%an", "%aI", "%s"].join(sep2);
|
|
2534
|
+
const r = await git(["log", `-n${Math.min(limit, 200)}`, `--pretty=format:${fmt}`], cwd);
|
|
2535
|
+
if (r.code !== 0) return { commits: [], error: r.stderr.trim() };
|
|
2536
|
+
const commits = r.stdout.split("\n").filter(Boolean).map((line) => {
|
|
2537
|
+
const [hash, shortHash, author, date, subject] = line.split(sep2);
|
|
2538
|
+
return { hash, shortHash, author, date, subject };
|
|
2539
|
+
});
|
|
2540
|
+
return { commits };
|
|
2541
|
+
}
|
|
2542
|
+
async function gitCommit(message, files, cwd) {
|
|
2543
|
+
if (!message || message.trim().length === 0) {
|
|
2544
|
+
return { error: "Commit message is required." };
|
|
2545
|
+
}
|
|
2546
|
+
if (files && files.length > 0) {
|
|
2547
|
+
const r2 = await git(["add", "--", ...files], cwd);
|
|
2548
|
+
if (r2.code !== 0) return { error: `git add failed: ${r2.stderr.trim()}` };
|
|
2549
|
+
} else {
|
|
2550
|
+
const r2 = await git(["add", "-A"], cwd);
|
|
2551
|
+
if (r2.code !== 0) return { error: `git add failed: ${r2.stderr.trim()}` };
|
|
2552
|
+
}
|
|
2553
|
+
const r = await git(["commit", "-m", message], cwd);
|
|
2554
|
+
if (r.code !== 0) {
|
|
2555
|
+
return { error: r.stderr.trim() || "git commit failed" };
|
|
2556
|
+
}
|
|
2557
|
+
const head = await git(["rev-parse", "HEAD"], cwd);
|
|
2558
|
+
return { ok: true, commit: head.stdout.trim() };
|
|
2559
|
+
}
|
|
2560
|
+
async function gitPush(cwd) {
|
|
2561
|
+
const r = await git(["push"], cwd);
|
|
2562
|
+
if (r.code !== 0) return { error: r.stderr.trim() || "git push failed" };
|
|
2563
|
+
return { ok: true, output: (r.stdout + r.stderr).trim() };
|
|
2564
|
+
}
|
|
2565
|
+
async function gitPull(cwd) {
|
|
2566
|
+
const r = await git(["pull", "--ff-only"], cwd);
|
|
2567
|
+
if (r.code !== 0) return { error: r.stderr.trim() || "git pull failed" };
|
|
2568
|
+
return { ok: true, output: (r.stdout + r.stderr).trim() };
|
|
2569
|
+
}
|
|
2570
|
+
async function gitResolve(file, side, cwd) {
|
|
2571
|
+
const r = await git(["checkout", `--${side}`, "--", file], cwd);
|
|
2572
|
+
if (r.code !== 0) return { error: r.stderr.trim() || `git checkout --${side} failed` };
|
|
2573
|
+
const add = await git(["add", "--", file], cwd);
|
|
2574
|
+
if (add.code !== 0) return { error: add.stderr.trim() || "git add (resolve) failed" };
|
|
2575
|
+
return { ok: true };
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2321
2578
|
// src/commands/start.ts
|
|
2322
2579
|
function saveFilesTemp(files) {
|
|
2323
2580
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
2324
2581
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
2325
|
-
const tmpPath =
|
|
2326
|
-
|
|
2582
|
+
const tmpPath = path7.join(os5.tmpdir(), `codeam-${(0, import_crypto.randomUUID)()}-${safeName}`);
|
|
2583
|
+
fs7.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
2327
2584
|
return tmpPath;
|
|
2328
2585
|
});
|
|
2329
2586
|
}
|
|
@@ -2396,14 +2653,14 @@ try:
|
|
|
2396
2653
|
sys.exit((st>>8)&0xFF)
|
|
2397
2654
|
except Exception:sys.exit(0)
|
|
2398
2655
|
`;
|
|
2399
|
-
const helperPath =
|
|
2400
|
-
|
|
2656
|
+
const helperPath = path7.join(os5.tmpdir(), "codeam-quota-helper.py");
|
|
2657
|
+
fs7.writeFileSync(helperPath, helperScript, { mode: 420 });
|
|
2401
2658
|
const python = findInPath("python3") ?? findInPath("python");
|
|
2402
2659
|
if (!python) {
|
|
2403
2660
|
quotaFetchInProgress = false;
|
|
2404
2661
|
return;
|
|
2405
2662
|
}
|
|
2406
|
-
const proc = (0,
|
|
2663
|
+
const proc = (0, import_child_process4.spawn)(python, [helperPath, claudeCmd, "--tools", ""], {
|
|
2407
2664
|
stdio: ["pipe", "pipe", "ignore"],
|
|
2408
2665
|
cwd: process.cwd(),
|
|
2409
2666
|
env: { ...process.env, TERM: "dumb", COLUMNS: "120", LINES: "30" }
|
|
@@ -2429,7 +2686,7 @@ except Exception:sys.exit(0)
|
|
|
2429
2686
|
} catch {
|
|
2430
2687
|
}
|
|
2431
2688
|
try {
|
|
2432
|
-
|
|
2689
|
+
fs7.unlinkSync(helperPath);
|
|
2433
2690
|
} catch {
|
|
2434
2691
|
}
|
|
2435
2692
|
quotaFetchInProgress = false;
|
|
@@ -2479,7 +2736,7 @@ except Exception:sys.exit(0)
|
|
|
2479
2736
|
setTimeout(() => {
|
|
2480
2737
|
for (const p2 of paths) {
|
|
2481
2738
|
try {
|
|
2482
|
-
|
|
2739
|
+
fs7.unlinkSync(p2);
|
|
2483
2740
|
} catch {
|
|
2484
2741
|
}
|
|
2485
2742
|
}
|
|
@@ -2571,6 +2828,62 @@ except Exception:sys.exit(0)
|
|
|
2571
2828
|
await relay.sendResult(cmd.id, "completed", result);
|
|
2572
2829
|
break;
|
|
2573
2830
|
}
|
|
2831
|
+
case "list_files": {
|
|
2832
|
+
const result = await listProjectFiles({ query: parsed.query });
|
|
2833
|
+
await relay.sendResult(cmd.id, "completed", result);
|
|
2834
|
+
break;
|
|
2835
|
+
}
|
|
2836
|
+
case "git_status": {
|
|
2837
|
+
const result = await gitStatus();
|
|
2838
|
+
await relay.sendResult(cmd.id, "completed", result);
|
|
2839
|
+
break;
|
|
2840
|
+
}
|
|
2841
|
+
case "git_diff": {
|
|
2842
|
+
const { path: filePath } = parsed;
|
|
2843
|
+
const result = await gitDiff(filePath ?? null);
|
|
2844
|
+
await relay.sendResult(cmd.id, "completed", result);
|
|
2845
|
+
break;
|
|
2846
|
+
}
|
|
2847
|
+
case "git_diff_staged": {
|
|
2848
|
+
const { path: filePath } = parsed;
|
|
2849
|
+
const result = await gitDiffStaged(filePath ?? null);
|
|
2850
|
+
await relay.sendResult(cmd.id, "completed", result);
|
|
2851
|
+
break;
|
|
2852
|
+
}
|
|
2853
|
+
case "git_log": {
|
|
2854
|
+
const result = await gitLog(parsed.limit ?? 30);
|
|
2855
|
+
await relay.sendResult(cmd.id, "completed", result);
|
|
2856
|
+
break;
|
|
2857
|
+
}
|
|
2858
|
+
case "git_commit": {
|
|
2859
|
+
if (!parsed.message) {
|
|
2860
|
+
await relay.sendResult(cmd.id, "failed", { error: "Missing message" });
|
|
2861
|
+
break;
|
|
2862
|
+
}
|
|
2863
|
+
const result = await gitCommit(parsed.message, parsed.paths);
|
|
2864
|
+
await relay.sendResult(cmd.id, "completed", result);
|
|
2865
|
+
break;
|
|
2866
|
+
}
|
|
2867
|
+
case "git_push": {
|
|
2868
|
+
const result = await gitPush();
|
|
2869
|
+
await relay.sendResult(cmd.id, "completed", result);
|
|
2870
|
+
break;
|
|
2871
|
+
}
|
|
2872
|
+
case "git_pull": {
|
|
2873
|
+
const result = await gitPull();
|
|
2874
|
+
await relay.sendResult(cmd.id, "completed", result);
|
|
2875
|
+
break;
|
|
2876
|
+
}
|
|
2877
|
+
case "git_resolve": {
|
|
2878
|
+
const { path: filePath, side } = parsed;
|
|
2879
|
+
if (!filePath || !side) {
|
|
2880
|
+
await relay.sendResult(cmd.id, "failed", { error: "Missing path or side" });
|
|
2881
|
+
break;
|
|
2882
|
+
}
|
|
2883
|
+
const result = await gitResolve(filePath, side);
|
|
2884
|
+
await relay.sendResult(cmd.id, "completed", result);
|
|
2885
|
+
break;
|
|
2886
|
+
}
|
|
2574
2887
|
}
|
|
2575
2888
|
});
|
|
2576
2889
|
ws.addHandler({
|
|
@@ -2598,7 +2911,7 @@ except Exception:sys.exit(0)
|
|
|
2598
2911
|
setTimeout(() => {
|
|
2599
2912
|
for (const p2 of paths) {
|
|
2600
2913
|
try {
|
|
2601
|
-
|
|
2914
|
+
fs7.unlinkSync(p2);
|
|
2602
2915
|
} catch {
|
|
2603
2916
|
}
|
|
2604
2917
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.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
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|