codeam-cli 2.12.14 → 2.12.16
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 +6 -0
- package/README.md +6 -2
- package/dist/index.js +80 -15
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ 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.12.14] — 2026-05-14
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Dedent Codex's 2-space chat margin from diff lines
|
|
12
|
+
|
|
7
13
|
## [2.12.13] — 2026-05-14
|
|
8
14
|
|
|
9
15
|
### Fixed
|
package/README.md
CHANGED
|
@@ -5,10 +5,12 @@
|
|
|
5
5
|
[](https://github.com/edgar-durand/codeagent-mobile-clients/blob/main/LICENSE)
|
|
6
6
|
[](https://nodejs.org/)
|
|
7
7
|
|
|
8
|
-
> **Remote control
|
|
8
|
+
> **Remote control AI coding agents from your phone.**
|
|
9
9
|
> Send prompts, stream responses, and approve commands in real-time — from the subway, the couch, or anywhere away from your desk.
|
|
10
10
|
|
|
11
|
-
`codeam-cli` is the companion CLI for [**CodeAgent Mobile**](https://codeagent-mobile.com). It wraps
|
|
11
|
+
`codeam-cli` is the companion CLI for [**CodeAgent Mobile**](https://codeagent-mobile.com). It wraps AI coding agents inside a pseudo-terminal, relays your mobile prompts to the agent, and streams the output back to your phone in real-time.
|
|
12
|
+
|
|
13
|
+
Currently supports **[Claude Code](https://claude.ai/code)** (Anthropic) and **[OpenAI Codex](https://github.com/openai/codex)** — start either via `codeam` (Claude Code) or `codeam codex` (OpenAI Codex).
|
|
12
14
|
|
|
13
15
|
---
|
|
14
16
|
|
|
@@ -42,6 +44,7 @@ That's it. Open the [CodeAgent Mobile app](https://codeagent-mobile.com), enter
|
|
|
42
44
|
| Command | What it does |
|
|
43
45
|
|---|---|
|
|
44
46
|
| `codeam` | Start Claude Code in the current directory, with mobile control |
|
|
47
|
+
| `codeam codex` | Start OpenAI Codex in the current directory, with mobile control |
|
|
45
48
|
| `codeam pair` | Pair a new mobile device (6-digit code or QR) |
|
|
46
49
|
| `codeam sessions` | List all paired devices |
|
|
47
50
|
| `codeam status` | Show connection status |
|
|
@@ -94,6 +97,7 @@ Adding more cloud backends (Gitpod, Coder, your own SSH host, …) is a single n
|
|
|
94
97
|
|
|
95
98
|
- **Node.js 18+**
|
|
96
99
|
- **Claude Code** — see the [official quickstart](https://code.claude.com/docs/en/quickstart)
|
|
100
|
+
- **OpenAI Codex** (optional) — see the [official quickstart](https://github.com/openai/codex)
|
|
97
101
|
- **[CodeAgent Mobile](https://codeagent-mobile.com)** app on your phone ([iOS](https://apps.apple.com/) / [Android](https://play.google.com/store/apps/details?id=com.codeagent.mobile))
|
|
98
102
|
|
|
99
103
|
---
|
package/dist/index.js
CHANGED
|
@@ -1658,6 +1658,13 @@ function makeConfig(baseDir) {
|
|
|
1658
1658
|
}
|
|
1659
1659
|
return session;
|
|
1660
1660
|
}
|
|
1661
|
+
function getActiveSessionForAgent2(agent) {
|
|
1662
|
+
const c2 = load();
|
|
1663
|
+
const matches = c2.sessions.filter((s) => s.agent === agent);
|
|
1664
|
+
if (matches.length === 0) return null;
|
|
1665
|
+
matches.sort((a, b) => b.pairedAt - a.pairedAt);
|
|
1666
|
+
return matches[0];
|
|
1667
|
+
}
|
|
1661
1668
|
function clearAll2() {
|
|
1662
1669
|
try {
|
|
1663
1670
|
fs.unlinkSync(file);
|
|
@@ -1670,10 +1677,10 @@ function makeConfig(baseDir) {
|
|
|
1670
1677
|
function loadCliConfig2() {
|
|
1671
1678
|
return load();
|
|
1672
1679
|
}
|
|
1673
|
-
return { getConfig: getConfig2, ensurePluginId: ensurePluginId2, addSession: addSession2, removeSession: removeSession2, setActiveSession: setActiveSession2, getActiveSession: getActiveSession2, clearAll: clearAll2, saveCliConfig: saveCliConfig2, loadCliConfig: loadCliConfig2 };
|
|
1680
|
+
return { getConfig: getConfig2, ensurePluginId: ensurePluginId2, addSession: addSession2, removeSession: removeSession2, setActiveSession: setActiveSession2, getActiveSession: getActiveSession2, getActiveSessionForAgent: getActiveSessionForAgent2, clearAll: clearAll2, saveCliConfig: saveCliConfig2, loadCliConfig: loadCliConfig2 };
|
|
1674
1681
|
}
|
|
1675
1682
|
var _default = makeConfig();
|
|
1676
|
-
var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, clearAll, saveCliConfig, loadCliConfig } = _default;
|
|
1683
|
+
var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, clearAll, saveCliConfig, loadCliConfig } = _default;
|
|
1677
1684
|
|
|
1678
1685
|
// src/ui/banner.ts
|
|
1679
1686
|
var import_picocolors = __toESM(require("picocolors"));
|
|
@@ -1682,7 +1689,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
1682
1689
|
// package.json
|
|
1683
1690
|
var package_default = {
|
|
1684
1691
|
name: "codeam-cli",
|
|
1685
|
-
version: "2.12.
|
|
1692
|
+
version: "2.12.16",
|
|
1686
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.",
|
|
1687
1694
|
type: "commonjs",
|
|
1688
1695
|
main: "dist/index.js",
|
|
@@ -5804,7 +5811,7 @@ var BOX_DRAW_RE = /^[╭─╮│╰╯]/u;
|
|
|
5804
5811
|
var BULLET_CHARS = "\u2022\xB7\u2027\u2219\u22C5";
|
|
5805
5812
|
var CODEX_AGENT_REPLY_RE = new RegExp(`^[${BULLET_CHARS}]\\s`, "u");
|
|
5806
5813
|
var STRIP_BULLET_RE = new RegExp(`^(\\s*)[${BULLET_CHARS}]\\s`, "u");
|
|
5807
|
-
var CODEX_USER_ECHO_RE = /^[›>]\s
|
|
5814
|
+
var CODEX_USER_ECHO_RE = /^[›>]\s+(?!\d+\.\s)\S/u;
|
|
5808
5815
|
var TIP_RE = /^\s*Tip:\s/i;
|
|
5809
5816
|
var LEARN_MORE_RE = /^\s*Learn more:\s/i;
|
|
5810
5817
|
var CODEX_STATUS_FOOTER_RE = /\bdefault\s+[·•]\s+\S+/i;
|
|
@@ -5834,7 +5841,7 @@ function filterCodexChrome(lines) {
|
|
|
5834
5841
|
}
|
|
5835
5842
|
out.push(t2);
|
|
5836
5843
|
}
|
|
5837
|
-
const dedented =
|
|
5844
|
+
const dedented = dedentCodexStructuredLines(out);
|
|
5838
5845
|
const wrapped = wrapCodexCodeBlocks(dedented);
|
|
5839
5846
|
const hasRealInput = lines.some((l) => /\w/.test(l));
|
|
5840
5847
|
if (out.length > 0 || hasRealInput) {
|
|
@@ -5865,10 +5872,11 @@ var PR_TITLE_RE = /^title:\s+\S/;
|
|
|
5865
5872
|
var PR_STATE_RE = /^state:\s+(?:OPEN|CLOSED|MERGED|DRAFT)/i;
|
|
5866
5873
|
var PR_URL_RE = /https?:\/\/github\.com\/[\w.-]+\/[\w.-]+\/pull\/\d+/;
|
|
5867
5874
|
var PR_BANNER_RE = /^\s*[✓✔]?\s*Pull request created\s*$/i;
|
|
5868
|
-
function
|
|
5875
|
+
function dedentCodexStructuredLines(lines) {
|
|
5876
|
+
const MARKER_RE = /^( +)(?:diff --git |@@ |--- |\+\+\+ |Updating [0-9a-f]|Fast-forward|Merge made by |To (?:https?:\/\/|git@|github\.com|[\w.-]+[:/])|From (?:https?:\/\/|git@|github\.com|[\w.-]+[:/])|\[[\w./@-]+\s+[0-9a-f]{7,40}\])/;
|
|
5869
5877
|
let margin = -1;
|
|
5870
5878
|
for (const line of lines) {
|
|
5871
|
-
const m = line.match(
|
|
5879
|
+
const m = line.match(MARKER_RE);
|
|
5872
5880
|
if (m) {
|
|
5873
5881
|
const w3 = m[1].length;
|
|
5874
5882
|
if (margin === -1 || w3 < margin) margin = w3;
|
|
@@ -5978,8 +5986,53 @@ function wrapCodexCodeBlocks(lines) {
|
|
|
5978
5986
|
function parseCodexChrome(_line) {
|
|
5979
5987
|
return null;
|
|
5980
5988
|
}
|
|
5981
|
-
function detectCodexSelector(
|
|
5982
|
-
|
|
5989
|
+
function detectCodexSelector(lines) {
|
|
5990
|
+
const hasConfirmTrailer = lines.some(
|
|
5991
|
+
(l) => /press\s+enter\s+to\s+confirm/i.test(l)
|
|
5992
|
+
);
|
|
5993
|
+
if (!hasConfirmTrailer) return null;
|
|
5994
|
+
let optionStartIdx = -1;
|
|
5995
|
+
for (let i = 0; i < lines.length; i++) {
|
|
5996
|
+
if (/^\s*(?:>\s+)?\d+\.\s/.test(lines[i])) {
|
|
5997
|
+
optionStartIdx = i;
|
|
5998
|
+
break;
|
|
5999
|
+
}
|
|
6000
|
+
}
|
|
6001
|
+
if (optionStartIdx === -1) return null;
|
|
6002
|
+
const questionParts = [];
|
|
6003
|
+
for (let i = 0; i < optionStartIdx; i++) {
|
|
6004
|
+
const t2 = lines[i].trim();
|
|
6005
|
+
if (!t2) continue;
|
|
6006
|
+
if (/^[>›]\s*$/.test(t2)) continue;
|
|
6007
|
+
questionParts.push(t2);
|
|
6008
|
+
}
|
|
6009
|
+
const question = questionParts.join("\n").trim();
|
|
6010
|
+
const optionLabels = /* @__PURE__ */ new Map();
|
|
6011
|
+
let cursorIndex = 0;
|
|
6012
|
+
let hasCursor = false;
|
|
6013
|
+
for (let i = optionStartIdx; i < lines.length; i++) {
|
|
6014
|
+
const t2 = lines[i].trim();
|
|
6015
|
+
if (!t2) continue;
|
|
6016
|
+
if (/^press\s+enter\s+to\s+confirm/i.test(t2)) break;
|
|
6017
|
+
const m = t2.match(/^(>\s+)?(\d+)\.\s+(.+)/);
|
|
6018
|
+
if (!m) continue;
|
|
6019
|
+
const num = parseInt(m[2], 10);
|
|
6020
|
+
if (!optionLabels.has(num)) {
|
|
6021
|
+
optionLabels.set(num, m[3].trim());
|
|
6022
|
+
if (m[1]) {
|
|
6023
|
+
cursorIndex = optionLabels.size - 1;
|
|
6024
|
+
hasCursor = true;
|
|
6025
|
+
}
|
|
6026
|
+
}
|
|
6027
|
+
}
|
|
6028
|
+
const keys = [...optionLabels.keys()].sort((a, b) => a - b);
|
|
6029
|
+
if (keys.length < 2 || keys[0] !== 1) return null;
|
|
6030
|
+
return {
|
|
6031
|
+
question,
|
|
6032
|
+
options: keys.map((k2) => optionLabels.get(k2)),
|
|
6033
|
+
optionDescriptions: keys.map(() => ""),
|
|
6034
|
+
currentIndex: hasCursor ? cursorIndex : 0
|
|
6035
|
+
};
|
|
5983
6036
|
}
|
|
5984
6037
|
|
|
5985
6038
|
// src/agents/codex/renderer.ts
|
|
@@ -8102,13 +8155,22 @@ async function dispatchCommand(ctx, cmd) {
|
|
|
8102
8155
|
}
|
|
8103
8156
|
|
|
8104
8157
|
// src/commands/start.ts
|
|
8105
|
-
async function start() {
|
|
8158
|
+
async function start(requestedAgent) {
|
|
8106
8159
|
showIntro();
|
|
8107
|
-
const session = getActiveSession();
|
|
8160
|
+
const session = requestedAgent ? getActiveSessionForAgent(requestedAgent) : getActiveSession();
|
|
8108
8161
|
if (!session) {
|
|
8109
|
-
|
|
8110
|
-
|
|
8162
|
+
if (requestedAgent) {
|
|
8163
|
+
const displayName = AGENT_REGISTRY[requestedAgent]?.displayName ?? requestedAgent;
|
|
8164
|
+
console.log(` ${import_picocolors2.default.dim(`No paired ${displayName} session found.`)}`);
|
|
8165
|
+
console.log(
|
|
8166
|
+
` ${import_picocolors2.default.dim(`Run ${import_picocolors2.default.white("codeam pair")} from a ${displayName} setup to connect your mobile app.`)}
|
|
8167
|
+
`
|
|
8168
|
+
);
|
|
8169
|
+
} else {
|
|
8170
|
+
console.log(` ${import_picocolors2.default.dim("No paired session found.")}`);
|
|
8171
|
+
console.log(` ${import_picocolors2.default.dim(`Run ${import_picocolors2.default.white("codeam pair")} to connect your mobile app.`)}
|
|
8111
8172
|
`);
|
|
8173
|
+
}
|
|
8112
8174
|
process.exit(0);
|
|
8113
8175
|
}
|
|
8114
8176
|
if (!session.agent) {
|
|
@@ -10442,7 +10504,7 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
10442
10504
|
// src/commands/version.ts
|
|
10443
10505
|
var import_picocolors11 = __toESM(require("picocolors"));
|
|
10444
10506
|
function version() {
|
|
10445
|
-
const v = true ? "2.12.
|
|
10507
|
+
const v = true ? "2.12.16" : "unknown";
|
|
10446
10508
|
console.log(`${import_picocolors11.default.bold("codeam-cli")} ${import_picocolors11.default.cyan(v)}`);
|
|
10447
10509
|
}
|
|
10448
10510
|
|
|
@@ -10577,7 +10639,7 @@ function checkForUpdates() {
|
|
|
10577
10639
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
10578
10640
|
if (process.env.CI) return;
|
|
10579
10641
|
if (!process.stdout.isTTY) return;
|
|
10580
|
-
const current = true ? "2.12.
|
|
10642
|
+
const current = true ? "2.12.16" : null;
|
|
10581
10643
|
if (!current) return;
|
|
10582
10644
|
const cache = readCache();
|
|
10583
10645
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -10620,6 +10682,9 @@ async function main() {
|
|
|
10620
10682
|
if (args[0] === "stop" || args[0] === "remove") return deployStop();
|
|
10621
10683
|
return deploy(args);
|
|
10622
10684
|
default:
|
|
10685
|
+
if (typeof command === "string" && isKnownAgentId(command)) {
|
|
10686
|
+
return start(command);
|
|
10687
|
+
}
|
|
10623
10688
|
return start();
|
|
10624
10689
|
}
|
|
10625
10690
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.16",
|
|
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",
|