codeam-cli 2.61.32 → 2.61.33
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 +6 -0
- package/dist/index.js +153 -35
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ 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.32] — 2026-07-24
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **shared:** Add GitLab as a version_control integration
|
|
12
|
+
|
|
7
13
|
## [2.61.31] — 2026-07-24
|
|
8
14
|
|
|
9
15
|
### 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.33" : "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.33",
|
|
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.33" ? { ideVersion: "2.61.33" } : {}
|
|
7711
7711
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
7712
7712
|
}
|
|
7713
7713
|
/**
|
|
@@ -17324,8 +17324,24 @@ function githubOwnerRepo(repoRef) {
|
|
|
17324
17324
|
if (httpsMatch) return { owner: httpsMatch[1], repo: httpsMatch[2] };
|
|
17325
17325
|
return null;
|
|
17326
17326
|
}
|
|
17327
|
-
function
|
|
17327
|
+
function gitlabProjectPath(repoRef) {
|
|
17328
17328
|
const trimmed = repoRef.trim();
|
|
17329
|
+
const https9 = /^https?:\/\/gitlab\.com\/(.+?)(?:\.git)?\/?$/.exec(trimmed);
|
|
17330
|
+
if (https9) return https9[1];
|
|
17331
|
+
if (!/^https?:\/\//.test(trimmed) && !trimmed.startsWith("git@") && trimmed.includes("/")) {
|
|
17332
|
+
return trimmed.replace(/\.git$/, "");
|
|
17333
|
+
}
|
|
17334
|
+
return null;
|
|
17335
|
+
}
|
|
17336
|
+
function repoCloneUrl(repoRef, cloneToken, provider = "github") {
|
|
17337
|
+
const trimmed = repoRef.trim();
|
|
17338
|
+
if (provider === "gitlab") {
|
|
17339
|
+
const glPath = gitlabProjectPath(trimmed);
|
|
17340
|
+
if (glPath) {
|
|
17341
|
+
return cloneToken ? `https://oauth2:${cloneToken}@gitlab.com/${glPath}.git` : `https://gitlab.com/${glPath}.git`;
|
|
17342
|
+
}
|
|
17343
|
+
if (/^https?:\/\//.test(trimmed) || trimmed.startsWith("git@")) return trimmed;
|
|
17344
|
+
}
|
|
17329
17345
|
if (cloneToken) {
|
|
17330
17346
|
const gh = githubOwnerRepo(trimmed);
|
|
17331
17347
|
if (gh) {
|
|
@@ -17354,12 +17370,15 @@ async function fetchGithubIdentity(token) {
|
|
|
17354
17370
|
return null;
|
|
17355
17371
|
}
|
|
17356
17372
|
}
|
|
17357
|
-
async function configureGitCredentials(dest, repoRef, cloneToken) {
|
|
17358
|
-
const
|
|
17359
|
-
if (!
|
|
17373
|
+
async function configureGitCredentials(dest, repoRef, cloneToken, provider = "github") {
|
|
17374
|
+
const isGitlab = provider === "gitlab";
|
|
17375
|
+
if (isGitlab ? !gitlabProjectPath(repoRef.trim()) : !githubOwnerRepo(repoRef.trim())) return;
|
|
17376
|
+
if (!cloneToken) return;
|
|
17360
17377
|
const credFile = path40.join(dest, ".git", "codeam-credentials");
|
|
17361
|
-
|
|
17362
|
-
|
|
17378
|
+
const credLine = isGitlab ? `https://oauth2:${cloneToken}@gitlab.com
|
|
17379
|
+
` : `https://x-access-token:${cloneToken}@github.com
|
|
17380
|
+
`;
|
|
17381
|
+
fs36.writeFileSync(credFile, credLine, { mode: 384 });
|
|
17363
17382
|
restrictToOwner(credFile);
|
|
17364
17383
|
const env = nonInteractiveGitEnv();
|
|
17365
17384
|
const git2 = (args2) => execFileP4("git", ["-C", dest, ...args2], { timeout: 3e4, env });
|
|
@@ -17374,20 +17393,17 @@ async function configureGitCredentials(dest, repoRef, cloneToken) {
|
|
|
17374
17393
|
`store --file=${credFilePosix}`
|
|
17375
17394
|
]).catch(() => {
|
|
17376
17395
|
});
|
|
17377
|
-
await git2(["remote", "set-url", "origin", repoCloneUrl(repoRef)]).catch(() => {
|
|
17396
|
+
await git2(["remote", "set-url", "origin", repoCloneUrl(repoRef, void 0, provider)]).catch(() => {
|
|
17378
17397
|
});
|
|
17379
17398
|
const hasIdentity = await git2(["config", "user.email"]).then(() => true).catch(() => false);
|
|
17380
17399
|
if (!hasIdentity) {
|
|
17381
|
-
const who = await fetchGithubIdentity(cloneToken);
|
|
17382
|
-
|
|
17383
|
-
|
|
17384
|
-
|
|
17385
|
-
}
|
|
17386
|
-
|
|
17387
|
-
|
|
17388
|
-
await git2(["config", "--local", "user.email", email]).catch(() => {
|
|
17389
|
-
});
|
|
17390
|
-
}
|
|
17400
|
+
const who = isGitlab ? null : await fetchGithubIdentity(cloneToken);
|
|
17401
|
+
const login = who?.login ?? "CodeAgent";
|
|
17402
|
+
await git2(["config", "--local", "user.name", login]).catch(() => {
|
|
17403
|
+
});
|
|
17404
|
+
const email = who?.email ?? (isGitlab ? "agent@codeagent-mobile.com" : `${login}@users.noreply.github.com`);
|
|
17405
|
+
await git2(["config", "--local", "user.email", email]).catch(() => {
|
|
17406
|
+
});
|
|
17391
17407
|
}
|
|
17392
17408
|
}
|
|
17393
17409
|
function maskToken(text, cloneToken) {
|
|
@@ -17397,7 +17413,7 @@ function maskToken(text, cloneToken) {
|
|
|
17397
17413
|
}
|
|
17398
17414
|
return masked;
|
|
17399
17415
|
}
|
|
17400
|
-
async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
|
|
17416
|
+
async function prepareWorkspace(repoOrPath, deployId, cloneToken, provider = "github") {
|
|
17401
17417
|
if (isAbsolutePathTarget(repoOrPath)) {
|
|
17402
17418
|
if (!fs36.existsSync(repoOrPath)) {
|
|
17403
17419
|
throw new Error(`deploy target path does not exist: ${repoOrPath}`);
|
|
@@ -17406,11 +17422,11 @@ async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
|
|
|
17406
17422
|
}
|
|
17407
17423
|
const dest = path40.join(selfHostedWorkspaceRoot(), deployId);
|
|
17408
17424
|
if (fs36.existsSync(path40.join(dest, ".git"))) {
|
|
17409
|
-
if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken);
|
|
17425
|
+
if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken, provider);
|
|
17410
17426
|
return dest;
|
|
17411
17427
|
}
|
|
17412
17428
|
fs36.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
|
|
17413
|
-
const cloneUrl = repoCloneUrl(repoOrPath, cloneToken);
|
|
17429
|
+
const cloneUrl = repoCloneUrl(repoOrPath, cloneToken, provider);
|
|
17414
17430
|
try {
|
|
17415
17431
|
await execFileP4("git", ["clone", "--depth", "1", cloneUrl, dest], {
|
|
17416
17432
|
timeout: 12e4,
|
|
@@ -17421,7 +17437,7 @@ async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
|
|
|
17421
17437
|
const reason = err instanceof Error ? err.message : String(err);
|
|
17422
17438
|
throw new Error(`git clone failed for ${maskCloneUrl(cloneUrl)}: ${maskToken(reason, cloneToken)}`);
|
|
17423
17439
|
}
|
|
17424
|
-
if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken);
|
|
17440
|
+
if (cloneToken) await configureGitCredentials(dest, repoOrPath, cloneToken, provider);
|
|
17425
17441
|
return dest;
|
|
17426
17442
|
}
|
|
17427
17443
|
|
|
@@ -17722,6 +17738,92 @@ async function ensureGhAuth(runner, ghCmd, token) {
|
|
|
17722
17738
|
log.warn("host-agent", `gh auth errored: ${e instanceof Error ? e.message : String(e)}`);
|
|
17723
17739
|
}
|
|
17724
17740
|
}
|
|
17741
|
+
var FALLBACK_GLAB_VERSION = "1.54.0";
|
|
17742
|
+
var GLAB_RELEASE_API = "https://gitlab.com/api/v4/projects/gitlab-org%2Fcli/releases/permalink/latest";
|
|
17743
|
+
async function resolveLatestGlabVersion() {
|
|
17744
|
+
try {
|
|
17745
|
+
const res = await fetch(GLAB_RELEASE_API, { headers: { Accept: "application/json" } });
|
|
17746
|
+
if (res.ok) {
|
|
17747
|
+
const body = await res.json();
|
|
17748
|
+
const tag = (body.tag_name ?? "").replace(/^v/, "");
|
|
17749
|
+
if (/^\d+\.\d+\.\d+$/.test(tag)) return tag;
|
|
17750
|
+
}
|
|
17751
|
+
} catch {
|
|
17752
|
+
}
|
|
17753
|
+
return FALLBACK_GLAB_VERSION;
|
|
17754
|
+
}
|
|
17755
|
+
async function ensureGlabCli(runner, deps = {}) {
|
|
17756
|
+
if (runner.which("glab")) return "glab";
|
|
17757
|
+
const arch2 = ghArch();
|
|
17758
|
+
const platform3 = process.platform;
|
|
17759
|
+
if (arch2 === null || platform3 !== "linux" && platform3 !== "darwin" && platform3 !== "win32") {
|
|
17760
|
+
log.warn("host-agent", `glab auto-install unsupported on ${platform3}/${process.arch} \u2014 skipping`);
|
|
17761
|
+
return null;
|
|
17762
|
+
}
|
|
17763
|
+
const osToken = platform3 === "darwin" ? "darwin" : platform3 === "win32" ? "windows" : "linux";
|
|
17764
|
+
const ext = platform3 === "win32" ? "zip" : "tar.gz";
|
|
17765
|
+
const binaryName = platform3 === "win32" ? "glab.exe" : "glab";
|
|
17766
|
+
const downloadFn = deps.downloadFn ?? download;
|
|
17767
|
+
try {
|
|
17768
|
+
const version3 = await resolveLatestGlabVersion();
|
|
17769
|
+
const asset = `glab_${version3}_${osToken}_${arch2}`;
|
|
17770
|
+
const url2 = `https://gitlab.com/gitlab-org/cli/-/releases/v${version3}/downloads/${asset}.${ext}`;
|
|
17771
|
+
const tmpRoot = fs38.mkdtempSync(path42.join(os34.tmpdir(), "codeam-glab-"));
|
|
17772
|
+
const archive = path42.join(tmpRoot, `${asset}.${ext}`);
|
|
17773
|
+
if (!await downloadFn(url2, archive)) {
|
|
17774
|
+
log.warn("host-agent", "glab download failed \u2014 skipping (git push/pull still work)");
|
|
17775
|
+
return null;
|
|
17776
|
+
}
|
|
17777
|
+
const extract = await runner.run("tar", ["-xf", archive, "-C", tmpRoot], { timeoutMs: 6e4 });
|
|
17778
|
+
if (extract.code !== 0) {
|
|
17779
|
+
log.warn("host-agent", `glab archive extraction failed (code=${String(extract.code)}) \u2014 skipping`);
|
|
17780
|
+
return null;
|
|
17781
|
+
}
|
|
17782
|
+
const candidates = [
|
|
17783
|
+
path42.join(tmpRoot, "bin", binaryName),
|
|
17784
|
+
path42.join(tmpRoot, asset, "bin", binaryName),
|
|
17785
|
+
path42.join(tmpRoot, binaryName)
|
|
17786
|
+
];
|
|
17787
|
+
const extractedBin = candidates.find((c2) => fs38.existsSync(c2));
|
|
17788
|
+
if (!extractedBin) {
|
|
17789
|
+
log.warn("host-agent", "glab binary not found in the extracted archive \u2014 skipping");
|
|
17790
|
+
return null;
|
|
17791
|
+
}
|
|
17792
|
+
const binDir = codeamBinDir();
|
|
17793
|
+
fs38.mkdirSync(binDir, { recursive: true });
|
|
17794
|
+
const target = path42.join(binDir, binaryName);
|
|
17795
|
+
fs38.copyFileSync(extractedBin, target);
|
|
17796
|
+
fs38.chmodSync(target, 493);
|
|
17797
|
+
log.info("host-agent", `glab installed to ${target} (v${version3})`);
|
|
17798
|
+
return target;
|
|
17799
|
+
} catch (e) {
|
|
17800
|
+
log.warn("host-agent", `glab auto-install errored: ${e instanceof Error ? e.message : String(e)} \u2014 skipping`);
|
|
17801
|
+
return null;
|
|
17802
|
+
}
|
|
17803
|
+
}
|
|
17804
|
+
async function ensureGlabAuth(runner, glabCmd, token) {
|
|
17805
|
+
if (!token) return;
|
|
17806
|
+
try {
|
|
17807
|
+
const status2 = await runner.run(glabCmd, ["auth", "status"], { timeoutMs: 15e3 });
|
|
17808
|
+
if (status2.code === 0) {
|
|
17809
|
+
log.info("host-agent", "glab already authenticated \u2014 leaving the existing login untouched");
|
|
17810
|
+
return;
|
|
17811
|
+
}
|
|
17812
|
+
const login = await runner.run(
|
|
17813
|
+
glabCmd,
|
|
17814
|
+
["auth", "login", "--hostname", "gitlab.com", "--stdin"],
|
|
17815
|
+
{ timeoutMs: 2e4, input: `${token}
|
|
17816
|
+
` }
|
|
17817
|
+
);
|
|
17818
|
+
if (login.code === 0) {
|
|
17819
|
+
log.info("host-agent", "glab authenticated with the linked GitLab token");
|
|
17820
|
+
} else {
|
|
17821
|
+
log.warn("host-agent", `glab auth login failed (code=${String(login.code)}) \u2014 glab unauthenticated`);
|
|
17822
|
+
}
|
|
17823
|
+
} catch (e) {
|
|
17824
|
+
log.warn("host-agent", `glab auth errored: ${e instanceof Error ? e.message : String(e)}`);
|
|
17825
|
+
}
|
|
17826
|
+
}
|
|
17725
17827
|
var defaultGitToolingRunner = {
|
|
17726
17828
|
which(cmd) {
|
|
17727
17829
|
try {
|
|
@@ -18569,7 +18671,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
18569
18671
|
if (process.env.NODE_ENV === "test") return;
|
|
18570
18672
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
18571
18673
|
if (process.env.CI) return;
|
|
18572
|
-
const current = true ? "2.61.
|
|
18674
|
+
const current = true ? "2.61.33" : null;
|
|
18573
18675
|
if (!current) return;
|
|
18574
18676
|
const cache = readCache();
|
|
18575
18677
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -18586,7 +18688,7 @@ function checkForUpdates() {
|
|
|
18586
18688
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
18587
18689
|
if (process.env.CI) return;
|
|
18588
18690
|
if (!process.stdout.isTTY) return;
|
|
18589
|
-
const current = true ? "2.61.
|
|
18691
|
+
const current = true ? "2.61.33" : null;
|
|
18590
18692
|
if (!current) return;
|
|
18591
18693
|
const cache = readCache();
|
|
18592
18694
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -18606,7 +18708,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
18606
18708
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
18607
18709
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
18608
18710
|
function currentCliVersion() {
|
|
18609
|
-
return true ? "2.61.
|
|
18711
|
+
return true ? "2.61.33" : null;
|
|
18610
18712
|
}
|
|
18611
18713
|
function runCmd(cmd, args2, timeoutMs) {
|
|
18612
18714
|
return new Promise((resolve8) => {
|
|
@@ -18815,6 +18917,9 @@ function isDeployPayload(p2) {
|
|
|
18815
18917
|
if (p2.cloneToken !== void 0 && typeof p2.cloneToken !== "string") {
|
|
18816
18918
|
return false;
|
|
18817
18919
|
}
|
|
18920
|
+
if (p2.repoProvider !== void 0 && p2.repoProvider !== "github" && p2.repoProvider !== "gitlab") {
|
|
18921
|
+
return false;
|
|
18922
|
+
}
|
|
18818
18923
|
if (p2.headroomEnabled !== void 0 && typeof p2.headroomEnabled !== "boolean") {
|
|
18819
18924
|
return false;
|
|
18820
18925
|
}
|
|
@@ -19463,7 +19568,12 @@ var HostAgentSupervisor = class {
|
|
|
19463
19568
|
if (!isAbsolutePathTarget(payload.repoOrPath)) {
|
|
19464
19569
|
report("cloning", "cloning repository");
|
|
19465
19570
|
}
|
|
19466
|
-
const cwd = await prepareWorkspace(
|
|
19571
|
+
const cwd = await prepareWorkspace(
|
|
19572
|
+
payload.repoOrPath,
|
|
19573
|
+
payload.deployId,
|
|
19574
|
+
payload.cloneToken,
|
|
19575
|
+
payload.repoProvider ?? "github"
|
|
19576
|
+
);
|
|
19467
19577
|
let childEnv;
|
|
19468
19578
|
let extraArgs = [];
|
|
19469
19579
|
if (payload.houseProxy) {
|
|
@@ -19504,15 +19614,23 @@ var HostAgentSupervisor = class {
|
|
|
19504
19614
|
if (payload.cloneToken) {
|
|
19505
19615
|
try {
|
|
19506
19616
|
report("preparing", "configuring git tooling");
|
|
19507
|
-
|
|
19508
|
-
|
|
19509
|
-
|
|
19510
|
-
|
|
19617
|
+
if ((payload.repoProvider ?? "github") === "gitlab") {
|
|
19618
|
+
const glabCmd = await ensureGlabCli(defaultGitToolingRunner);
|
|
19619
|
+
if (glabCmd) {
|
|
19620
|
+
childEnv.PATH = `${codeamBinDir()}${path46.delimiter}${childEnv.PATH}`;
|
|
19621
|
+
await ensureGlabAuth(defaultGitToolingRunner, glabCmd, payload.cloneToken);
|
|
19622
|
+
}
|
|
19623
|
+
} else {
|
|
19624
|
+
const ghCmd = await ensureGhCli(defaultGitToolingRunner, payload.cloneToken);
|
|
19625
|
+
if (ghCmd) {
|
|
19626
|
+
childEnv.PATH = `${codeamBinDir()}${path46.delimiter}${childEnv.PATH}`;
|
|
19627
|
+
await ensureGhAuth(defaultGitToolingRunner, ghCmd, payload.cloneToken);
|
|
19628
|
+
}
|
|
19511
19629
|
}
|
|
19512
19630
|
} catch (e) {
|
|
19513
19631
|
log.warn(
|
|
19514
19632
|
"host-agent",
|
|
19515
|
-
`
|
|
19633
|
+
`git tooling setup skipped: ${e instanceof Error ? e.message : String(e)}`
|
|
19516
19634
|
);
|
|
19517
19635
|
}
|
|
19518
19636
|
}
|
|
@@ -38599,7 +38717,7 @@ function checkChokidar() {
|
|
|
38599
38717
|
}
|
|
38600
38718
|
async function doctor(args2 = []) {
|
|
38601
38719
|
const json = args2.includes("--json");
|
|
38602
|
-
const cliVersion = true ? "2.61.
|
|
38720
|
+
const cliVersion = true ? "2.61.33" : "0.0.0-dev";
|
|
38603
38721
|
const apiBase2 = resolveApiBaseUrl();
|
|
38604
38722
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
38605
38723
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -39110,7 +39228,7 @@ async function mcpRun(args2) {
|
|
|
39110
39228
|
// src/commands/version.ts
|
|
39111
39229
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
39112
39230
|
function version2() {
|
|
39113
|
-
const v = true ? "2.61.
|
|
39231
|
+
const v = true ? "2.61.33" : "unknown";
|
|
39114
39232
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
39115
39233
|
}
|
|
39116
39234
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.61.
|
|
3
|
+
"version": "2.61.33",
|
|
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",
|