codeam-cli 2.16.0 → 2.16.2
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 +411 -232
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,6 +6,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
9
12
|
var __commonJS = (cb, mod) => function __require() {
|
|
10
13
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11
14
|
};
|
|
@@ -30,6 +33,38 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
33
|
mod
|
|
31
34
|
));
|
|
32
35
|
|
|
36
|
+
// src/services/pty/types.ts
|
|
37
|
+
var types_exports = {};
|
|
38
|
+
__export(types_exports, {
|
|
39
|
+
findInPath: () => findInPath
|
|
40
|
+
});
|
|
41
|
+
function findInPath(name) {
|
|
42
|
+
const isWin = process.platform === "win32";
|
|
43
|
+
const dirs = (process.env.PATH ?? "").split(path3.delimiter).filter(Boolean);
|
|
44
|
+
const hasExt = path3.extname(name).length > 0;
|
|
45
|
+
const candidates = isWin && !hasExt ? [`${name}.exe`, `${name}.cmd`, `${name}.bat`, `${name}.ps1`, name] : [name];
|
|
46
|
+
const accessFlag = isWin ? fs3.constants.F_OK : fs3.constants.X_OK;
|
|
47
|
+
for (const dir of dirs) {
|
|
48
|
+
for (const candidate of candidates) {
|
|
49
|
+
const full = path3.join(dir, candidate);
|
|
50
|
+
try {
|
|
51
|
+
fs3.accessSync(full, accessFlag);
|
|
52
|
+
return full;
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
var fs3, path3;
|
|
60
|
+
var init_types = __esm({
|
|
61
|
+
"src/services/pty/types.ts"() {
|
|
62
|
+
"use strict";
|
|
63
|
+
fs3 = __toESM(require("fs"));
|
|
64
|
+
path3 = __toESM(require("path"));
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
33
68
|
// ../../node_modules/sisteransi/src/index.js
|
|
34
69
|
var require_src = __commonJS({
|
|
35
70
|
"../../node_modules/sisteransi/src/index.js"(exports2, module2) {
|
|
@@ -389,7 +424,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
389
424
|
// package.json
|
|
390
425
|
var package_default = {
|
|
391
426
|
name: "codeam-cli",
|
|
392
|
-
version: "2.16.
|
|
427
|
+
version: "2.16.2",
|
|
393
428
|
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.",
|
|
394
429
|
type: "commonjs",
|
|
395
430
|
main: "dist/index.js",
|
|
@@ -676,7 +711,7 @@ async function postLinkCredential(input) {
|
|
|
676
711
|
}
|
|
677
712
|
}
|
|
678
713
|
async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
679
|
-
return new Promise((
|
|
714
|
+
return new Promise((resolve3, reject) => {
|
|
680
715
|
const data = JSON.stringify(body);
|
|
681
716
|
const u2 = new URL(url);
|
|
682
717
|
const transport = u2.protocol === "https:" ? https : http;
|
|
@@ -708,9 +743,9 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
|
708
743
|
return;
|
|
709
744
|
}
|
|
710
745
|
try {
|
|
711
|
-
|
|
746
|
+
resolve3(JSON.parse(responseBody));
|
|
712
747
|
} catch {
|
|
713
|
-
|
|
748
|
+
resolve3(null);
|
|
714
749
|
}
|
|
715
750
|
});
|
|
716
751
|
}
|
|
@@ -725,7 +760,7 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
|
|
|
725
760
|
});
|
|
726
761
|
}
|
|
727
762
|
async function _postJson(url, body) {
|
|
728
|
-
return new Promise((
|
|
763
|
+
return new Promise((resolve3, reject) => {
|
|
729
764
|
const data = JSON.stringify(body);
|
|
730
765
|
const u2 = new URL(url);
|
|
731
766
|
const transport = u2.protocol === "https:" ? https : http;
|
|
@@ -754,9 +789,9 @@ async function _postJson(url, body) {
|
|
|
754
789
|
return;
|
|
755
790
|
}
|
|
756
791
|
try {
|
|
757
|
-
|
|
792
|
+
resolve3(JSON.parse(body2));
|
|
758
793
|
} catch {
|
|
759
|
-
|
|
794
|
+
resolve3(null);
|
|
760
795
|
}
|
|
761
796
|
});
|
|
762
797
|
}
|
|
@@ -771,7 +806,7 @@ async function _postJson(url, body) {
|
|
|
771
806
|
});
|
|
772
807
|
}
|
|
773
808
|
async function _getJson(url) {
|
|
774
|
-
return new Promise((
|
|
809
|
+
return new Promise((resolve3, reject) => {
|
|
775
810
|
const u2 = new URL(url);
|
|
776
811
|
const transport = u2.protocol === "https:" ? https : http;
|
|
777
812
|
const req = transport.request(
|
|
@@ -795,9 +830,9 @@ async function _getJson(url) {
|
|
|
795
830
|
return;
|
|
796
831
|
}
|
|
797
832
|
try {
|
|
798
|
-
|
|
833
|
+
resolve3(JSON.parse(body));
|
|
799
834
|
} catch {
|
|
800
|
-
|
|
835
|
+
resolve3(null);
|
|
801
836
|
}
|
|
802
837
|
});
|
|
803
838
|
}
|
|
@@ -1105,30 +1140,7 @@ var import_child_process2 = require("child_process");
|
|
|
1105
1140
|
var fs4 = __toESM(require("fs"));
|
|
1106
1141
|
var os4 = __toESM(require("os"));
|
|
1107
1142
|
var path4 = __toESM(require("path"));
|
|
1108
|
-
|
|
1109
|
-
// src/services/pty/types.ts
|
|
1110
|
-
var fs3 = __toESM(require("fs"));
|
|
1111
|
-
var path3 = __toESM(require("path"));
|
|
1112
|
-
function findInPath(name) {
|
|
1113
|
-
const isWin = process.platform === "win32";
|
|
1114
|
-
const dirs = (process.env.PATH ?? "").split(path3.delimiter).filter(Boolean);
|
|
1115
|
-
const hasExt = path3.extname(name).length > 0;
|
|
1116
|
-
const candidates = isWin && !hasExt ? [`${name}.exe`, `${name}.cmd`, `${name}.bat`, `${name}.ps1`, name] : [name];
|
|
1117
|
-
const accessFlag = isWin ? fs3.constants.F_OK : fs3.constants.X_OK;
|
|
1118
|
-
for (const dir of dirs) {
|
|
1119
|
-
for (const candidate of candidates) {
|
|
1120
|
-
const full = path3.join(dir, candidate);
|
|
1121
|
-
try {
|
|
1122
|
-
fs3.accessSync(full, accessFlag);
|
|
1123
|
-
return full;
|
|
1124
|
-
} catch {
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
return null;
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
// src/services/pty/unix.strategy.ts
|
|
1143
|
+
init_types();
|
|
1132
1144
|
var PYTHON_PTY_HELPER = `import os,pty,sys,select,signal,struct,fcntl,termios,errno
|
|
1133
1145
|
m,s=pty.openpty()
|
|
1134
1146
|
try:
|
|
@@ -3441,6 +3453,7 @@ ${c2}
|
|
|
3441
3453
|
} }).prompt();
|
|
3442
3454
|
|
|
3443
3455
|
// src/services/claude-installer.ts
|
|
3456
|
+
init_types();
|
|
3444
3457
|
function probeInstallDirs() {
|
|
3445
3458
|
const home = os5.homedir();
|
|
3446
3459
|
if (process.platform === "win32") {
|
|
@@ -3478,15 +3491,15 @@ function runInstaller() {
|
|
|
3478
3491
|
"-Command",
|
|
3479
3492
|
"irm https://claude.ai/install.ps1 | iex"
|
|
3480
3493
|
] : ["-c", "curl -fsSL https://claude.ai/install.sh | bash"];
|
|
3481
|
-
return new Promise((
|
|
3494
|
+
return new Promise((resolve3) => {
|
|
3482
3495
|
const proc = (0, import_child_process4.spawn)(cmd, args2, { stdio: "inherit" });
|
|
3483
3496
|
proc.on("error", (err) => {
|
|
3484
3497
|
console.error(`
|
|
3485
3498
|
\u2717 Installer failed to launch: ${err.message}`);
|
|
3486
|
-
|
|
3499
|
+
resolve3(false);
|
|
3487
3500
|
});
|
|
3488
3501
|
proc.on("exit", (code) => {
|
|
3489
|
-
|
|
3502
|
+
resolve3(code === 0);
|
|
3490
3503
|
});
|
|
3491
3504
|
});
|
|
3492
3505
|
}
|
|
@@ -3520,6 +3533,7 @@ async function ensureClaudeInstalled() {
|
|
|
3520
3533
|
|
|
3521
3534
|
// src/services/claude-resolver.ts
|
|
3522
3535
|
var path7 = __toESM(require("path"));
|
|
3536
|
+
init_types();
|
|
3523
3537
|
function buildClaudeLaunch(extraArgs = []) {
|
|
3524
3538
|
const found = findInPath("claude") ?? findInPath("claude-code");
|
|
3525
3539
|
if (!found) return null;
|
|
@@ -3779,6 +3793,7 @@ var fs5 = __toESM(require("fs"));
|
|
|
3779
3793
|
var os6 = __toESM(require("os"));
|
|
3780
3794
|
var path8 = __toESM(require("path"));
|
|
3781
3795
|
var import_child_process5 = require("child_process");
|
|
3796
|
+
init_types();
|
|
3782
3797
|
var HELPER_SCRIPT = `import os,pty,sys,select,signal,struct,fcntl,termios,errno
|
|
3783
3798
|
m,s=pty.openpty()
|
|
3784
3799
|
try:
|
|
@@ -3834,17 +3849,17 @@ function parseUsageOutput(raw) {
|
|
|
3834
3849
|
return { percent, resetAt };
|
|
3835
3850
|
}
|
|
3836
3851
|
async function fetchClaudeQuota() {
|
|
3837
|
-
return new Promise((
|
|
3852
|
+
return new Promise((resolve3) => {
|
|
3838
3853
|
const claudeCmd = findInPath("claude") ? "claude" : "claude-code";
|
|
3839
3854
|
if (!claudeCmd) {
|
|
3840
|
-
|
|
3855
|
+
resolve3(null);
|
|
3841
3856
|
return;
|
|
3842
3857
|
}
|
|
3843
3858
|
const helperPath = path8.join(os6.tmpdir(), "codeam-quota-helper.py");
|
|
3844
3859
|
fs5.writeFileSync(helperPath, HELPER_SCRIPT, { mode: 420 });
|
|
3845
3860
|
const python = findInPath("python3") ?? findInPath("python");
|
|
3846
3861
|
if (!python) {
|
|
3847
|
-
|
|
3862
|
+
resolve3(null);
|
|
3848
3863
|
return;
|
|
3849
3864
|
}
|
|
3850
3865
|
const proc = (0, import_child_process5.spawn)(python, [helperPath, claudeCmd, "--tools", ""], {
|
|
@@ -3871,13 +3886,13 @@ async function fetchClaudeQuota() {
|
|
|
3871
3886
|
fs5.unlinkSync(helperPath);
|
|
3872
3887
|
} catch {
|
|
3873
3888
|
}
|
|
3874
|
-
|
|
3889
|
+
resolve3(result);
|
|
3875
3890
|
}, 5e3);
|
|
3876
3891
|
}, 8e3);
|
|
3877
3892
|
setTimeout(() => {
|
|
3878
3893
|
if (!resolved) {
|
|
3879
3894
|
resolved = true;
|
|
3880
|
-
|
|
3895
|
+
resolve3(null);
|
|
3881
3896
|
}
|
|
3882
3897
|
try {
|
|
3883
3898
|
proc.kill();
|
|
@@ -4522,6 +4537,7 @@ var ClaudeDeployStrategy = class {
|
|
|
4522
4537
|
|
|
4523
4538
|
// src/agents/codex/runtime.ts
|
|
4524
4539
|
var import_node_child_process = require("child_process");
|
|
4540
|
+
init_types();
|
|
4525
4541
|
|
|
4526
4542
|
// src/agents/codex/history.ts
|
|
4527
4543
|
var import_node_fs2 = __toESM(require("fs"));
|
|
@@ -5116,13 +5132,13 @@ var CodexRuntimeStrategy = class {
|
|
|
5116
5132
|
}
|
|
5117
5133
|
};
|
|
5118
5134
|
async function installCodexViaNpm() {
|
|
5119
|
-
return new Promise((
|
|
5135
|
+
return new Promise((resolve3, reject) => {
|
|
5120
5136
|
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
5121
5137
|
const proc = (0, import_node_child_process.spawn)(npm, ["install", "-g", "@openai/codex"], {
|
|
5122
5138
|
stdio: "inherit"
|
|
5123
5139
|
});
|
|
5124
5140
|
proc.on("close", (code) => {
|
|
5125
|
-
if (code === 0)
|
|
5141
|
+
if (code === 0) resolve3();
|
|
5126
5142
|
else reject(new Error(`npm install -g @openai/codex exited ${code}`));
|
|
5127
5143
|
});
|
|
5128
5144
|
proc.on("error", reject);
|
|
@@ -5321,14 +5337,14 @@ var ChunkEmitter = class {
|
|
|
5321
5337
|
"chunkEmitter",
|
|
5322
5338
|
`send type=${body.type ?? "(clear)"} bytes=${payload.length} done=${body.done === true}`
|
|
5323
5339
|
);
|
|
5324
|
-
return new Promise((
|
|
5340
|
+
return new Promise((resolve3) => {
|
|
5325
5341
|
const attempt = (attemptsLeft) => {
|
|
5326
5342
|
_transport2.post(this.url, this.headers, payload).then(({ statusCode, body: resBody }) => {
|
|
5327
5343
|
const tookMs = Date.now() - t0;
|
|
5328
5344
|
if (statusCode === 410 || statusCode === 404 && /SESSION_NOT_FOUND|SESSION_GONE/.test(resBody)) {
|
|
5329
5345
|
process.stderr.write("[codeam] session was deleted/disconnected \u2014 stopping output stream.\n");
|
|
5330
5346
|
log.info("chunkEmitter", `dead status=${statusCode} took=${tookMs}ms`);
|
|
5331
|
-
|
|
5347
|
+
resolve3({ dead: true });
|
|
5332
5348
|
return;
|
|
5333
5349
|
}
|
|
5334
5350
|
if (statusCode >= 400) {
|
|
@@ -5338,7 +5354,7 @@ var ChunkEmitter = class {
|
|
|
5338
5354
|
} else {
|
|
5339
5355
|
log.info("chunkEmitter", `ok status=${statusCode} took=${tookMs}ms`);
|
|
5340
5356
|
}
|
|
5341
|
-
|
|
5357
|
+
resolve3({ dead: false });
|
|
5342
5358
|
}).catch((err) => {
|
|
5343
5359
|
log.warn(
|
|
5344
5360
|
"chunkEmitter",
|
|
@@ -5349,7 +5365,7 @@ var ChunkEmitter = class {
|
|
|
5349
5365
|
const delay = 200 * (maxRetries - attemptsLeft + 1);
|
|
5350
5366
|
setTimeout(() => attempt(attemptsLeft - 1), delay);
|
|
5351
5367
|
} else {
|
|
5352
|
-
|
|
5368
|
+
resolve3({ dead: false });
|
|
5353
5369
|
}
|
|
5354
5370
|
});
|
|
5355
5371
|
};
|
|
@@ -5361,7 +5377,7 @@ var _transport2 = {
|
|
|
5361
5377
|
post: _post
|
|
5362
5378
|
};
|
|
5363
5379
|
function _post(url, headers, payload) {
|
|
5364
|
-
return new Promise((
|
|
5380
|
+
return new Promise((resolve3, reject) => {
|
|
5365
5381
|
let settled = false;
|
|
5366
5382
|
const u2 = new URL(url);
|
|
5367
5383
|
const transport = u2.protocol === "https:" ? https3 : http3;
|
|
@@ -5385,7 +5401,7 @@ function _post(url, headers, payload) {
|
|
|
5385
5401
|
res.on("end", () => {
|
|
5386
5402
|
if (settled) return;
|
|
5387
5403
|
settled = true;
|
|
5388
|
-
|
|
5404
|
+
resolve3({ statusCode: res.statusCode ?? 0, body: resData });
|
|
5389
5405
|
});
|
|
5390
5406
|
}
|
|
5391
5407
|
);
|
|
@@ -5821,7 +5837,7 @@ function parseJsonl(filePath) {
|
|
|
5821
5837
|
return messages;
|
|
5822
5838
|
}
|
|
5823
5839
|
function post(endpoint, body) {
|
|
5824
|
-
return new Promise((
|
|
5840
|
+
return new Promise((resolve3) => {
|
|
5825
5841
|
const payload = JSON.stringify(body);
|
|
5826
5842
|
const u2 = new URL(`${API_BASE4}${endpoint}`);
|
|
5827
5843
|
const transport = u2.protocol === "https:" ? https4 : http4;
|
|
@@ -5842,17 +5858,17 @@ function post(endpoint, body) {
|
|
|
5842
5858
|
res.resume();
|
|
5843
5859
|
const ok = res.statusCode !== void 0 && res.statusCode >= 200 && res.statusCode < 300;
|
|
5844
5860
|
if (!ok) log.warn("history:post", `${endpoint} \u2192 HTTP ${res.statusCode}`);
|
|
5845
|
-
|
|
5861
|
+
resolve3(ok);
|
|
5846
5862
|
}
|
|
5847
5863
|
);
|
|
5848
5864
|
req.on("error", (err) => {
|
|
5849
5865
|
log.warn("history:post", `${endpoint} network error`, err);
|
|
5850
|
-
|
|
5866
|
+
resolve3(false);
|
|
5851
5867
|
});
|
|
5852
5868
|
req.on("timeout", () => {
|
|
5853
5869
|
log.warn("history:post", `${endpoint} timeout after 15s`);
|
|
5854
5870
|
req.destroy();
|
|
5855
|
-
|
|
5871
|
+
resolve3(false);
|
|
5856
5872
|
});
|
|
5857
5873
|
req.write(payload);
|
|
5858
5874
|
req.end();
|
|
@@ -6246,6 +6262,7 @@ var HistoryService = class _HistoryService {
|
|
|
6246
6262
|
|
|
6247
6263
|
// src/services/file-watcher.service.ts
|
|
6248
6264
|
var import_child_process7 = require("child_process");
|
|
6265
|
+
var os13 = __toESM(require("os"));
|
|
6249
6266
|
var path15 = __toESM(require("path"));
|
|
6250
6267
|
|
|
6251
6268
|
// src/services/file-watcher/diff-parser.ts
|
|
@@ -6334,7 +6351,7 @@ var _transport3 = {
|
|
|
6334
6351
|
post: _post2
|
|
6335
6352
|
};
|
|
6336
6353
|
function _post2(url, headers, payload) {
|
|
6337
|
-
return new Promise((
|
|
6354
|
+
return new Promise((resolve3, reject) => {
|
|
6338
6355
|
let settled = false;
|
|
6339
6356
|
const u2 = new URL(url);
|
|
6340
6357
|
const lib = u2.protocol === "https:" ? https5 : http5;
|
|
@@ -6359,7 +6376,7 @@ function _post2(url, headers, payload) {
|
|
|
6359
6376
|
res.on("end", () => {
|
|
6360
6377
|
if (settled) return;
|
|
6361
6378
|
settled = true;
|
|
6362
|
-
|
|
6379
|
+
resolve3({ statusCode: res.statusCode ?? 0, body });
|
|
6363
6380
|
});
|
|
6364
6381
|
}
|
|
6365
6382
|
);
|
|
@@ -6381,6 +6398,44 @@ var API_BASE5 = process.env.CODEAM_API_URL ?? DEFAULT_API_BASE_URL;
|
|
|
6381
6398
|
var DEBOUNCE_MS = 250;
|
|
6382
6399
|
var MAX_RETRIES = 2;
|
|
6383
6400
|
var RETRY_BACKOFF_MS = 300;
|
|
6401
|
+
var WINDOWS_LEGACY_JUNCTIONS = [
|
|
6402
|
+
/[\\/]Application Data([\\/]|$)/i,
|
|
6403
|
+
/[\\/]Cookies([\\/]|$)/i,
|
|
6404
|
+
/[\\/]Local Settings([\\/]|$)/i,
|
|
6405
|
+
/[\\/]My Documents([\\/]|$)/i,
|
|
6406
|
+
/[\\/]NetHood([\\/]|$)/i,
|
|
6407
|
+
/[\\/]PrintHood([\\/]|$)/i,
|
|
6408
|
+
/[\\/]Recent([\\/]|$)/i,
|
|
6409
|
+
/[\\/]SendTo([\\/]|$)/i,
|
|
6410
|
+
/[\\/]Start Menu([\\/]|$)/i,
|
|
6411
|
+
/[\\/]Templates([\\/]|$)/i
|
|
6412
|
+
];
|
|
6413
|
+
function isUnsafeWindowsWatchRoot(dir, homedir12) {
|
|
6414
|
+
const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
|
|
6415
|
+
const cwd = norm(dir);
|
|
6416
|
+
const home = norm(homedir12);
|
|
6417
|
+
if (cwd === home) return true;
|
|
6418
|
+
if (/^[a-z]:$/.test(cwd)) return true;
|
|
6419
|
+
const sysRoots = [
|
|
6420
|
+
"c:\\windows",
|
|
6421
|
+
"c:\\program files",
|
|
6422
|
+
"c:\\program files (x86)",
|
|
6423
|
+
"c:\\programdata"
|
|
6424
|
+
];
|
|
6425
|
+
for (const root of sysRoots) {
|
|
6426
|
+
if (cwd === root || cwd.startsWith(root + "\\")) return true;
|
|
6427
|
+
}
|
|
6428
|
+
return false;
|
|
6429
|
+
}
|
|
6430
|
+
var _chokidarSeam = {
|
|
6431
|
+
load: () => {
|
|
6432
|
+
try {
|
|
6433
|
+
return require("chokidar");
|
|
6434
|
+
} catch {
|
|
6435
|
+
return null;
|
|
6436
|
+
}
|
|
6437
|
+
}
|
|
6438
|
+
};
|
|
6384
6439
|
var FileWatcherService = class {
|
|
6385
6440
|
constructor(opts) {
|
|
6386
6441
|
this.opts = opts;
|
|
@@ -6403,18 +6458,23 @@ var FileWatcherService = class {
|
|
|
6403
6458
|
if (this.stopped) {
|
|
6404
6459
|
throw new Error("FileWatcherService has already been stopped \u2014 re-instantiate to restart.");
|
|
6405
6460
|
}
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6461
|
+
const isWin = process.platform === "win32";
|
|
6462
|
+
if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os13.homedir())) {
|
|
6463
|
+
log.warn(
|
|
6464
|
+
"fileWatcher",
|
|
6465
|
+
`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.`
|
|
6466
|
+
);
|
|
6467
|
+
return;
|
|
6468
|
+
}
|
|
6469
|
+
const chokidar2 = _chokidarSeam.load();
|
|
6470
|
+
if (!chokidar2) {
|
|
6410
6471
|
log.warn(
|
|
6411
6472
|
"fileWatcher",
|
|
6412
|
-
`chokidar unavailable \u2014 file change emission disabled
|
|
6413
|
-
err
|
|
6473
|
+
`chokidar unavailable \u2014 file change emission disabled`
|
|
6414
6474
|
);
|
|
6415
6475
|
return;
|
|
6416
6476
|
}
|
|
6417
|
-
const watcher =
|
|
6477
|
+
const watcher = chokidar2.watch(this.opts.workingDir, {
|
|
6418
6478
|
ignored: [
|
|
6419
6479
|
/(^|[\\/])\../,
|
|
6420
6480
|
// dot-files & dot-dirs (.git, .next, .expo, .DS_Store, …)
|
|
@@ -6428,11 +6488,22 @@ var FileWatcherService = class {
|
|
|
6428
6488
|
/\.parcel-cache/,
|
|
6429
6489
|
// Build outputs that aren't a typical "dist" target
|
|
6430
6490
|
/target\//,
|
|
6431
|
-
/__pycache__
|
|
6491
|
+
/__pycache__/,
|
|
6492
|
+
// Windows-only: skip legacy user-profile junctions whose ACLs
|
|
6493
|
+
// throw EPERM during chokidar's recursive traversal.
|
|
6494
|
+
...isWin ? WINDOWS_LEGACY_JUNCTIONS : []
|
|
6432
6495
|
],
|
|
6433
6496
|
ignoreInitial: true,
|
|
6434
6497
|
// we only care about post-start changes
|
|
6435
6498
|
persistent: true,
|
|
6499
|
+
// Windows-only safety net: don't follow reparse points, and let
|
|
6500
|
+
// chokidar swallow EPERM/EACCES on unreadable paths instead of
|
|
6501
|
+
// bubbling them up as fatal errors. Both are no-ops on macOS
|
|
6502
|
+
// (fsevents traversal doesn't fail on permission errors).
|
|
6503
|
+
...isWin ? {
|
|
6504
|
+
followSymlinks: false,
|
|
6505
|
+
ignorePermissionErrors: true
|
|
6506
|
+
} : {},
|
|
6436
6507
|
awaitWriteFinish: {
|
|
6437
6508
|
// Coalesces rapid sequential writes (npm install spam, build
|
|
6438
6509
|
// tools emitting bursts). Lower than chokidar's default so
|
|
@@ -6445,6 +6516,13 @@ var FileWatcherService = class {
|
|
|
6445
6516
|
watcher.on("add", (filePath) => this.schedule(filePath, "add"));
|
|
6446
6517
|
watcher.on("change", (filePath) => this.schedule(filePath, "change"));
|
|
6447
6518
|
watcher.on("unlink", (filePath) => this.schedule(filePath, "unlink"));
|
|
6519
|
+
watcher.on("error", (err) => {
|
|
6520
|
+
const code = err?.code ?? "unknown";
|
|
6521
|
+
log.warn(
|
|
6522
|
+
"fileWatcher",
|
|
6523
|
+
`chokidar error (code=${code}) \u2014 watcher continues: ${err}`
|
|
6524
|
+
);
|
|
6525
|
+
});
|
|
6448
6526
|
this.watcher = watcher;
|
|
6449
6527
|
log.info(
|
|
6450
6528
|
"fileWatcher",
|
|
@@ -6667,12 +6745,12 @@ var _gitSeam = {
|
|
|
6667
6745
|
run: _runGitImpl
|
|
6668
6746
|
};
|
|
6669
6747
|
async function _runGitImpl(cwd, args2, opts = {}) {
|
|
6670
|
-
return new Promise((
|
|
6748
|
+
return new Promise((resolve3) => {
|
|
6671
6749
|
let proc;
|
|
6672
6750
|
try {
|
|
6673
6751
|
proc = (0, import_child_process7.spawn)("git", args2, { cwd, env: process.env });
|
|
6674
6752
|
} catch {
|
|
6675
|
-
|
|
6753
|
+
resolve3(null);
|
|
6676
6754
|
return;
|
|
6677
6755
|
}
|
|
6678
6756
|
let stdout = "";
|
|
@@ -6683,13 +6761,13 @@ async function _runGitImpl(cwd, args2, opts = {}) {
|
|
|
6683
6761
|
proc.stderr?.on("data", (c2) => {
|
|
6684
6762
|
stderr += c2.toString();
|
|
6685
6763
|
});
|
|
6686
|
-
proc.on("error", () =>
|
|
6764
|
+
proc.on("error", () => resolve3(null));
|
|
6687
6765
|
proc.on("close", (code) => {
|
|
6688
6766
|
if (code === 0 || opts.allowNonZeroExit) {
|
|
6689
|
-
|
|
6767
|
+
resolve3(stdout);
|
|
6690
6768
|
} else {
|
|
6691
6769
|
log.trace("fileWatcher", `git ${args2.join(" ")} exited ${code} stderr=${stderr.slice(0, 200)}`);
|
|
6692
|
-
|
|
6770
|
+
resolve3(null);
|
|
6693
6771
|
}
|
|
6694
6772
|
});
|
|
6695
6773
|
});
|
|
@@ -6709,7 +6787,7 @@ var _transport4 = {
|
|
|
6709
6787
|
get: _get
|
|
6710
6788
|
};
|
|
6711
6789
|
function _post3(url, headers, payload) {
|
|
6712
|
-
return new Promise((
|
|
6790
|
+
return new Promise((resolve3, reject) => {
|
|
6713
6791
|
let settled = false;
|
|
6714
6792
|
const u2 = new URL(url);
|
|
6715
6793
|
const lib = u2.protocol === "https:" ? https6 : http6;
|
|
@@ -6734,7 +6812,7 @@ function _post3(url, headers, payload) {
|
|
|
6734
6812
|
res.on("end", () => {
|
|
6735
6813
|
if (settled) return;
|
|
6736
6814
|
settled = true;
|
|
6737
|
-
|
|
6815
|
+
resolve3({ statusCode: res.statusCode ?? 0, body });
|
|
6738
6816
|
});
|
|
6739
6817
|
}
|
|
6740
6818
|
);
|
|
@@ -6751,7 +6829,7 @@ function _post3(url, headers, payload) {
|
|
|
6751
6829
|
});
|
|
6752
6830
|
}
|
|
6753
6831
|
function _get(url, headers) {
|
|
6754
|
-
return new Promise((
|
|
6832
|
+
return new Promise((resolve3, reject) => {
|
|
6755
6833
|
let settled = false;
|
|
6756
6834
|
const u2 = new URL(url);
|
|
6757
6835
|
const lib = u2.protocol === "https:" ? https6 : http6;
|
|
@@ -6775,7 +6853,7 @@ function _get(url, headers) {
|
|
|
6775
6853
|
res.on("end", () => {
|
|
6776
6854
|
if (settled) return;
|
|
6777
6855
|
settled = true;
|
|
6778
|
-
|
|
6856
|
+
resolve3({ statusCode: res.statusCode ?? 0, body });
|
|
6779
6857
|
});
|
|
6780
6858
|
}
|
|
6781
6859
|
);
|
|
@@ -7144,7 +7222,7 @@ function buildKeepAlive(ctx) {
|
|
|
7144
7222
|
let timer = null;
|
|
7145
7223
|
async function setIdleTimeout(minutes) {
|
|
7146
7224
|
if (!ctx.inCodespace || !ctx.codespaceName) return;
|
|
7147
|
-
await new Promise((
|
|
7225
|
+
await new Promise((resolve3) => {
|
|
7148
7226
|
const proc = (0, import_child_process8.spawn)(
|
|
7149
7227
|
"gh",
|
|
7150
7228
|
[
|
|
@@ -7158,8 +7236,8 @@ function buildKeepAlive(ctx) {
|
|
|
7158
7236
|
{ stdio: "ignore", detached: true }
|
|
7159
7237
|
);
|
|
7160
7238
|
proc.unref();
|
|
7161
|
-
proc.on("exit", () =>
|
|
7162
|
-
proc.on("error", () =>
|
|
7239
|
+
proc.on("exit", () => resolve3());
|
|
7240
|
+
proc.on("error", () => resolve3());
|
|
7163
7241
|
});
|
|
7164
7242
|
}
|
|
7165
7243
|
return {
|
|
@@ -7183,7 +7261,7 @@ function buildKeepAlive(ctx) {
|
|
|
7183
7261
|
|
|
7184
7262
|
// src/commands/start/handlers.ts
|
|
7185
7263
|
var fs14 = __toESM(require("fs"));
|
|
7186
|
-
var
|
|
7264
|
+
var os14 = __toESM(require("os"));
|
|
7187
7265
|
var path19 = __toESM(require("path"));
|
|
7188
7266
|
var import_crypto3 = require("crypto");
|
|
7189
7267
|
var import_child_process11 = require("child_process");
|
|
@@ -7991,7 +8069,7 @@ function closeTerminal(sessionId) {
|
|
|
7991
8069
|
function saveFilesTemp(files) {
|
|
7992
8070
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
7993
8071
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
7994
|
-
const tmpPath = path19.join(
|
|
8072
|
+
const tmpPath = path19.join(os14.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
|
|
7995
8073
|
fs14.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
7996
8074
|
return tmpPath;
|
|
7997
8075
|
});
|
|
@@ -8537,7 +8615,7 @@ async function pair(args2 = []) {
|
|
|
8537
8615
|
waitSpin.message(waitMessage());
|
|
8538
8616
|
}, 1e3);
|
|
8539
8617
|
countdownInterval.unref?.();
|
|
8540
|
-
await new Promise((
|
|
8618
|
+
await new Promise((resolve3) => {
|
|
8541
8619
|
let stopPolling = null;
|
|
8542
8620
|
function sigintHandler() {
|
|
8543
8621
|
clearInterval(countdownInterval);
|
|
@@ -8564,7 +8642,7 @@ async function pair(args2 = []) {
|
|
|
8564
8642
|
saveCliConfig({ ...loadCliConfig(), preferredAgent: agentId });
|
|
8565
8643
|
showSuccess(`Paired with ${info.userName} (${info.plan})`);
|
|
8566
8644
|
console.log("");
|
|
8567
|
-
|
|
8645
|
+
resolve3();
|
|
8568
8646
|
},
|
|
8569
8647
|
() => {
|
|
8570
8648
|
clearInterval(countdownInterval);
|
|
@@ -8580,7 +8658,7 @@ async function pair(args2 = []) {
|
|
|
8580
8658
|
|
|
8581
8659
|
// src/commands/pair-auto.ts
|
|
8582
8660
|
var fs15 = __toESM(require("fs"));
|
|
8583
|
-
var
|
|
8661
|
+
var os15 = __toESM(require("os"));
|
|
8584
8662
|
var import_crypto5 = require("crypto");
|
|
8585
8663
|
var API_BASE7 = process.env.CODEAM_API_URL ?? DEFAULT_API_BASE_URL;
|
|
8586
8664
|
function fail(msg) {
|
|
@@ -8597,12 +8675,12 @@ function readTokenFromArgs(args2) {
|
|
|
8597
8675
|
}
|
|
8598
8676
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
8599
8677
|
if (fileFlag) {
|
|
8600
|
-
const
|
|
8678
|
+
const path28 = fileFlag.slice("--token-file=".length);
|
|
8601
8679
|
try {
|
|
8602
|
-
const content = fs15.readFileSync(
|
|
8603
|
-
if (content.length === 0) fail(`--token-file ${
|
|
8680
|
+
const content = fs15.readFileSync(path28, "utf8").trim();
|
|
8681
|
+
if (content.length === 0) fail(`--token-file ${path28} is empty`);
|
|
8604
8682
|
try {
|
|
8605
|
-
fs15.unlinkSync(
|
|
8683
|
+
fs15.unlinkSync(path28);
|
|
8606
8684
|
} catch {
|
|
8607
8685
|
}
|
|
8608
8686
|
return content;
|
|
@@ -8620,7 +8698,7 @@ async function claim(token, pluginId) {
|
|
|
8620
8698
|
pluginId,
|
|
8621
8699
|
ideName: "codeam-cli (codespace)",
|
|
8622
8700
|
ideVersion: process.env.npm_package_version ?? "unknown",
|
|
8623
|
-
hostname:
|
|
8701
|
+
hostname: os15.hostname(),
|
|
8624
8702
|
codespaceName: process.env.CODESPACE_NAME ?? "",
|
|
8625
8703
|
// Current git branch of the codespace's working directory, so the
|
|
8626
8704
|
// backend can populate `PairedSession.branch` for the codespace pair.
|
|
@@ -8820,12 +8898,12 @@ var GitHubCodespacesProvider = class {
|
|
|
8820
8898
|
}
|
|
8821
8899
|
if (!isAuthed) {
|
|
8822
8900
|
resetStdinForChild();
|
|
8823
|
-
await new Promise((
|
|
8901
|
+
await new Promise((resolve3, reject) => {
|
|
8824
8902
|
const proc = (0, import_child_process12.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
|
|
8825
8903
|
stdio: "inherit"
|
|
8826
8904
|
});
|
|
8827
8905
|
proc.on("exit", (code) => {
|
|
8828
|
-
if (code === 0)
|
|
8906
|
+
if (code === 0) resolve3();
|
|
8829
8907
|
else reject(new Error("gh auth login failed."));
|
|
8830
8908
|
});
|
|
8831
8909
|
proc.on("error", reject);
|
|
@@ -8854,13 +8932,13 @@ var GitHubCodespacesProvider = class {
|
|
|
8854
8932
|
}
|
|
8855
8933
|
wt(noteLines.join("\n"), "One more permission needed");
|
|
8856
8934
|
resetStdinForChild();
|
|
8857
|
-
const refreshCode = await new Promise((
|
|
8935
|
+
const refreshCode = await new Promise((resolve3, reject) => {
|
|
8858
8936
|
const proc = (0, import_child_process12.spawn)(
|
|
8859
8937
|
"gh",
|
|
8860
8938
|
["auth", "refresh", "-h", "github.com", "-s", "codespace"],
|
|
8861
8939
|
{ stdio: "inherit" }
|
|
8862
8940
|
);
|
|
8863
|
-
proc.on("exit", (code) =>
|
|
8941
|
+
proc.on("exit", (code) => resolve3(code ?? 1));
|
|
8864
8942
|
proc.on("error", reject);
|
|
8865
8943
|
});
|
|
8866
8944
|
if (refreshCode !== 0) {
|
|
@@ -9004,10 +9082,10 @@ var GitHubCodespacesProvider = class {
|
|
|
9004
9082
|
if (q(proceed) || !proceed) return;
|
|
9005
9083
|
O2.step(`Installing gh via ${installCmd.describe}\u2026`);
|
|
9006
9084
|
resetStdinForChild();
|
|
9007
|
-
const ok = await new Promise((
|
|
9085
|
+
const ok = await new Promise((resolve3) => {
|
|
9008
9086
|
const proc = (0, import_child_process12.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
|
|
9009
|
-
proc.on("exit", (code) =>
|
|
9010
|
-
proc.on("error", () =>
|
|
9087
|
+
proc.on("exit", (code) => resolve3(code === 0));
|
|
9088
|
+
proc.on("error", () => resolve3(false));
|
|
9011
9089
|
});
|
|
9012
9090
|
if (ok) O2.success("gh installed");
|
|
9013
9091
|
else O2.error("gh install failed");
|
|
@@ -9031,14 +9109,14 @@ var GitHubCodespacesProvider = class {
|
|
|
9031
9109
|
"Expanding GitHub scopes"
|
|
9032
9110
|
);
|
|
9033
9111
|
resetStdinForChild();
|
|
9034
|
-
await new Promise((
|
|
9112
|
+
await new Promise((resolve3, reject) => {
|
|
9035
9113
|
const proc = (0, import_child_process12.spawn)(
|
|
9036
9114
|
"gh",
|
|
9037
9115
|
["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
|
|
9038
9116
|
{ stdio: "inherit" }
|
|
9039
9117
|
);
|
|
9040
9118
|
proc.on("exit", (code) => {
|
|
9041
|
-
if (code === 0)
|
|
9119
|
+
if (code === 0) resolve3();
|
|
9042
9120
|
else reject(new Error(
|
|
9043
9121
|
"gh auth refresh failed. Re-run `gh auth refresh -h github.com -s repo,read:org` manually."
|
|
9044
9122
|
));
|
|
@@ -9209,13 +9287,13 @@ var GitHubCodespacesProvider = class {
|
|
|
9209
9287
|
}
|
|
9210
9288
|
async streamCommand(workspaceId, command2) {
|
|
9211
9289
|
resetStdinForChild();
|
|
9212
|
-
return new Promise((
|
|
9290
|
+
return new Promise((resolve3, reject) => {
|
|
9213
9291
|
const proc = (0, import_child_process12.spawn)(
|
|
9214
9292
|
"gh",
|
|
9215
9293
|
["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
|
|
9216
9294
|
{ stdio: "inherit" }
|
|
9217
9295
|
);
|
|
9218
|
-
proc.on("exit", (code) =>
|
|
9296
|
+
proc.on("exit", (code) => resolve3({ code: code ?? 0 }));
|
|
9219
9297
|
proc.on("error", reject);
|
|
9220
9298
|
});
|
|
9221
9299
|
}
|
|
@@ -9236,7 +9314,7 @@ var GitHubCodespacesProvider = class {
|
|
|
9236
9314
|
"--",
|
|
9237
9315
|
`mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
|
|
9238
9316
|
];
|
|
9239
|
-
await new Promise((
|
|
9317
|
+
await new Promise((resolve3, reject) => {
|
|
9240
9318
|
const tar = (0, import_child_process12.spawn)("tar", tarArgs, {
|
|
9241
9319
|
stdio: ["ignore", "pipe", "pipe"],
|
|
9242
9320
|
env: tarEnv
|
|
@@ -9256,7 +9334,7 @@ var GitHubCodespacesProvider = class {
|
|
|
9256
9334
|
ssh.on("error", reject);
|
|
9257
9335
|
ssh.on("exit", (code) => {
|
|
9258
9336
|
if (code === 0) {
|
|
9259
|
-
|
|
9337
|
+
resolve3();
|
|
9260
9338
|
} else {
|
|
9261
9339
|
const reason = (sshErr || tarErr || `exit ${code}`).trim().slice(0, 500);
|
|
9262
9340
|
reject(new Error(`Remote tar failed: ${reason}`));
|
|
@@ -9274,7 +9352,7 @@ var GitHubCodespacesProvider = class {
|
|
|
9274
9352
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote(remotePath)}`);
|
|
9275
9353
|
}
|
|
9276
9354
|
const cmd = parts.join(" && ");
|
|
9277
|
-
await new Promise((
|
|
9355
|
+
await new Promise((resolve3, reject) => {
|
|
9278
9356
|
const proc = (0, import_child_process12.spawn)(
|
|
9279
9357
|
"gh",
|
|
9280
9358
|
["codespace", "ssh", "-c", workspaceId, "--", cmd],
|
|
@@ -9286,7 +9364,7 @@ var GitHubCodespacesProvider = class {
|
|
|
9286
9364
|
});
|
|
9287
9365
|
proc.on("error", reject);
|
|
9288
9366
|
proc.on("exit", (code) => {
|
|
9289
|
-
if (code === 0)
|
|
9367
|
+
if (code === 0) resolve3();
|
|
9290
9368
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
9291
9369
|
});
|
|
9292
9370
|
proc.stdin?.write(contents);
|
|
@@ -9376,10 +9454,10 @@ var GitpodProvider = class {
|
|
|
9376
9454
|
"Authenticating Gitpod"
|
|
9377
9455
|
);
|
|
9378
9456
|
resetStdinForChild2();
|
|
9379
|
-
await new Promise((
|
|
9457
|
+
await new Promise((resolve3, reject) => {
|
|
9380
9458
|
const proc = (0, import_child_process13.spawn)("gitpod", ["login"], { stdio: "inherit" });
|
|
9381
9459
|
proc.on("exit", (code) => {
|
|
9382
|
-
if (code === 0)
|
|
9460
|
+
if (code === 0) resolve3();
|
|
9383
9461
|
else reject(new Error("gitpod login failed."));
|
|
9384
9462
|
});
|
|
9385
9463
|
proc.on("error", reject);
|
|
@@ -9528,13 +9606,13 @@ var GitpodProvider = class {
|
|
|
9528
9606
|
}
|
|
9529
9607
|
async streamCommand(workspaceId, command2) {
|
|
9530
9608
|
resetStdinForChild2();
|
|
9531
|
-
return new Promise((
|
|
9609
|
+
return new Promise((resolve3, reject) => {
|
|
9532
9610
|
const proc = (0, import_child_process13.spawn)(
|
|
9533
9611
|
"gitpod",
|
|
9534
9612
|
["workspace", "ssh", workspaceId, "--", "-tt", command2],
|
|
9535
9613
|
{ stdio: "inherit" }
|
|
9536
9614
|
);
|
|
9537
|
-
proc.on("exit", (code) =>
|
|
9615
|
+
proc.on("exit", (code) => resolve3({ code: code ?? 0 }));
|
|
9538
9616
|
proc.on("error", reject);
|
|
9539
9617
|
});
|
|
9540
9618
|
}
|
|
@@ -9548,7 +9626,7 @@ var GitpodProvider = class {
|
|
|
9548
9626
|
tarArgs.push(".");
|
|
9549
9627
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
9550
9628
|
const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
|
|
9551
|
-
await new Promise((
|
|
9629
|
+
await new Promise((resolve3, reject) => {
|
|
9552
9630
|
const tar = (0, import_child_process13.spawn)("tar", tarArgs, {
|
|
9553
9631
|
stdio: ["ignore", "pipe", "pipe"],
|
|
9554
9632
|
env: tarEnv
|
|
@@ -9569,7 +9647,7 @@ var GitpodProvider = class {
|
|
|
9569
9647
|
tar.on("error", reject);
|
|
9570
9648
|
ssh.on("error", reject);
|
|
9571
9649
|
ssh.on("exit", (code) => {
|
|
9572
|
-
if (code === 0)
|
|
9650
|
+
if (code === 0) resolve3();
|
|
9573
9651
|
else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
9574
9652
|
});
|
|
9575
9653
|
});
|
|
@@ -9584,7 +9662,7 @@ var GitpodProvider = class {
|
|
|
9584
9662
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote2(remotePath)}`);
|
|
9585
9663
|
}
|
|
9586
9664
|
const cmd = parts.join(" && ");
|
|
9587
|
-
await new Promise((
|
|
9665
|
+
await new Promise((resolve3, reject) => {
|
|
9588
9666
|
const proc = (0, import_child_process13.spawn)(
|
|
9589
9667
|
"gitpod",
|
|
9590
9668
|
["workspace", "ssh", workspaceId, "--", cmd],
|
|
@@ -9596,7 +9674,7 @@ var GitpodProvider = class {
|
|
|
9596
9674
|
});
|
|
9597
9675
|
proc.on("error", reject);
|
|
9598
9676
|
proc.on("exit", (code) => {
|
|
9599
|
-
if (code === 0)
|
|
9677
|
+
if (code === 0) resolve3();
|
|
9600
9678
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
9601
9679
|
});
|
|
9602
9680
|
proc.stdin?.write(contents);
|
|
@@ -9653,14 +9731,14 @@ var GitLabWorkspacesProvider = class {
|
|
|
9653
9731
|
"Authenticating GitLab"
|
|
9654
9732
|
);
|
|
9655
9733
|
resetStdinForChild3();
|
|
9656
|
-
await new Promise((
|
|
9734
|
+
await new Promise((resolve3, reject) => {
|
|
9657
9735
|
const proc = (0, import_child_process14.spawn)(
|
|
9658
9736
|
"glab",
|
|
9659
9737
|
["auth", "login", "--scopes", "api,read_user,read_repository"],
|
|
9660
9738
|
{ stdio: "inherit" }
|
|
9661
9739
|
);
|
|
9662
9740
|
proc.on("exit", (code) => {
|
|
9663
|
-
if (code === 0)
|
|
9741
|
+
if (code === 0) resolve3();
|
|
9664
9742
|
else reject(new Error("glab auth login failed."));
|
|
9665
9743
|
});
|
|
9666
9744
|
proc.on("error", reject);
|
|
@@ -9825,13 +9903,13 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
9825
9903
|
async streamCommand(workspaceId, command2) {
|
|
9826
9904
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
9827
9905
|
resetStdinForChild3();
|
|
9828
|
-
return new Promise((
|
|
9906
|
+
return new Promise((resolve3, reject) => {
|
|
9829
9907
|
const proc = (0, import_child_process14.spawn)(
|
|
9830
9908
|
"ssh",
|
|
9831
9909
|
["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
|
|
9832
9910
|
{ stdio: "inherit" }
|
|
9833
9911
|
);
|
|
9834
|
-
proc.on("exit", (code) =>
|
|
9912
|
+
proc.on("exit", (code) => resolve3({ code: code ?? 0 }));
|
|
9835
9913
|
proc.on("error", reject);
|
|
9836
9914
|
});
|
|
9837
9915
|
}
|
|
@@ -9846,7 +9924,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
9846
9924
|
tarArgs.push(".");
|
|
9847
9925
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
9848
9926
|
const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
|
|
9849
|
-
await new Promise((
|
|
9927
|
+
await new Promise((resolve3, reject) => {
|
|
9850
9928
|
const tar = (0, import_child_process14.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
|
|
9851
9929
|
const ssh = (0, import_child_process14.spawn)(
|
|
9852
9930
|
"ssh",
|
|
@@ -9864,7 +9942,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
9864
9942
|
tar.on("error", reject);
|
|
9865
9943
|
ssh.on("error", reject);
|
|
9866
9944
|
ssh.on("exit", (code) => {
|
|
9867
|
-
if (code === 0)
|
|
9945
|
+
if (code === 0) resolve3();
|
|
9868
9946
|
else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
9869
9947
|
});
|
|
9870
9948
|
});
|
|
@@ -9877,7 +9955,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
9877
9955
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
9878
9956
|
}
|
|
9879
9957
|
const cmd = parts.join(" && ");
|
|
9880
|
-
await new Promise((
|
|
9958
|
+
await new Promise((resolve3, reject) => {
|
|
9881
9959
|
const proc = (0, import_child_process14.spawn)(
|
|
9882
9960
|
"ssh",
|
|
9883
9961
|
["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
|
|
@@ -9889,7 +9967,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
9889
9967
|
});
|
|
9890
9968
|
proc.on("error", reject);
|
|
9891
9969
|
proc.on("exit", (code) => {
|
|
9892
|
-
if (code === 0)
|
|
9970
|
+
if (code === 0) resolve3();
|
|
9893
9971
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
9894
9972
|
});
|
|
9895
9973
|
proc.stdin?.write(contents);
|
|
@@ -9980,10 +10058,10 @@ var RailwayProvider = class {
|
|
|
9980
10058
|
"Authenticating Railway"
|
|
9981
10059
|
);
|
|
9982
10060
|
resetStdinForChild4();
|
|
9983
|
-
await new Promise((
|
|
10061
|
+
await new Promise((resolve3, reject) => {
|
|
9984
10062
|
const proc = (0, import_child_process15.spawn)("railway", ["login"], { stdio: "inherit" });
|
|
9985
10063
|
proc.on("exit", (code) => {
|
|
9986
|
-
if (code === 0)
|
|
10064
|
+
if (code === 0) resolve3();
|
|
9987
10065
|
else reject(new Error("railway login failed."));
|
|
9988
10066
|
});
|
|
9989
10067
|
proc.on("error", reject);
|
|
@@ -10123,13 +10201,13 @@ var RailwayProvider = class {
|
|
|
10123
10201
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
10124
10202
|
}
|
|
10125
10203
|
resetStdinForChild4();
|
|
10126
|
-
return new Promise((
|
|
10204
|
+
return new Promise((resolve3, reject) => {
|
|
10127
10205
|
const proc = (0, import_child_process15.spawn)(
|
|
10128
10206
|
"railway",
|
|
10129
10207
|
["shell", "--project", projectId, "--service", serviceId, "--command", command2],
|
|
10130
10208
|
{ stdio: "inherit" }
|
|
10131
10209
|
);
|
|
10132
|
-
proc.on("exit", (code) =>
|
|
10210
|
+
proc.on("exit", (code) => resolve3({ code: code ?? 0 }));
|
|
10133
10211
|
proc.on("error", reject);
|
|
10134
10212
|
});
|
|
10135
10213
|
}
|
|
@@ -10147,7 +10225,7 @@ var RailwayProvider = class {
|
|
|
10147
10225
|
tarArgs.push(".");
|
|
10148
10226
|
const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
|
|
10149
10227
|
const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
|
|
10150
|
-
await new Promise((
|
|
10228
|
+
await new Promise((resolve3, reject) => {
|
|
10151
10229
|
const tar = (0, import_child_process15.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
|
|
10152
10230
|
const sh = (0, import_child_process15.spawn)(
|
|
10153
10231
|
"railway",
|
|
@@ -10165,7 +10243,7 @@ var RailwayProvider = class {
|
|
|
10165
10243
|
tar.on("error", reject);
|
|
10166
10244
|
sh.on("error", reject);
|
|
10167
10245
|
sh.on("exit", (code) => {
|
|
10168
|
-
if (code === 0)
|
|
10246
|
+
if (code === 0) resolve3();
|
|
10169
10247
|
else reject(new Error(`Remote tar failed: ${(shErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
10170
10248
|
});
|
|
10171
10249
|
});
|
|
@@ -10181,7 +10259,7 @@ var RailwayProvider = class {
|
|
|
10181
10259
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
10182
10260
|
}
|
|
10183
10261
|
const cmd = parts.join(" && ");
|
|
10184
|
-
await new Promise((
|
|
10262
|
+
await new Promise((resolve3, reject) => {
|
|
10185
10263
|
const proc = (0, import_child_process15.spawn)(
|
|
10186
10264
|
"railway",
|
|
10187
10265
|
["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
|
|
@@ -10193,7 +10271,7 @@ var RailwayProvider = class {
|
|
|
10193
10271
|
});
|
|
10194
10272
|
proc.on("error", reject);
|
|
10195
10273
|
proc.on("exit", (code) => {
|
|
10196
|
-
if (code === 0)
|
|
10274
|
+
if (code === 0) resolve3();
|
|
10197
10275
|
else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
|
|
10198
10276
|
});
|
|
10199
10277
|
proc.stdin?.write(contents);
|
|
@@ -10717,57 +10795,64 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
10717
10795
|
// src/commands/link.ts
|
|
10718
10796
|
var import_node_child_process3 = require("child_process");
|
|
10719
10797
|
var import_node_crypto = require("crypto");
|
|
10798
|
+
var fs18 = __toESM(require("fs"));
|
|
10799
|
+
var path26 = __toESM(require("path"));
|
|
10800
|
+
var import_chokidar = __toESM(require("chokidar"));
|
|
10720
10801
|
var import_picocolors11 = __toESM(require("picocolors"));
|
|
10721
10802
|
|
|
10722
10803
|
// src/agents/claude/local-token.ts
|
|
10723
10804
|
var import_node_child_process2 = require("child_process");
|
|
10724
10805
|
var fs16 = __toESM(require("fs"));
|
|
10725
|
-
var
|
|
10806
|
+
var os16 = __toESM(require("os"));
|
|
10726
10807
|
var path24 = __toESM(require("path"));
|
|
10727
10808
|
var import_node_util3 = require("util");
|
|
10728
10809
|
var execFileP7 = (0, import_node_util3.promisify)(import_node_child_process2.execFile);
|
|
10729
|
-
|
|
10730
|
-
|
|
10810
|
+
var KEYCHAIN_SERVICE_NAMES = [
|
|
10811
|
+
"Claude Code-credentials",
|
|
10812
|
+
"claude-code-credentials",
|
|
10813
|
+
"Claude",
|
|
10814
|
+
"Anthropic Claude"
|
|
10815
|
+
];
|
|
10816
|
+
function claudeCredentialsPaths() {
|
|
10817
|
+
const home = os16.homedir();
|
|
10818
|
+
return [
|
|
10819
|
+
path24.join(home, ".claude", ".credentials.json"),
|
|
10820
|
+
path24.join(home, ".config", "claude", ".credentials.json")
|
|
10821
|
+
];
|
|
10731
10822
|
}
|
|
10732
10823
|
async function extractLocalClaudeToken() {
|
|
10733
|
-
const flat
|
|
10734
|
-
|
|
10824
|
+
for (const flat of claudeCredentialsPaths()) {
|
|
10825
|
+
if (!fs16.existsSync(flat)) continue;
|
|
10735
10826
|
const credential = fs16.readFileSync(flat, "utf8").trim();
|
|
10736
10827
|
if (credential.length > 0) {
|
|
10737
10828
|
return { method: "oauth", credential, source: "flat-file" };
|
|
10738
10829
|
}
|
|
10739
10830
|
}
|
|
10740
10831
|
if (process.platform === "darwin") {
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10832
|
+
for (const service of KEYCHAIN_SERVICE_NAMES) {
|
|
10833
|
+
try {
|
|
10834
|
+
const { stdout } = await execFileP7(
|
|
10835
|
+
"security",
|
|
10836
|
+
["find-generic-password", "-s", service, "-w"],
|
|
10837
|
+
{ maxBuffer: 1024 * 1024 }
|
|
10838
|
+
);
|
|
10839
|
+
const credential = stdout.trim();
|
|
10840
|
+
if (credential.length > 0) {
|
|
10841
|
+
return { method: "oauth", credential, source: "macos-keychain" };
|
|
10842
|
+
}
|
|
10843
|
+
} catch {
|
|
10750
10844
|
}
|
|
10751
|
-
} catch {
|
|
10752
10845
|
}
|
|
10753
10846
|
}
|
|
10754
10847
|
return null;
|
|
10755
10848
|
}
|
|
10756
|
-
function claudeCredentialsMtime() {
|
|
10757
|
-
const flat = claudeCredentialsPath();
|
|
10758
|
-
try {
|
|
10759
|
-
return fs16.statSync(flat).mtimeMs;
|
|
10760
|
-
} catch {
|
|
10761
|
-
return null;
|
|
10762
|
-
}
|
|
10763
|
-
}
|
|
10764
10849
|
|
|
10765
10850
|
// src/agents/codex/local-token.ts
|
|
10766
10851
|
var fs17 = __toESM(require("fs"));
|
|
10767
|
-
var
|
|
10852
|
+
var os17 = __toESM(require("os"));
|
|
10768
10853
|
var path25 = __toESM(require("path"));
|
|
10769
10854
|
function codexCredentialsPath() {
|
|
10770
|
-
return path25.join(
|
|
10855
|
+
return path25.join(os17.homedir(), ".codex", "auth.json");
|
|
10771
10856
|
}
|
|
10772
10857
|
async function extractLocalCodexToken() {
|
|
10773
10858
|
const file = codexCredentialsPath();
|
|
@@ -10776,13 +10861,8 @@ async function extractLocalCodexToken() {
|
|
|
10776
10861
|
if (credential.length === 0) return null;
|
|
10777
10862
|
return { method: "oauth", credential, source: "flat-file" };
|
|
10778
10863
|
}
|
|
10779
|
-
function
|
|
10780
|
-
|
|
10781
|
-
try {
|
|
10782
|
-
return fs17.statSync(file).mtimeMs;
|
|
10783
|
-
} catch {
|
|
10784
|
-
return null;
|
|
10785
|
-
}
|
|
10864
|
+
function codexCredentialsPaths() {
|
|
10865
|
+
return [codexCredentialsPath()];
|
|
10786
10866
|
}
|
|
10787
10867
|
|
|
10788
10868
|
// src/commands/link.ts
|
|
@@ -10791,23 +10871,38 @@ var AGENT_META = {
|
|
|
10791
10871
|
internalId: "claude",
|
|
10792
10872
|
publicId: "claude_code",
|
|
10793
10873
|
binary: "claude",
|
|
10794
|
-
loginArgs: ["login"],
|
|
10795
10874
|
displayName: "Claude Code",
|
|
10796
10875
|
vendor: "Anthropic",
|
|
10797
|
-
credentialsHint: "~/.claude/.credentials.json
|
|
10876
|
+
credentialsHint: "~/.claude/.credentials.json or the macOS Keychain",
|
|
10877
|
+
watchPaths: claudeCredentialsPaths,
|
|
10798
10878
|
extract: extractLocalClaudeToken,
|
|
10799
|
-
|
|
10879
|
+
ensureInstalled: ensureClaudeInstalled,
|
|
10880
|
+
launchLogin: () => {
|
|
10881
|
+
const child = (0, import_node_child_process3.spawn)("claude", [], { stdio: ["pipe", "inherit", "inherit"] });
|
|
10882
|
+
child.stdin?.write("/login\n");
|
|
10883
|
+
return child;
|
|
10884
|
+
}
|
|
10800
10885
|
},
|
|
10801
10886
|
codex: {
|
|
10802
10887
|
internalId: "codex",
|
|
10803
10888
|
publicId: "codex",
|
|
10804
10889
|
binary: "codex",
|
|
10805
|
-
loginArgs: ["login"],
|
|
10806
10890
|
displayName: "Codex",
|
|
10807
10891
|
vendor: "OpenAI",
|
|
10808
10892
|
credentialsHint: "~/.codex/auth.json",
|
|
10893
|
+
watchPaths: codexCredentialsPaths,
|
|
10809
10894
|
extract: extractLocalCodexToken,
|
|
10810
|
-
|
|
10895
|
+
ensureInstalled: async () => {
|
|
10896
|
+
const { findInPath: findInPath2 } = await Promise.resolve().then(() => (init_types(), types_exports));
|
|
10897
|
+
if (findInPath2("codex")) return true;
|
|
10898
|
+
showError(
|
|
10899
|
+
"codex binary not found on PATH. Install it first (https://github.com/openai/codex-cli) then re-run `codeam link codex`."
|
|
10900
|
+
);
|
|
10901
|
+
return false;
|
|
10902
|
+
},
|
|
10903
|
+
launchLogin: () => {
|
|
10904
|
+
return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
|
|
10905
|
+
}
|
|
10811
10906
|
}
|
|
10812
10907
|
};
|
|
10813
10908
|
function parseLinkArgs(args2) {
|
|
@@ -10825,11 +10920,15 @@ function parseLinkArgs(args2) {
|
|
|
10825
10920
|
);
|
|
10826
10921
|
}
|
|
10827
10922
|
const reuseExisting = args2.includes("--reuse-existing");
|
|
10828
|
-
|
|
10923
|
+
const apiKeyArg = args2.find((a) => a.startsWith("--api-key="));
|
|
10924
|
+
const apiKey = apiKeyArg ? apiKeyArg.slice("--api-key=".length) : null;
|
|
10925
|
+
const tokenFileArg = args2.find((a) => a.startsWith("--token-file="));
|
|
10926
|
+
const tokenFile = tokenFileArg ? tokenFileArg.slice("--token-file=".length) : null;
|
|
10927
|
+
return { agent: normalised, reuseExisting, apiKey, tokenFile };
|
|
10829
10928
|
}
|
|
10830
10929
|
async function link(args2 = []) {
|
|
10831
|
-
const
|
|
10832
|
-
const meta = AGENT_META[agent];
|
|
10930
|
+
const parsed = parseLinkArgs(args2);
|
|
10931
|
+
const meta = AGENT_META[parsed.agent];
|
|
10833
10932
|
showIntro();
|
|
10834
10933
|
console.log(
|
|
10835
10934
|
import_picocolors11.default.bold(` Link ${meta.displayName}`) + import_picocolors11.default.dim(` \xB7 ${meta.vendor}`)
|
|
@@ -10853,7 +10952,7 @@ async function link(args2 = []) {
|
|
|
10853
10952
|
waitSpin.start(waitMsg());
|
|
10854
10953
|
const countdown = setInterval(() => waitSpin.message(waitMsg()), 1e3);
|
|
10855
10954
|
countdown.unref?.();
|
|
10856
|
-
const paired = await new Promise((
|
|
10955
|
+
const paired = await new Promise((resolve3, reject) => {
|
|
10857
10956
|
let stopPoll = null;
|
|
10858
10957
|
const sigint = () => {
|
|
10859
10958
|
clearInterval(countdown);
|
|
@@ -10866,7 +10965,7 @@ async function link(args2 = []) {
|
|
|
10866
10965
|
process.removeListener("SIGINT", sigint);
|
|
10867
10966
|
clearInterval(countdown);
|
|
10868
10967
|
waitSpin.stop("Paired");
|
|
10869
|
-
|
|
10968
|
+
resolve3(info);
|
|
10870
10969
|
},
|
|
10871
10970
|
() => {
|
|
10872
10971
|
clearInterval(countdown);
|
|
@@ -10893,36 +10992,135 @@ async function link(args2 = []) {
|
|
|
10893
10992
|
agent: meta.internalId
|
|
10894
10993
|
});
|
|
10895
10994
|
saveCliConfig({ ...loadCliConfig(), preferredAgent: meta.internalId });
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
);
|
|
10909
|
-
process.exit(1);
|
|
10910
|
-
}
|
|
10911
|
-
const refreshed = await meta.extract();
|
|
10912
|
-
const afterMtime = meta.mtime();
|
|
10913
|
-
if (!refreshed) {
|
|
10914
|
-
showError(
|
|
10915
|
-
`${meta.displayName} login finished but no credential was found at ${meta.credentialsHint}. Re-run when ready.`
|
|
10916
|
-
);
|
|
10995
|
+
if (parsed.apiKey) {
|
|
10996
|
+
await uploadAndSucceed(meta, paired, pluginId, {
|
|
10997
|
+
method: "api_key",
|
|
10998
|
+
credential: parsed.apiKey.trim(),
|
|
10999
|
+
source: "manual"
|
|
11000
|
+
});
|
|
11001
|
+
return;
|
|
11002
|
+
}
|
|
11003
|
+
if (parsed.tokenFile) {
|
|
11004
|
+
const credential = fs18.readFileSync(path26.resolve(parsed.tokenFile), "utf8").trim();
|
|
11005
|
+
if (!credential) {
|
|
11006
|
+
showError(`--token-file ${parsed.tokenFile} is empty.`);
|
|
10917
11007
|
process.exit(1);
|
|
10918
11008
|
}
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
|
|
11009
|
+
await uploadAndSucceed(meta, paired, pluginId, {
|
|
11010
|
+
method: "oauth",
|
|
11011
|
+
credential,
|
|
11012
|
+
source: "manual"
|
|
11013
|
+
});
|
|
11014
|
+
return;
|
|
11015
|
+
}
|
|
11016
|
+
const installSpin = dist_exports.spinner();
|
|
11017
|
+
installSpin.start(`Checking that ${meta.binary} is installed...`);
|
|
11018
|
+
const installed = await meta.ensureInstalled();
|
|
11019
|
+
if (!installed) {
|
|
11020
|
+
installSpin.stop("Failed");
|
|
11021
|
+
showError(`Could not install ${meta.displayName}. Install it manually then re-run.`);
|
|
11022
|
+
process.exit(1);
|
|
11023
|
+
}
|
|
11024
|
+
installSpin.stop(`${meta.displayName} is installed`);
|
|
11025
|
+
const existing = await meta.extract();
|
|
11026
|
+
if (existing) {
|
|
11027
|
+
showInfo(`Found existing ${meta.displayName} credentials at ${import_picocolors11.default.bold(existing.source)}.`);
|
|
11028
|
+
await uploadAndSucceed(meta, paired, pluginId, existing);
|
|
11029
|
+
return;
|
|
11030
|
+
}
|
|
11031
|
+
if (parsed.reuseExisting) {
|
|
11032
|
+
showError(
|
|
11033
|
+
`--reuse-existing set, but no local ${meta.displayName} credentials were found at ${meta.credentialsHint}.`
|
|
11034
|
+
);
|
|
11035
|
+
process.exit(1);
|
|
11036
|
+
}
|
|
11037
|
+
showInfo(
|
|
11038
|
+
`No local ${meta.displayName} credentials found. Launching the sign-in \u2014 complete it in your browser, the CLI will detect the new token and finish automatically.`
|
|
11039
|
+
);
|
|
11040
|
+
console.log("");
|
|
11041
|
+
const captured = await captureFreshCredentials(meta);
|
|
11042
|
+
console.log("");
|
|
11043
|
+
await uploadAndSucceed(meta, paired, pluginId, captured);
|
|
11044
|
+
}
|
|
11045
|
+
async function captureFreshCredentials(meta) {
|
|
11046
|
+
const isWin = process.platform === "win32";
|
|
11047
|
+
const watcher = import_chokidar.default.watch(meta.watchPaths(), {
|
|
11048
|
+
persistent: true,
|
|
11049
|
+
ignoreInitial: false,
|
|
11050
|
+
awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 },
|
|
11051
|
+
// Windows-only: when a credential file's ancestor is missing,
|
|
11052
|
+
// chokidar walks up to the closest existing parent and starts
|
|
11053
|
+
// traversing it. On a default Windows shell that ancestor is
|
|
11054
|
+
// `C:\Users\<u>`, which contains legacy junctions whose ACL makes
|
|
11055
|
+
// `fs.watch` throw EPERM (#43). These flags are no-ops on macOS,
|
|
11056
|
+
// where the user has read access to their entire home.
|
|
11057
|
+
...isWin ? { followSymlinks: false, ignorePermissionErrors: true } : {}
|
|
11058
|
+
});
|
|
11059
|
+
watcher.on("error", () => {
|
|
11060
|
+
});
|
|
11061
|
+
let child = null;
|
|
11062
|
+
let keychainPoll = null;
|
|
11063
|
+
const cleanup = () => {
|
|
11064
|
+
void watcher.close();
|
|
11065
|
+
if (keychainPoll) clearInterval(keychainPoll);
|
|
11066
|
+
if (child && !child.killed) {
|
|
11067
|
+
try {
|
|
11068
|
+
child.kill("SIGTERM");
|
|
11069
|
+
} catch {
|
|
11070
|
+
}
|
|
10924
11071
|
}
|
|
10925
|
-
|
|
11072
|
+
};
|
|
11073
|
+
try {
|
|
11074
|
+
const token = await new Promise((resolve3, reject) => {
|
|
11075
|
+
let settled = false;
|
|
11076
|
+
const tryExtract = async () => {
|
|
11077
|
+
if (settled) return;
|
|
11078
|
+
const t2 = await meta.extract();
|
|
11079
|
+
if (t2 && !settled) {
|
|
11080
|
+
settled = true;
|
|
11081
|
+
resolve3(t2);
|
|
11082
|
+
}
|
|
11083
|
+
};
|
|
11084
|
+
watcher.on("add", () => void tryExtract());
|
|
11085
|
+
watcher.on("change", () => void tryExtract());
|
|
11086
|
+
keychainPoll = setInterval(() => void tryExtract(), 2e3);
|
|
11087
|
+
keychainPoll.unref?.();
|
|
11088
|
+
const sigint = () => {
|
|
11089
|
+
if (settled) return;
|
|
11090
|
+
settled = true;
|
|
11091
|
+
reject(new Error("cancelled"));
|
|
11092
|
+
};
|
|
11093
|
+
process.once("SIGINT", sigint);
|
|
11094
|
+
setTimeout(() => {
|
|
11095
|
+
if (settled) return;
|
|
11096
|
+
settled = true;
|
|
11097
|
+
reject(new Error(`Timed out waiting for ${meta.displayName} sign-in (5 minutes).`));
|
|
11098
|
+
}, 5 * 6e4);
|
|
11099
|
+
child = meta.launchLogin();
|
|
11100
|
+
child.on("exit", () => {
|
|
11101
|
+
void tryExtract().then(() => {
|
|
11102
|
+
if (!settled) {
|
|
11103
|
+
settled = true;
|
|
11104
|
+
reject(
|
|
11105
|
+
new Error(
|
|
11106
|
+
`${meta.binary} exited but no credentials were written at ${meta.credentialsHint}.`
|
|
11107
|
+
)
|
|
11108
|
+
);
|
|
11109
|
+
}
|
|
11110
|
+
});
|
|
11111
|
+
});
|
|
11112
|
+
});
|
|
11113
|
+
cleanup();
|
|
11114
|
+
return token;
|
|
11115
|
+
} catch (err) {
|
|
11116
|
+
cleanup();
|
|
11117
|
+
throw err;
|
|
11118
|
+
}
|
|
11119
|
+
}
|
|
11120
|
+
async function uploadAndSucceed(meta, paired, pluginId, token) {
|
|
11121
|
+
if (!paired.pluginAuthToken) {
|
|
11122
|
+
showError("Missing pluginAuthToken; re-run codeam link.");
|
|
11123
|
+
process.exit(1);
|
|
10926
11124
|
}
|
|
10927
11125
|
const uploadSpin = dist_exports.spinner();
|
|
10928
11126
|
uploadSpin.start("Sealing credential in your vault...");
|
|
@@ -10937,12 +11135,10 @@ async function link(args2 = []) {
|
|
|
10937
11135
|
if (!result.ok) {
|
|
10938
11136
|
uploadSpin.stop("Failed");
|
|
10939
11137
|
if (result.status === 401) {
|
|
10940
|
-
showError(
|
|
10941
|
-
"Pair token rejected by the backend (401). Re-run `codeam link` to start fresh."
|
|
10942
|
-
);
|
|
11138
|
+
showError("Pair token rejected by the backend (401). Re-run `codeam link`.");
|
|
10943
11139
|
} else if (result.status === 404) {
|
|
10944
11140
|
showError(
|
|
10945
|
-
`${meta.displayName} link endpoint not available on this backend (404). The api-v2 deployment may not yet include the
|
|
11141
|
+
`${meta.displayName} link endpoint not available on this backend (404). The api-v2 deployment may not yet include the route.`
|
|
10946
11142
|
);
|
|
10947
11143
|
} else {
|
|
10948
11144
|
showError(`Upload failed: ${result.message}`);
|
|
@@ -10957,28 +11153,11 @@ async function link(args2 = []) {
|
|
|
10957
11153
|
);
|
|
10958
11154
|
console.log("");
|
|
10959
11155
|
}
|
|
10960
|
-
function runAgentLogin(meta) {
|
|
10961
|
-
return new Promise((resolve2) => {
|
|
10962
|
-
const child = (0, import_node_child_process3.spawn)(meta.binary, meta.loginArgs, { stdio: "inherit" });
|
|
10963
|
-
child.on("error", (err) => {
|
|
10964
|
-
if (err.code === "ENOENT") {
|
|
10965
|
-
showError(
|
|
10966
|
-
`${meta.binary} binary not found on PATH. Install ${meta.displayName} first, then re-run \`codeam link ${meta.internalId}\`.`
|
|
10967
|
-
);
|
|
10968
|
-
resolve2(127);
|
|
10969
|
-
return;
|
|
10970
|
-
}
|
|
10971
|
-
showError(`Failed to launch ${meta.binary}: ${err.message}`);
|
|
10972
|
-
resolve2(1);
|
|
10973
|
-
});
|
|
10974
|
-
child.on("exit", (code) => resolve2(code ?? 1));
|
|
10975
|
-
});
|
|
10976
|
-
}
|
|
10977
11156
|
|
|
10978
11157
|
// src/commands/version.ts
|
|
10979
11158
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
10980
11159
|
function version() {
|
|
10981
|
-
const v = true ? "2.16.
|
|
11160
|
+
const v = true ? "2.16.2" : "unknown";
|
|
10982
11161
|
console.log(`${import_picocolors12.default.bold("codeam-cli")} ${import_picocolors12.default.cyan(v)}`);
|
|
10983
11162
|
}
|
|
10984
11163
|
|
|
@@ -11020,9 +11199,9 @@ function help() {
|
|
|
11020
11199
|
}
|
|
11021
11200
|
|
|
11022
11201
|
// src/lib/updateNotifier.ts
|
|
11023
|
-
var
|
|
11024
|
-
var
|
|
11025
|
-
var
|
|
11202
|
+
var fs19 = __toESM(require("fs"));
|
|
11203
|
+
var os18 = __toESM(require("os"));
|
|
11204
|
+
var path27 = __toESM(require("path"));
|
|
11026
11205
|
var https7 = __toESM(require("https"));
|
|
11027
11206
|
var import_picocolors14 = __toESM(require("picocolors"));
|
|
11028
11207
|
var PKG_NAME = "codeam-cli";
|
|
@@ -11030,12 +11209,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
|
11030
11209
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
11031
11210
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
11032
11211
|
function cachePath() {
|
|
11033
|
-
const dir =
|
|
11034
|
-
return
|
|
11212
|
+
const dir = path27.join(os18.homedir(), ".codeam");
|
|
11213
|
+
return path27.join(dir, "update-check.json");
|
|
11035
11214
|
}
|
|
11036
11215
|
function readCache() {
|
|
11037
11216
|
try {
|
|
11038
|
-
const raw =
|
|
11217
|
+
const raw = fs19.readFileSync(cachePath(), "utf8");
|
|
11039
11218
|
const parsed = JSON.parse(raw);
|
|
11040
11219
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
11041
11220
|
return parsed;
|
|
@@ -11046,8 +11225,8 @@ function readCache() {
|
|
|
11046
11225
|
function writeCache(cache) {
|
|
11047
11226
|
try {
|
|
11048
11227
|
const file = cachePath();
|
|
11049
|
-
|
|
11050
|
-
|
|
11228
|
+
fs19.mkdirSync(path27.dirname(file), { recursive: true });
|
|
11229
|
+
fs19.writeFileSync(file, JSON.stringify(cache));
|
|
11051
11230
|
} catch {
|
|
11052
11231
|
}
|
|
11053
11232
|
}
|
|
@@ -11065,14 +11244,14 @@ function compareSemver(a, b) {
|
|
|
11065
11244
|
return 0;
|
|
11066
11245
|
}
|
|
11067
11246
|
function fetchLatest() {
|
|
11068
|
-
return new Promise((
|
|
11247
|
+
return new Promise((resolve3) => {
|
|
11069
11248
|
const req = https7.get(
|
|
11070
11249
|
REGISTRY_URL,
|
|
11071
11250
|
{ headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
|
|
11072
11251
|
(res) => {
|
|
11073
11252
|
if (res.statusCode !== 200) {
|
|
11074
11253
|
res.resume();
|
|
11075
|
-
|
|
11254
|
+
resolve3(null);
|
|
11076
11255
|
return;
|
|
11077
11256
|
}
|
|
11078
11257
|
let buf = "";
|
|
@@ -11084,21 +11263,21 @@ function fetchLatest() {
|
|
|
11084
11263
|
try {
|
|
11085
11264
|
const json = JSON.parse(buf);
|
|
11086
11265
|
if (typeof json.version === "string") {
|
|
11087
|
-
|
|
11266
|
+
resolve3(json.version);
|
|
11088
11267
|
} else {
|
|
11089
|
-
|
|
11268
|
+
resolve3(null);
|
|
11090
11269
|
}
|
|
11091
11270
|
} catch {
|
|
11092
|
-
|
|
11271
|
+
resolve3(null);
|
|
11093
11272
|
}
|
|
11094
11273
|
});
|
|
11095
11274
|
}
|
|
11096
11275
|
);
|
|
11097
11276
|
req.on("timeout", () => {
|
|
11098
11277
|
req.destroy();
|
|
11099
|
-
|
|
11278
|
+
resolve3(null);
|
|
11100
11279
|
});
|
|
11101
|
-
req.on("error", () =>
|
|
11280
|
+
req.on("error", () => resolve3(null));
|
|
11102
11281
|
});
|
|
11103
11282
|
}
|
|
11104
11283
|
function notifyIfStale(currentVersion, latest) {
|
|
@@ -11118,7 +11297,7 @@ function checkForUpdates() {
|
|
|
11118
11297
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
11119
11298
|
if (process.env.CI) return;
|
|
11120
11299
|
if (!process.stdout.isTTY) return;
|
|
11121
|
-
const current = true ? "2.16.
|
|
11300
|
+
const current = true ? "2.16.2" : null;
|
|
11122
11301
|
if (!current) return;
|
|
11123
11302
|
const cache = readCache();
|
|
11124
11303
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|