codeam-cli 2.11.0 → 2.12.1
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 +37 -0
- package/dist/index.js +392 -101
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,43 @@ 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.11.0] — 2026-05-13
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **shared:** Add agent type primitives
|
|
12
|
+
- **shared:** Add AGENT_REGISTRY with Claude enabled
|
|
13
|
+
- **shared:** Export agents module + bump minor
|
|
14
|
+
- **cli:** Define RuntimeStrategy + DeployStrategy interfaces
|
|
15
|
+
- **cli:** Implement ClaudeRuntimeStrategy
|
|
16
|
+
- **cli:** Implement ClaudeDeployStrategy + extract credential bridge
|
|
17
|
+
- **cli:** Add agent to SavedSession + preferredAgent to CliConfig
|
|
18
|
+
- **cli:** Add parseAgentFlag + promptForAgent helpers
|
|
19
|
+
- **cli:** Pair accepts --agent flag + prompts + remembers preferredAgent
|
|
20
|
+
- **cli:** Pair-auto consumes agent from API response
|
|
21
|
+
- **cli:** Change_model + summarize handlers route through RuntimeStrategy
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- **vsc-plugin:** Port JetBrains agent-strategy pattern
|
|
26
|
+
- **cli:** Extract Claude history parsing to agents/claude/history.ts
|
|
27
|
+
- **cli:** Extract Claude /usage parsing to agents/claude/quota.ts
|
|
28
|
+
- **cli:** Rename ClaudeService → AgentService, add registry factory
|
|
29
|
+
- **cli:** History + quota services delegate to RuntimeStrategy
|
|
30
|
+
- **cli:** Start.ts uses session.agent for runtime factory
|
|
31
|
+
- **cli:** Deploy uses DeployStrategy + switches to pair-auto
|
|
32
|
+
- **cli:** Pass args to pair command
|
|
33
|
+
|
|
34
|
+
### Documentation
|
|
35
|
+
|
|
36
|
+
- Align CLAUDE.md + bump in-source versions to v2.10.8
|
|
37
|
+
- **cli:** Drop misleading codeam-login note in deploy.ts
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- **cli:** Reload config after addSession to avoid clobbering activeSessionId
|
|
42
|
+
- **cli:** Revert deploy PM2 wrapper to pair --agent=<id> (Phase 1 lacks user-JWT)
|
|
43
|
+
|
|
7
44
|
## [2.10.8] — 2026-05-12
|
|
8
45
|
|
|
9
46
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -519,9 +519,9 @@ var require_windowsPtyAgent = __commonJS({
|
|
|
519
519
|
"use strict";
|
|
520
520
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
521
521
|
exports2.argsToCommandLine = exports2.WindowsPtyAgent = void 0;
|
|
522
|
-
var
|
|
523
|
-
var
|
|
524
|
-
var
|
|
522
|
+
var fs17 = require("fs");
|
|
523
|
+
var os16 = require("os");
|
|
524
|
+
var path23 = require("path");
|
|
525
525
|
var child_process_1 = require("child_process");
|
|
526
526
|
var net_1 = require("net");
|
|
527
527
|
var windowsConoutConnection_1 = require_windowsConoutConnection();
|
|
@@ -557,7 +557,7 @@ var require_windowsPtyAgent = __commonJS({
|
|
|
557
557
|
}
|
|
558
558
|
}
|
|
559
559
|
this._ptyNative = this._useConpty ? conptyNative : winptyNative;
|
|
560
|
-
cwd =
|
|
560
|
+
cwd = path23.resolve(cwd);
|
|
561
561
|
var commandLine = argsToCommandLine(file, args2);
|
|
562
562
|
var term;
|
|
563
563
|
if (this._useConpty) {
|
|
@@ -578,7 +578,7 @@ var require_windowsPtyAgent = __commonJS({
|
|
|
578
578
|
this._outSocket.on("connect", function() {
|
|
579
579
|
_this._outSocket.emit("ready_datapipe");
|
|
580
580
|
});
|
|
581
|
-
var inSocketFD =
|
|
581
|
+
var inSocketFD = fs17.openSync(term.conin, "w");
|
|
582
582
|
this._inSocket = new net_1.Socket({
|
|
583
583
|
fd: inSocketFD,
|
|
584
584
|
readable: false,
|
|
@@ -679,7 +679,7 @@ var require_windowsPtyAgent = __commonJS({
|
|
|
679
679
|
WindowsPtyAgent2.prototype._getConsoleProcessList = function() {
|
|
680
680
|
var _this = this;
|
|
681
681
|
return new Promise(function(resolve2) {
|
|
682
|
-
var agent = child_process_1.fork(
|
|
682
|
+
var agent = child_process_1.fork(path23.join(__dirname, "conpty_console_list_agent"), [_this._innerPid.toString()]);
|
|
683
683
|
agent.on("message", function(message) {
|
|
684
684
|
clearTimeout(timeout);
|
|
685
685
|
resolve2(message.consoleProcessList);
|
|
@@ -702,7 +702,7 @@ var require_windowsPtyAgent = __commonJS({
|
|
|
702
702
|
configurable: true
|
|
703
703
|
});
|
|
704
704
|
WindowsPtyAgent2.prototype._getWindowsBuildNumber = function() {
|
|
705
|
-
var osVersion = /(\d+)\.(\d+)\.(\d+)/g.exec(
|
|
705
|
+
var osVersion = /(\d+)\.(\d+)\.(\d+)/g.exec(os16.release());
|
|
706
706
|
var buildNumber = 0;
|
|
707
707
|
if (osVersion && osVersion.length === 4) {
|
|
708
708
|
buildNumber = parseInt(osVersion[3]);
|
|
@@ -1012,15 +1012,15 @@ var require_unixTerminal = __commonJS({
|
|
|
1012
1012
|
})();
|
|
1013
1013
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
1014
1014
|
exports2.UnixTerminal = void 0;
|
|
1015
|
-
var
|
|
1016
|
-
var
|
|
1015
|
+
var fs17 = require("fs");
|
|
1016
|
+
var path23 = require("path");
|
|
1017
1017
|
var tty = require("tty");
|
|
1018
1018
|
var terminal_1 = require_terminal();
|
|
1019
1019
|
var utils_1 = require_utils();
|
|
1020
1020
|
var native = utils_1.loadNativeModule("pty");
|
|
1021
1021
|
var pty = native.module;
|
|
1022
1022
|
var helperPath = native.dir + "/spawn-helper";
|
|
1023
|
-
helperPath =
|
|
1023
|
+
helperPath = path23.resolve(__dirname, helperPath);
|
|
1024
1024
|
helperPath = helperPath.replace("app.asar", "app.asar.unpacked");
|
|
1025
1025
|
helperPath = helperPath.replace("node_modules.asar", "node_modules.asar.unpacked");
|
|
1026
1026
|
var DEFAULT_FILE = "sh";
|
|
@@ -1275,7 +1275,7 @@ var require_unixTerminal = __commonJS({
|
|
|
1275
1275
|
return;
|
|
1276
1276
|
}
|
|
1277
1277
|
var task = this._writeQueue[0];
|
|
1278
|
-
|
|
1278
|
+
fs17.write(this._fd, task.buffer, task.offset, function(err, written) {
|
|
1279
1279
|
if (err) {
|
|
1280
1280
|
if ("code" in err && err.code === "EAGAIN") {
|
|
1281
1281
|
_this._writeImmediate = setImmediate(function() {
|
|
@@ -1313,10 +1313,10 @@ var require_lib = __commonJS({
|
|
|
1313
1313
|
} else {
|
|
1314
1314
|
terminalCtor = require_unixTerminal().UnixTerminal;
|
|
1315
1315
|
}
|
|
1316
|
-
function
|
|
1316
|
+
function spawn11(file, args2, opt) {
|
|
1317
1317
|
return new terminalCtor(file, args2, opt);
|
|
1318
1318
|
}
|
|
1319
|
-
exports2.spawn =
|
|
1319
|
+
exports2.spawn = spawn11;
|
|
1320
1320
|
function fork(file, args2, opt) {
|
|
1321
1321
|
return new terminalCtor(file, args2, opt);
|
|
1322
1322
|
}
|
|
@@ -1738,18 +1738,37 @@ function filterChrome(lines) {
|
|
|
1738
1738
|
|
|
1739
1739
|
// ../../packages/shared/src/models/pricing.ts
|
|
1740
1740
|
var MODEL_PRICING = {
|
|
1741
|
+
// ── Anthropic / Claude ────────────────────────────────────
|
|
1741
1742
|
"claude-sonnet-4": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
1742
1743
|
"claude-opus-4": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
|
|
1743
1744
|
"claude-3-5-sonnet": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
1744
1745
|
"claude-3-5-haiku": { input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1 },
|
|
1745
|
-
"claude-3-haiku": { input: 0.25, output: 1.25, cacheRead: 0.03, cacheWrite: 0.3 }
|
|
1746
|
+
"claude-3-haiku": { input: 0.25, output: 1.25, cacheRead: 0.03, cacheWrite: 0.3 },
|
|
1747
|
+
// ── Codex / OpenAI ────────────────────────────────────────
|
|
1748
|
+
// Phase 2 placeholder pricing: 0 across the board until OpenAI publishes
|
|
1749
|
+
// confirmed rates for the GPT-5.x catalog. Sync from
|
|
1750
|
+
// developers.openai.com/pricing when available.
|
|
1751
|
+
"gpt-5.5": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
1752
|
+
"gpt-5.4": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
1753
|
+
"gpt-5.4-mini": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
1754
|
+
"gpt-5.3-codex": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
1755
|
+
"gpt-5.2": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
1756
|
+
"codex-auto-review": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }
|
|
1746
1757
|
};
|
|
1747
1758
|
var MODEL_CONTEXT_WINDOW = {
|
|
1759
|
+
// ── Anthropic / Claude ────────────────────────────────────
|
|
1748
1760
|
"claude-opus-4": 1e6,
|
|
1749
1761
|
"claude-sonnet-4": 1e6,
|
|
1750
1762
|
"claude-3-5-sonnet": 2e5,
|
|
1751
1763
|
"claude-3-5-haiku": 2e5,
|
|
1752
|
-
"claude-3-haiku": 2e5
|
|
1764
|
+
"claude-3-haiku": 2e5,
|
|
1765
|
+
// ── Codex / OpenAI ────────────────────────────────────────
|
|
1766
|
+
"gpt-5.5": 272e3,
|
|
1767
|
+
"gpt-5.4": 272e3,
|
|
1768
|
+
"gpt-5.4-mini": 272e3,
|
|
1769
|
+
"gpt-5.3-codex": 272e3,
|
|
1770
|
+
"gpt-5.2": 272e3,
|
|
1771
|
+
"codex-auto-review": 272e3
|
|
1753
1772
|
};
|
|
1754
1773
|
var DEFAULT_CONTEXT_WINDOW = 2e5;
|
|
1755
1774
|
function getPricing(model) {
|
|
@@ -1780,7 +1799,7 @@ var AGENT_REGISTRY = {
|
|
|
1780
1799
|
id: "codex",
|
|
1781
1800
|
displayName: "Codex CLI",
|
|
1782
1801
|
binaryName: "codex",
|
|
1783
|
-
enabled:
|
|
1802
|
+
enabled: true,
|
|
1784
1803
|
supportedAuthKinds: ["oauth_token", "api_key"],
|
|
1785
1804
|
preferredAuthKind: "oauth_token"
|
|
1786
1805
|
},
|
|
@@ -1900,7 +1919,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
1900
1919
|
// package.json
|
|
1901
1920
|
var package_default = {
|
|
1902
1921
|
name: "codeam-cli",
|
|
1903
|
-
version: "2.
|
|
1922
|
+
version: "2.12.1",
|
|
1904
1923
|
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.",
|
|
1905
1924
|
type: "commonjs",
|
|
1906
1925
|
main: "dist/index.js",
|
|
@@ -5648,13 +5667,285 @@ var ClaudeDeployStrategy = class {
|
|
|
5648
5667
|
}
|
|
5649
5668
|
};
|
|
5650
5669
|
|
|
5670
|
+
// src/agents/codex/runtime.ts
|
|
5671
|
+
var import_node_child_process = require("child_process");
|
|
5672
|
+
|
|
5673
|
+
// src/agents/codex/history.ts
|
|
5674
|
+
var import_node_fs2 = __toESM(require("fs"));
|
|
5675
|
+
var import_node_path2 = __toESM(require("path"));
|
|
5676
|
+
var import_node_os = __toESM(require("os"));
|
|
5677
|
+
function resolveHistoryDir2(_cwd, homeOverride) {
|
|
5678
|
+
const home = homeOverride ?? import_node_os.default.homedir();
|
|
5679
|
+
const sessionsRoot = import_node_path2.default.join(home, ".codex", "sessions");
|
|
5680
|
+
if (!import_node_fs2.default.existsSync(sessionsRoot)) return null;
|
|
5681
|
+
const now = /* @__PURE__ */ new Date();
|
|
5682
|
+
const yyyy = String(now.getUTCFullYear());
|
|
5683
|
+
const mm = String(now.getUTCMonth() + 1).padStart(2, "0");
|
|
5684
|
+
const dd = String(now.getUTCDate()).padStart(2, "0");
|
|
5685
|
+
const todayDir = import_node_path2.default.join(sessionsRoot, yyyy, mm, dd);
|
|
5686
|
+
if (!import_node_fs2.default.existsSync(todayDir)) return null;
|
|
5687
|
+
return todayDir;
|
|
5688
|
+
}
|
|
5689
|
+
function parseLine(line) {
|
|
5690
|
+
try {
|
|
5691
|
+
const parsed = JSON.parse(line);
|
|
5692
|
+
if (parsed && typeof parsed === "object" && typeof parsed.timestamp === "string" && typeof parsed.type === "string") {
|
|
5693
|
+
return parsed;
|
|
5694
|
+
}
|
|
5695
|
+
} catch {
|
|
5696
|
+
}
|
|
5697
|
+
return null;
|
|
5698
|
+
}
|
|
5699
|
+
function extractMessageText(content) {
|
|
5700
|
+
if (!Array.isArray(content)) return "";
|
|
5701
|
+
const parts = [];
|
|
5702
|
+
for (const block of content) {
|
|
5703
|
+
if (!block || typeof block !== "object") continue;
|
|
5704
|
+
if (typeof block.text === "string" && block.text.length > 0) {
|
|
5705
|
+
if (block.type === "input_text" || block.type === "output_text") {
|
|
5706
|
+
parts.push(block.text);
|
|
5707
|
+
}
|
|
5708
|
+
}
|
|
5709
|
+
}
|
|
5710
|
+
return parts.join("\n");
|
|
5711
|
+
}
|
|
5712
|
+
function mapRole(codexRole) {
|
|
5713
|
+
if (codexRole === "user") return "user";
|
|
5714
|
+
if (codexRole === "assistant") return "agent";
|
|
5715
|
+
return "system";
|
|
5716
|
+
}
|
|
5717
|
+
function parseHistoryFile2(filePath) {
|
|
5718
|
+
const raw = import_node_fs2.default.readFileSync(filePath, "utf8");
|
|
5719
|
+
const lines = raw.split("\n").filter(Boolean);
|
|
5720
|
+
for (const line of lines) {
|
|
5721
|
+
const rec = parseLine(line);
|
|
5722
|
+
if (!rec) continue;
|
|
5723
|
+
if (rec.type === "session_meta") {
|
|
5724
|
+
const meta = rec.payload;
|
|
5725
|
+
if (meta && typeof meta.cwd === "string") {
|
|
5726
|
+
let resolvedMeta;
|
|
5727
|
+
let resolvedCurrent;
|
|
5728
|
+
try {
|
|
5729
|
+
resolvedMeta = import_node_fs2.default.realpathSync(meta.cwd);
|
|
5730
|
+
resolvedCurrent = import_node_fs2.default.realpathSync(process.cwd());
|
|
5731
|
+
} catch {
|
|
5732
|
+
resolvedMeta = import_node_path2.default.resolve(meta.cwd);
|
|
5733
|
+
resolvedCurrent = import_node_path2.default.resolve(process.cwd());
|
|
5734
|
+
}
|
|
5735
|
+
if (resolvedMeta !== resolvedCurrent) {
|
|
5736
|
+
return [];
|
|
5737
|
+
}
|
|
5738
|
+
}
|
|
5739
|
+
break;
|
|
5740
|
+
}
|
|
5741
|
+
}
|
|
5742
|
+
const out = [];
|
|
5743
|
+
let idx = 0;
|
|
5744
|
+
for (const line of lines) {
|
|
5745
|
+
const rec = parseLine(line);
|
|
5746
|
+
if (!rec) continue;
|
|
5747
|
+
if (rec.type !== "response_item") continue;
|
|
5748
|
+
const payload = rec.payload;
|
|
5749
|
+
const msg = payload?.Message;
|
|
5750
|
+
if (!msg) continue;
|
|
5751
|
+
const text = extractMessageText(msg.content);
|
|
5752
|
+
if (!text) continue;
|
|
5753
|
+
out.push({
|
|
5754
|
+
id: `rollout:${idx}`,
|
|
5755
|
+
role: mapRole(msg.role),
|
|
5756
|
+
text,
|
|
5757
|
+
timestamp: rec.timestamp
|
|
5758
|
+
});
|
|
5759
|
+
idx++;
|
|
5760
|
+
}
|
|
5761
|
+
return out;
|
|
5762
|
+
}
|
|
5763
|
+
function getCurrentUsage2(historyDir) {
|
|
5764
|
+
if (!import_node_fs2.default.existsSync(historyDir)) return null;
|
|
5765
|
+
const files = import_node_fs2.default.readdirSync(historyDir).filter((f) => f.startsWith("rollout-") && f.endsWith(".jsonl")).map((f) => ({ name: f, full: import_node_path2.default.join(historyDir, f) })).map((e) => ({ ...e, mtime: import_node_fs2.default.statSync(e.full).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
5766
|
+
if (files.length === 0) return null;
|
|
5767
|
+
const latest = files[0].full;
|
|
5768
|
+
const raw = import_node_fs2.default.readFileSync(latest, "utf8");
|
|
5769
|
+
let lastTokenCount = null;
|
|
5770
|
+
for (const line of raw.split("\n").filter(Boolean)) {
|
|
5771
|
+
const rec = parseLine(line);
|
|
5772
|
+
if (!rec || rec.type !== "event_msg") continue;
|
|
5773
|
+
const payload = rec.payload;
|
|
5774
|
+
const info = payload?.TokenCount?.info;
|
|
5775
|
+
const total2 = info?.total_token_usage?.total_tokens;
|
|
5776
|
+
const window = info?.model_context_window;
|
|
5777
|
+
if (typeof total2 === "number" && typeof window === "number" && window > 0) {
|
|
5778
|
+
lastTokenCount = { total: total2, window };
|
|
5779
|
+
}
|
|
5780
|
+
}
|
|
5781
|
+
if (!lastTokenCount) return null;
|
|
5782
|
+
const used = lastTokenCount.total;
|
|
5783
|
+
const total = lastTokenCount.window;
|
|
5784
|
+
return {
|
|
5785
|
+
used,
|
|
5786
|
+
total,
|
|
5787
|
+
percent: Math.min(100, Math.round(used / total * 100))
|
|
5788
|
+
};
|
|
5789
|
+
}
|
|
5790
|
+
|
|
5791
|
+
// src/agents/codex/runtime.ts
|
|
5792
|
+
var CODEX_CONTEXT_WINDOW = 272e3;
|
|
5793
|
+
var CODEX_MODELS = [
|
|
5794
|
+
{ id: "gpt-5.5", label: "GPT-5.5", contextWindow: CODEX_CONTEXT_WINDOW },
|
|
5795
|
+
{ id: "gpt-5.4", label: "GPT-5.4", contextWindow: CODEX_CONTEXT_WINDOW },
|
|
5796
|
+
{ id: "gpt-5.4-mini", label: "GPT-5.4 Mini", contextWindow: CODEX_CONTEXT_WINDOW },
|
|
5797
|
+
{ id: "gpt-5.3-codex", label: "GPT-5.3 Codex", contextWindow: CODEX_CONTEXT_WINDOW },
|
|
5798
|
+
{ id: "gpt-5.2", label: "GPT-5.2", contextWindow: CODEX_CONTEXT_WINDOW },
|
|
5799
|
+
{ id: "codex-auto-review", label: "Codex Auto Review", contextWindow: CODEX_CONTEXT_WINDOW }
|
|
5800
|
+
];
|
|
5801
|
+
var CodexRuntimeStrategy = class {
|
|
5802
|
+
id = "codex";
|
|
5803
|
+
meta = getAgent("codex");
|
|
5804
|
+
async prepareLaunch() {
|
|
5805
|
+
const binary = findInPath("codex");
|
|
5806
|
+
if (!binary) {
|
|
5807
|
+
await installCodexViaNpm();
|
|
5808
|
+
const afterInstall = findInPath("codex");
|
|
5809
|
+
if (!afterInstall) {
|
|
5810
|
+
throw new Error(
|
|
5811
|
+
"Could not find 'codex' on PATH after running 'npm install -g @openai/codex'. Install it manually and retry."
|
|
5812
|
+
);
|
|
5813
|
+
}
|
|
5814
|
+
return { cmd: afterInstall, args: [] };
|
|
5815
|
+
}
|
|
5816
|
+
return { cmd: binary, args: [] };
|
|
5817
|
+
}
|
|
5818
|
+
/** `codex resume <SESSION_ID>` — subcommand, not flag. */
|
|
5819
|
+
resumeLaunchArgs(sessionId) {
|
|
5820
|
+
return ["resume", sessionId];
|
|
5821
|
+
}
|
|
5822
|
+
resolveHistoryDir(cwd) {
|
|
5823
|
+
return resolveHistoryDir2(cwd);
|
|
5824
|
+
}
|
|
5825
|
+
parseHistoryFile(filePath) {
|
|
5826
|
+
return parseHistoryFile2(filePath);
|
|
5827
|
+
}
|
|
5828
|
+
getCurrentUsage(historyDir) {
|
|
5829
|
+
return getCurrentUsage2(historyDir);
|
|
5830
|
+
}
|
|
5831
|
+
/**
|
|
5832
|
+
* Codex's quota lives behind the `account/get_account_rate_limits` RPC,
|
|
5833
|
+
* not a TUI slash command. Phase 2 ships with this stubbed to null so the
|
|
5834
|
+
* mobile shows "—" for weekly usage on Codex sessions. A follow-up will
|
|
5835
|
+
* invoke the RPC directly.
|
|
5836
|
+
*/
|
|
5837
|
+
async fetchWeeklyUsage() {
|
|
5838
|
+
return null;
|
|
5839
|
+
}
|
|
5840
|
+
async listModels() {
|
|
5841
|
+
return CODEX_MODELS;
|
|
5842
|
+
}
|
|
5843
|
+
changeModelInstruction(modelId) {
|
|
5844
|
+
return { type: "pty", ptyInput: `/model ${modelId}\r` };
|
|
5845
|
+
}
|
|
5846
|
+
/**
|
|
5847
|
+
* Codex has no auto-compact (`auto_compact_token_limit: null` for every
|
|
5848
|
+
* model). Both modes fall through to the manual `/compact` slash command.
|
|
5849
|
+
*/
|
|
5850
|
+
summarizeInstruction(_mode) {
|
|
5851
|
+
return { ptyInput: "/compact\r" };
|
|
5852
|
+
}
|
|
5853
|
+
};
|
|
5854
|
+
async function installCodexViaNpm() {
|
|
5855
|
+
return new Promise((resolve2, reject) => {
|
|
5856
|
+
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
5857
|
+
const proc = (0, import_node_child_process.spawn)(npm, ["install", "-g", "@openai/codex"], {
|
|
5858
|
+
stdio: "inherit"
|
|
5859
|
+
});
|
|
5860
|
+
proc.on("close", (code) => {
|
|
5861
|
+
if (code === 0) resolve2();
|
|
5862
|
+
else reject(new Error(`npm install -g @openai/codex exited ${code}`));
|
|
5863
|
+
});
|
|
5864
|
+
proc.on("error", reject);
|
|
5865
|
+
});
|
|
5866
|
+
}
|
|
5867
|
+
|
|
5868
|
+
// src/agents/codex/credentials.ts
|
|
5869
|
+
var import_node_fs3 = __toESM(require("fs"));
|
|
5870
|
+
var import_node_path3 = __toESM(require("path"));
|
|
5871
|
+
var import_node_os2 = __toESM(require("os"));
|
|
5872
|
+
async function detectLocalCodexCredentials() {
|
|
5873
|
+
const home = process.env.HOME ?? import_node_os2.default.homedir();
|
|
5874
|
+
const authJson = import_node_path3.default.join(home, ".codex", "auth.json");
|
|
5875
|
+
if (import_node_fs3.default.existsSync(authJson)) {
|
|
5876
|
+
return { source: "flat-file", description: "~/.codex/auth.json" };
|
|
5877
|
+
}
|
|
5878
|
+
if (process.env.OPENAI_API_KEY) {
|
|
5879
|
+
return { source: "env-var", description: "OPENAI_API_KEY env var" };
|
|
5880
|
+
}
|
|
5881
|
+
return { source: "none", description: "" };
|
|
5882
|
+
}
|
|
5883
|
+
async function bridgeLocalCodexCredentials(provider, workspaceId) {
|
|
5884
|
+
const home = process.env.HOME ?? import_node_os2.default.homedir();
|
|
5885
|
+
const authJson = import_node_path3.default.join(home, ".codex", "auth.json");
|
|
5886
|
+
if (import_node_fs3.default.existsSync(authJson)) {
|
|
5887
|
+
const contents = import_node_fs3.default.readFileSync(authJson);
|
|
5888
|
+
await provider.exec(workspaceId, "mkdir -p ~/.codex && chmod 700 ~/.codex");
|
|
5889
|
+
await provider.uploadFile(workspaceId, "/home/codespace/.codex/auth.json", contents, { mode: 384 });
|
|
5890
|
+
return { source: "flat-file", description: "~/.codex/auth.json" };
|
|
5891
|
+
}
|
|
5892
|
+
const key = process.env.OPENAI_API_KEY;
|
|
5893
|
+
if (key) {
|
|
5894
|
+
const escaped = key.replace(/'/g, "'\\''");
|
|
5895
|
+
const line = `export OPENAI_API_KEY='${escaped}'`;
|
|
5896
|
+
await provider.exec(workspaceId, `grep -qxF "${line}" ~/.bashrc || echo "${line}" >> ~/.bashrc`);
|
|
5897
|
+
return { source: "env-var", description: "OPENAI_API_KEY env var" };
|
|
5898
|
+
}
|
|
5899
|
+
return { source: "none", description: "" };
|
|
5900
|
+
}
|
|
5901
|
+
async function runRemoteCodexLogin(provider, workspaceId) {
|
|
5902
|
+
await provider.streamCommand(workspaceId, 'bash -lc "codex login"');
|
|
5903
|
+
}
|
|
5904
|
+
async function verifyCodexAuth(provider, workspaceId) {
|
|
5905
|
+
const r = await provider.exec(workspaceId, 'bash -lc "codex --version"');
|
|
5906
|
+
return r.code === 0;
|
|
5907
|
+
}
|
|
5908
|
+
|
|
5909
|
+
// src/agents/codex/deploy.ts
|
|
5910
|
+
var CodexDeployStrategy = class {
|
|
5911
|
+
id = "codex";
|
|
5912
|
+
async detectLocalCredentials() {
|
|
5913
|
+
return detectLocalCodexCredentials();
|
|
5914
|
+
}
|
|
5915
|
+
async bridgeLocalCredentials(provider, workspaceId) {
|
|
5916
|
+
return bridgeLocalCodexCredentials(provider, workspaceId);
|
|
5917
|
+
}
|
|
5918
|
+
async runRemoteLogin(provider, workspaceId) {
|
|
5919
|
+
return runRemoteCodexLogin(provider, workspaceId);
|
|
5920
|
+
}
|
|
5921
|
+
/**
|
|
5922
|
+
* Steps 5–7 of the existing local-deploy flow, adapted for Codex:
|
|
5923
|
+
* 1. Install codex via npm
|
|
5924
|
+
* 2. (skipped — bridge already happened before this method runs, or the
|
|
5925
|
+
* fallback runs via runRemoteLogin)
|
|
5926
|
+
* 3. Verify auth; fallback to remote login if verify fails AND no
|
|
5927
|
+
* credentials were bridged.
|
|
5928
|
+
*/
|
|
5929
|
+
async setupOnWorkspace(provider, workspaceId, opts) {
|
|
5930
|
+
const installResult = await provider.exec(workspaceId, "npm install -g @openai/codex");
|
|
5931
|
+
if (installResult.code !== 0) {
|
|
5932
|
+
throw new Error(`codex install failed: ${installResult.stderr.slice(0, 500)}`);
|
|
5933
|
+
}
|
|
5934
|
+
const verified = await verifyCodexAuth(provider, workspaceId);
|
|
5935
|
+
if (!verified && opts.bridged === "none") {
|
|
5936
|
+
await runRemoteCodexLogin(provider, workspaceId);
|
|
5937
|
+
}
|
|
5938
|
+
}
|
|
5939
|
+
};
|
|
5940
|
+
|
|
5651
5941
|
// src/agents/registry.ts
|
|
5652
5942
|
var runtimeBuilders = {
|
|
5653
|
-
claude: () => new ClaudeRuntimeStrategy()
|
|
5654
|
-
|
|
5943
|
+
claude: () => new ClaudeRuntimeStrategy(),
|
|
5944
|
+
codex: () => new CodexRuntimeStrategy()
|
|
5655
5945
|
};
|
|
5656
5946
|
var deployBuilders = {
|
|
5657
|
-
claude: () => new ClaudeDeployStrategy()
|
|
5947
|
+
claude: () => new ClaudeDeployStrategy(),
|
|
5948
|
+
codex: () => new CodexDeployStrategy()
|
|
5658
5949
|
};
|
|
5659
5950
|
function createRuntimeStrategy(agent) {
|
|
5660
5951
|
if (!AGENT_REGISTRY[agent]?.enabled) {
|
|
@@ -6149,9 +6440,9 @@ var OutputService = class _OutputService {
|
|
|
6149
6440
|
};
|
|
6150
6441
|
|
|
6151
6442
|
// src/services/history.service.ts
|
|
6152
|
-
var
|
|
6153
|
-
var
|
|
6154
|
-
var
|
|
6443
|
+
var fs11 = __toESM(require("fs"));
|
|
6444
|
+
var path14 = __toESM(require("path"));
|
|
6445
|
+
var os12 = __toESM(require("os"));
|
|
6155
6446
|
var https4 = __toESM(require("https"));
|
|
6156
6447
|
var http4 = __toESM(require("http"));
|
|
6157
6448
|
var import_zod = require("zod");
|
|
@@ -6178,7 +6469,7 @@ function parseJsonl(filePath) {
|
|
|
6178
6469
|
const messages = [];
|
|
6179
6470
|
let raw;
|
|
6180
6471
|
try {
|
|
6181
|
-
raw =
|
|
6472
|
+
raw = fs11.readFileSync(filePath, "utf8");
|
|
6182
6473
|
} catch (err) {
|
|
6183
6474
|
if (err.code !== "ENOENT") {
|
|
6184
6475
|
log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
|
|
@@ -6312,7 +6603,7 @@ var HistoryService = class _HistoryService {
|
|
|
6312
6603
|
return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
|
|
6313
6604
|
}
|
|
6314
6605
|
get projectDir() {
|
|
6315
|
-
return this.runtime.resolveHistoryDir(this.cwd) ??
|
|
6606
|
+
return this.runtime.resolveHistoryDir(this.cwd) ?? path14.join(os12.homedir(), ".claude", "projects", encodeCwd(this.cwd));
|
|
6316
6607
|
}
|
|
6317
6608
|
/** Set the current Claude conversation ID (extracted from /cost command or session start) */
|
|
6318
6609
|
setCurrentConversationId(id) {
|
|
@@ -6324,7 +6615,7 @@ var HistoryService = class _HistoryService {
|
|
|
6324
6615
|
/** Return the current message count in the active conversation. */
|
|
6325
6616
|
getCurrentMessageCount() {
|
|
6326
6617
|
if (!this.currentConversationId) return 0;
|
|
6327
|
-
const filePath =
|
|
6618
|
+
const filePath = path14.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
6328
6619
|
return parseJsonl(filePath).length;
|
|
6329
6620
|
}
|
|
6330
6621
|
/**
|
|
@@ -6335,7 +6626,7 @@ var HistoryService = class _HistoryService {
|
|
|
6335
6626
|
const deadline = Date.now() + timeoutMs;
|
|
6336
6627
|
while (Date.now() < deadline) {
|
|
6337
6628
|
if (!this.currentConversationId) return null;
|
|
6338
|
-
const filePath =
|
|
6629
|
+
const filePath = path14.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
6339
6630
|
const messages = parseJsonl(filePath);
|
|
6340
6631
|
if (messages.length > previousCount) {
|
|
6341
6632
|
for (let i = messages.length - 1; i >= previousCount; i--) {
|
|
@@ -6361,16 +6652,16 @@ var HistoryService = class _HistoryService {
|
|
|
6361
6652
|
const dir = this.projectDir;
|
|
6362
6653
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
6363
6654
|
try {
|
|
6364
|
-
const files =
|
|
6655
|
+
const files = fs11.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
6365
6656
|
try {
|
|
6366
|
-
const stat3 =
|
|
6657
|
+
const stat3 = fs11.statSync(path14.join(dir, e.name));
|
|
6367
6658
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
6368
6659
|
} catch {
|
|
6369
6660
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
6370
6661
|
}
|
|
6371
6662
|
}).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
|
|
6372
6663
|
if (files.length > 0) {
|
|
6373
|
-
this.currentConversationId =
|
|
6664
|
+
this.currentConversationId = path14.basename(files[0].name, ".jsonl");
|
|
6374
6665
|
}
|
|
6375
6666
|
} catch {
|
|
6376
6667
|
}
|
|
@@ -6404,13 +6695,13 @@ var HistoryService = class _HistoryService {
|
|
|
6404
6695
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
6405
6696
|
let entries;
|
|
6406
6697
|
try {
|
|
6407
|
-
entries =
|
|
6698
|
+
entries = fs11.readdirSync(dir, { withFileTypes: true });
|
|
6408
6699
|
} catch {
|
|
6409
6700
|
return null;
|
|
6410
6701
|
}
|
|
6411
6702
|
const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
6412
6703
|
try {
|
|
6413
|
-
const stat3 =
|
|
6704
|
+
const stat3 = fs11.statSync(path14.join(dir, e.name));
|
|
6414
6705
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
6415
6706
|
} catch {
|
|
6416
6707
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
@@ -6419,12 +6710,12 @@ var HistoryService = class _HistoryService {
|
|
|
6419
6710
|
if (files.length === 0) return null;
|
|
6420
6711
|
const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
|
|
6421
6712
|
if (!files.some((f) => f.name === targetFile)) return null;
|
|
6422
|
-
return this.extractUsageFromFile(
|
|
6713
|
+
return this.extractUsageFromFile(path14.join(dir, targetFile));
|
|
6423
6714
|
}
|
|
6424
6715
|
extractUsageFromFile(filePath) {
|
|
6425
6716
|
let raw;
|
|
6426
6717
|
try {
|
|
6427
|
-
raw =
|
|
6718
|
+
raw = fs11.readFileSync(filePath, "utf8");
|
|
6428
6719
|
} catch {
|
|
6429
6720
|
return null;
|
|
6430
6721
|
}
|
|
@@ -6469,9 +6760,9 @@ var HistoryService = class _HistoryService {
|
|
|
6469
6760
|
let totalCost = 0;
|
|
6470
6761
|
let files;
|
|
6471
6762
|
try {
|
|
6472
|
-
files =
|
|
6763
|
+
files = fs11.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
|
|
6473
6764
|
try {
|
|
6474
|
-
return
|
|
6765
|
+
return fs11.statSync(path14.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
6475
6766
|
} catch {
|
|
6476
6767
|
return false;
|
|
6477
6768
|
}
|
|
@@ -6482,7 +6773,7 @@ var HistoryService = class _HistoryService {
|
|
|
6482
6773
|
for (const file of files) {
|
|
6483
6774
|
let raw;
|
|
6484
6775
|
try {
|
|
6485
|
-
raw =
|
|
6776
|
+
raw = fs11.readFileSync(path14.join(projectDir, file), "utf8");
|
|
6486
6777
|
} catch {
|
|
6487
6778
|
continue;
|
|
6488
6779
|
}
|
|
@@ -6517,23 +6808,23 @@ var HistoryService = class _HistoryService {
|
|
|
6517
6808
|
const dir = this.projectDir;
|
|
6518
6809
|
let entries;
|
|
6519
6810
|
try {
|
|
6520
|
-
entries =
|
|
6811
|
+
entries = fs11.readdirSync(dir, { withFileTypes: true });
|
|
6521
6812
|
} catch {
|
|
6522
6813
|
return;
|
|
6523
6814
|
}
|
|
6524
6815
|
const sessions2 = [];
|
|
6525
6816
|
for (const entry of entries) {
|
|
6526
6817
|
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
|
|
6527
|
-
const id =
|
|
6528
|
-
const filePath =
|
|
6818
|
+
const id = path14.basename(entry.name, ".jsonl");
|
|
6819
|
+
const filePath = path14.join(dir, entry.name);
|
|
6529
6820
|
let mtime = Date.now();
|
|
6530
6821
|
try {
|
|
6531
|
-
mtime =
|
|
6822
|
+
mtime = fs11.statSync(filePath).mtimeMs;
|
|
6532
6823
|
} catch {
|
|
6533
6824
|
}
|
|
6534
6825
|
let summary = "";
|
|
6535
6826
|
try {
|
|
6536
|
-
const raw =
|
|
6827
|
+
const raw = fs11.readFileSync(filePath, "utf8");
|
|
6537
6828
|
for (const line of raw.split("\n")) {
|
|
6538
6829
|
if (!line.trim()) continue;
|
|
6539
6830
|
try {
|
|
@@ -6566,7 +6857,7 @@ var HistoryService = class _HistoryService {
|
|
|
6566
6857
|
* showing an empty conversation.
|
|
6567
6858
|
*/
|
|
6568
6859
|
async loadConversation(sessionId) {
|
|
6569
|
-
const filePath =
|
|
6860
|
+
const filePath = path14.join(this.projectDir, `${sessionId}.jsonl`);
|
|
6570
6861
|
const messages = parseJsonl(filePath);
|
|
6571
6862
|
if (messages.length === 0) return;
|
|
6572
6863
|
const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
|
|
@@ -6609,7 +6900,7 @@ var HistoryService = class _HistoryService {
|
|
|
6609
6900
|
if (!this.currentConversationId) return 0;
|
|
6610
6901
|
}
|
|
6611
6902
|
const sessionId = this.currentConversationId;
|
|
6612
|
-
const filePath =
|
|
6903
|
+
const filePath = path14.join(this.projectDir, `${sessionId}.jsonl`);
|
|
6613
6904
|
const messages = parseJsonl(filePath);
|
|
6614
6905
|
if (messages.length === 0) return 0;
|
|
6615
6906
|
const marker = this.lastUploadedUuid.get(sessionId);
|
|
@@ -6695,9 +6986,9 @@ function buildKeepAlive(ctx) {
|
|
|
6695
6986
|
}
|
|
6696
6987
|
|
|
6697
6988
|
// src/commands/start/handlers.ts
|
|
6698
|
-
var
|
|
6699
|
-
var
|
|
6700
|
-
var
|
|
6989
|
+
var fs14 = __toESM(require("fs"));
|
|
6990
|
+
var os13 = __toESM(require("os"));
|
|
6991
|
+
var path17 = __toESM(require("path"));
|
|
6701
6992
|
var import_crypto = require("crypto");
|
|
6702
6993
|
var import_child_process8 = require("child_process");
|
|
6703
6994
|
|
|
@@ -6736,8 +7027,8 @@ function parsePayload(schema, raw) {
|
|
|
6736
7027
|
}
|
|
6737
7028
|
|
|
6738
7029
|
// src/services/file-ops.service.ts
|
|
6739
|
-
var
|
|
6740
|
-
var
|
|
7030
|
+
var fs12 = __toESM(require("fs/promises"));
|
|
7031
|
+
var path15 = __toESM(require("path"));
|
|
6741
7032
|
var MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
6742
7033
|
var MAX_WALK_DEPTH = 6;
|
|
6743
7034
|
var MAX_VISITED_DIRS = 5e3;
|
|
@@ -6772,12 +7063,12 @@ var SUBDIR_IGNORE = /* @__PURE__ */ new Set([
|
|
|
6772
7063
|
"__pycache__"
|
|
6773
7064
|
]);
|
|
6774
7065
|
function isUnder(parent, candidate) {
|
|
6775
|
-
const rel =
|
|
6776
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
7066
|
+
const rel = path15.relative(parent, candidate);
|
|
7067
|
+
return rel === "" || !rel.startsWith("..") && !path15.isAbsolute(rel);
|
|
6777
7068
|
}
|
|
6778
7069
|
async function isExistingFile(absPath) {
|
|
6779
7070
|
try {
|
|
6780
|
-
const stat3 = await
|
|
7071
|
+
const stat3 = await fs12.stat(absPath);
|
|
6781
7072
|
return stat3.isFile();
|
|
6782
7073
|
} catch {
|
|
6783
7074
|
return false;
|
|
@@ -6790,13 +7081,13 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
|
|
|
6790
7081
|
ctx.visited++;
|
|
6791
7082
|
let entries = [];
|
|
6792
7083
|
try {
|
|
6793
|
-
entries = await
|
|
7084
|
+
entries = await fs12.readdir(dir, { withFileTypes: true });
|
|
6794
7085
|
} catch {
|
|
6795
7086
|
return;
|
|
6796
7087
|
}
|
|
6797
7088
|
for (const e of entries) {
|
|
6798
7089
|
if (!e.isFile()) continue;
|
|
6799
|
-
const full =
|
|
7090
|
+
const full = path15.join(dir, e.name);
|
|
6800
7091
|
if (needleVariants.some((needle) => full.endsWith(needle))) {
|
|
6801
7092
|
ctx.matches.push(full);
|
|
6802
7093
|
if (ctx.matches.length >= ctx.cap) return;
|
|
@@ -6806,21 +7097,21 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
|
|
|
6806
7097
|
if (!e.isDirectory()) continue;
|
|
6807
7098
|
if (SUBDIR_IGNORE.has(e.name)) continue;
|
|
6808
7099
|
if (e.name.startsWith(".") && SUBDIR_IGNORE.has(e.name)) continue;
|
|
6809
|
-
await walkForSuffix(
|
|
7100
|
+
await walkForSuffix(path15.join(dir, e.name), needleVariants, depth + 1, ctx);
|
|
6810
7101
|
if (ctx.matches.length >= ctx.cap) return;
|
|
6811
7102
|
}
|
|
6812
7103
|
}
|
|
6813
7104
|
async function findFile(rawPath) {
|
|
6814
7105
|
const cwd = process.cwd();
|
|
6815
|
-
if (
|
|
6816
|
-
const abs =
|
|
7106
|
+
if (path15.isAbsolute(rawPath)) {
|
|
7107
|
+
const abs = path15.normalize(rawPath);
|
|
6817
7108
|
if (isUnder(cwd, abs) && await isExistingFile(abs)) return abs;
|
|
6818
7109
|
}
|
|
6819
|
-
const direct =
|
|
7110
|
+
const direct = path15.resolve(cwd, rawPath);
|
|
6820
7111
|
if (isUnder(cwd, direct) && await isExistingFile(direct)) return direct;
|
|
6821
|
-
const normalized =
|
|
7112
|
+
const normalized = path15.normalize(rawPath).replace(/^[./\\]+/, "");
|
|
6822
7113
|
const needles = [
|
|
6823
|
-
`${
|
|
7114
|
+
`${path15.sep}${normalized}`,
|
|
6824
7115
|
`/${normalized}`
|
|
6825
7116
|
].filter((v, i, a) => a.indexOf(v) === i);
|
|
6826
7117
|
const ctx = { visited: 0, matches: [], cap: 16 };
|
|
@@ -6834,7 +7125,7 @@ async function findWriteTarget(rawPath) {
|
|
|
6834
7125
|
const found = await findFile(rawPath);
|
|
6835
7126
|
if (found) return found;
|
|
6836
7127
|
const cwd = process.cwd();
|
|
6837
|
-
const fallback =
|
|
7128
|
+
const fallback = path15.isAbsolute(rawPath) ? path15.normalize(rawPath) : path15.resolve(cwd, rawPath);
|
|
6838
7129
|
if (!isUnder(cwd, fallback)) return null;
|
|
6839
7130
|
return fallback;
|
|
6840
7131
|
}
|
|
@@ -6851,11 +7142,11 @@ async function readProjectFile(rawPath) {
|
|
|
6851
7142
|
if (!abs) {
|
|
6852
7143
|
return { error: `File not found in the project tree: ${rawPath}` };
|
|
6853
7144
|
}
|
|
6854
|
-
const stat3 = await
|
|
7145
|
+
const stat3 = await fs12.stat(abs);
|
|
6855
7146
|
if (stat3.size > MAX_FILE_BYTES) {
|
|
6856
7147
|
return { error: `File too large (${(stat3.size / 1024 / 1024).toFixed(1)} MB > ${MAX_FILE_BYTES / 1024 / 1024} MB).` };
|
|
6857
7148
|
}
|
|
6858
|
-
const buf = await
|
|
7149
|
+
const buf = await fs12.readFile(abs);
|
|
6859
7150
|
if (looksBinary(buf)) {
|
|
6860
7151
|
return { error: "Binary file \u2014 refusing to open in a code editor." };
|
|
6861
7152
|
}
|
|
@@ -6874,8 +7165,8 @@ async function writeProjectFile(rawPath, content) {
|
|
|
6874
7165
|
if (Buffer.byteLength(content, "utf-8") > MAX_FILE_BYTES) {
|
|
6875
7166
|
return { error: "Content too large." };
|
|
6876
7167
|
}
|
|
6877
|
-
await
|
|
6878
|
-
await
|
|
7168
|
+
await fs12.mkdir(path15.dirname(abs), { recursive: true });
|
|
7169
|
+
await fs12.writeFile(abs, content, "utf-8");
|
|
6879
7170
|
return { ok: true };
|
|
6880
7171
|
} catch (e) {
|
|
6881
7172
|
const msg = e instanceof Error ? e.message : "Write failed";
|
|
@@ -6886,8 +7177,8 @@ async function writeProjectFile(rawPath, content) {
|
|
|
6886
7177
|
// src/services/project-ops.service.ts
|
|
6887
7178
|
var import_child_process7 = require("child_process");
|
|
6888
7179
|
var import_util2 = require("util");
|
|
6889
|
-
var
|
|
6890
|
-
var
|
|
7180
|
+
var fs13 = __toESM(require("fs/promises"));
|
|
7181
|
+
var path16 = __toESM(require("path"));
|
|
6891
7182
|
var execFileP2 = (0, import_util2.promisify)(import_child_process7.execFile);
|
|
6892
7183
|
var PROJECT_IGNORE = /* @__PURE__ */ new Set([
|
|
6893
7184
|
"node_modules",
|
|
@@ -6935,7 +7226,7 @@ async function listProjectFiles(opts = {}) {
|
|
|
6935
7226
|
}
|
|
6936
7227
|
let entries = [];
|
|
6937
7228
|
try {
|
|
6938
|
-
entries = await
|
|
7229
|
+
entries = await fs13.readdir(dir, { withFileTypes: true });
|
|
6939
7230
|
} catch {
|
|
6940
7231
|
return;
|
|
6941
7232
|
}
|
|
@@ -6945,18 +7236,18 @@ async function listProjectFiles(opts = {}) {
|
|
|
6945
7236
|
return;
|
|
6946
7237
|
}
|
|
6947
7238
|
if (PROJECT_IGNORE.has(e.name)) continue;
|
|
6948
|
-
const full =
|
|
7239
|
+
const full = path16.join(dir, e.name);
|
|
6949
7240
|
if (e.isDirectory()) {
|
|
6950
7241
|
if (depth >= 12) continue;
|
|
6951
7242
|
await walk(full, depth + 1);
|
|
6952
7243
|
} else if (e.isFile()) {
|
|
6953
|
-
const rel =
|
|
7244
|
+
const rel = path16.relative(root, full);
|
|
6954
7245
|
if (q2 && !rel.toLowerCase().includes(q2) && !e.name.toLowerCase().includes(q2)) {
|
|
6955
7246
|
continue;
|
|
6956
7247
|
}
|
|
6957
7248
|
let size = 0;
|
|
6958
7249
|
try {
|
|
6959
|
-
const st3 = await
|
|
7250
|
+
const st3 = await fs13.stat(full);
|
|
6960
7251
|
size = st3.size;
|
|
6961
7252
|
} catch {
|
|
6962
7253
|
}
|
|
@@ -7058,8 +7349,8 @@ async function gitStatus(cwd) {
|
|
|
7058
7349
|
let hasMergeInProgress = false;
|
|
7059
7350
|
try {
|
|
7060
7351
|
const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
|
|
7061
|
-
const mergeHead =
|
|
7062
|
-
await
|
|
7352
|
+
const mergeHead = path16.isAbsolute(gitDir) ? path16.join(gitDir, "MERGE_HEAD") : path16.join(root, gitDir, "MERGE_HEAD");
|
|
7353
|
+
await fs13.access(mergeHead);
|
|
7063
7354
|
hasMergeInProgress = true;
|
|
7064
7355
|
} catch {
|
|
7065
7356
|
}
|
|
@@ -7136,8 +7427,8 @@ async function gitResolve(file, side, cwd) {
|
|
|
7136
7427
|
function saveFilesTemp(files) {
|
|
7137
7428
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
7138
7429
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
7139
|
-
const tmpPath =
|
|
7140
|
-
|
|
7430
|
+
const tmpPath = path17.join(os13.tmpdir(), `codeam-${(0, import_crypto.randomUUID)()}-${safeName}`);
|
|
7431
|
+
fs14.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
7141
7432
|
return tmpPath;
|
|
7142
7433
|
});
|
|
7143
7434
|
}
|
|
@@ -7156,7 +7447,7 @@ var startTask = (ctx, _cmd, parsed) => {
|
|
|
7156
7447
|
setTimeout(() => {
|
|
7157
7448
|
for (const p2 of paths) {
|
|
7158
7449
|
try {
|
|
7159
|
-
|
|
7450
|
+
fs14.unlinkSync(p2);
|
|
7160
7451
|
} catch {
|
|
7161
7452
|
}
|
|
7162
7453
|
}
|
|
@@ -7615,8 +7906,8 @@ async function pair(args2 = []) {
|
|
|
7615
7906
|
}
|
|
7616
7907
|
|
|
7617
7908
|
// src/commands/pair-auto.ts
|
|
7618
|
-
var
|
|
7619
|
-
var
|
|
7909
|
+
var fs15 = __toESM(require("fs"));
|
|
7910
|
+
var os14 = __toESM(require("os"));
|
|
7620
7911
|
var import_crypto3 = require("crypto");
|
|
7621
7912
|
var API_BASE5 = process.env.CODEAM_API_URL ?? "https://codeagent-mobile-api.vercel.app";
|
|
7622
7913
|
function fail(msg) {
|
|
@@ -7633,12 +7924,12 @@ function readTokenFromArgs(args2) {
|
|
|
7633
7924
|
}
|
|
7634
7925
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
7635
7926
|
if (fileFlag) {
|
|
7636
|
-
const
|
|
7927
|
+
const path23 = fileFlag.slice("--token-file=".length);
|
|
7637
7928
|
try {
|
|
7638
|
-
const content =
|
|
7639
|
-
if (content.length === 0) fail(`--token-file ${
|
|
7929
|
+
const content = fs15.readFileSync(path23, "utf8").trim();
|
|
7930
|
+
if (content.length === 0) fail(`--token-file ${path23} is empty`);
|
|
7640
7931
|
try {
|
|
7641
|
-
|
|
7932
|
+
fs15.unlinkSync(path23);
|
|
7642
7933
|
} catch {
|
|
7643
7934
|
}
|
|
7644
7935
|
return content;
|
|
@@ -7656,7 +7947,7 @@ async function claim(token, pluginId) {
|
|
|
7656
7947
|
pluginId,
|
|
7657
7948
|
ideName: "codeam-cli (codespace)",
|
|
7658
7949
|
ideVersion: process.env.npm_package_version ?? "unknown",
|
|
7659
|
-
hostname:
|
|
7950
|
+
hostname: os14.hostname(),
|
|
7660
7951
|
codespaceName: process.env.CODESPACE_NAME ?? ""
|
|
7661
7952
|
};
|
|
7662
7953
|
const res = await fetch(url, {
|
|
@@ -7808,7 +8099,7 @@ var import_picocolors9 = __toESM(require("picocolors"));
|
|
|
7808
8099
|
var import_child_process9 = require("child_process");
|
|
7809
8100
|
var import_util3 = require("util");
|
|
7810
8101
|
var import_picocolors7 = __toESM(require("picocolors"));
|
|
7811
|
-
var
|
|
8102
|
+
var path18 = __toESM(require("path"));
|
|
7812
8103
|
var execFileP3 = (0, import_util3.promisify)(import_child_process9.execFile);
|
|
7813
8104
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
7814
8105
|
function resetStdinForChild() {
|
|
@@ -8297,7 +8588,7 @@ var GitHubCodespacesProvider = class {
|
|
|
8297
8588
|
});
|
|
8298
8589
|
}
|
|
8299
8590
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
8300
|
-
const remoteDir =
|
|
8591
|
+
const remoteDir = path18.posix.dirname(remotePath);
|
|
8301
8592
|
const parts = [
|
|
8302
8593
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
8303
8594
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -8367,7 +8658,7 @@ function shellQuote(s) {
|
|
|
8367
8658
|
// src/services/providers/gitpod.ts
|
|
8368
8659
|
var import_child_process10 = require("child_process");
|
|
8369
8660
|
var import_util4 = require("util");
|
|
8370
|
-
var
|
|
8661
|
+
var path19 = __toESM(require("path"));
|
|
8371
8662
|
var import_picocolors8 = __toESM(require("picocolors"));
|
|
8372
8663
|
var execFileP4 = (0, import_util4.promisify)(import_child_process10.execFile);
|
|
8373
8664
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
@@ -8607,7 +8898,7 @@ var GitpodProvider = class {
|
|
|
8607
8898
|
});
|
|
8608
8899
|
}
|
|
8609
8900
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
8610
|
-
const remoteDir =
|
|
8901
|
+
const remoteDir = path19.posix.dirname(remotePath);
|
|
8611
8902
|
const parts = [
|
|
8612
8903
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
8613
8904
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -8643,7 +8934,7 @@ function shellQuote2(s) {
|
|
|
8643
8934
|
// src/services/providers/gitlab-workspaces.ts
|
|
8644
8935
|
var import_child_process11 = require("child_process");
|
|
8645
8936
|
var import_util5 = require("util");
|
|
8646
|
-
var
|
|
8937
|
+
var path20 = __toESM(require("path"));
|
|
8647
8938
|
var execFileP5 = (0, import_util5.promisify)(import_child_process11.execFile);
|
|
8648
8939
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
8649
8940
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
@@ -8903,7 +9194,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
8903
9194
|
}
|
|
8904
9195
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
8905
9196
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
8906
|
-
const remoteDir =
|
|
9197
|
+
const remoteDir = path20.posix.dirname(remotePath);
|
|
8907
9198
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
8908
9199
|
if (options.mode != null) {
|
|
8909
9200
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
@@ -8971,7 +9262,7 @@ function shellQuote3(s) {
|
|
|
8971
9262
|
// src/services/providers/railway.ts
|
|
8972
9263
|
var import_child_process12 = require("child_process");
|
|
8973
9264
|
var import_util6 = require("util");
|
|
8974
|
-
var
|
|
9265
|
+
var path21 = __toESM(require("path"));
|
|
8975
9266
|
var execFileP6 = (0, import_util6.promisify)(import_child_process12.execFile);
|
|
8976
9267
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
8977
9268
|
function resetStdinForChild4() {
|
|
@@ -9207,7 +9498,7 @@ var RailwayProvider = class {
|
|
|
9207
9498
|
if (!projectId || !serviceId) {
|
|
9208
9499
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
9209
9500
|
}
|
|
9210
|
-
const remoteDir =
|
|
9501
|
+
const remoteDir = path21.posix.dirname(remotePath);
|
|
9211
9502
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
9212
9503
|
if (options.mode != null) {
|
|
9213
9504
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
@@ -9749,7 +10040,7 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
9749
10040
|
// src/commands/version.ts
|
|
9750
10041
|
var import_picocolors11 = __toESM(require("picocolors"));
|
|
9751
10042
|
function version() {
|
|
9752
|
-
const v = true ? "2.
|
|
10043
|
+
const v = true ? "2.12.1" : "unknown";
|
|
9753
10044
|
console.log(`${import_picocolors11.default.bold("codeam-cli")} ${import_picocolors11.default.cyan(v)}`);
|
|
9754
10045
|
}
|
|
9755
10046
|
|
|
@@ -9786,9 +10077,9 @@ function help() {
|
|
|
9786
10077
|
}
|
|
9787
10078
|
|
|
9788
10079
|
// src/lib/updateNotifier.ts
|
|
9789
|
-
var
|
|
9790
|
-
var
|
|
9791
|
-
var
|
|
10080
|
+
var fs16 = __toESM(require("fs"));
|
|
10081
|
+
var os15 = __toESM(require("os"));
|
|
10082
|
+
var path22 = __toESM(require("path"));
|
|
9792
10083
|
var https5 = __toESM(require("https"));
|
|
9793
10084
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
9794
10085
|
var PKG_NAME = "codeam-cli";
|
|
@@ -9796,12 +10087,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
|
9796
10087
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
9797
10088
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
9798
10089
|
function cachePath() {
|
|
9799
|
-
const dir =
|
|
9800
|
-
return
|
|
10090
|
+
const dir = path22.join(os15.homedir(), ".codeam");
|
|
10091
|
+
return path22.join(dir, "update-check.json");
|
|
9801
10092
|
}
|
|
9802
10093
|
function readCache() {
|
|
9803
10094
|
try {
|
|
9804
|
-
const raw =
|
|
10095
|
+
const raw = fs16.readFileSync(cachePath(), "utf8");
|
|
9805
10096
|
const parsed = JSON.parse(raw);
|
|
9806
10097
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
9807
10098
|
return parsed;
|
|
@@ -9812,8 +10103,8 @@ function readCache() {
|
|
|
9812
10103
|
function writeCache(cache) {
|
|
9813
10104
|
try {
|
|
9814
10105
|
const file = cachePath();
|
|
9815
|
-
|
|
9816
|
-
|
|
10106
|
+
fs16.mkdirSync(path22.dirname(file), { recursive: true });
|
|
10107
|
+
fs16.writeFileSync(file, JSON.stringify(cache));
|
|
9817
10108
|
} catch {
|
|
9818
10109
|
}
|
|
9819
10110
|
}
|
|
@@ -9884,7 +10175,7 @@ function checkForUpdates() {
|
|
|
9884
10175
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
9885
10176
|
if (process.env.CI) return;
|
|
9886
10177
|
if (!process.stdout.isTTY) return;
|
|
9887
|
-
const current = true ? "2.
|
|
10178
|
+
const current = true ? "2.12.1" : null;
|
|
9888
10179
|
if (!current) return;
|
|
9889
10180
|
const cache = readCache();
|
|
9890
10181
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.1",
|
|
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",
|