codeam-cli 2.29.0 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/index.js +243 -116
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,25 @@ 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.30.0] — 2026-06-06
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **vsc-plugin:** Banner recommends update when marketplace ships a fix
|
|
12
|
+
- **jetbrains-plugin:** Banner recommends update when marketplace ships a fix
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **cli:** Forward mobile image attachments to ACP as image blocks (QA #290)
|
|
17
|
+
- **cli, vsc-plugin:** Echo mobile prompts + clear Reconnecting UX (QA #287/#291)
|
|
18
|
+
- **cli:** Replace pair pollStatus with SSE pair_completed event (QA #285)
|
|
19
|
+
|
|
20
|
+
## [2.29.0] — 2026-06-06
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- **cli:** Forward originator HMAC to /api/pairing/code for QR-ready SSE
|
|
25
|
+
|
|
7
26
|
## [2.28.1] — 2026-06-06
|
|
8
27
|
|
|
9
28
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
498
498
|
// package.json
|
|
499
499
|
var package_default = {
|
|
500
500
|
name: "codeam-cli",
|
|
501
|
-
version: "2.
|
|
501
|
+
version: "2.31.0",
|
|
502
502
|
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.",
|
|
503
503
|
type: "commonjs",
|
|
504
504
|
main: "dist/index.js",
|
|
@@ -682,18 +682,10 @@ var _execSeam = {
|
|
|
682
682
|
}
|
|
683
683
|
};
|
|
684
684
|
|
|
685
|
-
// src/lib/poll-delay.ts
|
|
686
|
-
var MAX_DELAY_MS = 3e4;
|
|
687
|
-
function computePollDelay({ baseMs, failures }) {
|
|
688
|
-
const exp = Math.min(MAX_DELAY_MS, baseMs * Math.pow(2, failures));
|
|
689
|
-
const jitter = exp * (0.9 + Math.random() * 0.2);
|
|
690
|
-
return Math.round(jitter);
|
|
691
|
-
}
|
|
692
|
-
|
|
693
685
|
// src/services/pairing.service.ts
|
|
694
686
|
var API_BASE = resolveApiBaseUrl();
|
|
695
687
|
var REQUEST_CODE_TIMEOUT_MS = 1e4;
|
|
696
|
-
async function requestCode(pluginId
|
|
688
|
+
async function requestCode(pluginId) {
|
|
697
689
|
try {
|
|
698
690
|
const runtime = process.env.CODESPACES === "true" ? "github-codespaces" : "local";
|
|
699
691
|
const codespaceName = process.env.CODESPACE_NAME;
|
|
@@ -705,12 +697,7 @@ async function requestCode(pluginId, options = {}) {
|
|
|
705
697
|
hostname: os2.hostname(),
|
|
706
698
|
runtime,
|
|
707
699
|
branch,
|
|
708
|
-
...codespaceName ? { codespaceName } : {}
|
|
709
|
-
...options.originatorSessionId && options.originatorPluginId && options.originatorAuthToken ? {
|
|
710
|
-
originatorSessionId: options.originatorSessionId,
|
|
711
|
-
originatorPluginId: options.originatorPluginId,
|
|
712
|
-
originatorAuthToken: options.originatorAuthToken
|
|
713
|
-
} : {}
|
|
700
|
+
...codespaceName ? { codespaceName } : {}
|
|
714
701
|
});
|
|
715
702
|
let timer;
|
|
716
703
|
const timeoutSentinel = /* @__PURE__ */ Symbol("request-code-timeout");
|
|
@@ -741,59 +728,6 @@ async function fetchCurrentPluginAuthToken(sessionId, pluginId) {
|
|
|
741
728
|
return null;
|
|
742
729
|
}
|
|
743
730
|
}
|
|
744
|
-
function pollStatus(pluginId, onPaired, onTimeout) {
|
|
745
|
-
let stopped = false;
|
|
746
|
-
let pollTimer = null;
|
|
747
|
-
let consecutiveFailures = 0;
|
|
748
|
-
const tick = async () => {
|
|
749
|
-
if (stopped) return;
|
|
750
|
-
try {
|
|
751
|
-
const result = await _transport.getJson(
|
|
752
|
-
`${API_BASE}/api/pairing/status?pluginId=${pluginId}`
|
|
753
|
-
);
|
|
754
|
-
consecutiveFailures = 0;
|
|
755
|
-
const data = result?.data;
|
|
756
|
-
if (data?.paired) {
|
|
757
|
-
stop();
|
|
758
|
-
const user = data.user ?? {};
|
|
759
|
-
const rawToken = data.pluginAuthToken;
|
|
760
|
-
onPaired({
|
|
761
|
-
sessionId: data.sessionId,
|
|
762
|
-
userId: typeof user.id === "string" && user.id.length > 0 ? user.id : void 0,
|
|
763
|
-
userName: user.name || "",
|
|
764
|
-
userEmail: user.email || "",
|
|
765
|
-
plan: user.plan || "FREE",
|
|
766
|
-
pluginAuthToken: typeof rawToken === "string" && rawToken.length > 0 ? rawToken : void 0
|
|
767
|
-
});
|
|
768
|
-
return;
|
|
769
|
-
}
|
|
770
|
-
} catch {
|
|
771
|
-
consecutiveFailures += 1;
|
|
772
|
-
}
|
|
773
|
-
if (stopped) return;
|
|
774
|
-
const delay = computePollDelay({ baseMs: 3e3, failures: consecutiveFailures });
|
|
775
|
-
pollTimer = setTimeout(() => {
|
|
776
|
-
void tick();
|
|
777
|
-
}, delay);
|
|
778
|
-
};
|
|
779
|
-
const initialDelay = computePollDelay({ baseMs: 3e3, failures: 0 });
|
|
780
|
-
pollTimer = setTimeout(() => {
|
|
781
|
-
void tick();
|
|
782
|
-
}, initialDelay);
|
|
783
|
-
const timeout = setTimeout(() => {
|
|
784
|
-
stop();
|
|
785
|
-
onTimeout();
|
|
786
|
-
}, 3e5);
|
|
787
|
-
function stop() {
|
|
788
|
-
stopped = true;
|
|
789
|
-
if (pollTimer) {
|
|
790
|
-
clearTimeout(pollTimer);
|
|
791
|
-
pollTimer = null;
|
|
792
|
-
}
|
|
793
|
-
clearTimeout(timeout);
|
|
794
|
-
}
|
|
795
|
-
return stop;
|
|
796
|
-
}
|
|
797
731
|
var _transport = {
|
|
798
732
|
postJson: _postJson,
|
|
799
733
|
getJson: _getJson,
|
|
@@ -1032,6 +966,14 @@ async function _getJson(url) {
|
|
|
1032
966
|
});
|
|
1033
967
|
}
|
|
1034
968
|
|
|
969
|
+
// src/lib/poll-delay.ts
|
|
970
|
+
var MAX_DELAY_MS = 3e4;
|
|
971
|
+
function computePollDelay({ baseMs, failures }) {
|
|
972
|
+
const exp = Math.min(MAX_DELAY_MS, baseMs * Math.pow(2, failures));
|
|
973
|
+
const jitter = exp * (0.9 + Math.random() * 0.2);
|
|
974
|
+
return Math.round(jitter);
|
|
975
|
+
}
|
|
976
|
+
|
|
1035
977
|
// src/services/logger.ts
|
|
1036
978
|
var fs2 = __toESM(require("fs"));
|
|
1037
979
|
var os3 = __toESM(require("os"));
|
|
@@ -5902,7 +5844,7 @@ function readAnonId() {
|
|
|
5902
5844
|
}
|
|
5903
5845
|
function superProperties() {
|
|
5904
5846
|
return {
|
|
5905
|
-
cliVersion: true ? "2.
|
|
5847
|
+
cliVersion: true ? "2.31.0" : "0.0.0-dev",
|
|
5906
5848
|
nodeVersion: process.version,
|
|
5907
5849
|
platform: process.platform,
|
|
5908
5850
|
arch: process.arch,
|
|
@@ -14660,18 +14602,27 @@ var AcpClient = class {
|
|
|
14660
14602
|
* a ceiling the relay command sits "pending" forever and mobile
|
|
14661
14603
|
* shows a permanent "Thinking…" spinner with no way to recover.
|
|
14662
14604
|
*/
|
|
14663
|
-
async prompt(
|
|
14605
|
+
async prompt(input) {
|
|
14664
14606
|
if (!this.connection || !this.sessionId) {
|
|
14665
14607
|
throw new Error("AcpClient.prompt called before start()");
|
|
14666
14608
|
}
|
|
14609
|
+
const blocks = typeof input === "string" ? [{ type: "text", text: input }] : input;
|
|
14610
|
+
const textLen = blocks.reduce(
|
|
14611
|
+
(n, b) => b.type === "text" ? n + b.text.length : n,
|
|
14612
|
+
0
|
|
14613
|
+
);
|
|
14614
|
+
const imageCount = blocks.reduce(
|
|
14615
|
+
(n, b) => b.type === "image" ? n + 1 : n,
|
|
14616
|
+
0
|
|
14617
|
+
);
|
|
14667
14618
|
log.info(
|
|
14668
14619
|
"acpClient",
|
|
14669
|
-
`prompt \u2192 session=${this.sessionId.slice(0, 8)}
|
|
14620
|
+
`prompt \u2192 session=${this.sessionId.slice(0, 8)} textChars=${textLen} imageBlocks=${imageCount}`
|
|
14670
14621
|
);
|
|
14671
14622
|
const t0 = Date.now();
|
|
14672
14623
|
const send = this.connection.prompt({
|
|
14673
14624
|
sessionId: this.sessionId,
|
|
14674
|
-
prompt:
|
|
14625
|
+
prompt: blocks
|
|
14675
14626
|
});
|
|
14676
14627
|
let timeoutId;
|
|
14677
14628
|
const timeout = new Promise((_resolve, reject) => {
|
|
@@ -15143,6 +15094,59 @@ var AcpPublisher = class {
|
|
|
15143
15094
|
}
|
|
15144
15095
|
};
|
|
15145
15096
|
|
|
15097
|
+
// src/agents/acp/buildAcpPromptBlocks.ts
|
|
15098
|
+
var MIME_FROM_EXT = {
|
|
15099
|
+
png: "image/png",
|
|
15100
|
+
jpg: "image/jpeg",
|
|
15101
|
+
jpeg: "image/jpeg",
|
|
15102
|
+
gif: "image/gif",
|
|
15103
|
+
webp: "image/webp",
|
|
15104
|
+
heic: "image/heic",
|
|
15105
|
+
heif: "image/heif"
|
|
15106
|
+
};
|
|
15107
|
+
function inferMime(filename) {
|
|
15108
|
+
const ext = filename.toLowerCase().split(".").pop() ?? "";
|
|
15109
|
+
return MIME_FROM_EXT[ext] ?? "application/octet-stream";
|
|
15110
|
+
}
|
|
15111
|
+
var PLACEHOLDER_PROMPT = "Please review the attached image(s) and let me know what you find.";
|
|
15112
|
+
function buildAcpPromptBlocks(payload) {
|
|
15113
|
+
const blocks = [];
|
|
15114
|
+
for (const file of payload.files ?? []) {
|
|
15115
|
+
if (!file.base64 || file.base64.length === 0) continue;
|
|
15116
|
+
blocks.push({
|
|
15117
|
+
type: "image",
|
|
15118
|
+
mimeType: file.mimeType ?? inferMime(file.filename),
|
|
15119
|
+
data: file.base64
|
|
15120
|
+
});
|
|
15121
|
+
}
|
|
15122
|
+
const text = (payload.prompt ?? "").trim();
|
|
15123
|
+
if (text.length > 0) {
|
|
15124
|
+
blocks.push({ type: "text", text });
|
|
15125
|
+
} else if (blocks.length > 0) {
|
|
15126
|
+
blocks.push({ type: "text", text: PLACEHOLDER_PROMPT });
|
|
15127
|
+
}
|
|
15128
|
+
return blocks;
|
|
15129
|
+
}
|
|
15130
|
+
|
|
15131
|
+
// src/agents/acp/promptEcho.ts
|
|
15132
|
+
var MAX_PROMPT_CHARS = 200;
|
|
15133
|
+
function formatPromptEchoLine(payload) {
|
|
15134
|
+
const rawText = (payload.prompt ?? "").replace(/\s+/g, " ").trim();
|
|
15135
|
+
const imageCount = (payload.files ?? []).filter(
|
|
15136
|
+
(f) => typeof f.base64 === "string" && f.base64.length > 0
|
|
15137
|
+
).length;
|
|
15138
|
+
if (rawText.length === 0 && imageCount === 0) return "";
|
|
15139
|
+
const truncatedText = rawText.length > MAX_PROMPT_CHARS ? rawText.slice(0, MAX_PROMPT_CHARS) + "\u2026" : rawText;
|
|
15140
|
+
const parts = [];
|
|
15141
|
+
if (truncatedText.length > 0) {
|
|
15142
|
+
parts.push(`Mobile: ${truncatedText}`);
|
|
15143
|
+
}
|
|
15144
|
+
if (imageCount > 0) {
|
|
15145
|
+
parts.push(`+ ${imageCount} image${imageCount === 1 ? "" : "s"}`);
|
|
15146
|
+
}
|
|
15147
|
+
return `\u203A ${parts.join(" ")}`;
|
|
15148
|
+
}
|
|
15149
|
+
|
|
15146
15150
|
// src/services/terminal-ops.service.ts
|
|
15147
15151
|
var import_child_process8 = require("child_process");
|
|
15148
15152
|
var import_crypto2 = require("crypto");
|
|
@@ -16320,6 +16324,125 @@ async function selectSession(sessions3, activeId) {
|
|
|
16320
16324
|
return result;
|
|
16321
16325
|
}
|
|
16322
16326
|
|
|
16327
|
+
// src/services/pair-completion-subscriber.ts
|
|
16328
|
+
var https4 = __toESM(require("https"));
|
|
16329
|
+
var http4 = __toESM(require("http"));
|
|
16330
|
+
var API_BASE3 = resolveApiBaseUrl();
|
|
16331
|
+
var PAIR_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
16332
|
+
var dispatchers = /* @__PURE__ */ new Set();
|
|
16333
|
+
function subscribeToPairCompletion(pluginId, onPaired, onTimeout) {
|
|
16334
|
+
let stopped = false;
|
|
16335
|
+
let req = null;
|
|
16336
|
+
let timeoutTimer = null;
|
|
16337
|
+
const dispatch = (cmd) => {
|
|
16338
|
+
if (stopped) return;
|
|
16339
|
+
if (cmd.pluginId !== pluginId) return;
|
|
16340
|
+
if (cmd.type !== "pair_completed") return;
|
|
16341
|
+
const payload = cmd.payload ?? {};
|
|
16342
|
+
const info = {
|
|
16343
|
+
sessionId: typeof payload.sessionId === "string" ? payload.sessionId : cmd.sessionId,
|
|
16344
|
+
userId: typeof payload.userId === "string" ? payload.userId : void 0,
|
|
16345
|
+
userName: typeof payload.userName === "string" ? payload.userName : "",
|
|
16346
|
+
userEmail: typeof payload.userEmail === "string" ? payload.userEmail : "",
|
|
16347
|
+
plan: typeof payload.plan === "string" ? payload.plan : "FREE",
|
|
16348
|
+
pluginAuthToken: typeof payload.pluginAuthToken === "string" ? payload.pluginAuthToken : void 0
|
|
16349
|
+
};
|
|
16350
|
+
stop();
|
|
16351
|
+
onPaired(info);
|
|
16352
|
+
};
|
|
16353
|
+
dispatchers.add(dispatch);
|
|
16354
|
+
const connect = () => {
|
|
16355
|
+
if (stopped) return;
|
|
16356
|
+
const url = new URL(`${API_BASE3}/api/commands/pending/stream`);
|
|
16357
|
+
url.searchParams.set("pluginId", pluginId);
|
|
16358
|
+
const transport = url.protocol === "https:" ? https4 : http4;
|
|
16359
|
+
req = transport.request(
|
|
16360
|
+
{
|
|
16361
|
+
hostname: url.hostname,
|
|
16362
|
+
port: url.port || (url.protocol === "https:" ? 443 : 80),
|
|
16363
|
+
path: `${url.pathname}${url.search}`,
|
|
16364
|
+
method: "GET",
|
|
16365
|
+
headers: {
|
|
16366
|
+
Accept: "text/event-stream",
|
|
16367
|
+
"Cache-Control": "no-cache",
|
|
16368
|
+
...vercelBypassHeader()
|
|
16369
|
+
},
|
|
16370
|
+
timeout: 35e3
|
|
16371
|
+
},
|
|
16372
|
+
(res) => {
|
|
16373
|
+
if (res.statusCode !== 200) {
|
|
16374
|
+
log.trace(
|
|
16375
|
+
"pairSubscribe",
|
|
16376
|
+
`sse status=${res.statusCode}; will reconnect in 1s`
|
|
16377
|
+
);
|
|
16378
|
+
res.resume();
|
|
16379
|
+
setTimeout(connect, 1e3);
|
|
16380
|
+
return;
|
|
16381
|
+
}
|
|
16382
|
+
let buf = "";
|
|
16383
|
+
res.setEncoding("utf8");
|
|
16384
|
+
res.on("data", (chunk) => {
|
|
16385
|
+
buf += chunk;
|
|
16386
|
+
let idx;
|
|
16387
|
+
while ((idx = buf.indexOf("\n\n")) >= 0) {
|
|
16388
|
+
const frame = buf.slice(0, idx);
|
|
16389
|
+
buf = buf.slice(idx + 2);
|
|
16390
|
+
parseFrame(frame, dispatch);
|
|
16391
|
+
}
|
|
16392
|
+
});
|
|
16393
|
+
res.on("end", () => {
|
|
16394
|
+
if (!stopped) setTimeout(connect, 250);
|
|
16395
|
+
});
|
|
16396
|
+
res.on("error", () => {
|
|
16397
|
+
if (!stopped) setTimeout(connect, 1e3);
|
|
16398
|
+
});
|
|
16399
|
+
}
|
|
16400
|
+
);
|
|
16401
|
+
req.on("error", () => {
|
|
16402
|
+
if (!stopped) setTimeout(connect, 1e3);
|
|
16403
|
+
});
|
|
16404
|
+
req.on("timeout", () => {
|
|
16405
|
+
req?.destroy();
|
|
16406
|
+
if (!stopped) setTimeout(connect, 250);
|
|
16407
|
+
});
|
|
16408
|
+
req.end();
|
|
16409
|
+
};
|
|
16410
|
+
connect();
|
|
16411
|
+
timeoutTimer = setTimeout(() => {
|
|
16412
|
+
stop();
|
|
16413
|
+
onTimeout();
|
|
16414
|
+
}, PAIR_TIMEOUT_MS);
|
|
16415
|
+
function stop() {
|
|
16416
|
+
if (stopped) return;
|
|
16417
|
+
stopped = true;
|
|
16418
|
+
dispatchers.delete(dispatch);
|
|
16419
|
+
if (timeoutTimer) {
|
|
16420
|
+
clearTimeout(timeoutTimer);
|
|
16421
|
+
timeoutTimer = null;
|
|
16422
|
+
}
|
|
16423
|
+
if (req) {
|
|
16424
|
+
req.destroy();
|
|
16425
|
+
req = null;
|
|
16426
|
+
}
|
|
16427
|
+
}
|
|
16428
|
+
return stop;
|
|
16429
|
+
}
|
|
16430
|
+
function parseFrame(frame, dispatch) {
|
|
16431
|
+
let eventType = "message";
|
|
16432
|
+
let data = "";
|
|
16433
|
+
for (const line of frame.split("\n")) {
|
|
16434
|
+
if (line.startsWith("event:")) eventType = line.slice(6).trim();
|
|
16435
|
+
else if (line.startsWith("data:")) data += line.slice(5).trimStart();
|
|
16436
|
+
}
|
|
16437
|
+
if (eventType !== "commands") return;
|
|
16438
|
+
try {
|
|
16439
|
+
const parsed = JSON.parse(data);
|
|
16440
|
+
if (!Array.isArray(parsed.commands)) return;
|
|
16441
|
+
for (const cmd of parsed.commands) dispatch(cmd);
|
|
16442
|
+
} catch {
|
|
16443
|
+
}
|
|
16444
|
+
}
|
|
16445
|
+
|
|
16323
16446
|
// src/commands/link.ts
|
|
16324
16447
|
function buildLinkContext(agentId) {
|
|
16325
16448
|
const runtime = createRuntimeStrategy(agentId);
|
|
@@ -16386,12 +16509,7 @@ async function link(args2 = []) {
|
|
|
16386
16509
|
const pluginId = (0, import_node_crypto6.randomUUID)();
|
|
16387
16510
|
const spin = dist_exports.spinner();
|
|
16388
16511
|
spin.start("Requesting pairing code...");
|
|
16389
|
-
const
|
|
16390
|
-
const pairing = await requestCode(pluginId, {
|
|
16391
|
-
originatorSessionId: originator?.id,
|
|
16392
|
-
originatorPluginId: originator?.pluginId,
|
|
16393
|
-
originatorAuthToken: originator?.pluginAuthToken
|
|
16394
|
-
});
|
|
16512
|
+
const pairing = await requestCode(pluginId);
|
|
16395
16513
|
if (!pairing) {
|
|
16396
16514
|
spin.stop("Failed");
|
|
16397
16515
|
showError("Could not reach the server. Check your connection and try again.");
|
|
@@ -16413,7 +16531,7 @@ async function link(args2 = []) {
|
|
|
16413
16531
|
stopPoll?.();
|
|
16414
16532
|
reject(new Error("cancelled"));
|
|
16415
16533
|
};
|
|
16416
|
-
stopPoll =
|
|
16534
|
+
stopPoll = subscribeToPairCompletion(
|
|
16417
16535
|
pluginId,
|
|
16418
16536
|
(info) => {
|
|
16419
16537
|
process.removeListener("SIGINT", sigint);
|
|
@@ -18012,8 +18130,8 @@ function isIgnoredFilePath(filePath) {
|
|
|
18012
18130
|
}
|
|
18013
18131
|
|
|
18014
18132
|
// src/services/file-watcher/transport.ts
|
|
18015
|
-
var
|
|
18016
|
-
var
|
|
18133
|
+
var http5 = __toESM(require("http"));
|
|
18134
|
+
var https5 = __toESM(require("https"));
|
|
18017
18135
|
var _transport3 = {
|
|
18018
18136
|
post: _post2
|
|
18019
18137
|
};
|
|
@@ -18021,7 +18139,7 @@ function _post2(url, headers, payload) {
|
|
|
18021
18139
|
return new Promise((resolve6, reject) => {
|
|
18022
18140
|
let settled = false;
|
|
18023
18141
|
const u2 = new URL(url);
|
|
18024
|
-
const lib = u2.protocol === "https:" ?
|
|
18142
|
+
const lib = u2.protocol === "https:" ? https5 : http5;
|
|
18025
18143
|
const req = lib.request(
|
|
18026
18144
|
{
|
|
18027
18145
|
hostname: u2.hostname,
|
|
@@ -18061,7 +18179,7 @@ function _post2(url, headers, payload) {
|
|
|
18061
18179
|
}
|
|
18062
18180
|
|
|
18063
18181
|
// src/services/file-watcher.service.ts
|
|
18064
|
-
var
|
|
18182
|
+
var API_BASE4 = resolveApiBaseUrl();
|
|
18065
18183
|
var DEBOUNCE_MS = 250;
|
|
18066
18184
|
var COALESCE_WINDOW_MS = 250;
|
|
18067
18185
|
var COALESCE_MAX_HOLD_MS = 2e3;
|
|
@@ -18134,7 +18252,7 @@ function _defaultFindGitRoot(startDir) {
|
|
|
18134
18252
|
var FileWatcherService = class {
|
|
18135
18253
|
constructor(opts) {
|
|
18136
18254
|
this.opts = opts;
|
|
18137
|
-
this.apiBase = opts.apiBaseUrl ??
|
|
18255
|
+
this.apiBase = opts.apiBaseUrl ?? API_BASE4;
|
|
18138
18256
|
}
|
|
18139
18257
|
opts;
|
|
18140
18258
|
watcher = null;
|
|
@@ -19085,13 +19203,13 @@ function homeDir() {
|
|
|
19085
19203
|
}
|
|
19086
19204
|
|
|
19087
19205
|
// src/services/turn-files/turn-file-aggregator.ts
|
|
19088
|
-
var
|
|
19206
|
+
var API_BASE5 = resolveApiBaseUrl();
|
|
19089
19207
|
var ENDPOINT = "/api/files/batch";
|
|
19090
19208
|
var MAX_BATCH_SIZE = 1e3;
|
|
19091
19209
|
var TurnFileAggregator = class {
|
|
19092
19210
|
constructor(opts) {
|
|
19093
19211
|
this.opts = opts;
|
|
19094
|
-
this.apiBase = opts.apiBaseUrl ??
|
|
19212
|
+
this.apiBase = opts.apiBaseUrl ?? API_BASE5;
|
|
19095
19213
|
this.outbox = new FilesOutbox({
|
|
19096
19214
|
sessionId: opts.sessionId,
|
|
19097
19215
|
baseDir: opts.outboxDir,
|
|
@@ -19731,17 +19849,26 @@ async function handleCommand(cmd, client2, relay, acpSessionId, models, streamin
|
|
|
19731
19849
|
switch (cmd.type) {
|
|
19732
19850
|
case "start_task": {
|
|
19733
19851
|
const payload = cmd.payload;
|
|
19734
|
-
const
|
|
19735
|
-
if (
|
|
19736
|
-
log.warn("acpRunner", "start_task with empty prompt; ignoring");
|
|
19852
|
+
const blocks = buildAcpPromptBlocks(payload ?? {});
|
|
19853
|
+
if (blocks.length === 0) {
|
|
19854
|
+
log.warn("acpRunner", "start_task with empty prompt + no attachments; ignoring");
|
|
19737
19855
|
await relay.sendResult(cmd.id, "failed", { error: "empty prompt" });
|
|
19738
19856
|
return;
|
|
19739
19857
|
}
|
|
19740
|
-
|
|
19858
|
+
const promptText = blocks.filter((b) => b.type === "text").map((b) => b.text).join("\n");
|
|
19859
|
+
const imageCount = blocks.filter((b) => b.type === "image").length;
|
|
19860
|
+
log.info(
|
|
19861
|
+
"acpRunner",
|
|
19862
|
+
`start_task \u2192 forwarding textChars=${promptText.length} imageBlocks=${imageCount} id=${cmd.id.slice(0, 8)}`
|
|
19863
|
+
);
|
|
19864
|
+
const echoLine = formatPromptEchoLine(payload ?? {});
|
|
19865
|
+
if (echoLine.length > 0) {
|
|
19866
|
+
showInfo(echoLine);
|
|
19867
|
+
}
|
|
19741
19868
|
await streaming.beginTurn();
|
|
19742
|
-
history.appendUserPrompt(
|
|
19869
|
+
history.appendUserPrompt(promptText);
|
|
19743
19870
|
try {
|
|
19744
|
-
const reply = await client2.prompt(
|
|
19871
|
+
const reply = await client2.prompt(blocks);
|
|
19745
19872
|
const finalText = streaming.getCurrentText();
|
|
19746
19873
|
await streaming.closeTurnWithInteractiveDetection();
|
|
19747
19874
|
history.appendAgentReply(finalText);
|
|
@@ -20076,13 +20203,13 @@ var ChromeStepTracker = class {
|
|
|
20076
20203
|
};
|
|
20077
20204
|
|
|
20078
20205
|
// src/services/output/chunk-emitter.ts
|
|
20079
|
-
var
|
|
20080
|
-
var
|
|
20081
|
-
var
|
|
20206
|
+
var https6 = __toESM(require("https"));
|
|
20207
|
+
var http6 = __toESM(require("http"));
|
|
20208
|
+
var API_BASE6 = resolveApiBaseUrl();
|
|
20082
20209
|
async function refreshAuthToken(sessionId, pluginId) {
|
|
20083
20210
|
try {
|
|
20084
20211
|
const { statusCode, body } = await _transport4.post(
|
|
20085
|
-
`${
|
|
20212
|
+
`${API_BASE6}/api/pairing/reconnect`,
|
|
20086
20213
|
{
|
|
20087
20214
|
"Content-Type": "application/json",
|
|
20088
20215
|
"X-Codeam-Protocol-Version": PROTOCOL_VERSION,
|
|
@@ -20123,7 +20250,7 @@ var ChunkEmitter = class {
|
|
|
20123
20250
|
}
|
|
20124
20251
|
}
|
|
20125
20252
|
opts;
|
|
20126
|
-
url = `${
|
|
20253
|
+
url = `${API_BASE6}/api/commands/output`;
|
|
20127
20254
|
headers;
|
|
20128
20255
|
/**
|
|
20129
20256
|
* Send a chunk. `body` is the chunk fields minus `sessionId` /
|
|
@@ -20204,7 +20331,7 @@ function _post3(url, headers, payload) {
|
|
|
20204
20331
|
return new Promise((resolve6, reject) => {
|
|
20205
20332
|
let settled = false;
|
|
20206
20333
|
const u2 = new URL(url);
|
|
20207
|
-
const transport = u2.protocol === "https:" ?
|
|
20334
|
+
const transport = u2.protocol === "https:" ? https6 : http6;
|
|
20208
20335
|
const req = transport.request(
|
|
20209
20336
|
{
|
|
20210
20337
|
hostname: u2.hostname,
|
|
@@ -20802,8 +20929,8 @@ var OutputService = class _OutputService {
|
|
|
20802
20929
|
var fs32 = __toESM(require("fs"));
|
|
20803
20930
|
var path38 = __toESM(require("path"));
|
|
20804
20931
|
var os25 = __toESM(require("os"));
|
|
20805
|
-
var
|
|
20806
|
-
var
|
|
20932
|
+
var https7 = __toESM(require("https"));
|
|
20933
|
+
var http7 = __toESM(require("http"));
|
|
20807
20934
|
var import_zod2 = require("zod");
|
|
20808
20935
|
var historyRecordSchema = import_zod2.z.object({
|
|
20809
20936
|
type: import_zod2.z.string().optional(),
|
|
@@ -20815,7 +20942,7 @@ var historyRecordSchema = import_zod2.z.object({
|
|
|
20815
20942
|
content: import_zod2.z.union([import_zod2.z.string(), import_zod2.z.array(import_zod2.z.unknown())]).optional()
|
|
20816
20943
|
}).passthrough().optional()
|
|
20817
20944
|
}).passthrough();
|
|
20818
|
-
var
|
|
20945
|
+
var API_BASE7 = resolveApiBaseUrl();
|
|
20819
20946
|
function extractText3(content) {
|
|
20820
20947
|
if (typeof content === "string") return content;
|
|
20821
20948
|
if (Array.isArray(content)) {
|
|
@@ -20867,8 +20994,8 @@ function parseJsonl(filePath) {
|
|
|
20867
20994
|
function post(endpoint, body) {
|
|
20868
20995
|
return new Promise((resolve6) => {
|
|
20869
20996
|
const payload = JSON.stringify(body);
|
|
20870
|
-
const u2 = new URL(`${
|
|
20871
|
-
const transport = u2.protocol === "https:" ?
|
|
20997
|
+
const u2 = new URL(`${API_BASE7}${endpoint}`);
|
|
20998
|
+
const transport = u2.protocol === "https:" ? https7 : http7;
|
|
20872
20999
|
const req = transport.request(
|
|
20873
21000
|
{
|
|
20874
21001
|
hostname: u2.hostname,
|
|
@@ -21316,7 +21443,7 @@ var RepoDirtyTracker = class {
|
|
|
21316
21443
|
|
|
21317
21444
|
// src/services/streaming-emitter.service.ts
|
|
21318
21445
|
var import_crypto5 = require("crypto");
|
|
21319
|
-
var
|
|
21446
|
+
var API_BASE8 = resolveApiBaseUrl();
|
|
21320
21447
|
var TICK_MS = 50;
|
|
21321
21448
|
var ANSWER_POLL_MS = 1500;
|
|
21322
21449
|
var SELECTOR_STABLE_MS = 800;
|
|
@@ -21327,7 +21454,7 @@ var TAIL_KEEP_BYTES2 = 1.5 * 1024 * 1024;
|
|
|
21327
21454
|
var StreamingEmitterService = class {
|
|
21328
21455
|
constructor(opts) {
|
|
21329
21456
|
this.opts = opts;
|
|
21330
|
-
this.apiBase = opts.apiBaseUrl ??
|
|
21457
|
+
this.apiBase = opts.apiBaseUrl ?? API_BASE8;
|
|
21331
21458
|
this.headers = {
|
|
21332
21459
|
"Content-Type": "application/json",
|
|
21333
21460
|
"X-Codeam-Protocol-Version": "2.0.0",
|
|
@@ -22046,7 +22173,7 @@ async function pair(args2 = []) {
|
|
|
22046
22173
|
console.log("");
|
|
22047
22174
|
process.exit(0);
|
|
22048
22175
|
}
|
|
22049
|
-
stopPolling =
|
|
22176
|
+
stopPolling = subscribeToPairCompletion(
|
|
22050
22177
|
pluginId,
|
|
22051
22178
|
(info) => {
|
|
22052
22179
|
process.removeListener("SIGINT", sigintHandler);
|
|
@@ -22292,7 +22419,7 @@ async function startInfraOnly(agentId) {
|
|
|
22292
22419
|
}
|
|
22293
22420
|
|
|
22294
22421
|
// src/commands/pair-auto.ts
|
|
22295
|
-
var
|
|
22422
|
+
var API_BASE9 = resolveApiBaseUrl();
|
|
22296
22423
|
function fail(msg) {
|
|
22297
22424
|
console.error(`
|
|
22298
22425
|
${msg}
|
|
@@ -22332,7 +22459,7 @@ function networkError(msg, cause) {
|
|
|
22332
22459
|
return err;
|
|
22333
22460
|
}
|
|
22334
22461
|
async function claimOnce(token, pluginId) {
|
|
22335
|
-
const url = `${
|
|
22462
|
+
const url = `${API_BASE9}/api/pairing/claim-auto-token`;
|
|
22336
22463
|
const body = {
|
|
22337
22464
|
token,
|
|
22338
22465
|
pluginId,
|
|
@@ -22535,7 +22662,7 @@ function status() {
|
|
|
22535
22662
|
|
|
22536
22663
|
// src/commands/logout.ts
|
|
22537
22664
|
var import_picocolors7 = __toESM(require("picocolors"));
|
|
22538
|
-
var
|
|
22665
|
+
var API_BASE10 = resolveApiBaseUrl();
|
|
22539
22666
|
async function notifyBackendOffline() {
|
|
22540
22667
|
const cfg = loadCliConfig();
|
|
22541
22668
|
const pluginIds = /* @__PURE__ */ new Set([
|
|
@@ -22547,7 +22674,7 @@ async function notifyBackendOffline() {
|
|
|
22547
22674
|
try {
|
|
22548
22675
|
await Promise.all(
|
|
22549
22676
|
Array.from(pluginIds).map(
|
|
22550
|
-
(pluginId) => _postJson(`${
|
|
22677
|
+
(pluginId) => _postJson(`${API_BASE10}/api/plugin/heartbeat`, {
|
|
22551
22678
|
pluginId,
|
|
22552
22679
|
online: false
|
|
22553
22680
|
}).catch((err) => {
|
|
@@ -24689,7 +24816,7 @@ function checkChokidar() {
|
|
|
24689
24816
|
}
|
|
24690
24817
|
async function doctor(args2 = []) {
|
|
24691
24818
|
const json = args2.includes("--json");
|
|
24692
|
-
const cliVersion = true ? "2.
|
|
24819
|
+
const cliVersion = true ? "2.31.0" : "0.0.0-dev";
|
|
24693
24820
|
const apiBase = resolveApiBaseUrl();
|
|
24694
24821
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
24695
24822
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -24888,7 +25015,7 @@ async function completion(args2) {
|
|
|
24888
25015
|
// src/commands/version.ts
|
|
24889
25016
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
24890
25017
|
function version2() {
|
|
24891
|
-
const v = true ? "2.
|
|
25018
|
+
const v = true ? "2.31.0" : "unknown";
|
|
24892
25019
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
24893
25020
|
}
|
|
24894
25021
|
|
|
@@ -25019,7 +25146,7 @@ var _subcommandHelpKeys = Object.keys(HELPS);
|
|
|
25019
25146
|
var fs35 = __toESM(require("fs"));
|
|
25020
25147
|
var os27 = __toESM(require("os"));
|
|
25021
25148
|
var path44 = __toESM(require("path"));
|
|
25022
|
-
var
|
|
25149
|
+
var https8 = __toESM(require("https"));
|
|
25023
25150
|
var import_node_child_process12 = require("child_process");
|
|
25024
25151
|
var import_picocolors16 = __toESM(require("picocolors"));
|
|
25025
25152
|
var PKG_NAME = "codeam-cli";
|
|
@@ -25065,7 +25192,7 @@ function compareSemver(a, b) {
|
|
|
25065
25192
|
}
|
|
25066
25193
|
function fetchLatest() {
|
|
25067
25194
|
return new Promise((resolve6) => {
|
|
25068
|
-
const req =
|
|
25195
|
+
const req = https8.get(
|
|
25069
25196
|
REGISTRY_URL,
|
|
25070
25197
|
{ headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
|
|
25071
25198
|
(res) => {
|
|
@@ -25174,7 +25301,7 @@ function checkForUpdates() {
|
|
|
25174
25301
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
25175
25302
|
if (process.env.CI) return;
|
|
25176
25303
|
if (!process.stdout.isTTY) return;
|
|
25177
|
-
const current = true ? "2.
|
|
25304
|
+
const current = true ? "2.31.0" : null;
|
|
25178
25305
|
if (!current) return;
|
|
25179
25306
|
const cache = readCache();
|
|
25180
25307
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.31.0",
|
|
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",
|