codeam-cli 2.23.6 → 2.23.8
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/dist/index.js +109 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ 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.23.7] — 2026-05-26
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Emit typed agent_banner chunk for Claude startup splash (#195)
|
|
12
|
+
|
|
13
|
+
## [2.23.6] — 2026-05-26
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **cli:** Raise listProjectFiles cap from 5000 to 50000 (#194)
|
|
18
|
+
|
|
7
19
|
## [2.23.5] — 2026-05-25
|
|
8
20
|
|
|
9
21
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -441,7 +441,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
441
441
|
// package.json
|
|
442
442
|
var package_default = {
|
|
443
443
|
name: "codeam-cli",
|
|
444
|
-
version: "2.23.
|
|
444
|
+
version: "2.23.8",
|
|
445
445
|
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.",
|
|
446
446
|
type: "commonjs",
|
|
447
447
|
main: "dist/index.js",
|
|
@@ -718,6 +718,9 @@ async function postLinkCredential(input) {
|
|
|
718
718
|
if (input.modelPreference) {
|
|
719
719
|
body.modelPreference = input.modelPreference;
|
|
720
720
|
}
|
|
721
|
+
if (input.agentState) {
|
|
722
|
+
body.agentState = input.agentState;
|
|
723
|
+
}
|
|
721
724
|
try {
|
|
722
725
|
await _transport.postJsonAuthed(
|
|
723
726
|
`${API_BASE}/api/plugin/agents/${input.agentId}/link`,
|
|
@@ -5768,7 +5771,7 @@ function readAnonId() {
|
|
|
5768
5771
|
}
|
|
5769
5772
|
function superProperties() {
|
|
5770
5773
|
return {
|
|
5771
|
-
cliVersion: true ? "2.23.
|
|
5774
|
+
cliVersion: true ? "2.23.8" : "0.0.0-dev",
|
|
5772
5775
|
nodeVersion: process.version,
|
|
5773
5776
|
platform: process.platform,
|
|
5774
5777
|
arch: process.arch,
|
|
@@ -9036,11 +9039,12 @@ function claudeCredentialsPaths() {
|
|
|
9036
9039
|
];
|
|
9037
9040
|
}
|
|
9038
9041
|
async function extractLocalClaudeToken() {
|
|
9042
|
+
const agentState = readClaudeAgentState();
|
|
9039
9043
|
for (const flat of claudeCredentialsPaths()) {
|
|
9040
9044
|
if (!fs7.existsSync(flat)) continue;
|
|
9041
9045
|
const credential = fs7.readFileSync(flat, "utf8").trim();
|
|
9042
9046
|
if (credential.length > 0) {
|
|
9043
|
-
return { method: "oauth", credential, source: "flat-file" };
|
|
9047
|
+
return { method: "oauth", credential, source: "flat-file", agentState };
|
|
9044
9048
|
}
|
|
9045
9049
|
}
|
|
9046
9050
|
if (process.platform === "darwin") {
|
|
@@ -9053,7 +9057,7 @@ async function extractLocalClaudeToken() {
|
|
|
9053
9057
|
);
|
|
9054
9058
|
const credential = stdout.trim();
|
|
9055
9059
|
if (credential.length > 0) {
|
|
9056
|
-
return { method: "oauth", credential, source: "macos-keychain" };
|
|
9060
|
+
return { method: "oauth", credential, source: "macos-keychain", agentState };
|
|
9057
9061
|
}
|
|
9058
9062
|
} catch {
|
|
9059
9063
|
}
|
|
@@ -9061,6 +9065,19 @@ async function extractLocalClaudeToken() {
|
|
|
9061
9065
|
}
|
|
9062
9066
|
return null;
|
|
9063
9067
|
}
|
|
9068
|
+
function readClaudeAgentState() {
|
|
9069
|
+
const STATE_MAX_BYTES = 256 * 1024;
|
|
9070
|
+
const candidate = path10.join(os9.homedir(), ".claude.json");
|
|
9071
|
+
try {
|
|
9072
|
+
if (!fs7.existsSync(candidate)) return void 0;
|
|
9073
|
+
const buf = fs7.readFileSync(candidate);
|
|
9074
|
+
if (buf.length === 0 || buf.length > STATE_MAX_BYTES) return void 0;
|
|
9075
|
+
const text = buf.toString("utf8").trim();
|
|
9076
|
+
return text.length > 0 ? text : void 0;
|
|
9077
|
+
} catch {
|
|
9078
|
+
return void 0;
|
|
9079
|
+
}
|
|
9080
|
+
}
|
|
9064
9081
|
|
|
9065
9082
|
// src/agents/claude/link.ts
|
|
9066
9083
|
function claudeCredentialLocator() {
|
|
@@ -9633,6 +9650,38 @@ function detectListSelector(lines) {
|
|
|
9633
9650
|
currentIndex
|
|
9634
9651
|
};
|
|
9635
9652
|
}
|
|
9653
|
+
var BANNER_ART_RE = /[█▀▄▌▐▝▘▛▜▙▟▖▗▔▕▮▯▰▱▓▒░◆◇]/;
|
|
9654
|
+
var BANNER_META_RE = /(?:Sonnet|Opus|Haiku|Claude)(?:\s|·|-|\(|$)/i;
|
|
9655
|
+
function detectStartupBanner(lines) {
|
|
9656
|
+
for (let i = 0; i + 2 < lines.length; i++) {
|
|
9657
|
+
if (!/^▐▛[█]+▜▌/.test(lines[i])) continue;
|
|
9658
|
+
if (!/^▝▜[█]+▛▘/.test(lines[i + 1])) continue;
|
|
9659
|
+
if (!lines[i + 2].includes("\u2598\u2598")) continue;
|
|
9660
|
+
return {
|
|
9661
|
+
title: lines[i].replace(/^▐▛[█]+▜▌\s*/, "").trim(),
|
|
9662
|
+
subtitle: lines[i + 1].replace(/^▝▜[█]+▛▘\s*/, "").trim(),
|
|
9663
|
+
path: lines[i + 2].replace(/.*▝▝\s*/, "").trim(),
|
|
9664
|
+
startIdx: i,
|
|
9665
|
+
endIdx: i + 2
|
|
9666
|
+
};
|
|
9667
|
+
}
|
|
9668
|
+
const metaIdx = lines.findIndex(
|
|
9669
|
+
(l) => BANNER_META_RE.test(l) && /(?:Claude|API|Console)/i.test(l) && !BANNER_ART_RE.test(l)
|
|
9670
|
+
);
|
|
9671
|
+
if (metaIdx === -1) return null;
|
|
9672
|
+
let artStart = metaIdx;
|
|
9673
|
+
while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
|
|
9674
|
+
if (metaIdx - artStart < 2) return null;
|
|
9675
|
+
const pathLine = (lines[metaIdx + 1] ?? "").trim();
|
|
9676
|
+
const path40 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
|
|
9677
|
+
return {
|
|
9678
|
+
title: "",
|
|
9679
|
+
subtitle: lines[metaIdx].trim(),
|
|
9680
|
+
path: path40,
|
|
9681
|
+
startIdx: artStart,
|
|
9682
|
+
endIdx: metaIdx + (path40 ? 1 : 0)
|
|
9683
|
+
};
|
|
9684
|
+
}
|
|
9636
9685
|
|
|
9637
9686
|
// src/agents/claude/runtime.ts
|
|
9638
9687
|
var ClaudeRuntimeStrategy = class {
|
|
@@ -9705,6 +9754,9 @@ var ClaudeRuntimeStrategy = class {
|
|
|
9705
9754
|
detectReadyPrompt(lines) {
|
|
9706
9755
|
return lines.some((l) => /^\?\s.*shortcut/i.test(l.trim()));
|
|
9707
9756
|
}
|
|
9757
|
+
detectStartupBanner(lines) {
|
|
9758
|
+
return detectStartupBanner(lines);
|
|
9759
|
+
}
|
|
9708
9760
|
credentialLocator() {
|
|
9709
9761
|
return claudeCredentialLocator();
|
|
9710
9762
|
}
|
|
@@ -11565,6 +11617,16 @@ var OutputService = class _OutputService {
|
|
|
11565
11617
|
emitter;
|
|
11566
11618
|
runtime;
|
|
11567
11619
|
lastSentContent = "";
|
|
11620
|
+
/**
|
|
11621
|
+
* Per-session latch — emits the agent's startup banner as a typed
|
|
11622
|
+
* `agent_banner` chunk exactly once, then strips the banner lines
|
|
11623
|
+
* from every subsequent rendered frame so the ASCII art never
|
|
11624
|
+
* reaches the `text` chunk. Lives at the OutputService level (not
|
|
11625
|
+
* per-turn) because the banner is a session-boot artifact —
|
|
11626
|
+
* pair/re-pair spawns a fresh service so the latch naturally
|
|
11627
|
+
* resets.
|
|
11628
|
+
*/
|
|
11629
|
+
bannerEmitted = false;
|
|
11568
11630
|
/**
|
|
11569
11631
|
* Wall-clock of the most recent tick where the rendered + filtered
|
|
11570
11632
|
* content actually changed. Most agent TUIs keep redrawing a
|
|
@@ -11733,6 +11795,40 @@ var OutputService = class _OutputService {
|
|
|
11733
11795
|
this.startTime = Date.now();
|
|
11734
11796
|
this.pollTimer = setInterval(() => this.tick(), _OutputService.POLL_MS);
|
|
11735
11797
|
}
|
|
11798
|
+
/**
|
|
11799
|
+
* One-shot banner emit + per-tick strip. Runs the per-agent
|
|
11800
|
+
* `detectStartupBanner` (when the strategy exposes one) and, on
|
|
11801
|
+
* first match, fires a typed `agent_banner` OutputChunk to the
|
|
11802
|
+
* backend. On every tick from then on it slices the banner range
|
|
11803
|
+
* out of the rendered line array so the ASCII / box-art body
|
|
11804
|
+
* doesn't leak into a downstream `text` chunk. Agents that don't
|
|
11805
|
+
* implement the detector pass through unchanged.
|
|
11806
|
+
*/
|
|
11807
|
+
handleStartupBanner(lines) {
|
|
11808
|
+
const detect = this.runtime.detectStartupBanner?.bind(this.runtime);
|
|
11809
|
+
if (!detect) return lines;
|
|
11810
|
+
const banner = detect(lines);
|
|
11811
|
+
if (!banner) return lines;
|
|
11812
|
+
if (!this.bannerEmitted) {
|
|
11813
|
+
this.bannerEmitted = true;
|
|
11814
|
+
this.send(
|
|
11815
|
+
{
|
|
11816
|
+
type: "agent_banner",
|
|
11817
|
+
agentId: this.runtime.id,
|
|
11818
|
+
title: banner.title,
|
|
11819
|
+
subtitle: banner.subtitle,
|
|
11820
|
+
path: banner.path,
|
|
11821
|
+
done: true
|
|
11822
|
+
},
|
|
11823
|
+
{ critical: true }
|
|
11824
|
+
).catch(() => {
|
|
11825
|
+
});
|
|
11826
|
+
}
|
|
11827
|
+
return [
|
|
11828
|
+
...lines.slice(0, banner.startIdx),
|
|
11829
|
+
...lines.slice(banner.endIdx + 1)
|
|
11830
|
+
];
|
|
11831
|
+
}
|
|
11736
11832
|
async send(body, opts = {}) {
|
|
11737
11833
|
const outcome = await this.emitter.send(body, opts);
|
|
11738
11834
|
if (outcome.dead && this.pty.isActive) {
|
|
@@ -11779,7 +11875,8 @@ var OutputService = class _OutputService {
|
|
|
11779
11875
|
return;
|
|
11780
11876
|
}
|
|
11781
11877
|
if (elapsed < _OutputService.WARMUP_MS) return;
|
|
11782
|
-
const
|
|
11878
|
+
const rendered = this.runtime.renderToLines?.(this.pty.content) ?? renderLines(this.pty.content);
|
|
11879
|
+
const lines = this.handleStartupBanner(rendered);
|
|
11783
11880
|
const parseLine2 = this.runtime.parseTuiChrome?.bind(this.runtime) ?? (() => null);
|
|
11784
11881
|
this.steps.ingest(lines, parseLine2);
|
|
11785
11882
|
const stepsDelta = this.steps.consumeDelta();
|
|
@@ -11851,7 +11948,8 @@ var OutputService = class _OutputService {
|
|
|
11851
11948
|
}
|
|
11852
11949
|
}
|
|
11853
11950
|
finalize() {
|
|
11854
|
-
const
|
|
11951
|
+
const rendered = this.runtime.renderToLines?.(this.pty.content) ?? renderLines(this.pty.content);
|
|
11952
|
+
const lines = this.handleStartupBanner(rendered);
|
|
11855
11953
|
const parseLine2 = this.runtime.parseTuiChrome?.bind(this.runtime) ?? (() => null);
|
|
11856
11954
|
this.steps.ingest(lines, parseLine2);
|
|
11857
11955
|
const stepsDelta = this.steps.consumeDelta();
|
|
@@ -15170,7 +15268,8 @@ async function uploadAndSucceed(ctx, paired, pluginId, token) {
|
|
|
15170
15268
|
pluginId,
|
|
15171
15269
|
pluginAuthToken: paired.pluginAuthToken,
|
|
15172
15270
|
method: token.method,
|
|
15173
|
-
credential: token.credential
|
|
15271
|
+
credential: token.credential,
|
|
15272
|
+
agentState: token.agentState
|
|
15174
15273
|
});
|
|
15175
15274
|
if (!result.ok) {
|
|
15176
15275
|
uploadSpin.stop("Failed");
|
|
@@ -18401,7 +18500,7 @@ function checkChokidar() {
|
|
|
18401
18500
|
}
|
|
18402
18501
|
async function doctor(args2 = []) {
|
|
18403
18502
|
const json = args2.includes("--json");
|
|
18404
|
-
const cliVersion = true ? "2.23.
|
|
18503
|
+
const cliVersion = true ? "2.23.8" : "0.0.0-dev";
|
|
18405
18504
|
const apiBase = resolveApiBaseUrl();
|
|
18406
18505
|
const diagnosticId = (0, import_node_crypto5.randomUUID)();
|
|
18407
18506
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -18600,7 +18699,7 @@ async function completion(args2) {
|
|
|
18600
18699
|
// src/commands/version.ts
|
|
18601
18700
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
18602
18701
|
function version2() {
|
|
18603
|
-
const v = true ? "2.23.
|
|
18702
|
+
const v = true ? "2.23.8" : "unknown";
|
|
18604
18703
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
18605
18704
|
}
|
|
18606
18705
|
|
|
@@ -18828,7 +18927,7 @@ function checkForUpdates() {
|
|
|
18828
18927
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
18829
18928
|
if (process.env.CI) return;
|
|
18830
18929
|
if (!process.stdout.isTTY) return;
|
|
18831
|
-
const current = true ? "2.23.
|
|
18930
|
+
const current = true ? "2.23.8" : null;
|
|
18832
18931
|
if (!current) return;
|
|
18833
18932
|
const cache = readCache();
|
|
18834
18933
|
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.23.
|
|
3
|
+
"version": "2.23.8",
|
|
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",
|