codeam-cli 2.27.2 → 2.27.3
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 +7 -0
- package/dist/index.js +377 -212
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -306,12 +306,12 @@ var AGENT_REGISTRY = {
|
|
|
306
306
|
displayName: "Gemini CLI",
|
|
307
307
|
binaryName: "gemini",
|
|
308
308
|
enabled: true,
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
supportedAuthKinds: ["api_key"],
|
|
314
|
-
preferredAuthKind: "
|
|
309
|
+
// OAuth via `gemini auth login` (captured by `codeam link gemini`
|
|
310
|
+
// from ~/.gemini/oauth_creds.json) AND GEMINI_API_KEY are both
|
|
311
|
+
// accepted by the backend's GeminiProvisioningStrategy and propagated
|
|
312
|
+
// into codespace deploys.
|
|
313
|
+
supportedAuthKinds: ["oauth_token", "api_key"],
|
|
314
|
+
preferredAuthKind: "oauth_token"
|
|
315
315
|
}
|
|
316
316
|
};
|
|
317
317
|
function getEnabledAgents() {
|
|
@@ -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.27.
|
|
501
|
+
version: "2.27.3",
|
|
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",
|
|
@@ -1160,8 +1160,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
1160
1160
|
return decodedFile;
|
|
1161
1161
|
};
|
|
1162
1162
|
}
|
|
1163
|
-
function normalizeWindowsPath(
|
|
1164
|
-
return
|
|
1163
|
+
function normalizeWindowsPath(path45) {
|
|
1164
|
+
return path45.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
1165
1165
|
}
|
|
1166
1166
|
|
|
1167
1167
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -3641,9 +3641,9 @@ async function addSourceContext(frames) {
|
|
|
3641
3641
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
3642
3642
|
return frames;
|
|
3643
3643
|
}
|
|
3644
|
-
function getContextLinesFromFile(
|
|
3644
|
+
function getContextLinesFromFile(path45, ranges, output) {
|
|
3645
3645
|
return new Promise((resolve6) => {
|
|
3646
|
-
const stream = (0, import_node_fs.createReadStream)(
|
|
3646
|
+
const stream = (0, import_node_fs.createReadStream)(path45);
|
|
3647
3647
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
3648
3648
|
input: stream
|
|
3649
3649
|
});
|
|
@@ -3658,7 +3658,7 @@ function getContextLinesFromFile(path44, ranges, output) {
|
|
|
3658
3658
|
let rangeStart = range[0];
|
|
3659
3659
|
let rangeEnd = range[1];
|
|
3660
3660
|
function onStreamError() {
|
|
3661
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
3661
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path45, 1);
|
|
3662
3662
|
lineReaded.close();
|
|
3663
3663
|
lineReaded.removeAllListeners();
|
|
3664
3664
|
destroyStreamAndResolve();
|
|
@@ -3719,8 +3719,8 @@ function clearLineContext(frame) {
|
|
|
3719
3719
|
delete frame.context_line;
|
|
3720
3720
|
delete frame.post_context;
|
|
3721
3721
|
}
|
|
3722
|
-
function shouldSkipContextLinesForFile(
|
|
3723
|
-
return
|
|
3722
|
+
function shouldSkipContextLinesForFile(path45) {
|
|
3723
|
+
return path45.startsWith("node:") || path45.endsWith(".min.js") || path45.endsWith(".min.cjs") || path45.endsWith(".min.mjs") || path45.startsWith("data:");
|
|
3724
3724
|
}
|
|
3725
3725
|
function shouldSkipContextLinesForFrame(frame) {
|
|
3726
3726
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -5874,7 +5874,7 @@ function readAnonId() {
|
|
|
5874
5874
|
}
|
|
5875
5875
|
function superProperties() {
|
|
5876
5876
|
return {
|
|
5877
|
-
cliVersion: true ? "2.27.
|
|
5877
|
+
cliVersion: true ? "2.27.3" : "0.0.0-dev",
|
|
5878
5878
|
nodeVersion: process.version,
|
|
5879
5879
|
platform: process.platform,
|
|
5880
5880
|
arch: process.arch,
|
|
@@ -7216,10 +7216,10 @@ function buildForPlatform(platform2) {
|
|
|
7216
7216
|
var import_node_crypto4 = require("crypto");
|
|
7217
7217
|
|
|
7218
7218
|
// src/agents/claude/resolver.ts
|
|
7219
|
-
function buildClaudeLaunch(extraArgs = [],
|
|
7220
|
-
const found =
|
|
7219
|
+
function buildClaudeLaunch(extraArgs = [], os28 = createOsStrategy()) {
|
|
7220
|
+
const found = os28.findInPath("claude") ?? os28.findInPath("claude-code");
|
|
7221
7221
|
if (!found) return null;
|
|
7222
|
-
return
|
|
7222
|
+
return os28.buildLaunch(found, extraArgs);
|
|
7223
7223
|
}
|
|
7224
7224
|
|
|
7225
7225
|
// src/agents/claude/installer.ts
|
|
@@ -9946,13 +9946,13 @@ function detectStartupBanner(lines) {
|
|
|
9946
9946
|
while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
|
|
9947
9947
|
if (metaIdx - artStart < 2) return null;
|
|
9948
9948
|
const pathLine = (lines[metaIdx + 1] ?? "").trim();
|
|
9949
|
-
const
|
|
9949
|
+
const path45 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
|
|
9950
9950
|
return {
|
|
9951
9951
|
title: "",
|
|
9952
9952
|
subtitle: lines[metaIdx].trim(),
|
|
9953
|
-
path:
|
|
9953
|
+
path: path45,
|
|
9954
9954
|
startIdx: artStart,
|
|
9955
|
-
endIdx: metaIdx + (
|
|
9955
|
+
endIdx: metaIdx + (path45 ? 1 : 0)
|
|
9956
9956
|
};
|
|
9957
9957
|
}
|
|
9958
9958
|
|
|
@@ -9962,8 +9962,8 @@ var ClaudeRuntimeStrategy = class {
|
|
|
9962
9962
|
meta = getAgent("claude");
|
|
9963
9963
|
mode = "interactive";
|
|
9964
9964
|
os;
|
|
9965
|
-
constructor(
|
|
9966
|
-
this.os =
|
|
9965
|
+
constructor(os28) {
|
|
9966
|
+
this.os = os28;
|
|
9967
9967
|
}
|
|
9968
9968
|
/**
|
|
9969
9969
|
* Claude Code's react-ink TUI enables bracketed-paste mode at
|
|
@@ -10971,8 +10971,8 @@ function codexCredentialLocator() {
|
|
|
10971
10971
|
function codexLoginLauncher() {
|
|
10972
10972
|
return {
|
|
10973
10973
|
async ensureInstalled() {
|
|
10974
|
-
const
|
|
10975
|
-
return
|
|
10974
|
+
const os28 = createOsStrategy();
|
|
10975
|
+
return os28.findInPath("codex") !== null;
|
|
10976
10976
|
},
|
|
10977
10977
|
launch() {
|
|
10978
10978
|
return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
|
|
@@ -10995,8 +10995,8 @@ var CodexRuntimeStrategy = class {
|
|
|
10995
10995
|
meta = getAgent("codex");
|
|
10996
10996
|
mode = "interactive";
|
|
10997
10997
|
os;
|
|
10998
|
-
constructor(
|
|
10999
|
-
this.os =
|
|
10998
|
+
constructor(os28) {
|
|
10999
|
+
this.os = os28;
|
|
11000
11000
|
}
|
|
11001
11001
|
async prepareLaunch() {
|
|
11002
11002
|
let binary = this.os.findInPath("codex");
|
|
@@ -11102,12 +11102,12 @@ var CodexRuntimeStrategy = class {
|
|
|
11102
11102
|
});
|
|
11103
11103
|
}
|
|
11104
11104
|
};
|
|
11105
|
-
function resolveNpm(
|
|
11106
|
-
return
|
|
11105
|
+
function resolveNpm(os28) {
|
|
11106
|
+
return os28.id === "win32" ? "npm.cmd" : "npm";
|
|
11107
11107
|
}
|
|
11108
|
-
async function installCodexViaNpm(
|
|
11108
|
+
async function installCodexViaNpm(os28) {
|
|
11109
11109
|
return new Promise((resolve6, reject) => {
|
|
11110
|
-
const proc = (0, import_node_child_process4.spawn)(resolveNpm(
|
|
11110
|
+
const proc = (0, import_node_child_process4.spawn)(resolveNpm(os28), ["install", "-g", "@openai/codex"], {
|
|
11111
11111
|
stdio: "inherit"
|
|
11112
11112
|
});
|
|
11113
11113
|
proc.on("close", (code) => {
|
|
@@ -11124,16 +11124,16 @@ async function installCodexViaNpm(os27) {
|
|
|
11124
11124
|
});
|
|
11125
11125
|
});
|
|
11126
11126
|
}
|
|
11127
|
-
function augmentNpmGlobalBin(
|
|
11127
|
+
function augmentNpmGlobalBin(os28) {
|
|
11128
11128
|
try {
|
|
11129
|
-
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(
|
|
11129
|
+
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os28), ["prefix", "-g"], {
|
|
11130
11130
|
stdio: ["ignore", "pipe", "ignore"]
|
|
11131
11131
|
});
|
|
11132
11132
|
if (result.status !== 0) return;
|
|
11133
11133
|
const prefix = result.stdout.toString().trim();
|
|
11134
11134
|
if (!prefix) return;
|
|
11135
|
-
const binDir =
|
|
11136
|
-
|
|
11135
|
+
const binDir = os28.id === "win32" ? prefix : path17.join(prefix, "bin");
|
|
11136
|
+
os28.augmentPath([binDir]);
|
|
11137
11137
|
} catch {
|
|
11138
11138
|
}
|
|
11139
11139
|
}
|
|
@@ -11217,9 +11217,9 @@ var import_node_child_process7 = require("child_process");
|
|
|
11217
11217
|
// src/agents/coderabbit/installer.ts
|
|
11218
11218
|
var import_node_child_process5 = require("child_process");
|
|
11219
11219
|
var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
|
|
11220
|
-
async function ensureCoderabbitInstalled(
|
|
11221
|
-
if (
|
|
11222
|
-
if (
|
|
11220
|
+
async function ensureCoderabbitInstalled(os28) {
|
|
11221
|
+
if (os28.findInPath("coderabbit")) return true;
|
|
11222
|
+
if (os28.id === "win32") {
|
|
11223
11223
|
console.error(
|
|
11224
11224
|
"\n \u2717 CodeRabbit on Windows requires WSL.\n Install the CLI inside your WSL distribution\n (curl -fsSL https://cli.coderabbit.ai/install.sh | sh)\n then re-run `codeam link coderabbit` from WSL.\n"
|
|
11225
11225
|
);
|
|
@@ -11234,8 +11234,8 @@ async function ensureCoderabbitInstalled(os27) {
|
|
|
11234
11234
|
proc.on("error", () => resolve6(false));
|
|
11235
11235
|
});
|
|
11236
11236
|
if (!ok) return false;
|
|
11237
|
-
|
|
11238
|
-
return
|
|
11237
|
+
os28.augmentPath([`${os28.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
11238
|
+
return os28.findInPath("coderabbit") !== null;
|
|
11239
11239
|
}
|
|
11240
11240
|
|
|
11241
11241
|
// src/agents/coderabbit/link.ts
|
|
@@ -11262,10 +11262,10 @@ function coderabbitCredentialLocator() {
|
|
|
11262
11262
|
extract: extractLocalCoderabbitToken
|
|
11263
11263
|
};
|
|
11264
11264
|
}
|
|
11265
|
-
function coderabbitLoginLauncher(
|
|
11265
|
+
function coderabbitLoginLauncher(os28) {
|
|
11266
11266
|
return {
|
|
11267
11267
|
async ensureInstalled() {
|
|
11268
|
-
return ensureCoderabbitInstalled(
|
|
11268
|
+
return ensureCoderabbitInstalled(os28);
|
|
11269
11269
|
},
|
|
11270
11270
|
launch() {
|
|
11271
11271
|
return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
|
|
@@ -11288,11 +11288,11 @@ function parseReview(stdout) {
|
|
|
11288
11288
|
for (const line of lines) {
|
|
11289
11289
|
const m = line.match(HUNK_LINE_RE);
|
|
11290
11290
|
if (!m) continue;
|
|
11291
|
-
const [,
|
|
11292
|
-
if (!
|
|
11291
|
+
const [, path45, lineNo, sevToken, message] = m;
|
|
11292
|
+
if (!path45 || !lineNo || !message) continue;
|
|
11293
11293
|
const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
|
|
11294
11294
|
hunks.push({
|
|
11295
|
-
path:
|
|
11295
|
+
path: path45.trim(),
|
|
11296
11296
|
line: Number(lineNo),
|
|
11297
11297
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
11298
11298
|
message: cleanedMessage
|
|
@@ -11311,8 +11311,8 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
11311
11311
|
meta = getAgent("coderabbit");
|
|
11312
11312
|
mode = "batch";
|
|
11313
11313
|
os;
|
|
11314
|
-
constructor(
|
|
11315
|
-
this.os =
|
|
11314
|
+
constructor(os28) {
|
|
11315
|
+
this.os = os28;
|
|
11316
11316
|
}
|
|
11317
11317
|
getDefaultArgs() {
|
|
11318
11318
|
return ["review"];
|
|
@@ -11427,10 +11427,10 @@ function cursorCredentialLocator() {
|
|
|
11427
11427
|
extract: extractLocalCursorToken
|
|
11428
11428
|
};
|
|
11429
11429
|
}
|
|
11430
|
-
function cursorLoginLauncher(
|
|
11430
|
+
function cursorLoginLauncher(os28) {
|
|
11431
11431
|
return {
|
|
11432
11432
|
async ensureInstalled() {
|
|
11433
|
-
if (
|
|
11433
|
+
if (os28.findInPath("cursor-agent")) return true;
|
|
11434
11434
|
console.error(
|
|
11435
11435
|
"\n \u2717 cursor-agent binary not on PATH.\n Install Cursor (https://cursor.com/) and ensure the CLI\n plugin is enabled, then re-run `codeam link cursor`.\n"
|
|
11436
11436
|
);
|
|
@@ -11492,8 +11492,8 @@ var CursorRuntimeStrategy = class {
|
|
|
11492
11492
|
meta = getAgent("cursor");
|
|
11493
11493
|
mode = "interactive";
|
|
11494
11494
|
os;
|
|
11495
|
-
constructor(
|
|
11496
|
-
this.os =
|
|
11495
|
+
constructor(os28) {
|
|
11496
|
+
this.os = os28;
|
|
11497
11497
|
}
|
|
11498
11498
|
async prepareLaunch() {
|
|
11499
11499
|
const binary = this.os.findInPath("cursor-agent");
|
|
@@ -11613,10 +11613,10 @@ function aiderCredentialLocator() {
|
|
|
11613
11613
|
extract: extractLocalAiderToken
|
|
11614
11614
|
};
|
|
11615
11615
|
}
|
|
11616
|
-
function aiderLoginLauncher(
|
|
11616
|
+
function aiderLoginLauncher(os28) {
|
|
11617
11617
|
return {
|
|
11618
11618
|
async ensureInstalled() {
|
|
11619
|
-
if (
|
|
11619
|
+
if (os28.findInPath("aider")) return true;
|
|
11620
11620
|
console.error(
|
|
11621
11621
|
"\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
|
|
11622
11622
|
);
|
|
@@ -11626,7 +11626,7 @@ function aiderLoginLauncher(os27) {
|
|
|
11626
11626
|
console.error(
|
|
11627
11627
|
"\n Aider has no interactive login flow.\n Set ANTHROPIC_API_KEY or OPENAI_API_KEY in your shell,\n or re-run `codeam link aider --api-key=<your-key>`.\n"
|
|
11628
11628
|
);
|
|
11629
|
-
return (0, import_node_child_process9.spawn)(
|
|
11629
|
+
return (0, import_node_child_process9.spawn)(os28.id === "win32" ? "cmd.exe" : "sh", os28.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
|
|
11630
11630
|
stdio: "ignore"
|
|
11631
11631
|
});
|
|
11632
11632
|
}
|
|
@@ -11698,8 +11698,8 @@ var AiderRuntimeStrategy = class {
|
|
|
11698
11698
|
meta = getAgent("aider");
|
|
11699
11699
|
mode = "interactive";
|
|
11700
11700
|
os;
|
|
11701
|
-
constructor(
|
|
11702
|
-
this.os =
|
|
11701
|
+
constructor(os28) {
|
|
11702
|
+
this.os = os28;
|
|
11703
11703
|
}
|
|
11704
11704
|
async prepareLaunch() {
|
|
11705
11705
|
const binary = this.os.findInPath("aider");
|
|
@@ -11766,19 +11766,184 @@ var AiderRuntimeStrategy = class {
|
|
|
11766
11766
|
}
|
|
11767
11767
|
};
|
|
11768
11768
|
|
|
11769
|
+
// src/agents/gemini/link.ts
|
|
11770
|
+
var import_node_child_process10 = require("child_process");
|
|
11771
|
+
|
|
11772
|
+
// src/agents/gemini/local-token.ts
|
|
11773
|
+
var fs20 = __toESM(require("fs"));
|
|
11774
|
+
var os21 = __toESM(require("os"));
|
|
11775
|
+
var path24 = __toESM(require("path"));
|
|
11776
|
+
function geminiCredentialsPath() {
|
|
11777
|
+
return path24.join(os21.homedir(), ".gemini", "oauth_creds.json");
|
|
11778
|
+
}
|
|
11779
|
+
function geminiCredentialsPaths() {
|
|
11780
|
+
return [geminiCredentialsPath()];
|
|
11781
|
+
}
|
|
11782
|
+
async function extractLocalGeminiToken() {
|
|
11783
|
+
const file = geminiCredentialsPath();
|
|
11784
|
+
if (!fs20.existsSync(file)) return null;
|
|
11785
|
+
const credential = fs20.readFileSync(file, "utf8").trim();
|
|
11786
|
+
if (credential.length === 0) return null;
|
|
11787
|
+
return { method: "oauth", credential, source: "flat-file" };
|
|
11788
|
+
}
|
|
11789
|
+
function validateLocalGeminiToken(credential) {
|
|
11790
|
+
let parsed;
|
|
11791
|
+
try {
|
|
11792
|
+
parsed = JSON.parse(credential);
|
|
11793
|
+
} catch {
|
|
11794
|
+
return { status: "unknown" };
|
|
11795
|
+
}
|
|
11796
|
+
if (typeof parsed.expiry_date !== "number") return { status: "unknown" };
|
|
11797
|
+
const expiresAt = parsed.expiry_date;
|
|
11798
|
+
if (Date.now() >= expiresAt) {
|
|
11799
|
+
return {
|
|
11800
|
+
status: "expired",
|
|
11801
|
+
reason: "Gemini OAuth access token expired",
|
|
11802
|
+
expiresAt
|
|
11803
|
+
};
|
|
11804
|
+
}
|
|
11805
|
+
return { status: "valid", expiresAt };
|
|
11806
|
+
}
|
|
11807
|
+
|
|
11808
|
+
// src/agents/gemini/link.ts
|
|
11809
|
+
function geminiCredentialLocator() {
|
|
11810
|
+
return {
|
|
11811
|
+
publicId: "gemini",
|
|
11812
|
+
vendor: "Google",
|
|
11813
|
+
hint: "~/.gemini/oauth_creds.json",
|
|
11814
|
+
watchPaths: geminiCredentialsPaths,
|
|
11815
|
+
extract: extractLocalGeminiToken,
|
|
11816
|
+
validate: (token) => {
|
|
11817
|
+
const result = validateLocalGeminiToken(token.credential);
|
|
11818
|
+
return { status: result.status, reason: result.reason };
|
|
11819
|
+
}
|
|
11820
|
+
};
|
|
11821
|
+
}
|
|
11822
|
+
function geminiLoginLauncher() {
|
|
11823
|
+
return {
|
|
11824
|
+
async ensureInstalled() {
|
|
11825
|
+
const os28 = createOsStrategy();
|
|
11826
|
+
return os28.findInPath("gemini") !== null;
|
|
11827
|
+
},
|
|
11828
|
+
launch() {
|
|
11829
|
+
return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
|
|
11830
|
+
}
|
|
11831
|
+
};
|
|
11832
|
+
}
|
|
11833
|
+
|
|
11834
|
+
// src/agents/gemini/runtime.ts
|
|
11835
|
+
var GEMINI_PRO_CONTEXT_WINDOW = 1e6;
|
|
11836
|
+
var GEMINI_FLASH_CONTEXT_WINDOW = 1e6;
|
|
11837
|
+
var GEMINI_MODELS = [
|
|
11838
|
+
{
|
|
11839
|
+
id: "gemini-2.5-pro",
|
|
11840
|
+
label: "Gemini 2.5 Pro",
|
|
11841
|
+
contextWindow: GEMINI_PRO_CONTEXT_WINDOW
|
|
11842
|
+
},
|
|
11843
|
+
{
|
|
11844
|
+
id: "gemini-2.5-flash",
|
|
11845
|
+
label: "Gemini 2.5 Flash",
|
|
11846
|
+
contextWindow: GEMINI_FLASH_CONTEXT_WINDOW
|
|
11847
|
+
},
|
|
11848
|
+
{
|
|
11849
|
+
id: "gemini-2.5-flash-lite",
|
|
11850
|
+
label: "Gemini 2.5 Flash-Lite",
|
|
11851
|
+
contextWindow: GEMINI_FLASH_CONTEXT_WINDOW
|
|
11852
|
+
}
|
|
11853
|
+
];
|
|
11854
|
+
var GeminiRuntimeStrategy = class {
|
|
11855
|
+
id = "gemini";
|
|
11856
|
+
meta = getAgent("gemini");
|
|
11857
|
+
mode = "interactive";
|
|
11858
|
+
os;
|
|
11859
|
+
constructor(os28) {
|
|
11860
|
+
this.os = os28;
|
|
11861
|
+
}
|
|
11862
|
+
async prepareLaunch() {
|
|
11863
|
+
const binary = this.os.findInPath("gemini");
|
|
11864
|
+
if (!binary) {
|
|
11865
|
+
throw new Error(
|
|
11866
|
+
"Gemini CLI is not on PATH. Install it with:\n npm install -g @google/gemini-cli\n Then run `codeam pair` again.\n\n Tip: set CODEAM_ACP_ENABLED=1 before pairing to use the\n ACP runtime \u2014 it gives mobile typed messages instead of\n raw PTY output for Gemini."
|
|
11867
|
+
);
|
|
11868
|
+
}
|
|
11869
|
+
return this.os.buildLaunch(binary);
|
|
11870
|
+
}
|
|
11871
|
+
// Gemini's REPL has no documented "resume previous session" flag,
|
|
11872
|
+
// so a relaunch starts fresh. Returning an empty array is the
|
|
11873
|
+
// documented "no-op resume" path (Cursor / Aider do the same).
|
|
11874
|
+
resumeLaunchArgs(_sessionId, _opts) {
|
|
11875
|
+
return [];
|
|
11876
|
+
}
|
|
11877
|
+
resolveHistoryDir(_cwd) {
|
|
11878
|
+
return null;
|
|
11879
|
+
}
|
|
11880
|
+
parseHistoryFile(_filePath) {
|
|
11881
|
+
return [];
|
|
11882
|
+
}
|
|
11883
|
+
getCurrentUsage(_historyDir) {
|
|
11884
|
+
return null;
|
|
11885
|
+
}
|
|
11886
|
+
async fetchWeeklyUsage() {
|
|
11887
|
+
return null;
|
|
11888
|
+
}
|
|
11889
|
+
async listModels() {
|
|
11890
|
+
return GEMINI_MODELS;
|
|
11891
|
+
}
|
|
11892
|
+
/**
|
|
11893
|
+
* Gemini's `/model <id>` swaps the active model inside the REPL —
|
|
11894
|
+
* same shape as Claude / Codex / Cursor.
|
|
11895
|
+
*/
|
|
11896
|
+
changeModelInstruction(modelId) {
|
|
11897
|
+
return { type: "pty", ptyInput: `/model ${modelId}\r` };
|
|
11898
|
+
}
|
|
11899
|
+
/**
|
|
11900
|
+
* `/compress` is Gemini's context-compression slash command (the
|
|
11901
|
+
* closest analogue to Claude's `/compact`). No auto-mode equivalent.
|
|
11902
|
+
*/
|
|
11903
|
+
summarizeInstruction(_mode) {
|
|
11904
|
+
return { ptyInput: "/compress\r" };
|
|
11905
|
+
}
|
|
11906
|
+
/**
|
|
11907
|
+
* Pass-through filter. Gemini's TUI chrome isn't worth
|
|
11908
|
+
* hand-detecting — users who want clean output should use ACP
|
|
11909
|
+
* (`CODEAM_ACP_ENABLED=1`) instead. Returning the input verbatim
|
|
11910
|
+
* satisfies the contract's idempotency assertion and keeps mobile
|
|
11911
|
+
* showing whatever the REPL prints.
|
|
11912
|
+
*/
|
|
11913
|
+
filterTuiOutput(lines) {
|
|
11914
|
+
return lines;
|
|
11915
|
+
}
|
|
11916
|
+
/**
|
|
11917
|
+
* No interactive-selector detection — Gemini's REPL uses input
|
|
11918
|
+
* lines, not arrow-key menus we'd need to detect. ACP surfaces
|
|
11919
|
+
* permission requests as typed messages, which is the path we want
|
|
11920
|
+
* users on anyway.
|
|
11921
|
+
*/
|
|
11922
|
+
detectInteractivePrompt(_lines) {
|
|
11923
|
+
return null;
|
|
11924
|
+
}
|
|
11925
|
+
credentialLocator() {
|
|
11926
|
+
return geminiCredentialLocator();
|
|
11927
|
+
}
|
|
11928
|
+
loginLauncher() {
|
|
11929
|
+
return geminiLoginLauncher();
|
|
11930
|
+
}
|
|
11931
|
+
};
|
|
11932
|
+
|
|
11769
11933
|
// src/agents/registry.ts
|
|
11770
11934
|
var runtimeBuilders = {
|
|
11771
|
-
claude: (
|
|
11772
|
-
codex: (
|
|
11773
|
-
coderabbit: (
|
|
11774
|
-
cursor: (
|
|
11775
|
-
aider: (
|
|
11935
|
+
claude: (os28) => new ClaudeRuntimeStrategy(os28),
|
|
11936
|
+
codex: (os28) => new CodexRuntimeStrategy(os28),
|
|
11937
|
+
coderabbit: (os28) => new CoderabbitRuntimeStrategy(os28),
|
|
11938
|
+
cursor: (os28) => new CursorRuntimeStrategy(os28),
|
|
11939
|
+
aider: (os28) => new AiderRuntimeStrategy(os28),
|
|
11940
|
+
gemini: (os28) => new GeminiRuntimeStrategy(os28)
|
|
11776
11941
|
};
|
|
11777
11942
|
var deployBuilders = {
|
|
11778
11943
|
claude: () => new ClaudeDeployStrategy(),
|
|
11779
11944
|
codex: () => new CodexDeployStrategy()
|
|
11780
11945
|
};
|
|
11781
|
-
function createAgentStrategy(agent,
|
|
11946
|
+
function createAgentStrategy(agent, os28 = createOsStrategy()) {
|
|
11782
11947
|
if (!AGENT_REGISTRY[agent]?.enabled) {
|
|
11783
11948
|
throw new Error(
|
|
11784
11949
|
`Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
|
|
@@ -11788,10 +11953,10 @@ function createAgentStrategy(agent, os27 = createOsStrategy()) {
|
|
|
11788
11953
|
if (!build) {
|
|
11789
11954
|
throw new Error(`No runtime strategy registered for agent "${agent}"`);
|
|
11790
11955
|
}
|
|
11791
|
-
return build(
|
|
11956
|
+
return build(os28);
|
|
11792
11957
|
}
|
|
11793
|
-
function createInteractiveAgentStrategy(agent,
|
|
11794
|
-
const s = createAgentStrategy(agent,
|
|
11958
|
+
function createInteractiveAgentStrategy(agent, os28 = createOsStrategy()) {
|
|
11959
|
+
const s = createAgentStrategy(agent, os28);
|
|
11795
11960
|
if (s.mode !== "interactive") {
|
|
11796
11961
|
throw new Error(
|
|
11797
11962
|
`Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
|
|
@@ -11812,19 +11977,19 @@ function createDeployStrategy(agent) {
|
|
|
11812
11977
|
}
|
|
11813
11978
|
|
|
11814
11979
|
// src/agents/acp/adapters.ts
|
|
11815
|
-
var
|
|
11980
|
+
var path25 = __toESM(require("path"));
|
|
11816
11981
|
var require_ = require;
|
|
11817
11982
|
function resolveBin(pkgName, binName) {
|
|
11818
11983
|
try {
|
|
11819
11984
|
const manifestPath = require_.resolve(`${pkgName}/package.json`);
|
|
11820
11985
|
const manifest = require_(`${pkgName}/package.json`);
|
|
11821
|
-
const pkgDir =
|
|
11986
|
+
const pkgDir = path25.dirname(manifestPath);
|
|
11822
11987
|
const bin = manifest.bin;
|
|
11823
11988
|
if (!bin) return null;
|
|
11824
|
-
if (typeof bin === "string") return
|
|
11989
|
+
if (typeof bin === "string") return path25.resolve(pkgDir, bin);
|
|
11825
11990
|
const target = binName ?? Object.keys(bin)[0];
|
|
11826
11991
|
if (!target || !bin[target]) return null;
|
|
11827
|
-
return
|
|
11992
|
+
return path25.resolve(pkgDir, bin[target]);
|
|
11828
11993
|
} catch {
|
|
11829
11994
|
return null;
|
|
11830
11995
|
}
|
|
@@ -11876,8 +12041,8 @@ function getAcpAdapter(agent) {
|
|
|
11876
12041
|
var import_node_crypto6 = require("crypto");
|
|
11877
12042
|
|
|
11878
12043
|
// src/agents/acp/client.ts
|
|
11879
|
-
var
|
|
11880
|
-
var
|
|
12044
|
+
var import_node_child_process11 = require("child_process");
|
|
12045
|
+
var fs21 = __toESM(require("fs/promises"));
|
|
11881
12046
|
var import_node_stream = require("stream");
|
|
11882
12047
|
var import_sdk = require("@agentclientprotocol/sdk");
|
|
11883
12048
|
var PROTOCOL_VERSION2 = 1;
|
|
@@ -11902,7 +12067,7 @@ var AcpClient = class {
|
|
|
11902
12067
|
async start() {
|
|
11903
12068
|
if (this.child) throw new Error("AcpClient already started");
|
|
11904
12069
|
const { adapter, cwd } = this.opts;
|
|
11905
|
-
const child = (0,
|
|
12070
|
+
const child = (0, import_node_child_process11.spawn)(adapter.command, adapter.args, {
|
|
11906
12071
|
cwd,
|
|
11907
12072
|
env: process.env,
|
|
11908
12073
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -12006,11 +12171,11 @@ var AcpClient = class {
|
|
|
12006
12171
|
return this.opts.onRequestPermission(params);
|
|
12007
12172
|
},
|
|
12008
12173
|
readTextFile: async (params) => {
|
|
12009
|
-
const content = await
|
|
12174
|
+
const content = await fs21.readFile(params.path, "utf8");
|
|
12010
12175
|
return applyLineRange(content, params.line ?? null, params.limit ?? null);
|
|
12011
12176
|
},
|
|
12012
12177
|
writeTextFile: async (params) => {
|
|
12013
|
-
await
|
|
12178
|
+
await fs21.writeFile(params.path, params.content, "utf8");
|
|
12014
12179
|
return {};
|
|
12015
12180
|
},
|
|
12016
12181
|
// Terminal capability is declared `false` above so adapters
|
|
@@ -13255,9 +13420,9 @@ var OutputService = class _OutputService {
|
|
|
13255
13420
|
};
|
|
13256
13421
|
|
|
13257
13422
|
// src/services/history.service.ts
|
|
13258
|
-
var
|
|
13259
|
-
var
|
|
13260
|
-
var
|
|
13423
|
+
var fs22 = __toESM(require("fs"));
|
|
13424
|
+
var path26 = __toESM(require("path"));
|
|
13425
|
+
var os22 = __toESM(require("os"));
|
|
13261
13426
|
var https5 = __toESM(require("https"));
|
|
13262
13427
|
var http5 = __toESM(require("http"));
|
|
13263
13428
|
var import_zod = require("zod");
|
|
@@ -13284,7 +13449,7 @@ function parseJsonl(filePath) {
|
|
|
13284
13449
|
const messages = [];
|
|
13285
13450
|
let raw;
|
|
13286
13451
|
try {
|
|
13287
|
-
raw =
|
|
13452
|
+
raw = fs22.readFileSync(filePath, "utf8");
|
|
13288
13453
|
} catch (err) {
|
|
13289
13454
|
if (err.code !== "ENOENT") {
|
|
13290
13455
|
log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
|
|
@@ -13419,7 +13584,7 @@ var HistoryService = class _HistoryService {
|
|
|
13419
13584
|
return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
|
|
13420
13585
|
}
|
|
13421
13586
|
get projectDir() {
|
|
13422
|
-
return this.runtime.resolveHistoryDir(this.cwd) ??
|
|
13587
|
+
return this.runtime.resolveHistoryDir(this.cwd) ?? path26.join(os22.homedir(), ".claude", "projects", encodeCwd(this.cwd));
|
|
13423
13588
|
}
|
|
13424
13589
|
/** Set the current Claude conversation ID (extracted from /cost command or session start) */
|
|
13425
13590
|
setCurrentConversationId(id) {
|
|
@@ -13431,7 +13596,7 @@ var HistoryService = class _HistoryService {
|
|
|
13431
13596
|
/** Return the current message count in the active conversation. */
|
|
13432
13597
|
getCurrentMessageCount() {
|
|
13433
13598
|
if (!this.currentConversationId) return 0;
|
|
13434
|
-
const filePath =
|
|
13599
|
+
const filePath = path26.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
13435
13600
|
return parseJsonl(filePath).length;
|
|
13436
13601
|
}
|
|
13437
13602
|
/**
|
|
@@ -13442,7 +13607,7 @@ var HistoryService = class _HistoryService {
|
|
|
13442
13607
|
const deadline = Date.now() + timeoutMs;
|
|
13443
13608
|
while (Date.now() < deadline) {
|
|
13444
13609
|
if (!this.currentConversationId) return null;
|
|
13445
|
-
const filePath =
|
|
13610
|
+
const filePath = path26.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
13446
13611
|
const messages = parseJsonl(filePath);
|
|
13447
13612
|
if (messages.length > previousCount) {
|
|
13448
13613
|
for (let i = messages.length - 1; i >= previousCount; i--) {
|
|
@@ -13468,16 +13633,16 @@ var HistoryService = class _HistoryService {
|
|
|
13468
13633
|
const dir = this.projectDir;
|
|
13469
13634
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
13470
13635
|
try {
|
|
13471
|
-
const files =
|
|
13636
|
+
const files = fs22.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
13472
13637
|
try {
|
|
13473
|
-
const stat3 =
|
|
13638
|
+
const stat3 = fs22.statSync(path26.join(dir, e.name));
|
|
13474
13639
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
13475
13640
|
} catch {
|
|
13476
13641
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
13477
13642
|
}
|
|
13478
13643
|
}).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
|
|
13479
13644
|
if (files.length > 0) {
|
|
13480
|
-
this.currentConversationId =
|
|
13645
|
+
this.currentConversationId = path26.basename(files[0].name, ".jsonl");
|
|
13481
13646
|
}
|
|
13482
13647
|
} catch {
|
|
13483
13648
|
}
|
|
@@ -13511,13 +13676,13 @@ var HistoryService = class _HistoryService {
|
|
|
13511
13676
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
13512
13677
|
let entries;
|
|
13513
13678
|
try {
|
|
13514
|
-
entries =
|
|
13679
|
+
entries = fs22.readdirSync(dir, { withFileTypes: true });
|
|
13515
13680
|
} catch {
|
|
13516
13681
|
return null;
|
|
13517
13682
|
}
|
|
13518
13683
|
const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
13519
13684
|
try {
|
|
13520
|
-
const stat3 =
|
|
13685
|
+
const stat3 = fs22.statSync(path26.join(dir, e.name));
|
|
13521
13686
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
13522
13687
|
} catch {
|
|
13523
13688
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
@@ -13526,12 +13691,12 @@ var HistoryService = class _HistoryService {
|
|
|
13526
13691
|
if (files.length === 0) return null;
|
|
13527
13692
|
const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
|
|
13528
13693
|
if (!files.some((f) => f.name === targetFile)) return null;
|
|
13529
|
-
return this.extractUsageFromFile(
|
|
13694
|
+
return this.extractUsageFromFile(path26.join(dir, targetFile));
|
|
13530
13695
|
}
|
|
13531
13696
|
extractUsageFromFile(filePath) {
|
|
13532
13697
|
let raw;
|
|
13533
13698
|
try {
|
|
13534
|
-
raw =
|
|
13699
|
+
raw = fs22.readFileSync(filePath, "utf8");
|
|
13535
13700
|
} catch {
|
|
13536
13701
|
return null;
|
|
13537
13702
|
}
|
|
@@ -13576,9 +13741,9 @@ var HistoryService = class _HistoryService {
|
|
|
13576
13741
|
let totalCost = 0;
|
|
13577
13742
|
let files;
|
|
13578
13743
|
try {
|
|
13579
|
-
files =
|
|
13744
|
+
files = fs22.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
|
|
13580
13745
|
try {
|
|
13581
|
-
return
|
|
13746
|
+
return fs22.statSync(path26.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
13582
13747
|
} catch {
|
|
13583
13748
|
return false;
|
|
13584
13749
|
}
|
|
@@ -13589,7 +13754,7 @@ var HistoryService = class _HistoryService {
|
|
|
13589
13754
|
for (const file of files) {
|
|
13590
13755
|
let raw;
|
|
13591
13756
|
try {
|
|
13592
|
-
raw =
|
|
13757
|
+
raw = fs22.readFileSync(path26.join(projectDir, file), "utf8");
|
|
13593
13758
|
} catch {
|
|
13594
13759
|
continue;
|
|
13595
13760
|
}
|
|
@@ -13653,7 +13818,7 @@ var HistoryService = class _HistoryService {
|
|
|
13653
13818
|
* showing an empty conversation.
|
|
13654
13819
|
*/
|
|
13655
13820
|
async loadConversation(sessionId) {
|
|
13656
|
-
const filePath =
|
|
13821
|
+
const filePath = path26.join(this.projectDir, `${sessionId}.jsonl`);
|
|
13657
13822
|
const messages = parseJsonl(filePath);
|
|
13658
13823
|
if (messages.length === 0) return;
|
|
13659
13824
|
const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
|
|
@@ -13707,7 +13872,7 @@ var HistoryService = class _HistoryService {
|
|
|
13707
13872
|
if (!this.currentConversationId) return 0;
|
|
13708
13873
|
}
|
|
13709
13874
|
const sessionId = this.currentConversationId;
|
|
13710
|
-
const filePath =
|
|
13875
|
+
const filePath = path26.join(this.projectDir, `${sessionId}.jsonl`);
|
|
13711
13876
|
const messages = parseJsonl(filePath);
|
|
13712
13877
|
if (messages.length === 0) return 0;
|
|
13713
13878
|
const marker = this.lastUploadedUuid.get(sessionId);
|
|
@@ -13738,9 +13903,9 @@ var HistoryService = class _HistoryService {
|
|
|
13738
13903
|
|
|
13739
13904
|
// src/services/file-watcher.service.ts
|
|
13740
13905
|
var import_child_process8 = require("child_process");
|
|
13741
|
-
var
|
|
13742
|
-
var
|
|
13743
|
-
var
|
|
13906
|
+
var fs23 = __toESM(require("fs"));
|
|
13907
|
+
var os23 = __toESM(require("os"));
|
|
13908
|
+
var path27 = __toESM(require("path"));
|
|
13744
13909
|
|
|
13745
13910
|
// src/services/file-watcher/diff-parser.ts
|
|
13746
13911
|
var HUNK_HEADER_RE = /^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/;
|
|
@@ -13898,10 +14063,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
|
|
|
13898
14063
|
/[\\/]Start Menu([\\/]|$)/i,
|
|
13899
14064
|
/[\\/]Templates([\\/]|$)/i
|
|
13900
14065
|
];
|
|
13901
|
-
function isUnsafeWindowsWatchRoot(dir,
|
|
14066
|
+
function isUnsafeWindowsWatchRoot(dir, homedir20) {
|
|
13902
14067
|
const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
|
|
13903
14068
|
const cwd = norm(dir);
|
|
13904
|
-
const home = norm(
|
|
14069
|
+
const home = norm(homedir20);
|
|
13905
14070
|
if (cwd === home) return true;
|
|
13906
14071
|
if (/^[a-z]:$/.test(cwd)) return true;
|
|
13907
14072
|
const sysRoots = [
|
|
@@ -13931,18 +14096,18 @@ var _findGitRootSeam = {
|
|
|
13931
14096
|
resolve: _defaultFindGitRoot
|
|
13932
14097
|
};
|
|
13933
14098
|
function _defaultFindGitRoot(startDir) {
|
|
13934
|
-
let dir =
|
|
14099
|
+
let dir = path27.resolve(startDir);
|
|
13935
14100
|
const seen = /* @__PURE__ */ new Set();
|
|
13936
14101
|
for (let i = 0; i < 256; i++) {
|
|
13937
14102
|
if (seen.has(dir)) return null;
|
|
13938
14103
|
seen.add(dir);
|
|
13939
14104
|
try {
|
|
13940
|
-
const gitPath =
|
|
13941
|
-
const stat3 =
|
|
14105
|
+
const gitPath = path27.join(dir, ".git");
|
|
14106
|
+
const stat3 = fs23.statSync(gitPath, { throwIfNoEntry: false });
|
|
13942
14107
|
if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
|
|
13943
14108
|
} catch {
|
|
13944
14109
|
}
|
|
13945
|
-
const parent =
|
|
14110
|
+
const parent = path27.dirname(dir);
|
|
13946
14111
|
if (parent === dir) return null;
|
|
13947
14112
|
dir = parent;
|
|
13948
14113
|
}
|
|
@@ -13989,7 +14154,7 @@ var FileWatcherService = class {
|
|
|
13989
14154
|
throw new Error("FileWatcherService has already been stopped \u2014 re-instantiate to restart.");
|
|
13990
14155
|
}
|
|
13991
14156
|
const isWin = process.platform === "win32";
|
|
13992
|
-
if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir,
|
|
14157
|
+
if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os23.homedir())) {
|
|
13993
14158
|
log.warn(
|
|
13994
14159
|
"fileWatcher",
|
|
13995
14160
|
`refusing to watch ${this.opts.workingDir} \u2014 looks like a Windows user-profile or system path. Run codeam from your project folder to enable file change emission.`
|
|
@@ -14176,7 +14341,7 @@ var FileWatcherService = class {
|
|
|
14176
14341
|
}
|
|
14177
14342
|
async emitForFile(absPath, changeType) {
|
|
14178
14343
|
if (this.stopped) return;
|
|
14179
|
-
const fileDir =
|
|
14344
|
+
const fileDir = path27.dirname(absPath);
|
|
14180
14345
|
let gitRoot = this.gitRootByDir.get(fileDir);
|
|
14181
14346
|
if (gitRoot === void 0) {
|
|
14182
14347
|
gitRoot = findGitRoot(fileDir);
|
|
@@ -14190,10 +14355,10 @@ var FileWatcherService = class {
|
|
|
14190
14355
|
return;
|
|
14191
14356
|
}
|
|
14192
14357
|
this.opts.onRepoDirty?.(gitRoot);
|
|
14193
|
-
const relPathInRepo =
|
|
14358
|
+
const relPathInRepo = path27.relative(gitRoot, absPath);
|
|
14194
14359
|
if (!relPathInRepo || relPathInRepo.startsWith("..")) return;
|
|
14195
|
-
const repoPath =
|
|
14196
|
-
const repoName =
|
|
14360
|
+
const repoPath = path27.relative(this.opts.workingDir, gitRoot);
|
|
14361
|
+
const repoName = path27.basename(gitRoot);
|
|
14197
14362
|
let diffText = "";
|
|
14198
14363
|
let fileStatus = "modified";
|
|
14199
14364
|
if (changeType === "unlink") {
|
|
@@ -14492,7 +14657,7 @@ var import_crypto2 = require("crypto");
|
|
|
14492
14657
|
|
|
14493
14658
|
// src/services/turn-files/git-changeset.ts
|
|
14494
14659
|
var import_child_process9 = require("child_process");
|
|
14495
|
-
var
|
|
14660
|
+
var path28 = __toESM(require("path"));
|
|
14496
14661
|
async function collectRepoChangeset(opts) {
|
|
14497
14662
|
const status2 = await runGit2(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
|
|
14498
14663
|
if (status2 === null) return null;
|
|
@@ -14603,7 +14768,7 @@ function defaultRunGit(cwd, args2) {
|
|
|
14603
14768
|
});
|
|
14604
14769
|
}
|
|
14605
14770
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
14606
|
-
const
|
|
14771
|
+
const fs36 = await import("fs/promises");
|
|
14607
14772
|
const out2 = [];
|
|
14608
14773
|
await walk(workingDir, 0);
|
|
14609
14774
|
return out2;
|
|
@@ -14611,7 +14776,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
14611
14776
|
if (depth > maxDepth) return;
|
|
14612
14777
|
let entries = [];
|
|
14613
14778
|
try {
|
|
14614
|
-
const dirents = await
|
|
14779
|
+
const dirents = await fs36.readdir(dir, { withFileTypes: true });
|
|
14615
14780
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
14616
14781
|
} catch {
|
|
14617
14782
|
return;
|
|
@@ -14622,8 +14787,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
14622
14787
|
if (hasGit) {
|
|
14623
14788
|
out2.push({
|
|
14624
14789
|
repoRoot: dir,
|
|
14625
|
-
repoPath:
|
|
14626
|
-
repoName:
|
|
14790
|
+
repoPath: path28.relative(workingDir, dir),
|
|
14791
|
+
repoName: path28.basename(dir)
|
|
14627
14792
|
});
|
|
14628
14793
|
return;
|
|
14629
14794
|
}
|
|
@@ -14631,15 +14796,15 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
14631
14796
|
if (!entry.isDirectory) continue;
|
|
14632
14797
|
if (entry.name === "node_modules") continue;
|
|
14633
14798
|
if (entry.name === "dist" || entry.name === "build") continue;
|
|
14634
|
-
await walk(
|
|
14799
|
+
await walk(path28.join(dir, entry.name), depth + 1);
|
|
14635
14800
|
}
|
|
14636
14801
|
}
|
|
14637
14802
|
}
|
|
14638
14803
|
|
|
14639
14804
|
// src/services/turn-files/files-outbox.ts
|
|
14640
|
-
var
|
|
14641
|
-
var
|
|
14642
|
-
var
|
|
14805
|
+
var fs24 = __toESM(require("fs/promises"));
|
|
14806
|
+
var path29 = __toESM(require("path"));
|
|
14807
|
+
var import_os7 = require("os");
|
|
14643
14808
|
var HOME_OUTBOX_DIR = ".codeam/outbox";
|
|
14644
14809
|
var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
14645
14810
|
var BACKOFF_STEPS_MS = [
|
|
@@ -14671,16 +14836,16 @@ var FilesOutbox = class {
|
|
|
14671
14836
|
backoffIndex = 0;
|
|
14672
14837
|
stopped = false;
|
|
14673
14838
|
constructor(opts) {
|
|
14674
|
-
const base = opts.baseDir ??
|
|
14675
|
-
this.filePath =
|
|
14839
|
+
const base = opts.baseDir ?? path29.join(homeDir(), HOME_OUTBOX_DIR);
|
|
14840
|
+
this.filePath = path29.join(base, `${opts.sessionId}.jsonl`);
|
|
14676
14841
|
this.post = opts.post;
|
|
14677
14842
|
this.autoSchedule = opts.autoSchedule !== false;
|
|
14678
14843
|
}
|
|
14679
14844
|
/** Persist the entry to disk and trigger a flush. Returns once the
|
|
14680
14845
|
* line is durable on disk (not once the POST succeeds). */
|
|
14681
14846
|
async enqueue(entry) {
|
|
14682
|
-
await
|
|
14683
|
-
await
|
|
14847
|
+
await fs24.mkdir(path29.dirname(this.filePath), { recursive: true });
|
|
14848
|
+
await fs24.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
|
|
14684
14849
|
this.backoffIndex = 0;
|
|
14685
14850
|
if (this.autoSchedule) this.scheduleFlush(0);
|
|
14686
14851
|
}
|
|
@@ -14769,7 +14934,7 @@ var FilesOutbox = class {
|
|
|
14769
14934
|
async readAll() {
|
|
14770
14935
|
let raw = "";
|
|
14771
14936
|
try {
|
|
14772
|
-
raw = await
|
|
14937
|
+
raw = await fs24.readFile(this.filePath, "utf8");
|
|
14773
14938
|
} catch {
|
|
14774
14939
|
return [];
|
|
14775
14940
|
}
|
|
@@ -14793,12 +14958,12 @@ var FilesOutbox = class {
|
|
|
14793
14958
|
async rewrite(entries) {
|
|
14794
14959
|
const tmpPath = `${this.filePath}.${process.pid}.tmp`;
|
|
14795
14960
|
if (entries.length === 0) {
|
|
14796
|
-
await
|
|
14961
|
+
await fs24.unlink(this.filePath).catch(() => void 0);
|
|
14797
14962
|
return;
|
|
14798
14963
|
}
|
|
14799
14964
|
const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
14800
|
-
await
|
|
14801
|
-
await
|
|
14965
|
+
await fs24.writeFile(tmpPath, payload, "utf8");
|
|
14966
|
+
await fs24.rename(tmpPath, this.filePath);
|
|
14802
14967
|
}
|
|
14803
14968
|
};
|
|
14804
14969
|
function applyJitter(ms) {
|
|
@@ -14806,7 +14971,7 @@ function applyJitter(ms) {
|
|
|
14806
14971
|
return Math.round(ms * factor);
|
|
14807
14972
|
}
|
|
14808
14973
|
function homeDir() {
|
|
14809
|
-
return process.env.HOME ?? process.env.USERPROFILE ?? (0,
|
|
14974
|
+
return process.env.HOME ?? process.env.USERPROFILE ?? (0, import_os7.tmpdir)();
|
|
14810
14975
|
}
|
|
14811
14976
|
|
|
14812
14977
|
// src/services/turn-files/turn-file-aggregator.ts
|
|
@@ -15421,9 +15586,9 @@ function buildKeepAlive(ctx) {
|
|
|
15421
15586
|
}
|
|
15422
15587
|
|
|
15423
15588
|
// src/commands/start/handlers.ts
|
|
15424
|
-
var
|
|
15425
|
-
var
|
|
15426
|
-
var
|
|
15589
|
+
var fs32 = __toESM(require("fs"));
|
|
15590
|
+
var os25 = __toESM(require("os"));
|
|
15591
|
+
var path38 = __toESM(require("path"));
|
|
15427
15592
|
var import_crypto5 = require("crypto");
|
|
15428
15593
|
var import_child_process15 = require("child_process");
|
|
15429
15594
|
|
|
@@ -15547,8 +15712,8 @@ function parsePayload2(schema, raw) {
|
|
|
15547
15712
|
}
|
|
15548
15713
|
|
|
15549
15714
|
// src/services/file-ops.service.ts
|
|
15550
|
-
var
|
|
15551
|
-
var
|
|
15715
|
+
var fs25 = __toESM(require("fs/promises"));
|
|
15716
|
+
var path30 = __toESM(require("path"));
|
|
15552
15717
|
var MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
15553
15718
|
var MAX_WALK_DEPTH = 6;
|
|
15554
15719
|
var MAX_VISITED_DIRS = 5e3;
|
|
@@ -15583,12 +15748,12 @@ var SUBDIR_IGNORE = /* @__PURE__ */ new Set([
|
|
|
15583
15748
|
"__pycache__"
|
|
15584
15749
|
]);
|
|
15585
15750
|
function isUnder(parent, candidate) {
|
|
15586
|
-
const rel =
|
|
15587
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
15751
|
+
const rel = path30.relative(parent, candidate);
|
|
15752
|
+
return rel === "" || !rel.startsWith("..") && !path30.isAbsolute(rel);
|
|
15588
15753
|
}
|
|
15589
15754
|
async function isExistingFile(absPath) {
|
|
15590
15755
|
try {
|
|
15591
|
-
const stat3 = await
|
|
15756
|
+
const stat3 = await fs25.stat(absPath);
|
|
15592
15757
|
return stat3.isFile();
|
|
15593
15758
|
} catch {
|
|
15594
15759
|
return false;
|
|
@@ -15601,13 +15766,13 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
|
|
|
15601
15766
|
ctx.visited++;
|
|
15602
15767
|
let entries = [];
|
|
15603
15768
|
try {
|
|
15604
|
-
entries = await
|
|
15769
|
+
entries = await fs25.readdir(dir, { withFileTypes: true });
|
|
15605
15770
|
} catch {
|
|
15606
15771
|
return;
|
|
15607
15772
|
}
|
|
15608
15773
|
for (const e of entries) {
|
|
15609
15774
|
if (!e.isFile()) continue;
|
|
15610
|
-
const full =
|
|
15775
|
+
const full = path30.join(dir, e.name);
|
|
15611
15776
|
if (needleVariants.some((needle) => full.endsWith(needle))) {
|
|
15612
15777
|
ctx.matches.push(full);
|
|
15613
15778
|
if (ctx.matches.length >= ctx.cap) return;
|
|
@@ -15617,21 +15782,21 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
|
|
|
15617
15782
|
if (!e.isDirectory()) continue;
|
|
15618
15783
|
if (SUBDIR_IGNORE.has(e.name)) continue;
|
|
15619
15784
|
if (e.name.startsWith(".") && SUBDIR_IGNORE.has(e.name)) continue;
|
|
15620
|
-
await walkForSuffix(
|
|
15785
|
+
await walkForSuffix(path30.join(dir, e.name), needleVariants, depth + 1, ctx);
|
|
15621
15786
|
if (ctx.matches.length >= ctx.cap) return;
|
|
15622
15787
|
}
|
|
15623
15788
|
}
|
|
15624
15789
|
async function findFile(rawPath) {
|
|
15625
15790
|
const cwd = process.cwd();
|
|
15626
|
-
if (
|
|
15627
|
-
const abs =
|
|
15791
|
+
if (path30.isAbsolute(rawPath)) {
|
|
15792
|
+
const abs = path30.normalize(rawPath);
|
|
15628
15793
|
if (isUnder(cwd, abs) && await isExistingFile(abs)) return abs;
|
|
15629
15794
|
}
|
|
15630
|
-
const direct =
|
|
15795
|
+
const direct = path30.resolve(cwd, rawPath);
|
|
15631
15796
|
if (isUnder(cwd, direct) && await isExistingFile(direct)) return direct;
|
|
15632
|
-
const normalized =
|
|
15797
|
+
const normalized = path30.normalize(rawPath).replace(/^[./\\]+/, "");
|
|
15633
15798
|
const needles = [
|
|
15634
|
-
`${
|
|
15799
|
+
`${path30.sep}${normalized}`,
|
|
15635
15800
|
`/${normalized}`
|
|
15636
15801
|
].filter((v, i, a) => a.indexOf(v) === i);
|
|
15637
15802
|
const ctx = { visited: 0, matches: [], cap: 16 };
|
|
@@ -15645,7 +15810,7 @@ async function findWriteTarget(rawPath) {
|
|
|
15645
15810
|
const found = await findFile(rawPath);
|
|
15646
15811
|
if (found) return found;
|
|
15647
15812
|
const cwd = process.cwd();
|
|
15648
|
-
const fallback =
|
|
15813
|
+
const fallback = path30.isAbsolute(rawPath) ? path30.normalize(rawPath) : path30.resolve(cwd, rawPath);
|
|
15649
15814
|
if (!isUnder(cwd, fallback)) return null;
|
|
15650
15815
|
return fallback;
|
|
15651
15816
|
}
|
|
@@ -15662,11 +15827,11 @@ async function readProjectFile(rawPath) {
|
|
|
15662
15827
|
if (!abs) {
|
|
15663
15828
|
return { error: `File not found in the project tree: ${rawPath}` };
|
|
15664
15829
|
}
|
|
15665
|
-
const stat3 = await
|
|
15830
|
+
const stat3 = await fs25.stat(abs);
|
|
15666
15831
|
if (stat3.size > MAX_FILE_BYTES) {
|
|
15667
15832
|
return { error: `File too large (${(stat3.size / 1024 / 1024).toFixed(1)} MB > ${MAX_FILE_BYTES / 1024 / 1024} MB).` };
|
|
15668
15833
|
}
|
|
15669
|
-
const buf = await
|
|
15834
|
+
const buf = await fs25.readFile(abs);
|
|
15670
15835
|
if (looksBinary(buf)) {
|
|
15671
15836
|
return { error: "Binary file \u2014 refusing to open in a code editor." };
|
|
15672
15837
|
}
|
|
@@ -15685,8 +15850,8 @@ async function writeProjectFile(rawPath, content) {
|
|
|
15685
15850
|
if (Buffer.byteLength(content, "utf-8") > MAX_FILE_BYTES) {
|
|
15686
15851
|
return { error: "Content too large." };
|
|
15687
15852
|
}
|
|
15688
|
-
await
|
|
15689
|
-
await
|
|
15853
|
+
await fs25.mkdir(path30.dirname(abs), { recursive: true });
|
|
15854
|
+
await fs25.writeFile(abs, content, "utf-8");
|
|
15690
15855
|
return { ok: true };
|
|
15691
15856
|
} catch (e) {
|
|
15692
15857
|
const msg = e instanceof Error ? e.message : "Write failed";
|
|
@@ -15697,8 +15862,8 @@ async function writeProjectFile(rawPath, content) {
|
|
|
15697
15862
|
// src/services/project-ops.service.ts
|
|
15698
15863
|
var import_child_process11 = require("child_process");
|
|
15699
15864
|
var import_util2 = require("util");
|
|
15700
|
-
var
|
|
15701
|
-
var
|
|
15865
|
+
var fs26 = __toESM(require("fs/promises"));
|
|
15866
|
+
var path31 = __toESM(require("path"));
|
|
15702
15867
|
var execFileP3 = (0, import_util2.promisify)(import_child_process11.execFile);
|
|
15703
15868
|
var PROJECT_IGNORE = /* @__PURE__ */ new Set([
|
|
15704
15869
|
"node_modules",
|
|
@@ -15746,7 +15911,7 @@ async function listProjectFiles(opts = {}) {
|
|
|
15746
15911
|
}
|
|
15747
15912
|
let entries = [];
|
|
15748
15913
|
try {
|
|
15749
|
-
entries = await
|
|
15914
|
+
entries = await fs26.readdir(dir, { withFileTypes: true });
|
|
15750
15915
|
} catch {
|
|
15751
15916
|
return;
|
|
15752
15917
|
}
|
|
@@ -15756,18 +15921,18 @@ async function listProjectFiles(opts = {}) {
|
|
|
15756
15921
|
return;
|
|
15757
15922
|
}
|
|
15758
15923
|
if (PROJECT_IGNORE.has(e.name)) continue;
|
|
15759
|
-
const full =
|
|
15924
|
+
const full = path31.join(dir, e.name);
|
|
15760
15925
|
if (e.isDirectory()) {
|
|
15761
15926
|
if (depth >= 12) continue;
|
|
15762
15927
|
await walk(full, depth + 1);
|
|
15763
15928
|
} else if (e.isFile()) {
|
|
15764
|
-
const rel =
|
|
15929
|
+
const rel = path31.relative(root, full);
|
|
15765
15930
|
if (q2 && !rel.toLowerCase().includes(q2) && !e.name.toLowerCase().includes(q2)) {
|
|
15766
15931
|
continue;
|
|
15767
15932
|
}
|
|
15768
15933
|
let size = 0;
|
|
15769
15934
|
try {
|
|
15770
|
-
const st3 = await
|
|
15935
|
+
const st3 = await fs26.stat(full);
|
|
15771
15936
|
size = st3.size;
|
|
15772
15937
|
} catch {
|
|
15773
15938
|
}
|
|
@@ -15869,8 +16034,8 @@ async function gitStatus(cwd) {
|
|
|
15869
16034
|
let hasMergeInProgress = false;
|
|
15870
16035
|
try {
|
|
15871
16036
|
const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
|
|
15872
|
-
const mergeHead =
|
|
15873
|
-
await
|
|
16037
|
+
const mergeHead = path31.isAbsolute(gitDir) ? path31.join(gitDir, "MERGE_HEAD") : path31.join(root, gitDir, "MERGE_HEAD");
|
|
16038
|
+
await fs26.access(mergeHead);
|
|
15874
16039
|
hasMergeInProgress = true;
|
|
15875
16040
|
} catch {
|
|
15876
16041
|
}
|
|
@@ -16016,7 +16181,7 @@ async function jsSearchFiles(opts, cwd, cap) {
|
|
|
16016
16181
|
}
|
|
16017
16182
|
let content = "";
|
|
16018
16183
|
try {
|
|
16019
|
-
content = await
|
|
16184
|
+
content = await fs26.readFile(path31.join(cwd, f.path), "utf8");
|
|
16020
16185
|
} catch {
|
|
16021
16186
|
continue;
|
|
16022
16187
|
}
|
|
@@ -16297,14 +16462,14 @@ function closeAllTerminals() {
|
|
|
16297
16462
|
|
|
16298
16463
|
// src/services/apply-file-review.service.ts
|
|
16299
16464
|
var import_child_process13 = require("child_process");
|
|
16300
|
-
var
|
|
16301
|
-
var
|
|
16465
|
+
var fs27 = __toESM(require("fs"));
|
|
16466
|
+
var path33 = __toESM(require("path"));
|
|
16302
16467
|
async function applyFileReview(workingDir, filePath, action) {
|
|
16303
|
-
if (filePath.includes("..") ||
|
|
16468
|
+
if (filePath.includes("..") || path33.isAbsolute(filePath)) {
|
|
16304
16469
|
return { ok: false, action, filePath, error: "invalid file path" };
|
|
16305
16470
|
}
|
|
16306
|
-
const absFile =
|
|
16307
|
-
const repoRoot = findGitRoot2(
|
|
16471
|
+
const absFile = path33.resolve(workingDir, filePath);
|
|
16472
|
+
const repoRoot = findGitRoot2(path33.dirname(absFile));
|
|
16308
16473
|
if (!repoRoot) {
|
|
16309
16474
|
return {
|
|
16310
16475
|
ok: false,
|
|
@@ -16313,7 +16478,7 @@ async function applyFileReview(workingDir, filePath, action) {
|
|
|
16313
16478
|
error: `no enclosing git repo for ${filePath}`
|
|
16314
16479
|
};
|
|
16315
16480
|
}
|
|
16316
|
-
const relInRepo =
|
|
16481
|
+
const relInRepo = path33.relative(repoRoot, absFile);
|
|
16317
16482
|
if (!relInRepo || relInRepo.startsWith("..")) {
|
|
16318
16483
|
return { ok: false, action, filePath, error: "path escapes repo root" };
|
|
16319
16484
|
}
|
|
@@ -16362,17 +16527,17 @@ function runGit3(cwd, args2) {
|
|
|
16362
16527
|
});
|
|
16363
16528
|
}
|
|
16364
16529
|
function findGitRoot2(startDir) {
|
|
16365
|
-
let dir =
|
|
16530
|
+
let dir = path33.resolve(startDir);
|
|
16366
16531
|
const seen = /* @__PURE__ */ new Set();
|
|
16367
16532
|
for (let i = 0; i < 256; i++) {
|
|
16368
16533
|
if (seen.has(dir)) return null;
|
|
16369
16534
|
seen.add(dir);
|
|
16370
16535
|
try {
|
|
16371
|
-
const stat3 =
|
|
16536
|
+
const stat3 = fs27.statSync(path33.join(dir, ".git"), { throwIfNoEntry: false });
|
|
16372
16537
|
if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
|
|
16373
16538
|
} catch {
|
|
16374
16539
|
}
|
|
16375
|
-
const parent =
|
|
16540
|
+
const parent = path33.dirname(dir);
|
|
16376
16541
|
if (parent === dir) return null;
|
|
16377
16542
|
dir = parent;
|
|
16378
16543
|
}
|
|
@@ -16381,8 +16546,8 @@ function findGitRoot2(startDir) {
|
|
|
16381
16546
|
|
|
16382
16547
|
// src/commands/link.ts
|
|
16383
16548
|
var import_node_crypto7 = require("crypto");
|
|
16384
|
-
var
|
|
16385
|
-
var
|
|
16549
|
+
var fs28 = __toESM(require("fs"));
|
|
16550
|
+
var path34 = __toESM(require("path"));
|
|
16386
16551
|
var import_chokidar = __toESM(require("chokidar"));
|
|
16387
16552
|
var import_picocolors2 = __toESM(require("picocolors"));
|
|
16388
16553
|
|
|
@@ -16442,7 +16607,7 @@ function parseLinkArgs(args2) {
|
|
|
16442
16607
|
if (apiKeyFileArg) {
|
|
16443
16608
|
const filePath = apiKeyFileArg.slice("--api-key-file=".length);
|
|
16444
16609
|
try {
|
|
16445
|
-
apiKey =
|
|
16610
|
+
apiKey = fs28.readFileSync(path34.resolve(filePath), "utf8").trim();
|
|
16446
16611
|
} catch (err) {
|
|
16447
16612
|
throw new Error(`Could not read --api-key-file ${filePath}: ${err.message}`);
|
|
16448
16613
|
}
|
|
@@ -16536,7 +16701,7 @@ async function link(args2 = []) {
|
|
|
16536
16701
|
return;
|
|
16537
16702
|
}
|
|
16538
16703
|
if (parsed.tokenFile) {
|
|
16539
|
-
const credential =
|
|
16704
|
+
const credential = fs28.readFileSync(path34.resolve(parsed.tokenFile), "utf8").trim();
|
|
16540
16705
|
if (!credential) {
|
|
16541
16706
|
showError(`--token-file ${parsed.tokenFile} is empty.`);
|
|
16542
16707
|
process.exit(1);
|
|
@@ -16755,11 +16920,11 @@ async function linkDryRunPreflight(ctx) {
|
|
|
16755
16920
|
var import_promises = require("dns/promises");
|
|
16756
16921
|
var import_fs = require("fs");
|
|
16757
16922
|
var import_promises2 = __toESM(require("fs/promises"));
|
|
16758
|
-
var
|
|
16923
|
+
var import_os8 = __toESM(require("os"));
|
|
16759
16924
|
var import_path4 = __toESM(require("path"));
|
|
16760
16925
|
var import_promises3 = require("stream/promises");
|
|
16761
16926
|
var import_which = __toESM(require("which"));
|
|
16762
|
-
var CACHED_BINARY = import_path4.default.join(
|
|
16927
|
+
var CACHED_BINARY = import_path4.default.join(import_os8.default.homedir(), ".codeam", "bin", "cloudflared");
|
|
16763
16928
|
async function waitForCloudflaredReady(url, timeoutMs = 6e4) {
|
|
16764
16929
|
const hostname3 = new URL(url).hostname;
|
|
16765
16930
|
const resolver = new import_promises.Resolver();
|
|
@@ -17046,7 +17211,7 @@ var pendingAttachmentFiles = /* @__PURE__ */ new Set();
|
|
|
17046
17211
|
function cleanupAttachmentTempFiles() {
|
|
17047
17212
|
for (const p2 of pendingAttachmentFiles) {
|
|
17048
17213
|
try {
|
|
17049
|
-
|
|
17214
|
+
fs32.unlinkSync(p2);
|
|
17050
17215
|
} catch {
|
|
17051
17216
|
}
|
|
17052
17217
|
}
|
|
@@ -17055,8 +17220,8 @@ function cleanupAttachmentTempFiles() {
|
|
|
17055
17220
|
function saveFilesTemp(files) {
|
|
17056
17221
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
17057
17222
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
17058
|
-
const tmpPath =
|
|
17059
|
-
|
|
17223
|
+
const tmpPath = path38.join(os25.tmpdir(), `codeam-${(0, import_crypto5.randomUUID)()}-${safeName}`);
|
|
17224
|
+
fs32.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
17060
17225
|
pendingAttachmentFiles.add(tmpPath);
|
|
17061
17226
|
return tmpPath;
|
|
17062
17227
|
});
|
|
@@ -17076,7 +17241,7 @@ var startTask = (ctx, _cmd, parsed) => {
|
|
|
17076
17241
|
setTimeout(() => {
|
|
17077
17242
|
for (const p2 of paths) {
|
|
17078
17243
|
try {
|
|
17079
|
-
|
|
17244
|
+
fs32.unlinkSync(p2);
|
|
17080
17245
|
} catch {
|
|
17081
17246
|
}
|
|
17082
17247
|
pendingAttachmentFiles.delete(p2);
|
|
@@ -18404,8 +18569,8 @@ async function autoLinkAfterPair(opts) {
|
|
|
18404
18569
|
}
|
|
18405
18570
|
|
|
18406
18571
|
// src/commands/pair-auto.ts
|
|
18407
|
-
var
|
|
18408
|
-
var
|
|
18572
|
+
var fs33 = __toESM(require("fs"));
|
|
18573
|
+
var os26 = __toESM(require("os"));
|
|
18409
18574
|
var import_crypto7 = require("crypto");
|
|
18410
18575
|
|
|
18411
18576
|
// src/commands/start-infra-only.ts
|
|
@@ -18573,12 +18738,12 @@ function readTokenFromArgs(args2) {
|
|
|
18573
18738
|
}
|
|
18574
18739
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
18575
18740
|
if (fileFlag) {
|
|
18576
|
-
const
|
|
18741
|
+
const path45 = fileFlag.slice("--token-file=".length);
|
|
18577
18742
|
try {
|
|
18578
|
-
const content =
|
|
18579
|
-
if (content.length === 0) fail(`--token-file ${
|
|
18743
|
+
const content = fs33.readFileSync(path45, "utf8").trim();
|
|
18744
|
+
if (content.length === 0) fail(`--token-file ${path45} is empty`);
|
|
18580
18745
|
try {
|
|
18581
|
-
|
|
18746
|
+
fs33.unlinkSync(path45);
|
|
18582
18747
|
} catch {
|
|
18583
18748
|
}
|
|
18584
18749
|
return content;
|
|
@@ -18604,7 +18769,7 @@ async function claimOnce(token, pluginId) {
|
|
|
18604
18769
|
pluginId,
|
|
18605
18770
|
ideName: "codeam-cli (codespace)",
|
|
18606
18771
|
ideVersion: process.env.npm_package_version ?? "unknown",
|
|
18607
|
-
hostname:
|
|
18772
|
+
hostname: os26.hostname(),
|
|
18608
18773
|
codespaceName: process.env.CODESPACE_NAME ?? "",
|
|
18609
18774
|
// Current git branch of the codespace's working directory, so the
|
|
18610
18775
|
// backend can populate `PairedSession.branch` for the codespace pair.
|
|
@@ -18844,7 +19009,7 @@ var import_picocolors10 = __toESM(require("picocolors"));
|
|
|
18844
19009
|
var import_child_process16 = require("child_process");
|
|
18845
19010
|
var import_util4 = require("util");
|
|
18846
19011
|
var import_picocolors8 = __toESM(require("picocolors"));
|
|
18847
|
-
var
|
|
19012
|
+
var path39 = __toESM(require("path"));
|
|
18848
19013
|
var execFileP5 = (0, import_util4.promisify)(import_child_process16.execFile);
|
|
18849
19014
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
18850
19015
|
function resetStdinForChild() {
|
|
@@ -19333,7 +19498,7 @@ var GitHubCodespacesProvider = class {
|
|
|
19333
19498
|
});
|
|
19334
19499
|
}
|
|
19335
19500
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
19336
|
-
const remoteDir =
|
|
19501
|
+
const remoteDir = path39.posix.dirname(remotePath);
|
|
19337
19502
|
const parts = [
|
|
19338
19503
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
19339
19504
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -19403,7 +19568,7 @@ function shellQuote(s) {
|
|
|
19403
19568
|
// src/services/providers/gitpod.ts
|
|
19404
19569
|
var import_child_process17 = require("child_process");
|
|
19405
19570
|
var import_util5 = require("util");
|
|
19406
|
-
var
|
|
19571
|
+
var path40 = __toESM(require("path"));
|
|
19407
19572
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
19408
19573
|
var execFileP6 = (0, import_util5.promisify)(import_child_process17.execFile);
|
|
19409
19574
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
@@ -19643,7 +19808,7 @@ var GitpodProvider = class {
|
|
|
19643
19808
|
});
|
|
19644
19809
|
}
|
|
19645
19810
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
19646
|
-
const remoteDir =
|
|
19811
|
+
const remoteDir = path40.posix.dirname(remotePath);
|
|
19647
19812
|
const parts = [
|
|
19648
19813
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
19649
19814
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -19679,7 +19844,7 @@ function shellQuote2(s) {
|
|
|
19679
19844
|
// src/services/providers/gitlab-workspaces.ts
|
|
19680
19845
|
var import_child_process18 = require("child_process");
|
|
19681
19846
|
var import_util6 = require("util");
|
|
19682
|
-
var
|
|
19847
|
+
var path41 = __toESM(require("path"));
|
|
19683
19848
|
var execFileP7 = (0, import_util6.promisify)(import_child_process18.execFile);
|
|
19684
19849
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
19685
19850
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
@@ -19939,7 +20104,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
19939
20104
|
}
|
|
19940
20105
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
19941
20106
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
19942
|
-
const remoteDir =
|
|
20107
|
+
const remoteDir = path41.posix.dirname(remotePath);
|
|
19943
20108
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
19944
20109
|
if (options.mode != null) {
|
|
19945
20110
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
@@ -20007,7 +20172,7 @@ function shellQuote3(s) {
|
|
|
20007
20172
|
// src/services/providers/railway.ts
|
|
20008
20173
|
var import_child_process19 = require("child_process");
|
|
20009
20174
|
var import_util7 = require("util");
|
|
20010
|
-
var
|
|
20175
|
+
var path42 = __toESM(require("path"));
|
|
20011
20176
|
var execFileP8 = (0, import_util7.promisify)(import_child_process19.execFile);
|
|
20012
20177
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
20013
20178
|
function resetStdinForChild4() {
|
|
@@ -20243,7 +20408,7 @@ var RailwayProvider = class {
|
|
|
20243
20408
|
if (!projectId || !serviceId) {
|
|
20244
20409
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
20245
20410
|
}
|
|
20246
|
-
const remoteDir =
|
|
20411
|
+
const remoteDir = path42.posix.dirname(remotePath);
|
|
20247
20412
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
20248
20413
|
if (options.mode != null) {
|
|
20249
20414
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
@@ -20786,8 +20951,8 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
20786
20951
|
var import_node_dns = require("dns");
|
|
20787
20952
|
var import_node_util4 = require("util");
|
|
20788
20953
|
var import_node_crypto8 = require("crypto");
|
|
20789
|
-
var
|
|
20790
|
-
var
|
|
20954
|
+
var fs34 = __toESM(require("fs"));
|
|
20955
|
+
var path43 = __toESM(require("path"));
|
|
20791
20956
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
20792
20957
|
var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
|
|
20793
20958
|
async function checkDns(apiBase) {
|
|
@@ -20843,13 +21008,13 @@ async function checkHealth(apiBase) {
|
|
|
20843
21008
|
}
|
|
20844
21009
|
}
|
|
20845
21010
|
function checkConfigDir() {
|
|
20846
|
-
const dir =
|
|
21011
|
+
const dir = path43.join(require("os").homedir(), ".codeam");
|
|
20847
21012
|
try {
|
|
20848
|
-
|
|
20849
|
-
const probe =
|
|
20850
|
-
|
|
20851
|
-
const read =
|
|
20852
|
-
|
|
21013
|
+
fs34.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
21014
|
+
const probe = path43.join(dir, ".doctor-probe");
|
|
21015
|
+
fs34.writeFileSync(probe, "ok", { mode: 384 });
|
|
21016
|
+
const read = fs34.readFileSync(probe, "utf8");
|
|
21017
|
+
fs34.unlinkSync(probe);
|
|
20853
21018
|
if (read !== "ok") throw new Error("write/read round-trip mismatch");
|
|
20854
21019
|
return {
|
|
20855
21020
|
id: "config-dir",
|
|
@@ -20889,9 +21054,9 @@ function checkSessions() {
|
|
|
20889
21054
|
}
|
|
20890
21055
|
}
|
|
20891
21056
|
function checkAgentBinaries() {
|
|
20892
|
-
const
|
|
21057
|
+
const os28 = createOsStrategy();
|
|
20893
21058
|
return getEnabledAgents().map((meta) => {
|
|
20894
|
-
const found =
|
|
21059
|
+
const found = os28.findInPath(meta.binaryName);
|
|
20895
21060
|
return {
|
|
20896
21061
|
id: `agent-${meta.id}`,
|
|
20897
21062
|
label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
|
|
@@ -20913,7 +21078,7 @@ function checkNodePty() {
|
|
|
20913
21078
|
detail: "not required on this platform"
|
|
20914
21079
|
};
|
|
20915
21080
|
}
|
|
20916
|
-
const vendoredPath =
|
|
21081
|
+
const vendoredPath = path43.join(__dirname, "vendor", "node-pty");
|
|
20917
21082
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
20918
21083
|
try {
|
|
20919
21084
|
require(target);
|
|
@@ -20955,7 +21120,7 @@ function checkChokidar() {
|
|
|
20955
21120
|
}
|
|
20956
21121
|
async function doctor(args2 = []) {
|
|
20957
21122
|
const json = args2.includes("--json");
|
|
20958
|
-
const cliVersion = true ? "2.27.
|
|
21123
|
+
const cliVersion = true ? "2.27.3" : "0.0.0-dev";
|
|
20959
21124
|
const apiBase = resolveApiBaseUrl();
|
|
20960
21125
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
20961
21126
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -21154,7 +21319,7 @@ async function completion(args2) {
|
|
|
21154
21319
|
// src/commands/version.ts
|
|
21155
21320
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
21156
21321
|
function version2() {
|
|
21157
|
-
const v = true ? "2.27.
|
|
21322
|
+
const v = true ? "2.27.3" : "unknown";
|
|
21158
21323
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
21159
21324
|
}
|
|
21160
21325
|
|
|
@@ -21282,9 +21447,9 @@ function tryShowSubcommandHelp(cmd, args2) {
|
|
|
21282
21447
|
var _subcommandHelpKeys = Object.keys(HELPS);
|
|
21283
21448
|
|
|
21284
21449
|
// src/lib/updateNotifier.ts
|
|
21285
|
-
var
|
|
21286
|
-
var
|
|
21287
|
-
var
|
|
21450
|
+
var fs35 = __toESM(require("fs"));
|
|
21451
|
+
var os27 = __toESM(require("os"));
|
|
21452
|
+
var path44 = __toESM(require("path"));
|
|
21288
21453
|
var https7 = __toESM(require("https"));
|
|
21289
21454
|
var import_picocolors16 = __toESM(require("picocolors"));
|
|
21290
21455
|
var PKG_NAME = "codeam-cli";
|
|
@@ -21292,12 +21457,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
|
21292
21457
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
21293
21458
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
21294
21459
|
function cachePath() {
|
|
21295
|
-
const dir =
|
|
21296
|
-
return
|
|
21460
|
+
const dir = path44.join(os27.homedir(), ".codeam");
|
|
21461
|
+
return path44.join(dir, "update-check.json");
|
|
21297
21462
|
}
|
|
21298
21463
|
function readCache() {
|
|
21299
21464
|
try {
|
|
21300
|
-
const raw =
|
|
21465
|
+
const raw = fs35.readFileSync(cachePath(), "utf8");
|
|
21301
21466
|
const parsed = JSON.parse(raw);
|
|
21302
21467
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
21303
21468
|
return parsed;
|
|
@@ -21308,10 +21473,10 @@ function readCache() {
|
|
|
21308
21473
|
function writeCache(cache) {
|
|
21309
21474
|
try {
|
|
21310
21475
|
const file = cachePath();
|
|
21311
|
-
|
|
21476
|
+
fs35.mkdirSync(path44.dirname(file), { recursive: true });
|
|
21312
21477
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
21313
|
-
|
|
21314
|
-
|
|
21478
|
+
fs35.writeFileSync(tmp, JSON.stringify(cache));
|
|
21479
|
+
fs35.renameSync(tmp, file);
|
|
21315
21480
|
} catch {
|
|
21316
21481
|
}
|
|
21317
21482
|
}
|
|
@@ -21382,7 +21547,7 @@ function checkForUpdates() {
|
|
|
21382
21547
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21383
21548
|
if (process.env.CI) return;
|
|
21384
21549
|
if (!process.stdout.isTTY) return;
|
|
21385
|
-
const current = true ? "2.27.
|
|
21550
|
+
const current = true ? "2.27.3" : null;
|
|
21386
21551
|
if (!current) return;
|
|
21387
21552
|
const cache = readCache();
|
|
21388
21553
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|