codeam-cli 2.4.33 → 2.4.35
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/README.md +10 -0
- package/dist/index.js +483 -155
- package/package.json +2 -1
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 fs11 = require("fs");
|
|
523
|
+
var os10 = require("os");
|
|
524
|
+
var path18 = 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 = path18.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 = fs11.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(path18.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(os10.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 fs11 = require("fs");
|
|
1016
|
+
var path18 = 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 = path18.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
|
+
fs11.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() {
|
|
@@ -1390,9 +1390,9 @@ var require_src = __commonJS({
|
|
|
1390
1390
|
});
|
|
1391
1391
|
|
|
1392
1392
|
// src/commands/start.ts
|
|
1393
|
-
var
|
|
1394
|
-
var
|
|
1395
|
-
var
|
|
1393
|
+
var fs8 = __toESM(require("fs"));
|
|
1394
|
+
var os7 = __toESM(require("os"));
|
|
1395
|
+
var path11 = __toESM(require("path"));
|
|
1396
1396
|
var import_crypto = require("crypto");
|
|
1397
1397
|
var import_child_process5 = require("child_process");
|
|
1398
1398
|
var import_picocolors2 = __toESM(require("picocolors"));
|
|
@@ -1482,8 +1482,9 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
1482
1482
|
// package.json
|
|
1483
1483
|
var package_default = {
|
|
1484
1484
|
name: "codeam-cli",
|
|
1485
|
-
version: "2.4.
|
|
1485
|
+
version: "2.4.35",
|
|
1486
1486
|
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.",
|
|
1487
|
+
type: "commonjs",
|
|
1487
1488
|
main: "dist/index.js",
|
|
1488
1489
|
bin: {
|
|
1489
1490
|
codeam: "dist/index.js"
|
|
@@ -1611,6 +1612,60 @@ function computePollDelay({ baseMs, failures }) {
|
|
|
1611
1612
|
return Math.round(jitter);
|
|
1612
1613
|
}
|
|
1613
1614
|
|
|
1615
|
+
// src/services/logger.ts
|
|
1616
|
+
var fs2 = __toESM(require("fs"));
|
|
1617
|
+
var os2 = __toESM(require("os"));
|
|
1618
|
+
var path2 = __toESM(require("path"));
|
|
1619
|
+
var LEVELS = { silent: 0, error: 1, warn: 2, info: 3, debug: 4, trace: 5 };
|
|
1620
|
+
function currentLevel() {
|
|
1621
|
+
if (process.env.CODEAM_DEBUG === "1") return LEVELS.trace;
|
|
1622
|
+
const raw = (process.env.CODEAM_LOG ?? "error").toLowerCase();
|
|
1623
|
+
return LEVELS[raw] ?? LEVELS.error;
|
|
1624
|
+
}
|
|
1625
|
+
var fileEnabled = process.env.CODEAM_DEBUG === "1" || process.env.CODEAM_LOG === "debug" || process.env.CODEAM_LOG === "trace";
|
|
1626
|
+
var debugFilePath = path2.join(os2.homedir(), ".codeam", "debug.log");
|
|
1627
|
+
var fileInitialized = false;
|
|
1628
|
+
function appendToFile(line) {
|
|
1629
|
+
if (!fileEnabled) return;
|
|
1630
|
+
try {
|
|
1631
|
+
if (!fileInitialized) {
|
|
1632
|
+
fs2.mkdirSync(path2.dirname(debugFilePath), { recursive: true });
|
|
1633
|
+
fs2.writeFileSync(
|
|
1634
|
+
debugFilePath,
|
|
1635
|
+
`=== codeam debug log \u2014 pid ${process.pid} \u2014 ${(/* @__PURE__ */ new Date()).toISOString()} ===
|
|
1636
|
+
platform=${process.platform} node=${process.version} cwd=${process.cwd()}
|
|
1637
|
+
|
|
1638
|
+
`
|
|
1639
|
+
);
|
|
1640
|
+
fileInitialized = true;
|
|
1641
|
+
}
|
|
1642
|
+
fs2.appendFileSync(debugFilePath, line);
|
|
1643
|
+
} catch {
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
function emit(level, tag, msg, err) {
|
|
1647
|
+
if (LEVELS[level] > currentLevel()) return;
|
|
1648
|
+
const detail = err instanceof Error ? `: ${err.message}` : err !== void 0 ? `: ${String(err)}` : "";
|
|
1649
|
+
const line = `[codeam:${level}] ${tag} \u2014 ${msg}${detail}
|
|
1650
|
+
`;
|
|
1651
|
+
process.stderr.write(line);
|
|
1652
|
+
if (LEVELS[level] >= LEVELS.debug) {
|
|
1653
|
+
appendToFile(`${(/* @__PURE__ */ new Date()).toISOString()} ${line}`);
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
var log = {
|
|
1657
|
+
error: (tag, msg, err) => emit("error", tag, msg, err),
|
|
1658
|
+
warn: (tag, msg, err) => emit("warn", tag, msg, err),
|
|
1659
|
+
info: (tag, msg, err) => emit("info", tag, msg, err),
|
|
1660
|
+
debug: (tag, msg, err) => emit("debug", tag, msg, err),
|
|
1661
|
+
/**
|
|
1662
|
+
* Verbose pipeline breadcrumb. Only fires when CODEAM_LOG=trace or
|
|
1663
|
+
* CODEAM_DEBUG=1, so call sites can be liberal — they have zero
|
|
1664
|
+
* cost in normal runs.
|
|
1665
|
+
*/
|
|
1666
|
+
trace: (tag, msg, err) => emit("trace", tag, msg, err)
|
|
1667
|
+
};
|
|
1668
|
+
|
|
1614
1669
|
// src/services/websocket.service.ts
|
|
1615
1670
|
var API_BASE = process.env.CODEAM_API_URL ?? "https://codeagent-mobile-api.vercel.app";
|
|
1616
1671
|
var WS_URL = API_BASE.replace("https://", "wss://").replace("http://", "ws://") + "/api/ws";
|
|
@@ -1640,6 +1695,7 @@ var WebSocketService = class {
|
|
|
1640
1695
|
try {
|
|
1641
1696
|
this.client = new import_ws.default(WS_URL);
|
|
1642
1697
|
this.client.on("open", () => {
|
|
1698
|
+
log.trace("ws", `connected to ${WS_URL}`);
|
|
1643
1699
|
this._connected = true;
|
|
1644
1700
|
this.reconnectAttempts = 0;
|
|
1645
1701
|
this.client.send(JSON.stringify({
|
|
@@ -1653,12 +1709,18 @@ var WebSocketService = class {
|
|
|
1653
1709
|
this.client.on("message", (raw) => {
|
|
1654
1710
|
try {
|
|
1655
1711
|
const msg = JSON.parse(raw.toString());
|
|
1656
|
-
if (msg.type === "pong" || msg.type === "auth_success" || msg.type === "auth_error")
|
|
1712
|
+
if (msg.type === "pong" || msg.type === "auth_success" || msg.type === "auth_error") {
|
|
1713
|
+
log.trace("ws", `meta msg type=${msg.type}`);
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
log.trace("ws", `dispatch msg type=${msg.type}`);
|
|
1657
1717
|
this.handlers.forEach((h) => h.onMessage(msg.type, msg.payload ?? {}));
|
|
1658
|
-
} catch {
|
|
1718
|
+
} catch (err) {
|
|
1719
|
+
log.trace("ws", "malformed message", err);
|
|
1659
1720
|
}
|
|
1660
1721
|
});
|
|
1661
|
-
this.client.on("close", () => {
|
|
1722
|
+
this.client.on("close", (code, reason) => {
|
|
1723
|
+
log.trace("ws", `closed code=${code} reason=${reason?.toString() || "(empty)"}`);
|
|
1662
1724
|
this._connected = false;
|
|
1663
1725
|
this.stopHeartbeat();
|
|
1664
1726
|
this.handlers.forEach((h) => h.onDisconnected());
|
|
@@ -1668,9 +1730,11 @@ var WebSocketService = class {
|
|
|
1668
1730
|
this.reconnectTimer = setTimeout(() => this.connect(), delay);
|
|
1669
1731
|
}
|
|
1670
1732
|
});
|
|
1671
|
-
this.client.on("error", () => {
|
|
1733
|
+
this.client.on("error", (err) => {
|
|
1734
|
+
log.trace("ws", "error", err);
|
|
1672
1735
|
});
|
|
1673
|
-
} catch {
|
|
1736
|
+
} catch (err) {
|
|
1737
|
+
log.trace("ws", "sync connect threw", err);
|
|
1674
1738
|
}
|
|
1675
1739
|
}
|
|
1676
1740
|
send(type, payload) {
|
|
@@ -1706,7 +1770,7 @@ var WebSocketService = class {
|
|
|
1706
1770
|
// src/services/pairing.service.ts
|
|
1707
1771
|
var https = __toESM(require("https"));
|
|
1708
1772
|
var http = __toESM(require("http"));
|
|
1709
|
-
var
|
|
1773
|
+
var os3 = __toESM(require("os"));
|
|
1710
1774
|
var API_BASE2 = process.env.CODEAM_API_URL ?? "https://codeagent-mobile-api.vercel.app";
|
|
1711
1775
|
async function requestCode(pluginId) {
|
|
1712
1776
|
try {
|
|
@@ -1716,7 +1780,7 @@ async function requestCode(pluginId) {
|
|
|
1716
1780
|
pluginId,
|
|
1717
1781
|
ideName: "Terminal (codeam-cli)",
|
|
1718
1782
|
ideVersion: package_default.version,
|
|
1719
|
-
hostname:
|
|
1783
|
+
hostname: os3.hostname(),
|
|
1720
1784
|
runtime,
|
|
1721
1785
|
...codespaceName ? { codespaceName } : {}
|
|
1722
1786
|
});
|
|
@@ -1880,7 +1944,10 @@ var CommandRelayService = class {
|
|
|
1880
1944
|
_running = false;
|
|
1881
1945
|
pollTimer = null;
|
|
1882
1946
|
heartbeatTimer = null;
|
|
1947
|
+
agentsTimer = null;
|
|
1883
1948
|
consecutiveFailures = 0;
|
|
1949
|
+
/** True once `/api/plugin/agents` has accepted at least one report. */
|
|
1950
|
+
agentsRegistered = false;
|
|
1884
1951
|
start() {
|
|
1885
1952
|
if (this.pollTimer) {
|
|
1886
1953
|
clearTimeout(this.pollTimer);
|
|
@@ -1890,11 +1957,19 @@ var CommandRelayService = class {
|
|
|
1890
1957
|
clearInterval(this.heartbeatTimer);
|
|
1891
1958
|
this.heartbeatTimer = null;
|
|
1892
1959
|
}
|
|
1960
|
+
if (this.agentsTimer) {
|
|
1961
|
+
clearInterval(this.agentsTimer);
|
|
1962
|
+
this.agentsTimer = null;
|
|
1963
|
+
}
|
|
1893
1964
|
this._running = true;
|
|
1965
|
+
this.agentsRegistered = false;
|
|
1894
1966
|
this.sendHeartbeat(true);
|
|
1895
1967
|
this.heartbeatTimer = setInterval(() => this.sendHeartbeat(true), 2e4);
|
|
1896
1968
|
void this.pollLoop();
|
|
1897
1969
|
this.reportAgents();
|
|
1970
|
+
this.agentsTimer = setInterval(() => {
|
|
1971
|
+
if (this._running && !this.agentsRegistered) this.reportAgents();
|
|
1972
|
+
}, 5e3);
|
|
1898
1973
|
}
|
|
1899
1974
|
stop() {
|
|
1900
1975
|
if (!this._running) return;
|
|
@@ -1907,6 +1982,10 @@ var CommandRelayService = class {
|
|
|
1907
1982
|
clearInterval(this.heartbeatTimer);
|
|
1908
1983
|
this.heartbeatTimer = null;
|
|
1909
1984
|
}
|
|
1985
|
+
if (this.agentsTimer) {
|
|
1986
|
+
clearInterval(this.agentsTimer);
|
|
1987
|
+
this.agentsTimer = null;
|
|
1988
|
+
}
|
|
1910
1989
|
this.sendHeartbeat(false).catch(() => {
|
|
1911
1990
|
});
|
|
1912
1991
|
}
|
|
@@ -1932,32 +2011,43 @@ var CommandRelayService = class {
|
|
|
1932
2011
|
const commands = data?.data;
|
|
1933
2012
|
this.consecutiveFailures = 0;
|
|
1934
2013
|
if (!Array.isArray(commands)) return;
|
|
2014
|
+
if (commands.length > 0) {
|
|
2015
|
+
log.trace("relay", `poll received ${commands.length} command(s)`);
|
|
2016
|
+
}
|
|
1935
2017
|
for (const obj of commands) {
|
|
1936
2018
|
try {
|
|
2019
|
+
log.trace("relay", `dispatch type=${obj.type} id=${obj.id}`);
|
|
1937
2020
|
await this.onCommand({
|
|
1938
2021
|
id: obj.id,
|
|
1939
2022
|
sessionId: obj.sessionId,
|
|
1940
2023
|
type: obj.type,
|
|
1941
2024
|
payload: obj.payload ?? {}
|
|
1942
2025
|
});
|
|
1943
|
-
} catch {
|
|
2026
|
+
} catch (err) {
|
|
2027
|
+
log.trace("relay", `command handler threw`, err);
|
|
1944
2028
|
}
|
|
1945
2029
|
}
|
|
1946
|
-
} catch {
|
|
2030
|
+
} catch (err) {
|
|
1947
2031
|
this.consecutiveFailures += 1;
|
|
2032
|
+
log.trace(
|
|
2033
|
+
"relay",
|
|
2034
|
+
`poll failed (failures=${this.consecutiveFailures})`,
|
|
2035
|
+
err
|
|
2036
|
+
);
|
|
1948
2037
|
}
|
|
1949
2038
|
}
|
|
1950
2039
|
async sendHeartbeat(online) {
|
|
1951
2040
|
await _postJson(`${API_BASE3}/api/plugin/heartbeat`, {
|
|
1952
2041
|
pluginId: this.pluginId,
|
|
1953
2042
|
online
|
|
1954
|
-
}).catch(() => {
|
|
1955
|
-
});
|
|
2043
|
+
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
1956
2044
|
}
|
|
1957
2045
|
reportAgents() {
|
|
1958
2046
|
_postJson(`${API_BASE3}/api/plugin/agents`, {
|
|
1959
2047
|
pluginId: this.pluginId,
|
|
1960
2048
|
agents: [{ id: "claude-code", name: "Claude Code", icon: "\u{1F916}", installed: true }]
|
|
2049
|
+
}).then(() => {
|
|
2050
|
+
this.agentsRegistered = true;
|
|
1961
2051
|
}).catch(() => {
|
|
1962
2052
|
});
|
|
1963
2053
|
}
|
|
@@ -1965,24 +2055,24 @@ var CommandRelayService = class {
|
|
|
1965
2055
|
|
|
1966
2056
|
// src/services/pty/unix.strategy.ts
|
|
1967
2057
|
var import_child_process = require("child_process");
|
|
1968
|
-
var
|
|
1969
|
-
var
|
|
1970
|
-
var
|
|
2058
|
+
var fs4 = __toESM(require("fs"));
|
|
2059
|
+
var os4 = __toESM(require("os"));
|
|
2060
|
+
var path4 = __toESM(require("path"));
|
|
1971
2061
|
|
|
1972
2062
|
// src/services/pty/types.ts
|
|
1973
|
-
var
|
|
1974
|
-
var
|
|
2063
|
+
var fs3 = __toESM(require("fs"));
|
|
2064
|
+
var path3 = __toESM(require("path"));
|
|
1975
2065
|
function findInPath(name) {
|
|
1976
2066
|
const isWin = process.platform === "win32";
|
|
1977
|
-
const dirs = (process.env.PATH ?? "").split(
|
|
1978
|
-
const hasExt =
|
|
2067
|
+
const dirs = (process.env.PATH ?? "").split(path3.delimiter).filter(Boolean);
|
|
2068
|
+
const hasExt = path3.extname(name).length > 0;
|
|
1979
2069
|
const candidates = isWin && !hasExt ? [`${name}.exe`, `${name}.cmd`, `${name}.bat`, `${name}.ps1`, name] : [name];
|
|
1980
|
-
const accessFlag = isWin ?
|
|
2070
|
+
const accessFlag = isWin ? fs3.constants.F_OK : fs3.constants.X_OK;
|
|
1981
2071
|
for (const dir of dirs) {
|
|
1982
2072
|
for (const candidate of candidates) {
|
|
1983
|
-
const full =
|
|
2073
|
+
const full = path3.join(dir, candidate);
|
|
1984
2074
|
try {
|
|
1985
|
-
|
|
2075
|
+
fs3.accessSync(full, accessFlag);
|
|
1986
2076
|
return full;
|
|
1987
2077
|
} catch {
|
|
1988
2078
|
}
|
|
@@ -2066,8 +2156,8 @@ var UnixPtyStrategy = class {
|
|
|
2066
2156
|
}
|
|
2067
2157
|
const cols = process.stdout.columns || 220;
|
|
2068
2158
|
const rows = process.stdout.rows || 50;
|
|
2069
|
-
this.helperPath =
|
|
2070
|
-
|
|
2159
|
+
this.helperPath = path4.join(os4.tmpdir(), "codeam-pty-helper.py");
|
|
2160
|
+
fs4.writeFileSync(this.helperPath, PYTHON_PTY_HELPER, { mode: 420 });
|
|
2071
2161
|
this.proc = (0, import_child_process.spawn)(python, [this.helperPath, cmd, ...args2], {
|
|
2072
2162
|
stdio: ["pipe", "pipe", "inherit"],
|
|
2073
2163
|
cwd,
|
|
@@ -2196,7 +2286,7 @@ var UnixPtyStrategy = class {
|
|
|
2196
2286
|
removeTempFile() {
|
|
2197
2287
|
if (this.helperPath) {
|
|
2198
2288
|
try {
|
|
2199
|
-
|
|
2289
|
+
fs4.unlinkSync(this.helperPath);
|
|
2200
2290
|
} catch {
|
|
2201
2291
|
}
|
|
2202
2292
|
this.helperPath = null;
|
|
@@ -2268,9 +2358,9 @@ var WindowsPtyStrategy = class {
|
|
|
2268
2358
|
};
|
|
2269
2359
|
|
|
2270
2360
|
// src/services/pty/windows-conpty.strategy.ts
|
|
2271
|
-
var
|
|
2361
|
+
var path5 = __toESM(require("path"));
|
|
2272
2362
|
function loadNodePty() {
|
|
2273
|
-
const vendoredPath =
|
|
2363
|
+
const vendoredPath = path5.join(__dirname, "vendor", "node-pty");
|
|
2274
2364
|
try {
|
|
2275
2365
|
return require(vendoredPath);
|
|
2276
2366
|
} catch (vendorErr) {
|
|
@@ -2320,11 +2410,17 @@ var WindowsConPtyStrategy = class _WindowsConPtyStrategy {
|
|
|
2320
2410
|
useConpty: true,
|
|
2321
2411
|
conptyInheritCursor: false
|
|
2322
2412
|
});
|
|
2413
|
+
let traceCount = 0;
|
|
2323
2414
|
this.dataSub = this.pty.onData((data) => {
|
|
2324
2415
|
process.stdout.write(data);
|
|
2325
2416
|
this.opts.onData(data);
|
|
2417
|
+
traceCount++;
|
|
2418
|
+
if (traceCount <= 5 || traceCount % 50 === 0) {
|
|
2419
|
+
log.trace("conpty", `onData #${traceCount} ${data.length}B`);
|
|
2420
|
+
}
|
|
2326
2421
|
});
|
|
2327
2422
|
this.exitSub = this.pty.onExit(({ exitCode }) => {
|
|
2423
|
+
log.trace("conpty", `claude exited code=${exitCode ?? 0}`);
|
|
2328
2424
|
this.dispose();
|
|
2329
2425
|
this.opts.onExit(exitCode ?? 0);
|
|
2330
2426
|
});
|
|
@@ -2384,8 +2480,8 @@ var WindowsConPtyStrategy = class _WindowsConPtyStrategy {
|
|
|
2384
2480
|
|
|
2385
2481
|
// src/services/claude-installer.ts
|
|
2386
2482
|
var import_child_process3 = require("child_process");
|
|
2387
|
-
var
|
|
2388
|
-
var
|
|
2483
|
+
var path6 = __toESM(require("path"));
|
|
2484
|
+
var os5 = __toESM(require("os"));
|
|
2389
2485
|
|
|
2390
2486
|
// ../../node_modules/@clack/prompts/dist/index.mjs
|
|
2391
2487
|
var dist_exports = {};
|
|
@@ -4299,17 +4395,17 @@ ${c2}
|
|
|
4299
4395
|
|
|
4300
4396
|
// src/services/claude-installer.ts
|
|
4301
4397
|
function probeInstallDirs() {
|
|
4302
|
-
const home =
|
|
4398
|
+
const home = os5.homedir();
|
|
4303
4399
|
if (process.platform === "win32") {
|
|
4304
4400
|
return [
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4401
|
+
path6.join(home, ".claude", "local"),
|
|
4402
|
+
path6.join(home, "AppData", "Local", "AnthropicClaude"),
|
|
4403
|
+
path6.join(home, "AppData", "Local", "Programs", "AnthropicClaude")
|
|
4308
4404
|
];
|
|
4309
4405
|
}
|
|
4310
4406
|
return [
|
|
4311
|
-
|
|
4312
|
-
|
|
4407
|
+
path6.join(home, ".local", "bin"),
|
|
4408
|
+
path6.join(home, ".claude", "local"),
|
|
4313
4409
|
"/usr/local/bin"
|
|
4314
4410
|
];
|
|
4315
4411
|
}
|
|
@@ -4318,7 +4414,7 @@ function isAvailable() {
|
|
|
4318
4414
|
}
|
|
4319
4415
|
function augmentPath() {
|
|
4320
4416
|
const dirs = probeInstallDirs();
|
|
4321
|
-
const sep2 =
|
|
4417
|
+
const sep2 = path6.delimiter;
|
|
4322
4418
|
const current = process.env.PATH ?? "";
|
|
4323
4419
|
const existing = new Set(current.split(sep2).filter(Boolean));
|
|
4324
4420
|
const additions = dirs.filter((d3) => !existing.has(d3));
|
|
@@ -4376,12 +4472,12 @@ async function ensureClaudeInstalled() {
|
|
|
4376
4472
|
}
|
|
4377
4473
|
|
|
4378
4474
|
// src/services/claude-resolver.ts
|
|
4379
|
-
var
|
|
4475
|
+
var path7 = __toESM(require("path"));
|
|
4380
4476
|
function buildClaudeLaunch(extraArgs = []) {
|
|
4381
4477
|
const found = findInPath("claude") ?? findInPath("claude-code");
|
|
4382
4478
|
if (!found) return null;
|
|
4383
4479
|
if (process.platform === "win32") {
|
|
4384
|
-
const ext =
|
|
4480
|
+
const ext = path7.extname(found).toLowerCase();
|
|
4385
4481
|
if (ext === ".cmd" || ext === ".bat") {
|
|
4386
4482
|
return { cmd: "cmd.exe", args: ["/c", found, ...extraArgs] };
|
|
4387
4483
|
}
|
|
@@ -4429,11 +4525,13 @@ var ClaudeService = class {
|
|
|
4429
4525
|
}
|
|
4430
4526
|
}
|
|
4431
4527
|
if (process.platform === "win32") {
|
|
4528
|
+
log.trace("claude", `spawn (win32) cmd=${launch.cmd} args=${launch.args.join(" ")}`);
|
|
4432
4529
|
const conpty = WindowsConPtyStrategy.tryCreate(this.strategyOpts);
|
|
4433
4530
|
if (conpty) {
|
|
4434
4531
|
try {
|
|
4435
4532
|
conpty.spawn(launch.cmd, this.opts.cwd, launch.args);
|
|
4436
4533
|
this.strategy = conpty;
|
|
4534
|
+
log.trace("claude", "ConPTY spawn ok");
|
|
4437
4535
|
return;
|
|
4438
4536
|
} catch (err) {
|
|
4439
4537
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -4473,8 +4571,12 @@ var ClaudeService = class {
|
|
|
4473
4571
|
* a fresh event-loop tick, after React has flushed the text into input state.
|
|
4474
4572
|
*/
|
|
4475
4573
|
sendCommand(text) {
|
|
4476
|
-
if (!this.strategy)
|
|
4574
|
+
if (!this.strategy) {
|
|
4575
|
+
log.trace("claude", "sendCommand dropped (no strategy)");
|
|
4576
|
+
return;
|
|
4577
|
+
}
|
|
4477
4578
|
const s = this.strategy;
|
|
4579
|
+
log.trace("claude", `sendCommand text=${text.length}B`);
|
|
4478
4580
|
s.write(text);
|
|
4479
4581
|
setTimeout(() => s.write("\r"), 50);
|
|
4480
4582
|
}
|
|
@@ -4548,12 +4650,12 @@ var https2 = __toESM(require("https"));
|
|
|
4548
4650
|
var http2 = __toESM(require("http"));
|
|
4549
4651
|
|
|
4550
4652
|
// ../../packages/shared/src/protocol/parseChrome.ts
|
|
4551
|
-
var SPINNER_RE = /^[✳✢✶✻✽✴✷✸✹⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏◐◑◒◓▁▂▃▄▅▆▇█]\s
|
|
4653
|
+
var SPINNER_RE = /^(?:[✳✢✶✻✽✴✷✸✹⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏◐◑◒◓▁▂▃▄▅▆▇█]|🔴|🟠|🟡|🟢|🔵|🟣|🟤|⚫|⚪|🌀|💭|✨)\s/u;
|
|
4552
4654
|
var BULLET_TOOL_RE = /^•\s+(?:Read(?:ing)?|Edit(?:ing)?|Writ(?:e|ing)|Bash|Runn(?:ing)?|Search(?:ing)?|Glob(?:bing)?|Grep(?:ping)?|Creat(?:e|ing)|Execut(?:e|ing)|Task|Agent|NotebookEdit)\b/i;
|
|
4553
4655
|
var TREE_LINE_RE = /^└\s/;
|
|
4554
|
-
var STATUS_LINE_RE =
|
|
4656
|
+
var STATUS_LINE_RE = /^(?:\+|[🔴🟠🟡🟢🔵🟣🟤⚫⚪🌀💭✨])\s/u;
|
|
4555
4657
|
function isChromeLine(line) {
|
|
4556
|
-
const t2 = line.trim();
|
|
4658
|
+
const t2 = line.replace(/️/g, "").trim();
|
|
4557
4659
|
if (!t2) return false;
|
|
4558
4660
|
if (/^[─━—═─\-]{3,}$/.test(t2)) return true;
|
|
4559
4661
|
if (SPINNER_RE.test(t2)) return true;
|
|
@@ -4578,7 +4680,7 @@ function isChromeLine(line) {
|
|
|
4578
4680
|
return false;
|
|
4579
4681
|
}
|
|
4580
4682
|
function parseChromeLine(line) {
|
|
4581
|
-
const t2 = line.trim();
|
|
4683
|
+
const t2 = line.replace(/️/g, "").trim();
|
|
4582
4684
|
if (!t2) return null;
|
|
4583
4685
|
if (/^[─━—═─\-]{3,}$/.test(t2)) return null;
|
|
4584
4686
|
if (/^[❯>]\s*$/.test(t2)) return null;
|
|
@@ -4982,6 +5084,7 @@ var OutputService = class _OutputService {
|
|
|
4982
5084
|
this.pollTimer = setInterval(() => this.tick(), _OutputService.POLL_MS);
|
|
4983
5085
|
}
|
|
4984
5086
|
newTurn() {
|
|
5087
|
+
log.trace("outputSvc", "newTurn() \u2014 activating output stream");
|
|
4985
5088
|
this.stopPoll();
|
|
4986
5089
|
this.rawBuffer = "";
|
|
4987
5090
|
this.lastSentContent = "";
|
|
@@ -5019,9 +5122,11 @@ var OutputService = class _OutputService {
|
|
|
5019
5122
|
const printable2 = raw.replace(/\x1B\[[^@-~]*[@-~]/g, "").replace(/[\x00-\x1F\x7F]/g, "");
|
|
5020
5123
|
if (printable2.trim()) {
|
|
5021
5124
|
this.terminalTurnPending = true;
|
|
5125
|
+
log.trace("outputSvc", `terminal-turn detected (idle, ${raw.length}B)`);
|
|
5022
5126
|
this.onTerminalTurnDetected?.();
|
|
5023
5127
|
}
|
|
5024
5128
|
}
|
|
5129
|
+
log.trace("outputSvc", `push dropped (inactive, ${raw.length}B)`);
|
|
5025
5130
|
return;
|
|
5026
5131
|
}
|
|
5027
5132
|
this.rawBuffer += raw;
|
|
@@ -5031,6 +5136,10 @@ var OutputService = class _OutputService {
|
|
|
5031
5136
|
this.tryExtractSessionId(printable);
|
|
5032
5137
|
this.tryDetectRateLimit(printable);
|
|
5033
5138
|
}
|
|
5139
|
+
log.trace(
|
|
5140
|
+
"outputSvc",
|
|
5141
|
+
`push +${raw.length}B (buf=${this.rawBuffer.length}B printable=${printable.trim().length})`
|
|
5142
|
+
);
|
|
5034
5143
|
}
|
|
5035
5144
|
/** Extract Claude conversation ID from output text (e.g., from /cost command or session resume) */
|
|
5036
5145
|
tryExtractSessionId(text) {
|
|
@@ -5073,6 +5182,10 @@ var OutputService = class _OutputService {
|
|
|
5073
5182
|
const selector = detectSelector(lines) ?? detectListSelector(lines);
|
|
5074
5183
|
if (selector) {
|
|
5075
5184
|
const idleMs2 = this.lastPushTime > 0 ? now - this.lastPushTime : elapsed;
|
|
5185
|
+
log.trace(
|
|
5186
|
+
"outputSvc",
|
|
5187
|
+
`tick selector found (idleMs=${idleMs2}, options=${selector.options.length})`
|
|
5188
|
+
);
|
|
5076
5189
|
if (idleMs2 >= _OutputService.SELECTOR_IDLE_MS) {
|
|
5077
5190
|
this.stopPoll();
|
|
5078
5191
|
this.active = false;
|
|
@@ -5083,10 +5196,24 @@ var OutputService = class _OutputService {
|
|
|
5083
5196
|
}
|
|
5084
5197
|
const content = filterChrome(lines).join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
5085
5198
|
if (!content) {
|
|
5199
|
+
log.trace(
|
|
5200
|
+
"outputSvc",
|
|
5201
|
+
`tick empty content (raw=${this.rawBuffer.length}B lines=${lines.length} elapsed=${elapsed}ms)`
|
|
5202
|
+
);
|
|
5203
|
+
if (lines.length > 0 && this.rawBuffer.length > 200) {
|
|
5204
|
+
const dump = lines.map((l, i) => `${i}: ${JSON.stringify(l)}`).join("\n");
|
|
5205
|
+
const preview = dump.length > 1500 ? dump.slice(0, 1500) + "\u2026(truncated)" : dump;
|
|
5206
|
+
log.trace("outputSvc", `lines dump:
|
|
5207
|
+
${preview}`);
|
|
5208
|
+
}
|
|
5086
5209
|
if (elapsed >= _OutputService.EMPTY_TIMEOUT_MS) this.finalize();
|
|
5087
5210
|
return;
|
|
5088
5211
|
}
|
|
5089
5212
|
const idleMs = this.lastPushTime > 0 ? now - this.lastPushTime : elapsed;
|
|
5213
|
+
log.trace(
|
|
5214
|
+
"outputSvc",
|
|
5215
|
+
`tick content (raw=${this.rawBuffer.length}B lines=${lines.length} content=${content.length} idleMs=${idleMs})`
|
|
5216
|
+
);
|
|
5090
5217
|
if (idleMs >= _OutputService.IDLE_MS) {
|
|
5091
5218
|
this.finalize();
|
|
5092
5219
|
return;
|
|
@@ -5153,15 +5280,38 @@ var OutputService = class _OutputService {
|
|
|
5153
5280
|
if (this.pluginAuthToken) {
|
|
5154
5281
|
headers["X-Plugin-Auth-Token"] = this.pluginAuthToken;
|
|
5155
5282
|
}
|
|
5283
|
+
const chunkType = body.type ?? "(clear)";
|
|
5284
|
+
log.trace(
|
|
5285
|
+
"outputSvc",
|
|
5286
|
+
`postChunk type=${chunkType} done=${body.done === true} bytes=${payload.length}`
|
|
5287
|
+
);
|
|
5288
|
+
if (chunkType === "select_prompt" || chunkType === "new_turn" || body.type === "text" && body.done === true) {
|
|
5289
|
+
const preview = payload.length > 2048 ? payload.slice(0, 2048) + "\u2026(truncated)" : payload;
|
|
5290
|
+
log.trace("outputSvc", `payload ${preview}`);
|
|
5291
|
+
}
|
|
5156
5292
|
return new Promise((resolve2) => {
|
|
5157
5293
|
const attempt = (attemptsLeft) => {
|
|
5158
5294
|
_transport2.sendOutputChunk(`${API_BASE4}/api/commands/output`, headers, payload).then(({ statusCode, body: resBody }) => {
|
|
5295
|
+
log.trace("outputSvc", `postChunk status=${statusCode}`);
|
|
5296
|
+
if (statusCode === 410 || statusCode === 404 && /SESSION_NOT_FOUND|SESSION_GONE/.test(resBody)) {
|
|
5297
|
+
if (this.active) {
|
|
5298
|
+
process.stderr.write("[codeam] session was deleted/disconnected \u2014 stopping output stream.\n");
|
|
5299
|
+
this.dispose();
|
|
5300
|
+
}
|
|
5301
|
+
resolve2();
|
|
5302
|
+
return;
|
|
5303
|
+
}
|
|
5159
5304
|
if (statusCode >= 400) {
|
|
5160
5305
|
process.stderr.write(`[codeam] output API error ${statusCode}: ${resBody}
|
|
5161
5306
|
`);
|
|
5162
5307
|
}
|
|
5163
5308
|
resolve2();
|
|
5164
|
-
}).catch(() => {
|
|
5309
|
+
}).catch((err) => {
|
|
5310
|
+
log.trace(
|
|
5311
|
+
"outputSvc",
|
|
5312
|
+
`postChunk error (retries left=${attemptsLeft})`,
|
|
5313
|
+
err
|
|
5314
|
+
);
|
|
5165
5315
|
if (attemptsLeft > 0) {
|
|
5166
5316
|
const delay = 200 * (maxRetries - attemptsLeft + 1);
|
|
5167
5317
|
setTimeout(() => attempt(attemptsLeft - 1), delay);
|
|
@@ -5220,33 +5370,12 @@ function _sendOutputChunk(url, headers, payload) {
|
|
|
5220
5370
|
}
|
|
5221
5371
|
|
|
5222
5372
|
// src/services/history.service.ts
|
|
5223
|
-
var
|
|
5224
|
-
var
|
|
5225
|
-
var
|
|
5373
|
+
var fs5 = __toESM(require("fs"));
|
|
5374
|
+
var path8 = __toESM(require("path"));
|
|
5375
|
+
var os6 = __toESM(require("os"));
|
|
5226
5376
|
var https3 = __toESM(require("https"));
|
|
5227
5377
|
var http3 = __toESM(require("http"));
|
|
5228
5378
|
var import_zod = require("zod");
|
|
5229
|
-
|
|
5230
|
-
// src/services/logger.ts
|
|
5231
|
-
var LEVELS = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
|
|
5232
|
-
function currentLevel() {
|
|
5233
|
-
const raw = (process.env.CODEAM_LOG ?? "error").toLowerCase();
|
|
5234
|
-
return LEVELS[raw] ?? LEVELS.error;
|
|
5235
|
-
}
|
|
5236
|
-
function emit(level, tag, msg, err) {
|
|
5237
|
-
if (LEVELS[level] > currentLevel()) return;
|
|
5238
|
-
const detail = err instanceof Error ? `: ${err.message}` : err !== void 0 ? `: ${String(err)}` : "";
|
|
5239
|
-
process.stderr.write(`[codeam:${level}] ${tag} \u2014 ${msg}${detail}
|
|
5240
|
-
`);
|
|
5241
|
-
}
|
|
5242
|
-
var log = {
|
|
5243
|
-
error: (tag, msg, err) => emit("error", tag, msg, err),
|
|
5244
|
-
warn: (tag, msg, err) => emit("warn", tag, msg, err),
|
|
5245
|
-
info: (tag, msg, err) => emit("info", tag, msg, err),
|
|
5246
|
-
debug: (tag, msg, err) => emit("debug", tag, msg, err)
|
|
5247
|
-
};
|
|
5248
|
-
|
|
5249
|
-
// src/services/history.service.ts
|
|
5250
5379
|
var historyRecordSchema = import_zod.z.object({
|
|
5251
5380
|
type: import_zod.z.string().optional(),
|
|
5252
5381
|
timestamp: import_zod.z.union([import_zod.z.string(), import_zod.z.number()]).optional(),
|
|
@@ -5259,7 +5388,25 @@ var historyRecordSchema = import_zod.z.object({
|
|
|
5259
5388
|
}).passthrough();
|
|
5260
5389
|
var API_BASE5 = process.env.CODEAM_API_URL ?? "https://codeagent-mobile-api.vercel.app";
|
|
5261
5390
|
function encodeCwd(cwd) {
|
|
5262
|
-
return cwd.replace(
|
|
5391
|
+
return cwd.replace(/[\\/:]/g, "-");
|
|
5392
|
+
}
|
|
5393
|
+
function findProjectDir(cwd) {
|
|
5394
|
+
const projectsRoot = path8.join(os6.homedir(), ".claude", "projects");
|
|
5395
|
+
const primary = path8.join(projectsRoot, encodeCwd(cwd));
|
|
5396
|
+
if (fs5.existsSync(primary)) return primary;
|
|
5397
|
+
try {
|
|
5398
|
+
const entries = fs5.readdirSync(projectsRoot, { withFileTypes: true });
|
|
5399
|
+
const wanted = encodeCwd(cwd);
|
|
5400
|
+
for (const e of entries) {
|
|
5401
|
+
if (!e.isDirectory()) continue;
|
|
5402
|
+
const candidate = e.name.replace(/-+/g, "-");
|
|
5403
|
+
if (candidate === wanted.replace(/-+/g, "-")) {
|
|
5404
|
+
return path8.join(projectsRoot, e.name);
|
|
5405
|
+
}
|
|
5406
|
+
}
|
|
5407
|
+
} catch {
|
|
5408
|
+
}
|
|
5409
|
+
return null;
|
|
5263
5410
|
}
|
|
5264
5411
|
function extractText(content) {
|
|
5265
5412
|
if (typeof content === "string") return content;
|
|
@@ -5273,7 +5420,7 @@ function parseJsonl(filePath) {
|
|
|
5273
5420
|
const messages = [];
|
|
5274
5421
|
let raw;
|
|
5275
5422
|
try {
|
|
5276
|
-
raw =
|
|
5423
|
+
raw = fs5.readFileSync(filePath, "utf8");
|
|
5277
5424
|
} catch (err) {
|
|
5278
5425
|
if (err.code !== "ENOENT") {
|
|
5279
5426
|
log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
|
|
@@ -5377,7 +5524,7 @@ var HistoryService = class {
|
|
|
5377
5524
|
return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
|
|
5378
5525
|
}
|
|
5379
5526
|
get projectDir() {
|
|
5380
|
-
return
|
|
5527
|
+
return findProjectDir(this.cwd) ?? path8.join(os6.homedir(), ".claude", "projects", encodeCwd(this.cwd));
|
|
5381
5528
|
}
|
|
5382
5529
|
/** Set the current Claude conversation ID (extracted from /cost command or session start) */
|
|
5383
5530
|
setCurrentConversationId(id) {
|
|
@@ -5389,7 +5536,7 @@ var HistoryService = class {
|
|
|
5389
5536
|
/** Return the current message count in the active conversation. */
|
|
5390
5537
|
getCurrentMessageCount() {
|
|
5391
5538
|
if (!this.currentConversationId) return 0;
|
|
5392
|
-
const filePath =
|
|
5539
|
+
const filePath = path8.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
5393
5540
|
return parseJsonl(filePath).length;
|
|
5394
5541
|
}
|
|
5395
5542
|
/**
|
|
@@ -5400,7 +5547,7 @@ var HistoryService = class {
|
|
|
5400
5547
|
const deadline = Date.now() + timeoutMs;
|
|
5401
5548
|
while (Date.now() < deadline) {
|
|
5402
5549
|
if (!this.currentConversationId) return null;
|
|
5403
|
-
const filePath =
|
|
5550
|
+
const filePath = path8.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
5404
5551
|
const messages = parseJsonl(filePath);
|
|
5405
5552
|
if (messages.length > previousCount) {
|
|
5406
5553
|
for (let i = messages.length - 1; i >= previousCount; i--) {
|
|
@@ -5415,15 +5562,15 @@ var HistoryService = class {
|
|
|
5415
5562
|
detectCurrentConversation() {
|
|
5416
5563
|
const dir = this.projectDir;
|
|
5417
5564
|
try {
|
|
5418
|
-
const files =
|
|
5565
|
+
const files = fs5.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
5419
5566
|
try {
|
|
5420
|
-
return { name: e.name, mtime:
|
|
5567
|
+
return { name: e.name, mtime: fs5.statSync(path8.join(dir, e.name)).mtimeMs };
|
|
5421
5568
|
} catch {
|
|
5422
5569
|
return { name: e.name, mtime: 0 };
|
|
5423
5570
|
}
|
|
5424
5571
|
}).sort((a, b) => b.mtime - a.mtime);
|
|
5425
5572
|
if (files.length > 0) {
|
|
5426
|
-
this.currentConversationId =
|
|
5573
|
+
this.currentConversationId = path8.basename(files[0].name, ".jsonl");
|
|
5427
5574
|
}
|
|
5428
5575
|
} catch {
|
|
5429
5576
|
}
|
|
@@ -5455,13 +5602,13 @@ var HistoryService = class {
|
|
|
5455
5602
|
const dir = this.projectDir;
|
|
5456
5603
|
let entries;
|
|
5457
5604
|
try {
|
|
5458
|
-
entries =
|
|
5605
|
+
entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
5459
5606
|
} catch {
|
|
5460
5607
|
return null;
|
|
5461
5608
|
}
|
|
5462
5609
|
const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
5463
5610
|
try {
|
|
5464
|
-
return { name: e.name, mtime:
|
|
5611
|
+
return { name: e.name, mtime: fs5.statSync(path8.join(dir, e.name)).mtimeMs };
|
|
5465
5612
|
} catch {
|
|
5466
5613
|
return { name: e.name, mtime: 0 };
|
|
5467
5614
|
}
|
|
@@ -5469,12 +5616,12 @@ var HistoryService = class {
|
|
|
5469
5616
|
if (files.length === 0) return null;
|
|
5470
5617
|
const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
|
|
5471
5618
|
if (!files.some((f) => f.name === targetFile)) return null;
|
|
5472
|
-
return this.extractUsageFromFile(
|
|
5619
|
+
return this.extractUsageFromFile(path8.join(dir, targetFile));
|
|
5473
5620
|
}
|
|
5474
5621
|
extractUsageFromFile(filePath) {
|
|
5475
5622
|
let raw;
|
|
5476
5623
|
try {
|
|
5477
|
-
raw =
|
|
5624
|
+
raw = fs5.readFileSync(filePath, "utf8");
|
|
5478
5625
|
} catch {
|
|
5479
5626
|
return null;
|
|
5480
5627
|
}
|
|
@@ -5519,9 +5666,9 @@ var HistoryService = class {
|
|
|
5519
5666
|
let totalCost = 0;
|
|
5520
5667
|
let files;
|
|
5521
5668
|
try {
|
|
5522
|
-
files =
|
|
5669
|
+
files = fs5.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
|
|
5523
5670
|
try {
|
|
5524
|
-
return
|
|
5671
|
+
return fs5.statSync(path8.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
5525
5672
|
} catch {
|
|
5526
5673
|
return false;
|
|
5527
5674
|
}
|
|
@@ -5532,7 +5679,7 @@ var HistoryService = class {
|
|
|
5532
5679
|
for (const file of files) {
|
|
5533
5680
|
let raw;
|
|
5534
5681
|
try {
|
|
5535
|
-
raw =
|
|
5682
|
+
raw = fs5.readFileSync(path8.join(projectDir, file), "utf8");
|
|
5536
5683
|
} catch {
|
|
5537
5684
|
continue;
|
|
5538
5685
|
}
|
|
@@ -5567,23 +5714,23 @@ var HistoryService = class {
|
|
|
5567
5714
|
const dir = this.projectDir;
|
|
5568
5715
|
let entries;
|
|
5569
5716
|
try {
|
|
5570
|
-
entries =
|
|
5717
|
+
entries = fs5.readdirSync(dir, { withFileTypes: true });
|
|
5571
5718
|
} catch {
|
|
5572
5719
|
return;
|
|
5573
5720
|
}
|
|
5574
5721
|
const sessions2 = [];
|
|
5575
5722
|
for (const entry of entries) {
|
|
5576
5723
|
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
|
|
5577
|
-
const id =
|
|
5578
|
-
const filePath =
|
|
5724
|
+
const id = path8.basename(entry.name, ".jsonl");
|
|
5725
|
+
const filePath = path8.join(dir, entry.name);
|
|
5579
5726
|
let mtime = Date.now();
|
|
5580
5727
|
try {
|
|
5581
|
-
mtime =
|
|
5728
|
+
mtime = fs5.statSync(filePath).mtimeMs;
|
|
5582
5729
|
} catch {
|
|
5583
5730
|
}
|
|
5584
5731
|
let summary = "";
|
|
5585
5732
|
try {
|
|
5586
|
-
const raw =
|
|
5733
|
+
const raw = fs5.readFileSync(filePath, "utf8");
|
|
5587
5734
|
for (const line of raw.split("\n")) {
|
|
5588
5735
|
if (!line.trim()) continue;
|
|
5589
5736
|
try {
|
|
@@ -5616,7 +5763,7 @@ var HistoryService = class {
|
|
|
5616
5763
|
* showing an empty conversation.
|
|
5617
5764
|
*/
|
|
5618
5765
|
async loadConversation(sessionId) {
|
|
5619
|
-
const filePath =
|
|
5766
|
+
const filePath = path8.join(this.projectDir, `${sessionId}.jsonl`);
|
|
5620
5767
|
const messages = parseJsonl(filePath);
|
|
5621
5768
|
if (messages.length === 0) return;
|
|
5622
5769
|
const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
|
|
@@ -5671,8 +5818,8 @@ function parsePayload(schema, raw) {
|
|
|
5671
5818
|
}
|
|
5672
5819
|
|
|
5673
5820
|
// src/services/file-ops.service.ts
|
|
5674
|
-
var
|
|
5675
|
-
var
|
|
5821
|
+
var fs6 = __toESM(require("fs/promises"));
|
|
5822
|
+
var path9 = __toESM(require("path"));
|
|
5676
5823
|
var MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
5677
5824
|
var MAX_WALK_DEPTH = 6;
|
|
5678
5825
|
var MAX_VISITED_DIRS = 5e3;
|
|
@@ -5707,12 +5854,12 @@ var SUBDIR_IGNORE = /* @__PURE__ */ new Set([
|
|
|
5707
5854
|
"__pycache__"
|
|
5708
5855
|
]);
|
|
5709
5856
|
function isUnder(parent, candidate) {
|
|
5710
|
-
const rel =
|
|
5711
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
5857
|
+
const rel = path9.relative(parent, candidate);
|
|
5858
|
+
return rel === "" || !rel.startsWith("..") && !path9.isAbsolute(rel);
|
|
5712
5859
|
}
|
|
5713
5860
|
async function isExistingFile(absPath) {
|
|
5714
5861
|
try {
|
|
5715
|
-
const stat3 = await
|
|
5862
|
+
const stat3 = await fs6.stat(absPath);
|
|
5716
5863
|
return stat3.isFile();
|
|
5717
5864
|
} catch {
|
|
5718
5865
|
return false;
|
|
@@ -5725,13 +5872,13 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
|
|
|
5725
5872
|
ctx.visited++;
|
|
5726
5873
|
let entries = [];
|
|
5727
5874
|
try {
|
|
5728
|
-
entries = await
|
|
5875
|
+
entries = await fs6.readdir(dir, { withFileTypes: true });
|
|
5729
5876
|
} catch {
|
|
5730
5877
|
return;
|
|
5731
5878
|
}
|
|
5732
5879
|
for (const e of entries) {
|
|
5733
5880
|
if (!e.isFile()) continue;
|
|
5734
|
-
const full =
|
|
5881
|
+
const full = path9.join(dir, e.name);
|
|
5735
5882
|
if (needleVariants.some((needle) => full.endsWith(needle))) {
|
|
5736
5883
|
ctx.matches.push(full);
|
|
5737
5884
|
if (ctx.matches.length >= ctx.cap) return;
|
|
@@ -5741,21 +5888,21 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
|
|
|
5741
5888
|
if (!e.isDirectory()) continue;
|
|
5742
5889
|
if (SUBDIR_IGNORE.has(e.name)) continue;
|
|
5743
5890
|
if (e.name.startsWith(".") && SUBDIR_IGNORE.has(e.name)) continue;
|
|
5744
|
-
await walkForSuffix(
|
|
5891
|
+
await walkForSuffix(path9.join(dir, e.name), needleVariants, depth + 1, ctx);
|
|
5745
5892
|
if (ctx.matches.length >= ctx.cap) return;
|
|
5746
5893
|
}
|
|
5747
5894
|
}
|
|
5748
5895
|
async function findFile(rawPath) {
|
|
5749
5896
|
const cwd = process.cwd();
|
|
5750
|
-
if (
|
|
5751
|
-
const abs =
|
|
5897
|
+
if (path9.isAbsolute(rawPath)) {
|
|
5898
|
+
const abs = path9.normalize(rawPath);
|
|
5752
5899
|
if (isUnder(cwd, abs) && await isExistingFile(abs)) return abs;
|
|
5753
5900
|
}
|
|
5754
|
-
const direct =
|
|
5901
|
+
const direct = path9.resolve(cwd, rawPath);
|
|
5755
5902
|
if (isUnder(cwd, direct) && await isExistingFile(direct)) return direct;
|
|
5756
|
-
const normalized =
|
|
5903
|
+
const normalized = path9.normalize(rawPath).replace(/^[./\\]+/, "");
|
|
5757
5904
|
const needles = [
|
|
5758
|
-
`${
|
|
5905
|
+
`${path9.sep}${normalized}`,
|
|
5759
5906
|
`/${normalized}`
|
|
5760
5907
|
].filter((v, i, a) => a.indexOf(v) === i);
|
|
5761
5908
|
const ctx = { visited: 0, matches: [], cap: 16 };
|
|
@@ -5769,7 +5916,7 @@ async function findWriteTarget(rawPath) {
|
|
|
5769
5916
|
const found = await findFile(rawPath);
|
|
5770
5917
|
if (found) return found;
|
|
5771
5918
|
const cwd = process.cwd();
|
|
5772
|
-
const fallback =
|
|
5919
|
+
const fallback = path9.isAbsolute(rawPath) ? path9.normalize(rawPath) : path9.resolve(cwd, rawPath);
|
|
5773
5920
|
if (!isUnder(cwd, fallback)) return null;
|
|
5774
5921
|
return fallback;
|
|
5775
5922
|
}
|
|
@@ -5786,11 +5933,11 @@ async function readProjectFile(rawPath) {
|
|
|
5786
5933
|
if (!abs) {
|
|
5787
5934
|
return { error: `File not found in the project tree: ${rawPath}` };
|
|
5788
5935
|
}
|
|
5789
|
-
const stat3 = await
|
|
5936
|
+
const stat3 = await fs6.stat(abs);
|
|
5790
5937
|
if (stat3.size > MAX_FILE_BYTES) {
|
|
5791
5938
|
return { error: `File too large (${(stat3.size / 1024 / 1024).toFixed(1)} MB > ${MAX_FILE_BYTES / 1024 / 1024} MB).` };
|
|
5792
5939
|
}
|
|
5793
|
-
const buf = await
|
|
5940
|
+
const buf = await fs6.readFile(abs);
|
|
5794
5941
|
if (looksBinary(buf)) {
|
|
5795
5942
|
return { error: "Binary file \u2014 refusing to open in a code editor." };
|
|
5796
5943
|
}
|
|
@@ -5809,8 +5956,8 @@ async function writeProjectFile(rawPath, content) {
|
|
|
5809
5956
|
if (Buffer.byteLength(content, "utf-8") > MAX_FILE_BYTES) {
|
|
5810
5957
|
return { error: "Content too large." };
|
|
5811
5958
|
}
|
|
5812
|
-
await
|
|
5813
|
-
await
|
|
5959
|
+
await fs6.mkdir(path9.dirname(abs), { recursive: true });
|
|
5960
|
+
await fs6.writeFile(abs, content, "utf-8");
|
|
5814
5961
|
return { ok: true };
|
|
5815
5962
|
} catch (e) {
|
|
5816
5963
|
const msg = e instanceof Error ? e.message : "Write failed";
|
|
@@ -5821,8 +5968,8 @@ async function writeProjectFile(rawPath, content) {
|
|
|
5821
5968
|
// src/services/project-ops.service.ts
|
|
5822
5969
|
var import_child_process4 = require("child_process");
|
|
5823
5970
|
var import_util = require("util");
|
|
5824
|
-
var
|
|
5825
|
-
var
|
|
5971
|
+
var fs7 = __toESM(require("fs/promises"));
|
|
5972
|
+
var path10 = __toESM(require("path"));
|
|
5826
5973
|
var execFileP = (0, import_util.promisify)(import_child_process4.execFile);
|
|
5827
5974
|
var PROJECT_IGNORE = /* @__PURE__ */ new Set([
|
|
5828
5975
|
"node_modules",
|
|
@@ -5870,7 +6017,7 @@ async function listProjectFiles(opts = {}) {
|
|
|
5870
6017
|
}
|
|
5871
6018
|
let entries = [];
|
|
5872
6019
|
try {
|
|
5873
|
-
entries = await
|
|
6020
|
+
entries = await fs7.readdir(dir, { withFileTypes: true });
|
|
5874
6021
|
} catch {
|
|
5875
6022
|
return;
|
|
5876
6023
|
}
|
|
@@ -5880,18 +6027,18 @@ async function listProjectFiles(opts = {}) {
|
|
|
5880
6027
|
return;
|
|
5881
6028
|
}
|
|
5882
6029
|
if (PROJECT_IGNORE.has(e.name)) continue;
|
|
5883
|
-
const full =
|
|
6030
|
+
const full = path10.join(dir, e.name);
|
|
5884
6031
|
if (e.isDirectory()) {
|
|
5885
6032
|
if (depth >= 12) continue;
|
|
5886
6033
|
await walk(full, depth + 1);
|
|
5887
6034
|
} else if (e.isFile()) {
|
|
5888
|
-
const rel =
|
|
6035
|
+
const rel = path10.relative(root, full);
|
|
5889
6036
|
if (q2 && !rel.toLowerCase().includes(q2) && !e.name.toLowerCase().includes(q2)) {
|
|
5890
6037
|
continue;
|
|
5891
6038
|
}
|
|
5892
6039
|
let size = 0;
|
|
5893
6040
|
try {
|
|
5894
|
-
const st3 = await
|
|
6041
|
+
const st3 = await fs7.stat(full);
|
|
5895
6042
|
size = st3.size;
|
|
5896
6043
|
} catch {
|
|
5897
6044
|
}
|
|
@@ -5993,8 +6140,8 @@ async function gitStatus(cwd) {
|
|
|
5993
6140
|
let hasMergeInProgress = false;
|
|
5994
6141
|
try {
|
|
5995
6142
|
const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
|
|
5996
|
-
const mergeHead =
|
|
5997
|
-
await
|
|
6143
|
+
const mergeHead = path10.isAbsolute(gitDir) ? path10.join(gitDir, "MERGE_HEAD") : path10.join(root, gitDir, "MERGE_HEAD");
|
|
6144
|
+
await fs7.access(mergeHead);
|
|
5998
6145
|
hasMergeInProgress = true;
|
|
5999
6146
|
} catch {
|
|
6000
6147
|
}
|
|
@@ -6071,8 +6218,8 @@ async function gitResolve(file, side, cwd) {
|
|
|
6071
6218
|
function saveFilesTemp(files) {
|
|
6072
6219
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
6073
6220
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
6074
|
-
const tmpPath =
|
|
6075
|
-
|
|
6221
|
+
const tmpPath = path11.join(os7.tmpdir(), `codeam-${(0, import_crypto.randomUUID)()}-${safeName}`);
|
|
6222
|
+
fs8.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
6076
6223
|
return tmpPath;
|
|
6077
6224
|
});
|
|
6078
6225
|
}
|
|
@@ -6145,8 +6292,8 @@ try:
|
|
|
6145
6292
|
sys.exit((st>>8)&0xFF)
|
|
6146
6293
|
except Exception:sys.exit(0)
|
|
6147
6294
|
`;
|
|
6148
|
-
const helperPath =
|
|
6149
|
-
|
|
6295
|
+
const helperPath = path11.join(os7.tmpdir(), "codeam-quota-helper.py");
|
|
6296
|
+
fs8.writeFileSync(helperPath, helperScript, { mode: 420 });
|
|
6150
6297
|
const python = findInPath("python3") ?? findInPath("python");
|
|
6151
6298
|
if (!python) {
|
|
6152
6299
|
quotaFetchInProgress = false;
|
|
@@ -6178,7 +6325,7 @@ except Exception:sys.exit(0)
|
|
|
6178
6325
|
} catch {
|
|
6179
6326
|
}
|
|
6180
6327
|
try {
|
|
6181
|
-
|
|
6328
|
+
fs8.unlinkSync(helperPath);
|
|
6182
6329
|
} catch {
|
|
6183
6330
|
}
|
|
6184
6331
|
quotaFetchInProgress = false;
|
|
@@ -6228,7 +6375,7 @@ except Exception:sys.exit(0)
|
|
|
6228
6375
|
setTimeout(() => {
|
|
6229
6376
|
for (const p2 of paths) {
|
|
6230
6377
|
try {
|
|
6231
|
-
|
|
6378
|
+
fs8.unlinkSync(p2);
|
|
6232
6379
|
} catch {
|
|
6233
6380
|
}
|
|
6234
6381
|
}
|
|
@@ -6271,6 +6418,25 @@ except Exception:sys.exit(0)
|
|
|
6271
6418
|
}
|
|
6272
6419
|
break;
|
|
6273
6420
|
}
|
|
6421
|
+
case "session_terminated": {
|
|
6422
|
+
showInfo("Session was deleted from the app \u2014 exiting.");
|
|
6423
|
+
try {
|
|
6424
|
+
claude.kill();
|
|
6425
|
+
} catch {
|
|
6426
|
+
}
|
|
6427
|
+
try {
|
|
6428
|
+
const proc = (0, import_child_process5.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
|
|
6429
|
+
detached: true,
|
|
6430
|
+
stdio: "ignore"
|
|
6431
|
+
});
|
|
6432
|
+
proc.unref();
|
|
6433
|
+
} catch {
|
|
6434
|
+
}
|
|
6435
|
+
outputSvc.dispose();
|
|
6436
|
+
relay.stop();
|
|
6437
|
+
ws.disconnect();
|
|
6438
|
+
process.exit(0);
|
|
6439
|
+
}
|
|
6274
6440
|
case "shutdown_session": {
|
|
6275
6441
|
try {
|
|
6276
6442
|
await relay.sendResult(cmd.id, "success", { ok: true });
|
|
@@ -6451,7 +6617,7 @@ except Exception:sys.exit(0)
|
|
|
6451
6617
|
setTimeout(() => {
|
|
6452
6618
|
for (const p2 of paths) {
|
|
6453
6619
|
try {
|
|
6454
|
-
|
|
6620
|
+
fs8.unlinkSync(p2);
|
|
6455
6621
|
} catch {
|
|
6456
6622
|
}
|
|
6457
6623
|
}
|
|
@@ -6746,9 +6912,9 @@ async function logout() {
|
|
|
6746
6912
|
|
|
6747
6913
|
// src/commands/deploy.ts
|
|
6748
6914
|
var import_child_process10 = require("child_process");
|
|
6749
|
-
var
|
|
6750
|
-
var
|
|
6751
|
-
var
|
|
6915
|
+
var fs9 = __toESM(require("fs"));
|
|
6916
|
+
var os8 = __toESM(require("os"));
|
|
6917
|
+
var path16 = __toESM(require("path"));
|
|
6752
6918
|
var import_util6 = require("util");
|
|
6753
6919
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
6754
6920
|
|
|
@@ -6756,7 +6922,7 @@ var import_picocolors9 = __toESM(require("picocolors"));
|
|
|
6756
6922
|
var import_child_process6 = require("child_process");
|
|
6757
6923
|
var import_util2 = require("util");
|
|
6758
6924
|
var import_picocolors7 = __toESM(require("picocolors"));
|
|
6759
|
-
var
|
|
6925
|
+
var path12 = __toESM(require("path"));
|
|
6760
6926
|
var execFileP2 = (0, import_util2.promisify)(import_child_process6.execFile);
|
|
6761
6927
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
6762
6928
|
function resetStdinForChild() {
|
|
@@ -7245,7 +7411,7 @@ var GitHubCodespacesProvider = class {
|
|
|
7245
7411
|
});
|
|
7246
7412
|
}
|
|
7247
7413
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
7248
|
-
const remoteDir =
|
|
7414
|
+
const remoteDir = path12.posix.dirname(remotePath);
|
|
7249
7415
|
const parts = [
|
|
7250
7416
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
7251
7417
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -7315,7 +7481,7 @@ function shellQuote(s) {
|
|
|
7315
7481
|
// src/services/providers/gitpod.ts
|
|
7316
7482
|
var import_child_process7 = require("child_process");
|
|
7317
7483
|
var import_util3 = require("util");
|
|
7318
|
-
var
|
|
7484
|
+
var path13 = __toESM(require("path"));
|
|
7319
7485
|
var import_picocolors8 = __toESM(require("picocolors"));
|
|
7320
7486
|
var execFileP3 = (0, import_util3.promisify)(import_child_process7.execFile);
|
|
7321
7487
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
@@ -7555,7 +7721,7 @@ var GitpodProvider = class {
|
|
|
7555
7721
|
});
|
|
7556
7722
|
}
|
|
7557
7723
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
7558
|
-
const remoteDir =
|
|
7724
|
+
const remoteDir = path13.posix.dirname(remotePath);
|
|
7559
7725
|
const parts = [
|
|
7560
7726
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
7561
7727
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -7591,7 +7757,7 @@ function shellQuote2(s) {
|
|
|
7591
7757
|
// src/services/providers/gitlab-workspaces.ts
|
|
7592
7758
|
var import_child_process8 = require("child_process");
|
|
7593
7759
|
var import_util4 = require("util");
|
|
7594
|
-
var
|
|
7760
|
+
var path14 = __toESM(require("path"));
|
|
7595
7761
|
var execFileP4 = (0, import_util4.promisify)(import_child_process8.execFile);
|
|
7596
7762
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
7597
7763
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
@@ -7851,7 +8017,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
7851
8017
|
}
|
|
7852
8018
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
7853
8019
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
7854
|
-
const remoteDir =
|
|
8020
|
+
const remoteDir = path14.posix.dirname(remotePath);
|
|
7855
8021
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
7856
8022
|
if (options.mode != null) {
|
|
7857
8023
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
@@ -7919,7 +8085,7 @@ function shellQuote3(s) {
|
|
|
7919
8085
|
// src/services/providers/railway.ts
|
|
7920
8086
|
var import_child_process9 = require("child_process");
|
|
7921
8087
|
var import_util5 = require("util");
|
|
7922
|
-
var
|
|
8088
|
+
var path15 = __toESM(require("path"));
|
|
7923
8089
|
var execFileP5 = (0, import_util5.promisify)(import_child_process9.execFile);
|
|
7924
8090
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
7925
8091
|
function resetStdinForChild4() {
|
|
@@ -8155,7 +8321,7 @@ var RailwayProvider = class {
|
|
|
8155
8321
|
if (!projectId || !serviceId) {
|
|
8156
8322
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
8157
8323
|
}
|
|
8158
|
-
const remoteDir =
|
|
8324
|
+
const remoteDir = path15.posix.dirname(remotePath);
|
|
8159
8325
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
8160
8326
|
if (options.mode != null) {
|
|
8161
8327
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
@@ -8347,7 +8513,7 @@ async function deploy() {
|
|
|
8347
8513
|
process.exit(1);
|
|
8348
8514
|
}
|
|
8349
8515
|
}
|
|
8350
|
-
const localClaudeDir =
|
|
8516
|
+
const localClaudeDir = path16.join(os8.homedir(), ".claude");
|
|
8351
8517
|
const localCredsKind = await detectLocalClaudeCredentials(localClaudeDir);
|
|
8352
8518
|
let bridged = "none";
|
|
8353
8519
|
if (localCredsKind !== "none") {
|
|
@@ -8391,7 +8557,7 @@ async function deploy() {
|
|
|
8391
8557
|
process.exit(1);
|
|
8392
8558
|
}
|
|
8393
8559
|
claudeStep.stop("\u2713 Claude CLI installed");
|
|
8394
|
-
const haveLocalClaude =
|
|
8560
|
+
const haveLocalClaude = fs9.existsSync(localClaudeDir) && fs9.statSync(localClaudeDir).isDirectory();
|
|
8395
8561
|
if (haveLocalClaude) {
|
|
8396
8562
|
const copyStep = fe();
|
|
8397
8563
|
copyStep.start("Copying local Claude config to workspace\u2026");
|
|
@@ -8445,10 +8611,10 @@ async function deploy() {
|
|
|
8445
8611
|
}
|
|
8446
8612
|
}
|
|
8447
8613
|
if (bridged !== "none") {
|
|
8448
|
-
const localClaudeJson =
|
|
8449
|
-
if (
|
|
8614
|
+
const localClaudeJson = path16.join(os8.homedir(), ".claude.json");
|
|
8615
|
+
if (fs9.existsSync(localClaudeJson)) {
|
|
8450
8616
|
try {
|
|
8451
|
-
const contents =
|
|
8617
|
+
const contents = fs9.readFileSync(localClaudeJson);
|
|
8452
8618
|
await provider.uploadFile(
|
|
8453
8619
|
workspace.id,
|
|
8454
8620
|
"/home/codespace/.claude.json",
|
|
@@ -8638,7 +8804,7 @@ async function runRemoteClaudeLogin(provider, workspaceId) {
|
|
|
8638
8804
|
}
|
|
8639
8805
|
}
|
|
8640
8806
|
async function detectLocalClaudeCredentials(localClaudeDir) {
|
|
8641
|
-
if (
|
|
8807
|
+
if (fs9.existsSync(path16.join(localClaudeDir, ".credentials.json"))) {
|
|
8642
8808
|
return "flat-file";
|
|
8643
8809
|
}
|
|
8644
8810
|
if (process.platform === "darwin") {
|
|
@@ -8671,8 +8837,8 @@ async function verifyClaudeAuth(provider, workspaceId) {
|
|
|
8671
8837
|
}
|
|
8672
8838
|
}
|
|
8673
8839
|
async function bridgeClaudeCredentials(provider, workspaceId, localClaudeDir) {
|
|
8674
|
-
const fileBased =
|
|
8675
|
-
if (
|
|
8840
|
+
const fileBased = path16.join(localClaudeDir, ".credentials.json");
|
|
8841
|
+
if (fs9.existsSync(fileBased)) return "flat-file";
|
|
8676
8842
|
if (process.platform === "darwin") {
|
|
8677
8843
|
try {
|
|
8678
8844
|
const { stdout } = await execFileP6(
|
|
@@ -8877,10 +9043,172 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
8877
9043
|
}
|
|
8878
9044
|
}
|
|
8879
9045
|
|
|
9046
|
+
// src/commands/version.ts
|
|
9047
|
+
var import_picocolors11 = __toESM(require("picocolors"));
|
|
9048
|
+
function version() {
|
|
9049
|
+
const v = true ? "2.4.35" : "unknown";
|
|
9050
|
+
console.log(`${import_picocolors11.default.bold("codeam-cli")} ${import_picocolors11.default.cyan(v)}`);
|
|
9051
|
+
}
|
|
9052
|
+
|
|
9053
|
+
// src/commands/help.ts
|
|
9054
|
+
var import_picocolors12 = __toESM(require("picocolors"));
|
|
9055
|
+
function help() {
|
|
9056
|
+
const lines = [
|
|
9057
|
+
"",
|
|
9058
|
+
` ${import_picocolors12.default.bold(import_picocolors12.default.magenta("codeam-cli"))} ${import_picocolors12.default.dim("\u2014 Claude Code remote control")}`,
|
|
9059
|
+
"",
|
|
9060
|
+
` ${import_picocolors12.default.bold("Usage")}`,
|
|
9061
|
+
` ${import_picocolors12.default.cyan("codeam")} ${import_picocolors12.default.dim("[command]")}`,
|
|
9062
|
+
"",
|
|
9063
|
+
` ${import_picocolors12.default.bold("Commands")}`,
|
|
9064
|
+
` ${import_picocolors12.default.white("codeam")} ${import_picocolors12.default.dim("start Claude Code with mobile control")}`,
|
|
9065
|
+
` ${import_picocolors12.default.white("codeam pair")} ${import_picocolors12.default.dim("pair a new mobile device")}`,
|
|
9066
|
+
` ${import_picocolors12.default.white("codeam sessions")} ${import_picocolors12.default.dim("list paired devices")}`,
|
|
9067
|
+
` ${import_picocolors12.default.white("codeam status")} ${import_picocolors12.default.dim("show connection info")}`,
|
|
9068
|
+
` ${import_picocolors12.default.white("codeam logout")} ${import_picocolors12.default.dim("remove all paired sessions")}`,
|
|
9069
|
+
` ${import_picocolors12.default.white("codeam deploy")} ${import_picocolors12.default.dim("provision a cloud workspace (Codespaces) and pair it")}`,
|
|
9070
|
+
` ${import_picocolors12.default.white("codeam deploy ls")} ${import_picocolors12.default.dim("list deployed cloud workspaces")}`,
|
|
9071
|
+
` ${import_picocolors12.default.white("codeam deploy stop")} ${import_picocolors12.default.dim("stop a deployed workspace session")}`,
|
|
9072
|
+
"",
|
|
9073
|
+
` ${import_picocolors12.default.bold("Flags")}`,
|
|
9074
|
+
` ${import_picocolors12.default.white("-v, --version")} ${import_picocolors12.default.dim("print the CLI version")}`,
|
|
9075
|
+
` ${import_picocolors12.default.white("-h, --help")} ${import_picocolors12.default.dim("show this help")}`,
|
|
9076
|
+
"",
|
|
9077
|
+
` ${import_picocolors12.default.bold("Links")}`,
|
|
9078
|
+
` ${import_picocolors12.default.dim("Docs:")} ${import_picocolors12.default.green("https://www.codeagent-mobile.com")}`,
|
|
9079
|
+
` ${import_picocolors12.default.dim("Issues:")} ${import_picocolors12.default.green("https://github.com/edgar-durand/codeagent-mobile-clients/issues")}`,
|
|
9080
|
+
""
|
|
9081
|
+
];
|
|
9082
|
+
process.stdout.write(lines.join("\n") + "\n");
|
|
9083
|
+
}
|
|
9084
|
+
|
|
9085
|
+
// src/lib/updateNotifier.ts
|
|
9086
|
+
var fs10 = __toESM(require("fs"));
|
|
9087
|
+
var os9 = __toESM(require("os"));
|
|
9088
|
+
var path17 = __toESM(require("path"));
|
|
9089
|
+
var https4 = __toESM(require("https"));
|
|
9090
|
+
var import_picocolors13 = __toESM(require("picocolors"));
|
|
9091
|
+
var PKG_NAME = "codeam-cli";
|
|
9092
|
+
var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
9093
|
+
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
9094
|
+
var REQUEST_TIMEOUT_MS = 1500;
|
|
9095
|
+
function cachePath() {
|
|
9096
|
+
const dir = path17.join(os9.homedir(), ".codeam");
|
|
9097
|
+
return path17.join(dir, "update-check.json");
|
|
9098
|
+
}
|
|
9099
|
+
function readCache() {
|
|
9100
|
+
try {
|
|
9101
|
+
const raw = fs10.readFileSync(cachePath(), "utf8");
|
|
9102
|
+
const parsed = JSON.parse(raw);
|
|
9103
|
+
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
9104
|
+
return parsed;
|
|
9105
|
+
} catch {
|
|
9106
|
+
return null;
|
|
9107
|
+
}
|
|
9108
|
+
}
|
|
9109
|
+
function writeCache(cache) {
|
|
9110
|
+
try {
|
|
9111
|
+
const file = cachePath();
|
|
9112
|
+
fs10.mkdirSync(path17.dirname(file), { recursive: true });
|
|
9113
|
+
fs10.writeFileSync(file, JSON.stringify(cache));
|
|
9114
|
+
} catch {
|
|
9115
|
+
}
|
|
9116
|
+
}
|
|
9117
|
+
function compareSemver(a, b) {
|
|
9118
|
+
const stripPre = (s) => s.split("-")[0];
|
|
9119
|
+
const aParts = stripPre(a).split(".").map(Number);
|
|
9120
|
+
const bParts = stripPre(b).split(".").map(Number);
|
|
9121
|
+
for (let i = 0; i < 3; i++) {
|
|
9122
|
+
const ai = aParts[i] ?? 0;
|
|
9123
|
+
const bi = bParts[i] ?? 0;
|
|
9124
|
+
if (Number.isNaN(ai) || Number.isNaN(bi)) return 0;
|
|
9125
|
+
if (ai > bi) return 1;
|
|
9126
|
+
if (ai < bi) return -1;
|
|
9127
|
+
}
|
|
9128
|
+
return 0;
|
|
9129
|
+
}
|
|
9130
|
+
function fetchLatest() {
|
|
9131
|
+
return new Promise((resolve2) => {
|
|
9132
|
+
const req = https4.get(
|
|
9133
|
+
REGISTRY_URL,
|
|
9134
|
+
{ headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
|
|
9135
|
+
(res) => {
|
|
9136
|
+
if (res.statusCode !== 200) {
|
|
9137
|
+
res.resume();
|
|
9138
|
+
resolve2(null);
|
|
9139
|
+
return;
|
|
9140
|
+
}
|
|
9141
|
+
let buf = "";
|
|
9142
|
+
res.setEncoding("utf8");
|
|
9143
|
+
res.on("data", (chunk) => {
|
|
9144
|
+
buf += chunk;
|
|
9145
|
+
});
|
|
9146
|
+
res.on("end", () => {
|
|
9147
|
+
try {
|
|
9148
|
+
const json = JSON.parse(buf);
|
|
9149
|
+
if (typeof json.version === "string") {
|
|
9150
|
+
resolve2(json.version);
|
|
9151
|
+
} else {
|
|
9152
|
+
resolve2(null);
|
|
9153
|
+
}
|
|
9154
|
+
} catch {
|
|
9155
|
+
resolve2(null);
|
|
9156
|
+
}
|
|
9157
|
+
});
|
|
9158
|
+
}
|
|
9159
|
+
);
|
|
9160
|
+
req.on("timeout", () => {
|
|
9161
|
+
req.destroy();
|
|
9162
|
+
resolve2(null);
|
|
9163
|
+
});
|
|
9164
|
+
req.on("error", () => resolve2(null));
|
|
9165
|
+
});
|
|
9166
|
+
}
|
|
9167
|
+
function notifyIfStale(currentVersion, latest) {
|
|
9168
|
+
if (compareSemver(latest, currentVersion) <= 0) return;
|
|
9169
|
+
const arrow = import_picocolors13.default.dim("\u2192");
|
|
9170
|
+
const cmd = import_picocolors13.default.cyan("npm install -g codeam-cli");
|
|
9171
|
+
const lines = [
|
|
9172
|
+
"",
|
|
9173
|
+
` ${import_picocolors13.default.yellow("\u25CF")} ${import_picocolors13.default.bold("Update available")} ${import_picocolors13.default.dim(currentVersion)} ${arrow} ${import_picocolors13.default.green(latest)}`,
|
|
9174
|
+
` Run ${cmd} to upgrade.`,
|
|
9175
|
+
""
|
|
9176
|
+
];
|
|
9177
|
+
process.stderr.write(lines.join("\n"));
|
|
9178
|
+
}
|
|
9179
|
+
function checkForUpdates() {
|
|
9180
|
+
if (process.env.NODE_ENV === "test") return;
|
|
9181
|
+
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
9182
|
+
if (process.env.CI) return;
|
|
9183
|
+
if (!process.stdout.isTTY) return;
|
|
9184
|
+
const current = true ? "2.4.35" : null;
|
|
9185
|
+
if (!current) return;
|
|
9186
|
+
const cache = readCache();
|
|
9187
|
+
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
9188
|
+
if (fresh && cache) {
|
|
9189
|
+
notifyIfStale(current, cache.latest);
|
|
9190
|
+
return;
|
|
9191
|
+
}
|
|
9192
|
+
void fetchLatest().then((latest) => {
|
|
9193
|
+
if (!latest) return;
|
|
9194
|
+
writeCache({ fetchedAt: Date.now(), latest });
|
|
9195
|
+
});
|
|
9196
|
+
}
|
|
9197
|
+
|
|
8880
9198
|
// src/index.ts
|
|
8881
9199
|
var [, , command, ...args] = process.argv;
|
|
8882
9200
|
async function main() {
|
|
9201
|
+
const isMetaCommand = command === "--version" || command === "-v" || command === "version" || command === "--help" || command === "-h" || command === "help";
|
|
9202
|
+
if (!isMetaCommand) checkForUpdates();
|
|
8883
9203
|
switch (command) {
|
|
9204
|
+
case "--version":
|
|
9205
|
+
case "-v":
|
|
9206
|
+
case "version":
|
|
9207
|
+
return version();
|
|
9208
|
+
case "--help":
|
|
9209
|
+
case "-h":
|
|
9210
|
+
case "help":
|
|
9211
|
+
return help();
|
|
8884
9212
|
case "pair":
|
|
8885
9213
|
return pair();
|
|
8886
9214
|
case "sessions":
|