codeam-cli 2.61.34 → 2.61.36
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 +130 -69
- package/dist/postinstall.js +33 -0
- 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.61.35] — 2026-07-24
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **box:** Box user must own /home/box — set HOME late so the build doesn't root-own ~/.codeam
|
|
12
|
+
|
|
13
|
+
## [2.61.34] — 2026-07-24
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **box:** Pre-install every agent + gh/glab + beads/dolt/headroom in the fleet image
|
|
18
|
+
|
|
7
19
|
## [2.61.33] — 2026-07-24
|
|
8
20
|
|
|
9
21
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -6355,7 +6355,7 @@ function readAnonId() {
|
|
|
6355
6355
|
}
|
|
6356
6356
|
function superProperties() {
|
|
6357
6357
|
return {
|
|
6358
|
-
cliVersion: true ? "2.61.
|
|
6358
|
+
cliVersion: true ? "2.61.36" : "0.0.0-dev",
|
|
6359
6359
|
nodeVersion: process.version,
|
|
6360
6360
|
platform: process.platform,
|
|
6361
6361
|
arch: process.arch,
|
|
@@ -6536,7 +6536,7 @@ var os4 = __toESM(require("os"));
|
|
|
6536
6536
|
// package.json
|
|
6537
6537
|
var package_default = {
|
|
6538
6538
|
name: "codeam-cli",
|
|
6539
|
-
version: "2.61.
|
|
6539
|
+
version: "2.61.36",
|
|
6540
6540
|
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.",
|
|
6541
6541
|
type: "commonjs",
|
|
6542
6542
|
main: "dist/index.js",
|
|
@@ -7707,7 +7707,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
7707
7707
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
7708
7708
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
7709
7709
|
// pair/reconnect). Older backends ignore the extra field.
|
|
7710
|
-
..."2.61.
|
|
7710
|
+
..."2.61.36" ? { ideVersion: "2.61.36" } : {}
|
|
7711
7711
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
7712
7712
|
}
|
|
7713
7713
|
/**
|
|
@@ -18691,7 +18691,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
18691
18691
|
if (process.env.NODE_ENV === "test") return;
|
|
18692
18692
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
18693
18693
|
if (process.env.CI) return;
|
|
18694
|
-
const current = true ? "2.61.
|
|
18694
|
+
const current = true ? "2.61.36" : null;
|
|
18695
18695
|
if (!current) return;
|
|
18696
18696
|
const cache = readCache();
|
|
18697
18697
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -18708,7 +18708,7 @@ function checkForUpdates() {
|
|
|
18708
18708
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
18709
18709
|
if (process.env.CI) return;
|
|
18710
18710
|
if (!process.stdout.isTTY) return;
|
|
18711
|
-
const current = true ? "2.61.
|
|
18711
|
+
const current = true ? "2.61.36" : null;
|
|
18712
18712
|
if (!current) return;
|
|
18713
18713
|
const cache = readCache();
|
|
18714
18714
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -18728,7 +18728,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
18728
18728
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
18729
18729
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
18730
18730
|
function currentCliVersion() {
|
|
18731
|
-
return true ? "2.61.
|
|
18731
|
+
return true ? "2.61.36" : null;
|
|
18732
18732
|
}
|
|
18733
18733
|
function runCmd(cmd, args2, timeoutMs) {
|
|
18734
18734
|
return new Promise((resolve8) => {
|
|
@@ -18978,8 +18978,16 @@ function isFleetBoxRefPayload(p2) {
|
|
|
18978
18978
|
if (typeof p2.boxId !== "string") return false;
|
|
18979
18979
|
if (!isFleetContainerName(p2.containerName)) return false;
|
|
18980
18980
|
if (p2.removeVolume !== void 0 && typeof p2.removeVolume !== "boolean") return false;
|
|
18981
|
+
if (p2.enrollToken !== void 0 && (typeof p2.enrollToken !== "string" || !p2.enrollToken)) {
|
|
18982
|
+
return false;
|
|
18983
|
+
}
|
|
18984
|
+
if (p2.apiOrigin !== void 0 && (typeof p2.apiOrigin !== "string" || !p2.apiOrigin)) return false;
|
|
18985
|
+
if (p2.limits !== void 0 && !isFleetLimits(p2.limits)) return false;
|
|
18981
18986
|
return true;
|
|
18982
18987
|
}
|
|
18988
|
+
function fleetRefCanRecreate(p2) {
|
|
18989
|
+
return typeof p2.enrollToken === "string" && p2.enrollToken.length > 0 && typeof p2.apiOrigin === "string" && p2.apiOrigin.length > 0 && p2.limits !== void 0;
|
|
18990
|
+
}
|
|
18983
18991
|
function fleetUserIdFromContainerName(containerName) {
|
|
18984
18992
|
return containerName.slice("codeam-box-".length);
|
|
18985
18993
|
}
|
|
@@ -18992,6 +19000,57 @@ function isMissingVolumeError(stderr) {
|
|
|
18992
19000
|
function resolveFleetBoxImage() {
|
|
18993
19001
|
return process.env.CODEAM_FLEET_BOX_IMAGE || "ghcr.io/edgar-durand/codeam-box:latest";
|
|
18994
19002
|
}
|
|
19003
|
+
function buildFleetBoxRunArgs(p2) {
|
|
19004
|
+
const userId = fleetUserIdFromContainerName(p2.containerName);
|
|
19005
|
+
const image = resolveFleetBoxImage();
|
|
19006
|
+
return [
|
|
19007
|
+
"run",
|
|
19008
|
+
"-d",
|
|
19009
|
+
// Registry-default image: always pull so the box never silently runs this
|
|
19010
|
+
// host's STALE cached :latest. An explicit CODEAM_FLEET_BOX_IMAGE override
|
|
19011
|
+
// (int test / operator) keeps docker's default policy — a local-only tag
|
|
19012
|
+
// can't be pulled.
|
|
19013
|
+
...process.env.CODEAM_FLEET_BOX_IMAGE ? [] : ["--pull=always"],
|
|
19014
|
+
"--name",
|
|
19015
|
+
p2.containerName,
|
|
19016
|
+
"--cap-drop",
|
|
19017
|
+
"ALL",
|
|
19018
|
+
"--security-opt",
|
|
19019
|
+
"no-new-privileges",
|
|
19020
|
+
"--memory",
|
|
19021
|
+
`${p2.limits.memoryMb}m`,
|
|
19022
|
+
"--cpus",
|
|
19023
|
+
String(p2.limits.cpus),
|
|
19024
|
+
"--pids-limit",
|
|
19025
|
+
String(p2.limits.pidsLimit),
|
|
19026
|
+
"--network",
|
|
19027
|
+
"fleet-net",
|
|
19028
|
+
"--label",
|
|
19029
|
+
`com.codeagent.user-id=${userId}`,
|
|
19030
|
+
"--label",
|
|
19031
|
+
`com.codeagent.box-id=${p2.boxId}`,
|
|
19032
|
+
"--label",
|
|
19033
|
+
"com.codeagent.created-by=fleet",
|
|
19034
|
+
"-v",
|
|
19035
|
+
`${p2.containerName}:/home/box`,
|
|
19036
|
+
// Bare `-e NAME` — docker reads the value from ITS OWN process env (supplied
|
|
19037
|
+
// via opts.env), never from this argv.
|
|
19038
|
+
"-e",
|
|
19039
|
+
"CODEAM_ENROLL_TOKEN",
|
|
19040
|
+
"-e",
|
|
19041
|
+
`CODEAM_API_URL=${p2.apiOrigin}`,
|
|
19042
|
+
// User-facing "My Servers" label; read at redeem via resolveHostLabel.
|
|
19043
|
+
"-e",
|
|
19044
|
+
"CODEAM_HOST_LABEL=CodeAgent Box",
|
|
19045
|
+
// The enroll token is single-use but lives in the container's fixed env;
|
|
19046
|
+
// resolveHostIdentity resumes from the sealed identity on a terminal
|
|
19047
|
+
// enroll-token rejection (a plain wake/restart replaying the consumed
|
|
19048
|
+
// token). Kept for observability / older-CLI back-compat.
|
|
19049
|
+
"-e",
|
|
19050
|
+
"CODEAM_ENROLL_EPHEMERAL=1",
|
|
19051
|
+
image
|
|
19052
|
+
];
|
|
19053
|
+
}
|
|
18995
19054
|
var DOCKER_RUN_TIMEOUT_MS = 12e4;
|
|
18996
19055
|
var defaultDockerRunner = {
|
|
18997
19056
|
run(args2, opts = {}) {
|
|
@@ -19423,7 +19482,6 @@ var HostAgentSupervisor = class {
|
|
|
19423
19482
|
*/
|
|
19424
19483
|
async fleetCreateBox(payload) {
|
|
19425
19484
|
const { containerName, limits } = payload;
|
|
19426
|
-
const userId = fleetUserIdFromContainerName(containerName);
|
|
19427
19485
|
log.info(
|
|
19428
19486
|
"host-agent",
|
|
19429
19487
|
`fleet_create_box id=${payload.boxId} name=${containerName} mem=${limits.memoryMb}m cpus=${limits.cpus} pids=${limits.pidsLimit}`
|
|
@@ -19437,63 +19495,7 @@ var HostAgentSupervisor = class {
|
|
|
19437
19495
|
`fleet_create_box: pre-create rm of ${containerName} failed (code=${rm.code}): ${rm.stderr.trim().slice(-200)} \u2014 attempting run anyway`
|
|
19438
19496
|
);
|
|
19439
19497
|
}
|
|
19440
|
-
const
|
|
19441
|
-
const args2 = [
|
|
19442
|
-
"run",
|
|
19443
|
-
"-d",
|
|
19444
|
-
// Registry-default image: always pull so a new box never silently
|
|
19445
|
-
// runs this host's STALE cached :latest (2026-07-16: cache had CLI
|
|
19446
|
-
// 2.61.4 while the registry had 2.61.9). An explicit
|
|
19447
|
-
// CODEAM_FLEET_BOX_IMAGE override (int test / operator) keeps
|
|
19448
|
-
// docker's default policy — a local-only tag can't be pulled.
|
|
19449
|
-
...process.env.CODEAM_FLEET_BOX_IMAGE ? [] : ["--pull=always"],
|
|
19450
|
-
"--name",
|
|
19451
|
-
containerName,
|
|
19452
|
-
"--cap-drop",
|
|
19453
|
-
"ALL",
|
|
19454
|
-
"--security-opt",
|
|
19455
|
-
"no-new-privileges",
|
|
19456
|
-
"--memory",
|
|
19457
|
-
`${limits.memoryMb}m`,
|
|
19458
|
-
"--cpus",
|
|
19459
|
-
String(limits.cpus),
|
|
19460
|
-
"--pids-limit",
|
|
19461
|
-
String(limits.pidsLimit),
|
|
19462
|
-
"--network",
|
|
19463
|
-
"fleet-net",
|
|
19464
|
-
"--label",
|
|
19465
|
-
`com.codeagent.user-id=${userId}`,
|
|
19466
|
-
"--label",
|
|
19467
|
-
`com.codeagent.box-id=${payload.boxId}`,
|
|
19468
|
-
"--label",
|
|
19469
|
-
"com.codeagent.created-by=fleet",
|
|
19470
|
-
"-v",
|
|
19471
|
-
`${containerName}:/home/box`,
|
|
19472
|
-
// Bare `-e NAME` (no `=value`) — docker reads the value from ITS OWN
|
|
19473
|
-
// process env (supplied below via `opts.env`), never from this argv.
|
|
19474
|
-
"-e",
|
|
19475
|
-
"CODEAM_ENROLL_TOKEN",
|
|
19476
|
-
"-e",
|
|
19477
|
-
`CODEAM_API_URL=${payload.apiOrigin}`,
|
|
19478
|
-
// User-facing label for the rescued box's "My Servers" card. Not a
|
|
19479
|
-
// secret → plain `-e KEY=value`. The box's host-agent reads it at
|
|
19480
|
-
// redeem (resolveHostLabel) so a rescued user sees "CodeAgent Box",
|
|
19481
|
-
// not the generic "my-server" or the ugly container cuid.
|
|
19482
|
-
"-e",
|
|
19483
|
-
"CODEAM_HOST_LABEL=CodeAgent Box",
|
|
19484
|
-
// The enroll token above is a SINGLE-USE bootstrap, but it lives in the
|
|
19485
|
-
// container's fixed env — it can't be stripped after first boot like the
|
|
19486
|
-
// self-hosted systemd unit does, so on every restart (docker restart /
|
|
19487
|
-
// reboot / fleet_start_box wake) the redeem terminally expires.
|
|
19488
|
-
// `resolveHostIdentity` now resumes from a sealed identity on ANY
|
|
19489
|
-
// terminal enroll-token rejection (not just ephemeral boxes — see its
|
|
19490
|
-
// doc comment), so this flag is no longer load-bearing for that
|
|
19491
|
-
// decision; kept set for observability/back-compat with older CLI
|
|
19492
|
-
// builds that still gate on it. Not a secret → plain KEY=value.
|
|
19493
|
-
"-e",
|
|
19494
|
-
"CODEAM_ENROLL_EPHEMERAL=1",
|
|
19495
|
-
image
|
|
19496
|
-
];
|
|
19498
|
+
const args2 = buildFleetBoxRunArgs(payload);
|
|
19497
19499
|
const res = await this.docker.run(args2, {
|
|
19498
19500
|
timeoutMs: DOCKER_RUN_TIMEOUT_MS,
|
|
19499
19501
|
env: { CODEAM_ENROLL_TOKEN: payload.enrollToken }
|
|
@@ -19513,15 +19515,74 @@ var HostAgentSupervisor = class {
|
|
|
19513
19515
|
/** `fleet_start_box` — wake a sleeping box (`docker start`). Idempotent: a
|
|
19514
19516
|
* container the host already removed is treated as success. */
|
|
19515
19517
|
async fleetStartBox(payload) {
|
|
19516
|
-
|
|
19517
|
-
|
|
19518
|
+
const { containerName } = payload;
|
|
19519
|
+
if (fleetRefCanRecreate(payload) && await this.fleetBoxImageStale(containerName)) {
|
|
19520
|
+
log.info(
|
|
19521
|
+
"host-agent",
|
|
19522
|
+
`fleet_start_box id=${payload.boxId} name=${containerName} \u2014 image stale \u2192 recreating from :latest`
|
|
19523
|
+
);
|
|
19524
|
+
const rm = await this.docker.run(["rm", "-f", containerName], {
|
|
19525
|
+
timeoutMs: DOCKER_RUN_TIMEOUT_MS
|
|
19526
|
+
});
|
|
19527
|
+
if (rm.code !== 0 && !isMissingContainerError(rm.stderr)) {
|
|
19528
|
+
log.warn(
|
|
19529
|
+
"host-agent",
|
|
19530
|
+
`fleet_start_box: pre-recreate rm of ${containerName} failed (code=${rm.code}): ${rm.stderr.trim().slice(-200)} \u2014 attempting run anyway`
|
|
19531
|
+
);
|
|
19532
|
+
}
|
|
19533
|
+
const args2 = buildFleetBoxRunArgs({
|
|
19534
|
+
boxId: payload.boxId,
|
|
19535
|
+
containerName,
|
|
19536
|
+
apiOrigin: payload.apiOrigin,
|
|
19537
|
+
limits: payload.limits
|
|
19538
|
+
});
|
|
19539
|
+
const res2 = await this.docker.run(args2, {
|
|
19540
|
+
timeoutMs: DOCKER_RUN_TIMEOUT_MS,
|
|
19541
|
+
env: { CODEAM_ENROLL_TOKEN: payload.enrollToken }
|
|
19542
|
+
});
|
|
19543
|
+
if (res2.code === 0) {
|
|
19544
|
+
log.info(
|
|
19545
|
+
"host-agent",
|
|
19546
|
+
`fleet box ${containerName} recreated from :latest (${res2.stdout.trim().slice(0, 12)})`
|
|
19547
|
+
);
|
|
19548
|
+
} else {
|
|
19549
|
+
log.warn(
|
|
19550
|
+
"host-agent",
|
|
19551
|
+
`fleet_start_box recreate ${containerName} failed (code=${res2.code}): ${res2.stderr.trim().slice(-300)}`
|
|
19552
|
+
);
|
|
19553
|
+
}
|
|
19554
|
+
return;
|
|
19555
|
+
}
|
|
19556
|
+
log.info("host-agent", `fleet_start_box id=${payload.boxId} name=${containerName}`);
|
|
19557
|
+
const res = await this.docker.run(["start", containerName]);
|
|
19518
19558
|
if (res.code !== 0 && !isMissingContainerError(res.stderr)) {
|
|
19519
19559
|
log.warn(
|
|
19520
19560
|
"host-agent",
|
|
19521
|
-
`fleet_start_box ${
|
|
19561
|
+
`fleet_start_box ${containerName} failed (code=${res.code}): ${res.stderr.trim().slice(-300)}`
|
|
19522
19562
|
);
|
|
19523
19563
|
}
|
|
19524
19564
|
}
|
|
19565
|
+
/**
|
|
19566
|
+
* True when the box's container was created from an image OTHER than the
|
|
19567
|
+
* current registry `:latest` (a stale runtime), or the container is gone.
|
|
19568
|
+
* Pulls `:latest` first so the comparison is against the freshest image.
|
|
19569
|
+
* Best-effort + fail-SAFE: a local-image override (int test / operator) or any
|
|
19570
|
+
* pull/inspect error returns false → the caller falls back to a plain
|
|
19571
|
+
* `docker start`, so a transient docker hiccup can never wedge a wake.
|
|
19572
|
+
*/
|
|
19573
|
+
async fleetBoxImageStale(containerName) {
|
|
19574
|
+
if (process.env.CODEAM_FLEET_BOX_IMAGE) return false;
|
|
19575
|
+
const image = resolveFleetBoxImage();
|
|
19576
|
+
const cur = await this.docker.run(["inspect", "--format", "{{.Image}}", containerName]);
|
|
19577
|
+
if (cur.code !== 0) {
|
|
19578
|
+
return isMissingContainerError(cur.stderr);
|
|
19579
|
+
}
|
|
19580
|
+
const pull = await this.docker.run(["pull", image], { timeoutMs: DOCKER_RUN_TIMEOUT_MS });
|
|
19581
|
+
if (pull.code !== 0) return false;
|
|
19582
|
+
const latest = await this.docker.run(["inspect", "--format", "{{.Id}}", image]);
|
|
19583
|
+
if (latest.code !== 0) return false;
|
|
19584
|
+
return cur.stdout.trim() !== "" && cur.stdout.trim() !== latest.stdout.trim();
|
|
19585
|
+
}
|
|
19525
19586
|
/** `fleet_stop_box` — sleep an idle box (`docker stop`). MUST be
|
|
19526
19587
|
* idempotent — the backend's reap sweeps may re-send a stop for a box
|
|
19527
19588
|
* the host already stopped/removed; "No such container" is success. */
|
|
@@ -38737,7 +38798,7 @@ function checkChokidar() {
|
|
|
38737
38798
|
}
|
|
38738
38799
|
async function doctor(args2 = []) {
|
|
38739
38800
|
const json = args2.includes("--json");
|
|
38740
|
-
const cliVersion = true ? "2.61.
|
|
38801
|
+
const cliVersion = true ? "2.61.36" : "0.0.0-dev";
|
|
38741
38802
|
const apiBase2 = resolveApiBaseUrl();
|
|
38742
38803
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
38743
38804
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -39248,7 +39309,7 @@ async function mcpRun(args2) {
|
|
|
39248
39309
|
// src/commands/version.ts
|
|
39249
39310
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
39250
39311
|
function version2() {
|
|
39251
|
-
const v = true ? "2.61.
|
|
39312
|
+
const v = true ? "2.61.36" : "unknown";
|
|
39252
39313
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
39253
39314
|
}
|
|
39254
39315
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// src/postinstall.ts
|
|
5
|
+
var c = {
|
|
6
|
+
reset: "\x1B[0m",
|
|
7
|
+
bold: "\x1B[1m",
|
|
8
|
+
dim: "\x1B[2m",
|
|
9
|
+
green: "\x1B[32m",
|
|
10
|
+
cyan: "\x1B[36m",
|
|
11
|
+
violet: "\x1B[35m",
|
|
12
|
+
white: "\x1B[97m"
|
|
13
|
+
};
|
|
14
|
+
var lines = [
|
|
15
|
+
"",
|
|
16
|
+
` ${c.violet}${c.bold}codeam-cli${c.reset} ${c.dim}\u2014 Claude Code remote control${c.reset}`,
|
|
17
|
+
"",
|
|
18
|
+
` ${c.dim}1.${c.reset} Pair your phone:`,
|
|
19
|
+
` ${c.cyan}codeam pair${c.reset}`,
|
|
20
|
+
"",
|
|
21
|
+
` ${c.dim}2.${c.reset} Launch Claude Code with mobile control:`,
|
|
22
|
+
` ${c.cyan}codeam${c.reset}`,
|
|
23
|
+
"",
|
|
24
|
+
` ${c.dim}Other commands:${c.reset}`,
|
|
25
|
+
` ${c.white}codeam sessions${c.reset} ${c.dim}list paired devices${c.reset}`,
|
|
26
|
+
` ${c.white}codeam status${c.reset} ${c.dim}show connection info${c.reset}`,
|
|
27
|
+
` ${c.white}codeam logout${c.reset} ${c.dim}remove all sessions${c.reset}`,
|
|
28
|
+
"",
|
|
29
|
+
` ${c.dim}Requires Claude Code:${c.reset} ${c.green}npm install -g @anthropic-ai/claude-code${c.reset}`,
|
|
30
|
+
` ${c.dim}Mobile app:${c.reset} ${c.green}https://www.codeagent-mobile.com${c.reset}`,
|
|
31
|
+
""
|
|
32
|
+
];
|
|
33
|
+
process.stdout.write(lines.join("\n") + "\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.61.
|
|
3
|
+
"version": "2.61.36",
|
|
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",
|