codeam-cli 2.15.5 → 2.15.7
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 +20 -0
- package/README.md +1 -1
- package/dist/index.js +552 -75
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@ 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.15.6] — 2026-05-20
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Send current git branch on pair
|
|
12
|
+
- **vsc-plugin:** Emit file-change + review-hunk events from Path B (direct claude)
|
|
13
|
+
- **jetbrains-plugin:** Emit file-change + review-hunk events from Path B
|
|
14
|
+
- **cli:** Epic C — emit streaming chunks + subscribe to answer channel
|
|
15
|
+
|
|
16
|
+
## [2.15.5] — 2026-05-20
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **shared:** Add FileChangedEvent + PendingReviewHunkEvent wire types
|
|
21
|
+
- **cli:** Emit file-change + review-hunk events during paired sessions
|
|
22
|
+
|
|
23
|
+
### CI
|
|
24
|
+
|
|
25
|
+
- **release:** Make CLI npm publish idempotent
|
|
26
|
+
|
|
7
27
|
## [2.15.1] — 2026-05-17
|
|
8
28
|
|
|
9
29
|
### Fixed
|
package/README.md
CHANGED
|
@@ -111,7 +111,7 @@ Adding more cloud backends (Gitpod, Coder, your own SSH host, …) is a single n
|
|
|
111
111
|
|
|
112
112
|
| Variable | Default | Effect |
|
|
113
113
|
|---|---|---|
|
|
114
|
-
| `CODEAM_API_URL` | `https://codeagent-mobile
|
|
114
|
+
| `CODEAM_API_URL` | `https://api.codeagent-mobile.com` | Override the backend relay URL. Useful for hitting a staging environment or self-hosted backend. |
|
|
115
115
|
| `CODEAM_DISABLE_UPDATE_CHECK` | unset | Set to `1` to suppress the "update available" banner. The check also auto-skips on non-TTY stdout, when `CI=true`, and during tests. |
|
|
116
116
|
| `CODEAM_AUTO_TOKEN` | unset | One-shot pairing token consumed by `codeam pair-auto`. Used by the `codeam deploy` bootstrap; see *Advanced / scripted pairing* below. |
|
|
117
117
|
|
package/dist/index.js
CHANGED
|
@@ -284,6 +284,9 @@ function isKnownAgentId(id) {
|
|
|
284
284
|
return id === "claude" || id === "codex" || id === "copilot";
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
// ../../packages/shared/src/api-url.ts
|
|
288
|
+
var DEFAULT_API_BASE_URL = "https://api.codeagent-mobile.com";
|
|
289
|
+
|
|
287
290
|
// src/config.ts
|
|
288
291
|
var fs = __toESM(require("fs"));
|
|
289
292
|
var os = __toESM(require("os"));
|
|
@@ -386,7 +389,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
386
389
|
// package.json
|
|
387
390
|
var package_default = {
|
|
388
391
|
name: "codeam-cli",
|
|
389
|
-
version: "2.15.
|
|
392
|
+
version: "2.15.7",
|
|
390
393
|
description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
|
|
391
394
|
type: "commonjs",
|
|
392
395
|
main: "dist/index.js",
|
|
@@ -521,6 +524,34 @@ function vercelBypassHeader() {
|
|
|
521
524
|
return token ? { "x-vercel-protection-bypass": token } : {};
|
|
522
525
|
}
|
|
523
526
|
|
|
527
|
+
// src/lib/git-branch.ts
|
|
528
|
+
var import_child_process = require("child_process");
|
|
529
|
+
function detectCurrentBranch(cwd = process.cwd()) {
|
|
530
|
+
try {
|
|
531
|
+
const raw = _execSeam.exec("git branch --show-current", {
|
|
532
|
+
cwd,
|
|
533
|
+
// 1 s ceiling is comfortably above normal git latency (<50 ms
|
|
534
|
+
// on a healthy repo) and well below the pair POST's 10 s budget.
|
|
535
|
+
timeout: 1e3,
|
|
536
|
+
// Swallow stderr — non-git directories print "fatal: not a git
|
|
537
|
+
// repository" to stderr and we don't want that on the CLI's
|
|
538
|
+
// own stderr while pairing.
|
|
539
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
540
|
+
encoding: "utf8"
|
|
541
|
+
});
|
|
542
|
+
const trimmed = raw.trim();
|
|
543
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
544
|
+
} catch {
|
|
545
|
+
return null;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
var _execSeam = {
|
|
549
|
+
exec: (cmd, opts) => {
|
|
550
|
+
const out = (0, import_child_process.execSync)(cmd, opts);
|
|
551
|
+
return typeof out === "string" ? out : out.toString("utf8");
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
|
|
524
555
|
// src/lib/poll-delay.ts
|
|
525
556
|
var MAX_DELAY_MS = 3e4;
|
|
526
557
|
function computePollDelay({ baseMs, failures }) {
|
|
@@ -530,17 +561,19 @@ function computePollDelay({ baseMs, failures }) {
|
|
|
530
561
|
}
|
|
531
562
|
|
|
532
563
|
// src/services/pairing.service.ts
|
|
533
|
-
var API_BASE = process.env.CODEAM_API_URL ??
|
|
564
|
+
var API_BASE = process.env.CODEAM_API_URL ?? DEFAULT_API_BASE_URL;
|
|
534
565
|
async function requestCode(pluginId) {
|
|
535
566
|
try {
|
|
536
567
|
const runtime = process.env.CODESPACES === "true" ? "github-codespaces" : "local";
|
|
537
568
|
const codespaceName = process.env.CODESPACE_NAME;
|
|
569
|
+
const branch = detectCurrentBranch();
|
|
538
570
|
const result = await _transport.postJson(`${API_BASE}/api/pairing/code`, {
|
|
539
571
|
pluginId,
|
|
540
572
|
ideName: "Terminal (codeam-cli)",
|
|
541
573
|
ideVersion: package_default.version,
|
|
542
574
|
hostname: os2.hostname(),
|
|
543
575
|
runtime,
|
|
576
|
+
branch,
|
|
544
577
|
...codespaceName ? { codespaceName } : {}
|
|
545
578
|
});
|
|
546
579
|
const data = result?.data;
|
|
@@ -748,7 +781,7 @@ var log = {
|
|
|
748
781
|
};
|
|
749
782
|
|
|
750
783
|
// src/services/command-relay.service.ts
|
|
751
|
-
var API_BASE2 = process.env.CODEAM_API_URL ??
|
|
784
|
+
var API_BASE2 = process.env.CODEAM_API_URL ?? DEFAULT_API_BASE_URL;
|
|
752
785
|
var CommandRelayService = class {
|
|
753
786
|
constructor(pluginId, onCommand, agentMeta) {
|
|
754
787
|
this.pluginId = pluginId;
|
|
@@ -983,7 +1016,7 @@ var CommandRelayService = class {
|
|
|
983
1016
|
};
|
|
984
1017
|
|
|
985
1018
|
// src/services/pty/unix.strategy.ts
|
|
986
|
-
var
|
|
1019
|
+
var import_child_process2 = require("child_process");
|
|
987
1020
|
var fs4 = __toESM(require("fs"));
|
|
988
1021
|
var os4 = __toESM(require("os"));
|
|
989
1022
|
var path4 = __toESM(require("path"));
|
|
@@ -1087,7 +1120,7 @@ var UnixPtyStrategy = class {
|
|
|
1087
1120
|
const rows = process.stdout.rows || 50;
|
|
1088
1121
|
this.helperPath = path4.join(os4.tmpdir(), "codeam-pty-helper.py");
|
|
1089
1122
|
fs4.writeFileSync(this.helperPath, PYTHON_PTY_HELPER, { mode: 420 });
|
|
1090
|
-
this.proc = (0,
|
|
1123
|
+
this.proc = (0, import_child_process2.spawn)(python, [this.helperPath, cmd, ...args2], {
|
|
1091
1124
|
stdio: ["pipe", "pipe", "inherit"],
|
|
1092
1125
|
cwd,
|
|
1093
1126
|
env: {
|
|
@@ -1152,7 +1185,7 @@ var UnixPtyStrategy = class {
|
|
|
1152
1185
|
* are NOT interpreted by /bin/sh.
|
|
1153
1186
|
*/
|
|
1154
1187
|
spawnDirect(cmd, cwd, args2 = []) {
|
|
1155
|
-
this.proc = (0,
|
|
1188
|
+
this.proc = (0, import_child_process2.spawn)(cmd, args2, {
|
|
1156
1189
|
stdio: ["pipe", "inherit", "inherit"],
|
|
1157
1190
|
cwd,
|
|
1158
1191
|
env: process.env,
|
|
@@ -1224,7 +1257,7 @@ var UnixPtyStrategy = class {
|
|
|
1224
1257
|
};
|
|
1225
1258
|
|
|
1226
1259
|
// src/services/pty/windows.strategy.ts
|
|
1227
|
-
var
|
|
1260
|
+
var import_child_process3 = require("child_process");
|
|
1228
1261
|
var WindowsPtyStrategy = class {
|
|
1229
1262
|
constructor(opts) {
|
|
1230
1263
|
this.opts = opts;
|
|
@@ -1232,7 +1265,7 @@ var WindowsPtyStrategy = class {
|
|
|
1232
1265
|
opts;
|
|
1233
1266
|
proc = null;
|
|
1234
1267
|
spawn(cmd, cwd, args2 = []) {
|
|
1235
|
-
this.proc = (0,
|
|
1268
|
+
this.proc = (0, import_child_process3.spawn)(cmd, args2, {
|
|
1236
1269
|
stdio: ["pipe", "pipe", "inherit"],
|
|
1237
1270
|
cwd,
|
|
1238
1271
|
env: {
|
|
@@ -1408,7 +1441,7 @@ var WindowsConPtyStrategy = class _WindowsConPtyStrategy {
|
|
|
1408
1441
|
};
|
|
1409
1442
|
|
|
1410
1443
|
// src/services/claude-installer.ts
|
|
1411
|
-
var
|
|
1444
|
+
var import_child_process4 = require("child_process");
|
|
1412
1445
|
var path6 = __toESM(require("path"));
|
|
1413
1446
|
var os5 = __toESM(require("os"));
|
|
1414
1447
|
|
|
@@ -3361,7 +3394,7 @@ function runInstaller() {
|
|
|
3361
3394
|
"irm https://claude.ai/install.ps1 | iex"
|
|
3362
3395
|
] : ["-c", "curl -fsSL https://claude.ai/install.sh | bash"];
|
|
3363
3396
|
return new Promise((resolve2) => {
|
|
3364
|
-
const proc = (0,
|
|
3397
|
+
const proc = (0, import_child_process4.spawn)(cmd, args2, { stdio: "inherit" });
|
|
3365
3398
|
proc.on("error", (err) => {
|
|
3366
3399
|
console.error(`
|
|
3367
3400
|
\u2717 Installer failed to launch: ${err.message}`);
|
|
@@ -3660,7 +3693,7 @@ var AgentService = class {
|
|
|
3660
3693
|
var fs5 = __toESM(require("fs"));
|
|
3661
3694
|
var os6 = __toESM(require("os"));
|
|
3662
3695
|
var path8 = __toESM(require("path"));
|
|
3663
|
-
var
|
|
3696
|
+
var import_child_process5 = require("child_process");
|
|
3664
3697
|
var HELPER_SCRIPT = `import os,pty,sys,select,signal,struct,fcntl,termios,errno
|
|
3665
3698
|
m,s=pty.openpty()
|
|
3666
3699
|
try:
|
|
@@ -3729,7 +3762,7 @@ async function fetchClaudeQuota() {
|
|
|
3729
3762
|
resolve2(null);
|
|
3730
3763
|
return;
|
|
3731
3764
|
}
|
|
3732
|
-
const proc = (0,
|
|
3765
|
+
const proc = (0, import_child_process5.spawn)(python, [helperPath, claudeCmd, "--tools", ""], {
|
|
3733
3766
|
stdio: ["pipe", "pipe", "ignore"],
|
|
3734
3767
|
cwd: process.cwd(),
|
|
3735
3768
|
env: { ...process.env, TERM: "dumb", COLUMNS: "120", LINES: "30" }
|
|
@@ -4192,12 +4225,12 @@ var os9 = __toESM(require("os"));
|
|
|
4192
4225
|
var path11 = __toESM(require("path"));
|
|
4193
4226
|
|
|
4194
4227
|
// src/agents/claude/credentials.ts
|
|
4195
|
-
var
|
|
4228
|
+
var import_child_process6 = require("child_process");
|
|
4196
4229
|
var fs7 = __toESM(require("fs"));
|
|
4197
4230
|
var os8 = __toESM(require("os"));
|
|
4198
4231
|
var path10 = __toESM(require("path"));
|
|
4199
4232
|
var import_util = require("util");
|
|
4200
|
-
var execFileP = (0, import_util.promisify)(
|
|
4233
|
+
var execFileP = (0, import_util.promisify)(import_child_process6.execFile);
|
|
4201
4234
|
async function detectLocalClaudeCredentials() {
|
|
4202
4235
|
const localClaudeDir = path10.join(os8.homedir(), ".claude");
|
|
4203
4236
|
const flat = path10.join(localClaudeDir, ".credentials.json");
|
|
@@ -5164,7 +5197,7 @@ var ChromeStepTracker = class {
|
|
|
5164
5197
|
// src/services/output/chunk-emitter.ts
|
|
5165
5198
|
var https3 = __toESM(require("https"));
|
|
5166
5199
|
var http3 = __toESM(require("http"));
|
|
5167
|
-
var API_BASE3 = process.env.CODEAM_API_URL ??
|
|
5200
|
+
var API_BASE3 = process.env.CODEAM_API_URL ?? DEFAULT_API_BASE_URL;
|
|
5168
5201
|
var ChunkEmitter = class {
|
|
5169
5202
|
constructor(opts) {
|
|
5170
5203
|
this.opts = opts;
|
|
@@ -5653,7 +5686,7 @@ var historyRecordSchema = import_zod.z.object({
|
|
|
5653
5686
|
content: import_zod.z.union([import_zod.z.string(), import_zod.z.array(import_zod.z.unknown())]).optional()
|
|
5654
5687
|
}).passthrough().optional()
|
|
5655
5688
|
}).passthrough();
|
|
5656
|
-
var API_BASE4 = process.env.CODEAM_API_URL ??
|
|
5689
|
+
var API_BASE4 = process.env.CODEAM_API_URL ?? DEFAULT_API_BASE_URL;
|
|
5657
5690
|
function extractText2(content) {
|
|
5658
5691
|
if (typeof content === "string") return content;
|
|
5659
5692
|
if (Array.isArray(content)) {
|
|
@@ -6127,7 +6160,7 @@ var HistoryService = class _HistoryService {
|
|
|
6127
6160
|
};
|
|
6128
6161
|
|
|
6129
6162
|
// src/services/file-watcher.service.ts
|
|
6130
|
-
var
|
|
6163
|
+
var import_child_process7 = require("child_process");
|
|
6131
6164
|
var path15 = __toESM(require("path"));
|
|
6132
6165
|
|
|
6133
6166
|
// src/services/file-watcher/diff-parser.ts
|
|
@@ -6259,7 +6292,7 @@ function _post2(url, headers, payload) {
|
|
|
6259
6292
|
}
|
|
6260
6293
|
|
|
6261
6294
|
// src/services/file-watcher.service.ts
|
|
6262
|
-
var API_BASE5 = process.env.CODEAM_API_URL ??
|
|
6295
|
+
var API_BASE5 = process.env.CODEAM_API_URL ?? DEFAULT_API_BASE_URL;
|
|
6263
6296
|
var DEBOUNCE_MS = 250;
|
|
6264
6297
|
var MAX_RETRIES = 2;
|
|
6265
6298
|
var RETRY_BACKOFF_MS = 300;
|
|
@@ -6552,7 +6585,7 @@ async function _runGitImpl(cwd, args2, opts = {}) {
|
|
|
6552
6585
|
return new Promise((resolve2) => {
|
|
6553
6586
|
let proc;
|
|
6554
6587
|
try {
|
|
6555
|
-
proc = (0,
|
|
6588
|
+
proc = (0, import_child_process7.spawn)("git", args2, { cwd, env: process.env });
|
|
6556
6589
|
} catch {
|
|
6557
6590
|
resolve2(null);
|
|
6558
6591
|
return;
|
|
@@ -6580,6 +6613,432 @@ function _runGit(cwd, args2, opts = {}) {
|
|
|
6580
6613
|
return _gitSeam.run(cwd, args2, opts);
|
|
6581
6614
|
}
|
|
6582
6615
|
|
|
6616
|
+
// src/services/streaming-emitter.service.ts
|
|
6617
|
+
var import_crypto = require("crypto");
|
|
6618
|
+
|
|
6619
|
+
// src/services/streaming/transport.ts
|
|
6620
|
+
var http6 = __toESM(require("http"));
|
|
6621
|
+
var https6 = __toESM(require("https"));
|
|
6622
|
+
var _transport4 = {
|
|
6623
|
+
post: _post3,
|
|
6624
|
+
get: _get
|
|
6625
|
+
};
|
|
6626
|
+
function _post3(url, headers, payload) {
|
|
6627
|
+
return new Promise((resolve2, reject) => {
|
|
6628
|
+
let settled = false;
|
|
6629
|
+
const u2 = new URL(url);
|
|
6630
|
+
const lib = u2.protocol === "https:" ? https6 : http6;
|
|
6631
|
+
const req = lib.request(
|
|
6632
|
+
{
|
|
6633
|
+
hostname: u2.hostname,
|
|
6634
|
+
port: u2.port || (u2.protocol === "https:" ? 443 : 80),
|
|
6635
|
+
path: u2.pathname + u2.search,
|
|
6636
|
+
method: "POST",
|
|
6637
|
+
headers: {
|
|
6638
|
+
...headers,
|
|
6639
|
+
...vercelBypassHeader(),
|
|
6640
|
+
"Content-Length": Buffer.byteLength(payload)
|
|
6641
|
+
},
|
|
6642
|
+
timeout: 8e3
|
|
6643
|
+
},
|
|
6644
|
+
(res) => {
|
|
6645
|
+
let body = "";
|
|
6646
|
+
res.on("data", (c2) => {
|
|
6647
|
+
body += c2.toString();
|
|
6648
|
+
});
|
|
6649
|
+
res.on("end", () => {
|
|
6650
|
+
if (settled) return;
|
|
6651
|
+
settled = true;
|
|
6652
|
+
resolve2({ statusCode: res.statusCode ?? 0, body });
|
|
6653
|
+
});
|
|
6654
|
+
}
|
|
6655
|
+
);
|
|
6656
|
+
req.on("error", (err) => {
|
|
6657
|
+
if (settled) return;
|
|
6658
|
+
settled = true;
|
|
6659
|
+
reject(err);
|
|
6660
|
+
});
|
|
6661
|
+
req.on("timeout", () => {
|
|
6662
|
+
req.destroy();
|
|
6663
|
+
});
|
|
6664
|
+
req.write(payload);
|
|
6665
|
+
req.end();
|
|
6666
|
+
});
|
|
6667
|
+
}
|
|
6668
|
+
function _get(url, headers) {
|
|
6669
|
+
return new Promise((resolve2, reject) => {
|
|
6670
|
+
let settled = false;
|
|
6671
|
+
const u2 = new URL(url);
|
|
6672
|
+
const lib = u2.protocol === "https:" ? https6 : http6;
|
|
6673
|
+
const req = lib.request(
|
|
6674
|
+
{
|
|
6675
|
+
hostname: u2.hostname,
|
|
6676
|
+
port: u2.port || (u2.protocol === "https:" ? 443 : 80),
|
|
6677
|
+
path: u2.pathname + u2.search,
|
|
6678
|
+
method: "GET",
|
|
6679
|
+
headers: {
|
|
6680
|
+
...headers,
|
|
6681
|
+
...vercelBypassHeader()
|
|
6682
|
+
},
|
|
6683
|
+
timeout: 8e3
|
|
6684
|
+
},
|
|
6685
|
+
(res) => {
|
|
6686
|
+
let body = "";
|
|
6687
|
+
res.on("data", (c2) => {
|
|
6688
|
+
body += c2.toString();
|
|
6689
|
+
});
|
|
6690
|
+
res.on("end", () => {
|
|
6691
|
+
if (settled) return;
|
|
6692
|
+
settled = true;
|
|
6693
|
+
resolve2({ statusCode: res.statusCode ?? 0, body });
|
|
6694
|
+
});
|
|
6695
|
+
}
|
|
6696
|
+
);
|
|
6697
|
+
req.on("error", (err) => {
|
|
6698
|
+
if (settled) return;
|
|
6699
|
+
settled = true;
|
|
6700
|
+
reject(err);
|
|
6701
|
+
});
|
|
6702
|
+
req.on("timeout", () => {
|
|
6703
|
+
req.destroy();
|
|
6704
|
+
});
|
|
6705
|
+
req.end();
|
|
6706
|
+
});
|
|
6707
|
+
}
|
|
6708
|
+
|
|
6709
|
+
// src/services/streaming-emitter.service.ts
|
|
6710
|
+
var API_BASE6 = process.env.CODEAM_API_URL ?? DEFAULT_API_BASE_URL;
|
|
6711
|
+
var TICK_MS = 50;
|
|
6712
|
+
var ANSWER_POLL_MS = 1500;
|
|
6713
|
+
var SELECTOR_STABLE_MS = 800;
|
|
6714
|
+
var MAX_RETRIES2 = 1;
|
|
6715
|
+
var RETRY_BACKOFF_MS2 = 200;
|
|
6716
|
+
var StreamingEmitterService = class {
|
|
6717
|
+
constructor(opts) {
|
|
6718
|
+
this.opts = opts;
|
|
6719
|
+
this.apiBase = opts.apiBaseUrl ?? API_BASE6;
|
|
6720
|
+
this.headers = {
|
|
6721
|
+
"Content-Type": "application/json",
|
|
6722
|
+
"X-Codeam-Protocol-Version": "2.0.0",
|
|
6723
|
+
"X-Plugin-Auth-Token": opts.pluginAuthToken
|
|
6724
|
+
};
|
|
6725
|
+
}
|
|
6726
|
+
opts;
|
|
6727
|
+
apiBase;
|
|
6728
|
+
headers;
|
|
6729
|
+
rawBuffer = "";
|
|
6730
|
+
active = false;
|
|
6731
|
+
tickTimer = null;
|
|
6732
|
+
answerPollTimer = null;
|
|
6733
|
+
/** Open chunk we're appending bytes to; cleared on kind change or stop. */
|
|
6734
|
+
activeChunk = null;
|
|
6735
|
+
/** Outstanding answer we're polling the backend for. Null when idle. */
|
|
6736
|
+
pendingAnswer = null;
|
|
6737
|
+
/**
|
|
6738
|
+
* Memoised selector signature so we don't fire `awaiting-answer` on
|
|
6739
|
+
* every tick while the user thinks. Cleared once an answer resolves.
|
|
6740
|
+
*/
|
|
6741
|
+
lastSelectorSignature = null;
|
|
6742
|
+
selectorFirstSeenAt = 0;
|
|
6743
|
+
// ─── Lifecycle ─────────────────────────────────────────────────────
|
|
6744
|
+
start() {
|
|
6745
|
+
if (this.active) return;
|
|
6746
|
+
this.active = true;
|
|
6747
|
+
this.tickTimer = setInterval(() => this.tick(), TICK_MS);
|
|
6748
|
+
this.answerPollTimer = setInterval(() => {
|
|
6749
|
+
void this.pollPendingAnswer();
|
|
6750
|
+
}, ANSWER_POLL_MS);
|
|
6751
|
+
log.trace("streamingEmitter", `started session=${this.opts.sessionId.slice(0, 8)}`);
|
|
6752
|
+
}
|
|
6753
|
+
/**
|
|
6754
|
+
* Stop the emitter. Finalises the open chunk (if any) so the
|
|
6755
|
+
* backend doesn't leave a half-streamed message in the SSE
|
|
6756
|
+
* buffer. Idempotent.
|
|
6757
|
+
*/
|
|
6758
|
+
async stop() {
|
|
6759
|
+
if (!this.active) return;
|
|
6760
|
+
this.active = false;
|
|
6761
|
+
if (this.tickTimer) {
|
|
6762
|
+
clearInterval(this.tickTimer);
|
|
6763
|
+
this.tickTimer = null;
|
|
6764
|
+
}
|
|
6765
|
+
if (this.answerPollTimer) {
|
|
6766
|
+
clearInterval(this.answerPollTimer);
|
|
6767
|
+
this.answerPollTimer = null;
|
|
6768
|
+
}
|
|
6769
|
+
if (this.activeChunk) {
|
|
6770
|
+
const finalContent = this.activeChunk.currentContent;
|
|
6771
|
+
const chunk = this.activeChunk;
|
|
6772
|
+
this.activeChunk = null;
|
|
6773
|
+
await this.postChunk({
|
|
6774
|
+
chunkId: chunk.chunkId,
|
|
6775
|
+
kind: chunk.kind,
|
|
6776
|
+
content: finalContent,
|
|
6777
|
+
isFinal: true
|
|
6778
|
+
});
|
|
6779
|
+
}
|
|
6780
|
+
log.trace("streamingEmitter", `stopped session=${this.opts.sessionId.slice(0, 8)}`);
|
|
6781
|
+
}
|
|
6782
|
+
// ─── Input pump ────────────────────────────────────────────────────
|
|
6783
|
+
/**
|
|
6784
|
+
* Forward a chunk of raw PTY bytes into the emitter. Safe to call
|
|
6785
|
+
* before `start()` — bytes accumulate in the internal buffer and the
|
|
6786
|
+
* first tick processes the backlog.
|
|
6787
|
+
*/
|
|
6788
|
+
push(raw) {
|
|
6789
|
+
if (raw.length === 0) return;
|
|
6790
|
+
this.rawBuffer += raw;
|
|
6791
|
+
}
|
|
6792
|
+
// ─── Tick ──────────────────────────────────────────────────────────
|
|
6793
|
+
/**
|
|
6794
|
+
* Visible for tests. Runs one classify-and-emit pass against the
|
|
6795
|
+
* current PTY buffer.
|
|
6796
|
+
*/
|
|
6797
|
+
/* @internal */
|
|
6798
|
+
_tickForTest() {
|
|
6799
|
+
this.tick();
|
|
6800
|
+
}
|
|
6801
|
+
tick() {
|
|
6802
|
+
if (!this.active) return;
|
|
6803
|
+
const lines = (this.opts.runtime.renderToLines ?? renderToLines)(this.rawBuffer);
|
|
6804
|
+
const selector = this.opts.runtime.detectInteractivePrompt(lines);
|
|
6805
|
+
if (selector) {
|
|
6806
|
+
this.maybeEmitAwaitingAnswer(selector);
|
|
6807
|
+
return;
|
|
6808
|
+
}
|
|
6809
|
+
this.lastSelectorSignature = null;
|
|
6810
|
+
this.selectorFirstSeenAt = 0;
|
|
6811
|
+
const groups = this.classifyLines(lines, this.opts.runtime);
|
|
6812
|
+
if (groups.length === 0) return;
|
|
6813
|
+
const last = groups[groups.length - 1];
|
|
6814
|
+
if (this.activeChunk && this.activeChunk.kind === last.kind) {
|
|
6815
|
+
this.activeChunk.currentContent = last.content;
|
|
6816
|
+
this.maybeFlushActive(false);
|
|
6817
|
+
return;
|
|
6818
|
+
}
|
|
6819
|
+
if (this.activeChunk) {
|
|
6820
|
+
const closing = this.activeChunk;
|
|
6821
|
+
this.activeChunk = null;
|
|
6822
|
+
void this.postChunk({
|
|
6823
|
+
chunkId: closing.chunkId,
|
|
6824
|
+
kind: closing.kind,
|
|
6825
|
+
content: closing.currentContent,
|
|
6826
|
+
isFinal: true
|
|
6827
|
+
});
|
|
6828
|
+
}
|
|
6829
|
+
this.activeChunk = {
|
|
6830
|
+
chunkId: (0, import_crypto.randomUUID)(),
|
|
6831
|
+
kind: last.kind,
|
|
6832
|
+
emittedContent: "",
|
|
6833
|
+
currentContent: last.content,
|
|
6834
|
+
lastEmitAt: 0
|
|
6835
|
+
};
|
|
6836
|
+
this.maybeFlushActive(false);
|
|
6837
|
+
}
|
|
6838
|
+
maybeFlushActive(force) {
|
|
6839
|
+
const chunk = this.activeChunk;
|
|
6840
|
+
if (!chunk) return;
|
|
6841
|
+
const now = Date.now();
|
|
6842
|
+
if (!force && now - chunk.lastEmitAt < TICK_MS) return;
|
|
6843
|
+
if (chunk.currentContent === chunk.emittedContent) return;
|
|
6844
|
+
chunk.emittedContent = chunk.currentContent;
|
|
6845
|
+
chunk.lastEmitAt = now;
|
|
6846
|
+
void this.postChunk({
|
|
6847
|
+
chunkId: chunk.chunkId,
|
|
6848
|
+
kind: chunk.kind,
|
|
6849
|
+
content: chunk.currentContent,
|
|
6850
|
+
isFinal: false
|
|
6851
|
+
});
|
|
6852
|
+
}
|
|
6853
|
+
// ─── Line classification ───────────────────────────────────────────
|
|
6854
|
+
/**
|
|
6855
|
+
* Walk the rendered screen lines and bucket them into kind-groups.
|
|
6856
|
+
*
|
|
6857
|
+
* Visible for tests so we can assert discrimination against fixture
|
|
6858
|
+
* inputs without standing up the full POST loop.
|
|
6859
|
+
*/
|
|
6860
|
+
/* @internal */
|
|
6861
|
+
_classifyForTest(lines) {
|
|
6862
|
+
return this.classifyLines(lines, this.opts.runtime);
|
|
6863
|
+
}
|
|
6864
|
+
classifyLines(lines, runtime) {
|
|
6865
|
+
const parseLine2 = runtime.parseTuiChrome?.bind(runtime);
|
|
6866
|
+
const groups = [];
|
|
6867
|
+
let current = null;
|
|
6868
|
+
const flush = () => {
|
|
6869
|
+
if (!current) return;
|
|
6870
|
+
const text = current.lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
6871
|
+
if (text.length > 0) groups.push({ kind: current.kind, content: text });
|
|
6872
|
+
current = null;
|
|
6873
|
+
};
|
|
6874
|
+
for (const rawLine of lines) {
|
|
6875
|
+
const kind = classifyLine(rawLine, parseLine2, runtime);
|
|
6876
|
+
if (kind === null) continue;
|
|
6877
|
+
if (!current || current.kind !== kind) {
|
|
6878
|
+
flush();
|
|
6879
|
+
current = { kind, lines: [rawLine] };
|
|
6880
|
+
} else {
|
|
6881
|
+
current.lines.push(rawLine);
|
|
6882
|
+
}
|
|
6883
|
+
}
|
|
6884
|
+
flush();
|
|
6885
|
+
return groups;
|
|
6886
|
+
}
|
|
6887
|
+
// ─── Awaiting-answer + answer subscription ─────────────────────────
|
|
6888
|
+
maybeEmitAwaitingAnswer(selector) {
|
|
6889
|
+
const signature = `${selector.question}::${selector.options.join("|")}`;
|
|
6890
|
+
const now = Date.now();
|
|
6891
|
+
if (this.lastSelectorSignature !== signature) {
|
|
6892
|
+
this.lastSelectorSignature = signature;
|
|
6893
|
+
this.selectorFirstSeenAt = now;
|
|
6894
|
+
return;
|
|
6895
|
+
}
|
|
6896
|
+
if (this.pendingAnswer) return;
|
|
6897
|
+
if (now - this.selectorFirstSeenAt < SELECTOR_STABLE_MS) return;
|
|
6898
|
+
const questionId = (0, import_crypto.randomUUID)();
|
|
6899
|
+
this.pendingAnswer = {
|
|
6900
|
+
questionId,
|
|
6901
|
+
options: selector.options.length > 0 ? selector.options : void 0,
|
|
6902
|
+
fromIndex: selector.currentIndex
|
|
6903
|
+
};
|
|
6904
|
+
const event = {
|
|
6905
|
+
questionId,
|
|
6906
|
+
prompt: selector.question,
|
|
6907
|
+
...selector.options.length > 0 ? { options: selector.options } : {}
|
|
6908
|
+
};
|
|
6909
|
+
void this.postAwaitingAnswer(event);
|
|
6910
|
+
}
|
|
6911
|
+
async pollPendingAnswer() {
|
|
6912
|
+
if (!this.active) return;
|
|
6913
|
+
if (!this.pendingAnswer) return;
|
|
6914
|
+
const questionId = this.pendingAnswer.questionId;
|
|
6915
|
+
try {
|
|
6916
|
+
const { statusCode, body } = await _transport4.get(
|
|
6917
|
+
`${this.apiBase}/api/sessions/${encodeURIComponent(this.opts.sessionId)}/pending-answer?questionId=${encodeURIComponent(questionId)}`,
|
|
6918
|
+
this.headers
|
|
6919
|
+
);
|
|
6920
|
+
if (statusCode === 204 || statusCode === 404) {
|
|
6921
|
+
return;
|
|
6922
|
+
}
|
|
6923
|
+
if (statusCode < 200 || statusCode >= 300) {
|
|
6924
|
+
log.warn("streamingEmitter", `pending-answer status=${statusCode} body=${body.slice(0, 200)}`);
|
|
6925
|
+
return;
|
|
6926
|
+
}
|
|
6927
|
+
const parsed = parsePendingAnswerResponse(body);
|
|
6928
|
+
if (!parsed || parsed.questionId !== questionId) return;
|
|
6929
|
+
const pending = this.pendingAnswer;
|
|
6930
|
+
this.pendingAnswer = null;
|
|
6931
|
+
this.lastSelectorSignature = null;
|
|
6932
|
+
this.selectorFirstSeenAt = 0;
|
|
6933
|
+
this.deliverAnswer(parsed, pending);
|
|
6934
|
+
} catch (err) {
|
|
6935
|
+
log.trace("streamingEmitter", "pending-answer poll failed", err);
|
|
6936
|
+
}
|
|
6937
|
+
}
|
|
6938
|
+
deliverAnswer(answer, pending) {
|
|
6939
|
+
if (pending.options && pending.options.length > 0) {
|
|
6940
|
+
let targetIndex = answer.optionIndex ?? -1;
|
|
6941
|
+
if (targetIndex < 0) {
|
|
6942
|
+
targetIndex = pending.options.findIndex((o) => o === answer.answer);
|
|
6943
|
+
}
|
|
6944
|
+
if (targetIndex < 0 || targetIndex >= pending.options.length) {
|
|
6945
|
+
log.warn(
|
|
6946
|
+
"streamingEmitter",
|
|
6947
|
+
`answer label "${answer.answer}" not found in selector options \u2014 defaulting to 0`
|
|
6948
|
+
);
|
|
6949
|
+
targetIndex = 0;
|
|
6950
|
+
}
|
|
6951
|
+
this.opts.ptyInput.selectOption(targetIndex, pending.fromIndex ?? 0);
|
|
6952
|
+
return;
|
|
6953
|
+
}
|
|
6954
|
+
this.opts.ptyInput.sendCommand(answer.answer);
|
|
6955
|
+
}
|
|
6956
|
+
// ─── POSTs ─────────────────────────────────────────────────────────
|
|
6957
|
+
async postChunk(event) {
|
|
6958
|
+
await this.postWithRetries(
|
|
6959
|
+
`${this.apiBase}/api/sessions/${encodeURIComponent(this.opts.sessionId)}/streaming-chunk`,
|
|
6960
|
+
event
|
|
6961
|
+
);
|
|
6962
|
+
}
|
|
6963
|
+
async postAwaitingAnswer(event) {
|
|
6964
|
+
await this.postWithRetries(
|
|
6965
|
+
`${this.apiBase}/api/sessions/${encodeURIComponent(this.opts.sessionId)}/awaiting-answer`,
|
|
6966
|
+
event
|
|
6967
|
+
);
|
|
6968
|
+
}
|
|
6969
|
+
async postWithRetries(url, body) {
|
|
6970
|
+
const payload = JSON.stringify(body);
|
|
6971
|
+
for (let attempt = 0; attempt <= MAX_RETRIES2; attempt += 1) {
|
|
6972
|
+
try {
|
|
6973
|
+
const { statusCode, body: resBody } = await _transport4.post(url, this.headers, payload);
|
|
6974
|
+
if (statusCode >= 200 && statusCode < 300) {
|
|
6975
|
+
log.trace("streamingEmitter", `post ok url=${url} status=${statusCode}`);
|
|
6976
|
+
return;
|
|
6977
|
+
}
|
|
6978
|
+
if (statusCode === 410 || statusCode === 404) {
|
|
6979
|
+
log.warn("streamingEmitter", `session dead (status=${statusCode}) \u2014 disabling emitter`);
|
|
6980
|
+
this.active = false;
|
|
6981
|
+
if (this.tickTimer) {
|
|
6982
|
+
clearInterval(this.tickTimer);
|
|
6983
|
+
this.tickTimer = null;
|
|
6984
|
+
}
|
|
6985
|
+
if (this.answerPollTimer) {
|
|
6986
|
+
clearInterval(this.answerPollTimer);
|
|
6987
|
+
this.answerPollTimer = null;
|
|
6988
|
+
}
|
|
6989
|
+
return;
|
|
6990
|
+
}
|
|
6991
|
+
log.warn(
|
|
6992
|
+
"streamingEmitter",
|
|
6993
|
+
`post failed url=${url} status=${statusCode} attempt=${attempt + 1} body=${resBody.slice(0, 200)}`
|
|
6994
|
+
);
|
|
6995
|
+
} catch (err) {
|
|
6996
|
+
log.warn("streamingEmitter", `post error url=${url} attempt=${attempt + 1}`, err);
|
|
6997
|
+
}
|
|
6998
|
+
if (attempt < MAX_RETRIES2) {
|
|
6999
|
+
await sleep2(RETRY_BACKOFF_MS2 * (attempt + 1));
|
|
7000
|
+
}
|
|
7001
|
+
}
|
|
7002
|
+
}
|
|
7003
|
+
};
|
|
7004
|
+
function sleep2(ms) {
|
|
7005
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
7006
|
+
}
|
|
7007
|
+
var TREE_CONTINUATION_RE = /^\s*└/;
|
|
7008
|
+
function classifyLine(line, parseChrome, runtime) {
|
|
7009
|
+
if (line.trim().length === 0) return null;
|
|
7010
|
+
if (TREE_CONTINUATION_RE.test(line)) return "tool_result";
|
|
7011
|
+
const step = parseChrome?.(line) ?? null;
|
|
7012
|
+
if (step) {
|
|
7013
|
+
if (step.tool === "thinking") return "thinking";
|
|
7014
|
+
return "tool_use";
|
|
7015
|
+
}
|
|
7016
|
+
const filtered = runtime.filterTuiOutput([line]);
|
|
7017
|
+
if (filtered.length === 0) return null;
|
|
7018
|
+
return "text";
|
|
7019
|
+
}
|
|
7020
|
+
function parsePendingAnswerResponse(body) {
|
|
7021
|
+
if (!body) return null;
|
|
7022
|
+
let parsed;
|
|
7023
|
+
try {
|
|
7024
|
+
parsed = JSON.parse(body);
|
|
7025
|
+
} catch {
|
|
7026
|
+
return null;
|
|
7027
|
+
}
|
|
7028
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
7029
|
+
const root = parsed;
|
|
7030
|
+
const candidate = root.data && typeof root.data === "object" ? root.data : root;
|
|
7031
|
+
const questionId = candidate.questionId;
|
|
7032
|
+
const answer = candidate.answer;
|
|
7033
|
+
const optionIndex = candidate.optionIndex;
|
|
7034
|
+
if (typeof questionId !== "string" || typeof answer !== "string") return null;
|
|
7035
|
+
const result = { questionId, answer };
|
|
7036
|
+
if (typeof optionIndex === "number" && Number.isInteger(optionIndex)) {
|
|
7037
|
+
result.optionIndex = optionIndex;
|
|
7038
|
+
}
|
|
7039
|
+
return result;
|
|
7040
|
+
}
|
|
7041
|
+
|
|
6583
7042
|
// src/commands/start/quota-fetcher.ts
|
|
6584
7043
|
var inProgress = false;
|
|
6585
7044
|
function fetchQuotaUsage(runtime, historySvc) {
|
|
@@ -6595,13 +7054,13 @@ function fetchQuotaUsage(runtime, historySvc) {
|
|
|
6595
7054
|
}
|
|
6596
7055
|
|
|
6597
7056
|
// src/commands/start/keep-alive.ts
|
|
6598
|
-
var
|
|
7057
|
+
var import_child_process8 = require("child_process");
|
|
6599
7058
|
function buildKeepAlive(ctx) {
|
|
6600
7059
|
let timer = null;
|
|
6601
7060
|
async function setIdleTimeout(minutes) {
|
|
6602
7061
|
if (!ctx.inCodespace || !ctx.codespaceName) return;
|
|
6603
7062
|
await new Promise((resolve2) => {
|
|
6604
|
-
const proc = (0,
|
|
7063
|
+
const proc = (0, import_child_process8.spawn)(
|
|
6605
7064
|
"gh",
|
|
6606
7065
|
[
|
|
6607
7066
|
"api",
|
|
@@ -6641,8 +7100,8 @@ function buildKeepAlive(ctx) {
|
|
|
6641
7100
|
var fs14 = __toESM(require("fs"));
|
|
6642
7101
|
var os13 = __toESM(require("os"));
|
|
6643
7102
|
var path19 = __toESM(require("path"));
|
|
6644
|
-
var
|
|
6645
|
-
var
|
|
7103
|
+
var import_crypto3 = require("crypto");
|
|
7104
|
+
var import_child_process11 = require("child_process");
|
|
6646
7105
|
|
|
6647
7106
|
// src/lib/payload.ts
|
|
6648
7107
|
var import_zod2 = require("zod");
|
|
@@ -6846,11 +7305,11 @@ async function writeProjectFile(rawPath, content) {
|
|
|
6846
7305
|
}
|
|
6847
7306
|
|
|
6848
7307
|
// src/services/project-ops.service.ts
|
|
6849
|
-
var
|
|
7308
|
+
var import_child_process9 = require("child_process");
|
|
6850
7309
|
var import_util2 = require("util");
|
|
6851
7310
|
var fs13 = __toESM(require("fs/promises"));
|
|
6852
7311
|
var path17 = __toESM(require("path"));
|
|
6853
|
-
var execFileP2 = (0, import_util2.promisify)(
|
|
7312
|
+
var execFileP2 = (0, import_util2.promisify)(import_child_process9.execFile);
|
|
6854
7313
|
var PROJECT_IGNORE = /* @__PURE__ */ new Set([
|
|
6855
7314
|
"node_modules",
|
|
6856
7315
|
".git",
|
|
@@ -7190,8 +7649,8 @@ async function jsSearchFiles(opts, cwd, cap) {
|
|
|
7190
7649
|
}
|
|
7191
7650
|
|
|
7192
7651
|
// src/services/terminal-ops.service.ts
|
|
7193
|
-
var
|
|
7194
|
-
var
|
|
7652
|
+
var import_child_process10 = require("child_process");
|
|
7653
|
+
var import_crypto2 = require("crypto");
|
|
7195
7654
|
var import_path = __toESM(require("path"));
|
|
7196
7655
|
var MAX_CONCURRENT_SESSIONS = 4;
|
|
7197
7656
|
var nodePtyModule;
|
|
@@ -7312,7 +7771,7 @@ function createPythonSession(id, shell, cwd, env, cols, rows) {
|
|
|
7312
7771
|
}
|
|
7313
7772
|
let child;
|
|
7314
7773
|
try {
|
|
7315
|
-
child = (0,
|
|
7774
|
+
child = (0, import_child_process10.spawn)(python, ["-c", PYTHON_TERMINAL_HELPER, shell], {
|
|
7316
7775
|
cwd,
|
|
7317
7776
|
env: { ...env, COLUMNS: String(cols), LINES: String(rows) },
|
|
7318
7777
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -7367,7 +7826,7 @@ function openTerminal(opts) {
|
|
|
7367
7826
|
};
|
|
7368
7827
|
const cols = Math.max(1, Math.min(opts.cols ?? 80, 500));
|
|
7369
7828
|
const rows = Math.max(1, Math.min(opts.rows ?? 24, 200));
|
|
7370
|
-
const id = (0,
|
|
7829
|
+
const id = (0, import_crypto2.randomUUID)();
|
|
7371
7830
|
const ptyMod = loadNodePty2();
|
|
7372
7831
|
if (ptyMod) {
|
|
7373
7832
|
try {
|
|
@@ -7447,7 +7906,7 @@ function closeTerminal(sessionId) {
|
|
|
7447
7906
|
function saveFilesTemp(files) {
|
|
7448
7907
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
7449
7908
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
7450
|
-
const tmpPath = path19.join(os13.tmpdir(), `codeam-${(0,
|
|
7909
|
+
const tmpPath = path19.join(os13.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
|
|
7451
7910
|
fs14.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
7452
7911
|
return tmpPath;
|
|
7453
7912
|
});
|
|
@@ -7579,7 +8038,7 @@ var sessionTerminated = (ctx) => {
|
|
|
7579
8038
|
} catch {
|
|
7580
8039
|
}
|
|
7581
8040
|
try {
|
|
7582
|
-
const proc = (0,
|
|
8041
|
+
const proc = (0, import_child_process11.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
|
|
7583
8042
|
detached: true,
|
|
7584
8043
|
stdio: "ignore"
|
|
7585
8044
|
});
|
|
@@ -7601,7 +8060,7 @@ var shutdownSession = async (ctx, cmd) => {
|
|
|
7601
8060
|
}
|
|
7602
8061
|
if (ctx.keepAliveCtx.inCodespace && ctx.keepAliveCtx.codespaceName) {
|
|
7603
8062
|
try {
|
|
7604
|
-
const stopProc = (0,
|
|
8063
|
+
const stopProc = (0, import_child_process11.spawn)(
|
|
7605
8064
|
"bash",
|
|
7606
8065
|
["-lc", `sleep 1; gh codespace stop -c ${JSON.stringify(ctx.keepAliveCtx.codespaceName)} >/dev/null 2>&1 || true`],
|
|
7607
8066
|
{ detached: true, stdio: "ignore" }
|
|
@@ -7611,7 +8070,7 @@ var shutdownSession = async (ctx, cmd) => {
|
|
|
7611
8070
|
}
|
|
7612
8071
|
}
|
|
7613
8072
|
try {
|
|
7614
|
-
const proc = (0,
|
|
8073
|
+
const proc = (0, import_child_process11.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
|
|
7615
8074
|
detached: true,
|
|
7616
8075
|
stdio: "ignore"
|
|
7617
8076
|
});
|
|
@@ -7836,22 +8295,34 @@ async function start(requestedAgent) {
|
|
|
7836
8295
|
pluginId,
|
|
7837
8296
|
pluginAuthToken: session.pluginAuthToken
|
|
7838
8297
|
}) : null;
|
|
8298
|
+
let streamingEmitter = null;
|
|
7839
8299
|
const claude = new AgentService(
|
|
7840
8300
|
runtime,
|
|
7841
8301
|
{
|
|
7842
8302
|
cwd,
|
|
7843
8303
|
onData(raw) {
|
|
7844
8304
|
outputSvc.push(raw);
|
|
8305
|
+
streamingEmitter?.push(raw);
|
|
7845
8306
|
},
|
|
7846
8307
|
onExit(code) {
|
|
7847
8308
|
process.removeListener("SIGINT", sigintHandler);
|
|
7848
8309
|
outputSvc.dispose();
|
|
7849
8310
|
relay.stop();
|
|
7850
8311
|
void fileWatcher?.stop();
|
|
8312
|
+
void streamingEmitter?.stop();
|
|
7851
8313
|
process.exit(code);
|
|
7852
8314
|
}
|
|
7853
8315
|
}
|
|
7854
8316
|
);
|
|
8317
|
+
if (session.pluginAuthToken) {
|
|
8318
|
+
streamingEmitter = new StreamingEmitterService({
|
|
8319
|
+
sessionId: session.id,
|
|
8320
|
+
pluginId,
|
|
8321
|
+
pluginAuthToken: session.pluginAuthToken,
|
|
8322
|
+
runtime,
|
|
8323
|
+
ptyInput: claude
|
|
8324
|
+
});
|
|
8325
|
+
}
|
|
7855
8326
|
const ctx = {
|
|
7856
8327
|
outputSvc,
|
|
7857
8328
|
claude,
|
|
@@ -7878,6 +8349,7 @@ async function start(requestedAgent) {
|
|
|
7878
8349
|
outputSvc.dispose();
|
|
7879
8350
|
relay.stop();
|
|
7880
8351
|
void fileWatcher?.stop();
|
|
8352
|
+
void streamingEmitter?.stop();
|
|
7881
8353
|
process.exit(0);
|
|
7882
8354
|
}
|
|
7883
8355
|
process.once("SIGINT", sigintHandler);
|
|
@@ -7888,6 +8360,7 @@ async function start(requestedAgent) {
|
|
|
7888
8360
|
fileWatcher.start().catch(() => {
|
|
7889
8361
|
});
|
|
7890
8362
|
}
|
|
8363
|
+
streamingEmitter?.start();
|
|
7891
8364
|
setTimeout(() => {
|
|
7892
8365
|
historySvc.load().catch(() => {
|
|
7893
8366
|
});
|
|
@@ -7896,7 +8369,7 @@ async function start(requestedAgent) {
|
|
|
7896
8369
|
}
|
|
7897
8370
|
|
|
7898
8371
|
// src/commands/pair.ts
|
|
7899
|
-
var
|
|
8372
|
+
var import_crypto4 = require("crypto");
|
|
7900
8373
|
var import_picocolors3 = __toESM(require("picocolors"));
|
|
7901
8374
|
|
|
7902
8375
|
// src/ui/prompts.ts
|
|
@@ -7959,7 +8432,7 @@ async function pair(args2 = []) {
|
|
|
7959
8432
|
const flagAgent = parseAgentFlag(args2);
|
|
7960
8433
|
const agentId = flagAgent ?? await promptForAgent(config.preferredAgent ?? "claude");
|
|
7961
8434
|
showIntro();
|
|
7962
|
-
const pluginId = (0,
|
|
8435
|
+
const pluginId = (0, import_crypto4.randomUUID)();
|
|
7963
8436
|
const spin = dist_exports.spinner();
|
|
7964
8437
|
spin.start("Requesting pairing code...");
|
|
7965
8438
|
const result = await requestCode(pluginId);
|
|
@@ -8015,8 +8488,8 @@ async function pair(args2 = []) {
|
|
|
8015
8488
|
// src/commands/pair-auto.ts
|
|
8016
8489
|
var fs15 = __toESM(require("fs"));
|
|
8017
8490
|
var os14 = __toESM(require("os"));
|
|
8018
|
-
var
|
|
8019
|
-
var
|
|
8491
|
+
var import_crypto5 = require("crypto");
|
|
8492
|
+
var API_BASE7 = process.env.CODEAM_API_URL ?? DEFAULT_API_BASE_URL;
|
|
8020
8493
|
function fail(msg) {
|
|
8021
8494
|
console.error(`
|
|
8022
8495
|
${msg}
|
|
@@ -8048,14 +8521,18 @@ function readTokenFromArgs(args2) {
|
|
|
8048
8521
|
fail("codeam pair-auto requires --token-file=<path>, --token=<value>, or CODEAM_AUTO_TOKEN env");
|
|
8049
8522
|
}
|
|
8050
8523
|
async function claim(token, pluginId) {
|
|
8051
|
-
const url = `${
|
|
8524
|
+
const url = `${API_BASE7}/api/pairing/claim-auto-token`;
|
|
8052
8525
|
const body = {
|
|
8053
8526
|
token,
|
|
8054
8527
|
pluginId,
|
|
8055
8528
|
ideName: "codeam-cli (codespace)",
|
|
8056
8529
|
ideVersion: process.env.npm_package_version ?? "unknown",
|
|
8057
8530
|
hostname: os14.hostname(),
|
|
8058
|
-
codespaceName: process.env.CODESPACE_NAME ?? ""
|
|
8531
|
+
codespaceName: process.env.CODESPACE_NAME ?? "",
|
|
8532
|
+
// Current git branch of the codespace's working directory, so the
|
|
8533
|
+
// backend can populate `PairedSession.branch` for the codespace pair.
|
|
8534
|
+
// `null` when detached HEAD / not a git repo.
|
|
8535
|
+
branch: detectCurrentBranch()
|
|
8059
8536
|
};
|
|
8060
8537
|
const res = await fetch(url, {
|
|
8061
8538
|
method: "POST",
|
|
@@ -8077,7 +8554,7 @@ async function claim(token, pluginId) {
|
|
|
8077
8554
|
}
|
|
8078
8555
|
async function pairAuto(args2) {
|
|
8079
8556
|
const token = readTokenFromArgs(args2);
|
|
8080
|
-
const pluginId = (0,
|
|
8557
|
+
const pluginId = (0, import_crypto5.randomUUID)();
|
|
8081
8558
|
console.log(" Claiming pairing token\u2026");
|
|
8082
8559
|
const claimed = await claim(token, pluginId);
|
|
8083
8560
|
if (!isKnownAgentId(claimed.agent)) {
|
|
@@ -8203,11 +8680,11 @@ async function logout() {
|
|
|
8203
8680
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
8204
8681
|
|
|
8205
8682
|
// src/services/providers/github-codespaces.ts
|
|
8206
|
-
var
|
|
8683
|
+
var import_child_process12 = require("child_process");
|
|
8207
8684
|
var import_util3 = require("util");
|
|
8208
8685
|
var import_picocolors7 = __toESM(require("picocolors"));
|
|
8209
8686
|
var path20 = __toESM(require("path"));
|
|
8210
|
-
var execFileP3 = (0, import_util3.promisify)(
|
|
8687
|
+
var execFileP3 = (0, import_util3.promisify)(import_child_process12.execFile);
|
|
8211
8688
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
8212
8689
|
function resetStdinForChild() {
|
|
8213
8690
|
if (process.stdin.isTTY) {
|
|
@@ -8251,7 +8728,7 @@ var GitHubCodespacesProvider = class {
|
|
|
8251
8728
|
if (!isAuthed) {
|
|
8252
8729
|
resetStdinForChild();
|
|
8253
8730
|
await new Promise((resolve2, reject) => {
|
|
8254
|
-
const proc = (0,
|
|
8731
|
+
const proc = (0, import_child_process12.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
|
|
8255
8732
|
stdio: "inherit"
|
|
8256
8733
|
});
|
|
8257
8734
|
proc.on("exit", (code) => {
|
|
@@ -8285,7 +8762,7 @@ var GitHubCodespacesProvider = class {
|
|
|
8285
8762
|
wt(noteLines.join("\n"), "One more permission needed");
|
|
8286
8763
|
resetStdinForChild();
|
|
8287
8764
|
const refreshCode = await new Promise((resolve2, reject) => {
|
|
8288
|
-
const proc = (0,
|
|
8765
|
+
const proc = (0, import_child_process12.spawn)(
|
|
8289
8766
|
"gh",
|
|
8290
8767
|
["auth", "refresh", "-h", "github.com", "-s", "codespace"],
|
|
8291
8768
|
{ stdio: "inherit" }
|
|
@@ -8435,7 +8912,7 @@ var GitHubCodespacesProvider = class {
|
|
|
8435
8912
|
O2.step(`Installing gh via ${installCmd.describe}\u2026`);
|
|
8436
8913
|
resetStdinForChild();
|
|
8437
8914
|
const ok = await new Promise((resolve2) => {
|
|
8438
|
-
const proc = (0,
|
|
8915
|
+
const proc = (0, import_child_process12.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
|
|
8439
8916
|
proc.on("exit", (code) => resolve2(code === 0));
|
|
8440
8917
|
proc.on("error", () => resolve2(false));
|
|
8441
8918
|
});
|
|
@@ -8462,7 +8939,7 @@ var GitHubCodespacesProvider = class {
|
|
|
8462
8939
|
);
|
|
8463
8940
|
resetStdinForChild();
|
|
8464
8941
|
await new Promise((resolve2, reject) => {
|
|
8465
|
-
const proc = (0,
|
|
8942
|
+
const proc = (0, import_child_process12.spawn)(
|
|
8466
8943
|
"gh",
|
|
8467
8944
|
["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
|
|
8468
8945
|
{ stdio: "inherit" }
|
|
@@ -8640,7 +9117,7 @@ var GitHubCodespacesProvider = class {
|
|
|
8640
9117
|
async streamCommand(workspaceId, command2) {
|
|
8641
9118
|
resetStdinForChild();
|
|
8642
9119
|
return new Promise((resolve2, reject) => {
|
|
8643
|
-
const proc = (0,
|
|
9120
|
+
const proc = (0, import_child_process12.spawn)(
|
|
8644
9121
|
"gh",
|
|
8645
9122
|
["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
|
|
8646
9123
|
{ stdio: "inherit" }
|
|
@@ -8667,11 +9144,11 @@ var GitHubCodespacesProvider = class {
|
|
|
8667
9144
|
`mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
|
|
8668
9145
|
];
|
|
8669
9146
|
await new Promise((resolve2, reject) => {
|
|
8670
|
-
const tar = (0,
|
|
9147
|
+
const tar = (0, import_child_process12.spawn)("tar", tarArgs, {
|
|
8671
9148
|
stdio: ["ignore", "pipe", "pipe"],
|
|
8672
9149
|
env: tarEnv
|
|
8673
9150
|
});
|
|
8674
|
-
const ssh = (0,
|
|
9151
|
+
const ssh = (0, import_child_process12.spawn)("gh", sshArgs, {
|
|
8675
9152
|
stdio: [tar.stdout, "pipe", "pipe"]
|
|
8676
9153
|
});
|
|
8677
9154
|
let tarErr = "";
|
|
@@ -8705,7 +9182,7 @@ var GitHubCodespacesProvider = class {
|
|
|
8705
9182
|
}
|
|
8706
9183
|
const cmd = parts.join(" && ");
|
|
8707
9184
|
await new Promise((resolve2, reject) => {
|
|
8708
|
-
const proc = (0,
|
|
9185
|
+
const proc = (0, import_child_process12.spawn)(
|
|
8709
9186
|
"gh",
|
|
8710
9187
|
["codespace", "ssh", "-c", workspaceId, "--", cmd],
|
|
8711
9188
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -8763,11 +9240,11 @@ function shellQuote(s) {
|
|
|
8763
9240
|
}
|
|
8764
9241
|
|
|
8765
9242
|
// src/services/providers/gitpod.ts
|
|
8766
|
-
var
|
|
9243
|
+
var import_child_process13 = require("child_process");
|
|
8767
9244
|
var import_util4 = require("util");
|
|
8768
9245
|
var path21 = __toESM(require("path"));
|
|
8769
9246
|
var import_picocolors8 = __toESM(require("picocolors"));
|
|
8770
|
-
var execFileP4 = (0, import_util4.promisify)(
|
|
9247
|
+
var execFileP4 = (0, import_util4.promisify)(import_child_process13.execFile);
|
|
8771
9248
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
8772
9249
|
function resetStdinForChild2() {
|
|
8773
9250
|
if (process.stdin.isTTY) {
|
|
@@ -8807,7 +9284,7 @@ var GitpodProvider = class {
|
|
|
8807
9284
|
);
|
|
8808
9285
|
resetStdinForChild2();
|
|
8809
9286
|
await new Promise((resolve2, reject) => {
|
|
8810
|
-
const proc = (0,
|
|
9287
|
+
const proc = (0, import_child_process13.spawn)("gitpod", ["login"], { stdio: "inherit" });
|
|
8811
9288
|
proc.on("exit", (code) => {
|
|
8812
9289
|
if (code === 0) resolve2();
|
|
8813
9290
|
else reject(new Error("gitpod login failed."));
|
|
@@ -8959,7 +9436,7 @@ var GitpodProvider = class {
|
|
|
8959
9436
|
async streamCommand(workspaceId, command2) {
|
|
8960
9437
|
resetStdinForChild2();
|
|
8961
9438
|
return new Promise((resolve2, reject) => {
|
|
8962
|
-
const proc = (0,
|
|
9439
|
+
const proc = (0, import_child_process13.spawn)(
|
|
8963
9440
|
"gitpod",
|
|
8964
9441
|
["workspace", "ssh", workspaceId, "--", "-tt", command2],
|
|
8965
9442
|
{ stdio: "inherit" }
|
|
@@ -8979,11 +9456,11 @@ var GitpodProvider = class {
|
|
|
8979
9456
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
8980
9457
|
const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
|
|
8981
9458
|
await new Promise((resolve2, reject) => {
|
|
8982
|
-
const tar = (0,
|
|
9459
|
+
const tar = (0, import_child_process13.spawn)("tar", tarArgs, {
|
|
8983
9460
|
stdio: ["ignore", "pipe", "pipe"],
|
|
8984
9461
|
env: tarEnv
|
|
8985
9462
|
});
|
|
8986
|
-
const ssh = (0,
|
|
9463
|
+
const ssh = (0, import_child_process13.spawn)(
|
|
8987
9464
|
"gitpod",
|
|
8988
9465
|
["workspace", "ssh", workspaceId, "--", remoteCmd],
|
|
8989
9466
|
{ stdio: [tar.stdout, "pipe", "pipe"] }
|
|
@@ -9015,7 +9492,7 @@ var GitpodProvider = class {
|
|
|
9015
9492
|
}
|
|
9016
9493
|
const cmd = parts.join(" && ");
|
|
9017
9494
|
await new Promise((resolve2, reject) => {
|
|
9018
|
-
const proc = (0,
|
|
9495
|
+
const proc = (0, import_child_process13.spawn)(
|
|
9019
9496
|
"gitpod",
|
|
9020
9497
|
["workspace", "ssh", workspaceId, "--", cmd],
|
|
9021
9498
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -9039,10 +9516,10 @@ function shellQuote2(s) {
|
|
|
9039
9516
|
}
|
|
9040
9517
|
|
|
9041
9518
|
// src/services/providers/gitlab-workspaces.ts
|
|
9042
|
-
var
|
|
9519
|
+
var import_child_process14 = require("child_process");
|
|
9043
9520
|
var import_util5 = require("util");
|
|
9044
9521
|
var path22 = __toESM(require("path"));
|
|
9045
|
-
var execFileP5 = (0, import_util5.promisify)(
|
|
9522
|
+
var execFileP5 = (0, import_util5.promisify)(import_child_process14.execFile);
|
|
9046
9523
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
9047
9524
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
9048
9525
|
function resetStdinForChild3() {
|
|
@@ -9084,7 +9561,7 @@ var GitLabWorkspacesProvider = class {
|
|
|
9084
9561
|
);
|
|
9085
9562
|
resetStdinForChild3();
|
|
9086
9563
|
await new Promise((resolve2, reject) => {
|
|
9087
|
-
const proc = (0,
|
|
9564
|
+
const proc = (0, import_child_process14.spawn)(
|
|
9088
9565
|
"glab",
|
|
9089
9566
|
["auth", "login", "--scopes", "api,read_user,read_repository"],
|
|
9090
9567
|
{ stdio: "inherit" }
|
|
@@ -9256,7 +9733,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
9256
9733
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
9257
9734
|
resetStdinForChild3();
|
|
9258
9735
|
return new Promise((resolve2, reject) => {
|
|
9259
|
-
const proc = (0,
|
|
9736
|
+
const proc = (0, import_child_process14.spawn)(
|
|
9260
9737
|
"ssh",
|
|
9261
9738
|
["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
|
|
9262
9739
|
{ stdio: "inherit" }
|
|
@@ -9277,8 +9754,8 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
9277
9754
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
9278
9755
|
const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
|
|
9279
9756
|
await new Promise((resolve2, reject) => {
|
|
9280
|
-
const tar = (0,
|
|
9281
|
-
const ssh = (0,
|
|
9757
|
+
const tar = (0, import_child_process14.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
|
|
9758
|
+
const ssh = (0, import_child_process14.spawn)(
|
|
9282
9759
|
"ssh",
|
|
9283
9760
|
["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, remoteCmd],
|
|
9284
9761
|
{ stdio: [tar.stdout, "pipe", "pipe"] }
|
|
@@ -9308,7 +9785,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
9308
9785
|
}
|
|
9309
9786
|
const cmd = parts.join(" && ");
|
|
9310
9787
|
await new Promise((resolve2, reject) => {
|
|
9311
|
-
const proc = (0,
|
|
9788
|
+
const proc = (0, import_child_process14.spawn)(
|
|
9312
9789
|
"ssh",
|
|
9313
9790
|
["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
|
|
9314
9791
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -9367,10 +9844,10 @@ function shellQuote3(s) {
|
|
|
9367
9844
|
}
|
|
9368
9845
|
|
|
9369
9846
|
// src/services/providers/railway.ts
|
|
9370
|
-
var
|
|
9847
|
+
var import_child_process15 = require("child_process");
|
|
9371
9848
|
var import_util6 = require("util");
|
|
9372
9849
|
var path23 = __toESM(require("path"));
|
|
9373
|
-
var execFileP6 = (0, import_util6.promisify)(
|
|
9850
|
+
var execFileP6 = (0, import_util6.promisify)(import_child_process15.execFile);
|
|
9374
9851
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
9375
9852
|
function resetStdinForChild4() {
|
|
9376
9853
|
if (process.stdin.isTTY) {
|
|
@@ -9411,7 +9888,7 @@ var RailwayProvider = class {
|
|
|
9411
9888
|
);
|
|
9412
9889
|
resetStdinForChild4();
|
|
9413
9890
|
await new Promise((resolve2, reject) => {
|
|
9414
|
-
const proc = (0,
|
|
9891
|
+
const proc = (0, import_child_process15.spawn)("railway", ["login"], { stdio: "inherit" });
|
|
9415
9892
|
proc.on("exit", (code) => {
|
|
9416
9893
|
if (code === 0) resolve2();
|
|
9417
9894
|
else reject(new Error("railway login failed."));
|
|
@@ -9554,7 +10031,7 @@ var RailwayProvider = class {
|
|
|
9554
10031
|
}
|
|
9555
10032
|
resetStdinForChild4();
|
|
9556
10033
|
return new Promise((resolve2, reject) => {
|
|
9557
|
-
const proc = (0,
|
|
10034
|
+
const proc = (0, import_child_process15.spawn)(
|
|
9558
10035
|
"railway",
|
|
9559
10036
|
["shell", "--project", projectId, "--service", serviceId, "--command", command2],
|
|
9560
10037
|
{ stdio: "inherit" }
|
|
@@ -9578,8 +10055,8 @@ var RailwayProvider = class {
|
|
|
9578
10055
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
9579
10056
|
const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
|
|
9580
10057
|
await new Promise((resolve2, reject) => {
|
|
9581
|
-
const tar = (0,
|
|
9582
|
-
const sh = (0,
|
|
10058
|
+
const tar = (0, import_child_process15.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
|
|
10059
|
+
const sh = (0, import_child_process15.spawn)(
|
|
9583
10060
|
"railway",
|
|
9584
10061
|
["shell", "--project", projectId, "--service", serviceId, "--command", remoteCmd],
|
|
9585
10062
|
{ stdio: [tar.stdout, "pipe", "pipe"] }
|
|
@@ -9612,7 +10089,7 @@ var RailwayProvider = class {
|
|
|
9612
10089
|
}
|
|
9613
10090
|
const cmd = parts.join(" && ");
|
|
9614
10091
|
await new Promise((resolve2, reject) => {
|
|
9615
|
-
const proc = (0,
|
|
10092
|
+
const proc = (0, import_child_process15.spawn)(
|
|
9616
10093
|
"railway",
|
|
9617
10094
|
["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
|
|
9618
10095
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -10147,7 +10624,7 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
10147
10624
|
// src/commands/version.ts
|
|
10148
10625
|
var import_picocolors11 = __toESM(require("picocolors"));
|
|
10149
10626
|
function version() {
|
|
10150
|
-
const v = true ? "2.15.
|
|
10627
|
+
const v = true ? "2.15.7" : "unknown";
|
|
10151
10628
|
console.log(`${import_picocolors11.default.bold("codeam-cli")} ${import_picocolors11.default.cyan(v)}`);
|
|
10152
10629
|
}
|
|
10153
10630
|
|
|
@@ -10191,7 +10668,7 @@ function help() {
|
|
|
10191
10668
|
var fs16 = __toESM(require("fs"));
|
|
10192
10669
|
var os15 = __toESM(require("os"));
|
|
10193
10670
|
var path24 = __toESM(require("path"));
|
|
10194
|
-
var
|
|
10671
|
+
var https7 = __toESM(require("https"));
|
|
10195
10672
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
10196
10673
|
var PKG_NAME = "codeam-cli";
|
|
10197
10674
|
var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
@@ -10234,7 +10711,7 @@ function compareSemver(a, b) {
|
|
|
10234
10711
|
}
|
|
10235
10712
|
function fetchLatest() {
|
|
10236
10713
|
return new Promise((resolve2) => {
|
|
10237
|
-
const req =
|
|
10714
|
+
const req = https7.get(
|
|
10238
10715
|
REGISTRY_URL,
|
|
10239
10716
|
{ headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
|
|
10240
10717
|
(res) => {
|
|
@@ -10286,7 +10763,7 @@ function checkForUpdates() {
|
|
|
10286
10763
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
10287
10764
|
if (process.env.CI) return;
|
|
10288
10765
|
if (!process.stdout.isTTY) return;
|
|
10289
|
-
const current = true ? "2.15.
|
|
10766
|
+
const current = true ? "2.15.7" : null;
|
|
10290
10767
|
if (!current) return;
|
|
10291
10768
|
const cache = readCache();
|
|
10292
10769
|
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.15.
|
|
3
|
+
"version": "2.15.7",
|
|
4
4
|
"description": "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device — async. The terminal companion for CodeAgent Mobile.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "dist/index.js",
|