@getmonoceros/workbench 1.28.0 → 1.29.0
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/dist/bin.js +177 -7
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -5175,7 +5175,7 @@ var init_transform = __esm({
|
|
|
5175
5175
|
// src/devcontainer/ssh-attach.ts
|
|
5176
5176
|
import { spawn as spawn4 } from "child_process";
|
|
5177
5177
|
import { promises as fs10 } from "fs";
|
|
5178
|
-
import { existsSync as existsSync8 } from "fs";
|
|
5178
|
+
import { existsSync as existsSync8, readFileSync as readFileSync4 } from "fs";
|
|
5179
5179
|
import os2 from "os";
|
|
5180
5180
|
import path13 from "path";
|
|
5181
5181
|
function sshHomeDir(home) {
|
|
@@ -5275,6 +5275,155 @@ ${existing}` : prefix;
|
|
|
5275
5275
|
await fs10.chmod(configPath, 384).catch(() => {
|
|
5276
5276
|
});
|
|
5277
5277
|
}
|
|
5278
|
+
function runCapture(cmd, args) {
|
|
5279
|
+
return new Promise((resolve, reject) => {
|
|
5280
|
+
const child = spawn4(cmd, args, {
|
|
5281
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
5282
|
+
});
|
|
5283
|
+
let stdout = "";
|
|
5284
|
+
child.stdout.on("data", (c) => {
|
|
5285
|
+
stdout += c.toString();
|
|
5286
|
+
});
|
|
5287
|
+
child.on("error", reject);
|
|
5288
|
+
child.on("exit", (code) => resolve({ stdout, exitCode: code ?? 0 }));
|
|
5289
|
+
});
|
|
5290
|
+
}
|
|
5291
|
+
function realIsWsl() {
|
|
5292
|
+
try {
|
|
5293
|
+
if (process.env.WSL_DISTRO_NAME) return true;
|
|
5294
|
+
const rel = readFileSync4(
|
|
5295
|
+
"/proc/sys/kernel/osrelease",
|
|
5296
|
+
"utf8"
|
|
5297
|
+
).toLowerCase();
|
|
5298
|
+
return rel.includes("microsoft") || rel.includes("wsl");
|
|
5299
|
+
} catch {
|
|
5300
|
+
return false;
|
|
5301
|
+
}
|
|
5302
|
+
}
|
|
5303
|
+
async function realResolveWindowsProfile() {
|
|
5304
|
+
try {
|
|
5305
|
+
const r = await runCapture("cmd.exe", ["/c", "echo %USERPROFILE%"]);
|
|
5306
|
+
const homeWin = r.stdout.replace(/\r/g, "").trim();
|
|
5307
|
+
if (r.exitCode !== 0 || !homeWin || homeWin.includes("%USERPROFILE%")) {
|
|
5308
|
+
return null;
|
|
5309
|
+
}
|
|
5310
|
+
const w = await runCapture("wslpath", ["-u", homeWin]);
|
|
5311
|
+
const homeWsl = w.stdout.trim();
|
|
5312
|
+
const user = homeWin.split("\\").pop() ?? "";
|
|
5313
|
+
if (w.exitCode !== 0 || !homeWsl || !user) return null;
|
|
5314
|
+
return { homeWsl, homeWin, user };
|
|
5315
|
+
} catch {
|
|
5316
|
+
return null;
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5319
|
+
async function realLockWindowsKey(winKeyPath, user) {
|
|
5320
|
+
await runCapture("icacls.exe", [
|
|
5321
|
+
winKeyPath,
|
|
5322
|
+
"/inheritance:r",
|
|
5323
|
+
"/grant:r",
|
|
5324
|
+
`${user}:R`
|
|
5325
|
+
]);
|
|
5326
|
+
}
|
|
5327
|
+
function resolveWindowsDeps(d) {
|
|
5328
|
+
return {
|
|
5329
|
+
isWsl: d?.isWsl ?? realIsWsl,
|
|
5330
|
+
resolveProfile: d?.resolveProfile ?? realResolveWindowsProfile,
|
|
5331
|
+
lockKey: d?.lockKey ?? realLockWindowsKey
|
|
5332
|
+
};
|
|
5333
|
+
}
|
|
5334
|
+
function windowsHostBlock(hostAlias, keyWin) {
|
|
5335
|
+
return [
|
|
5336
|
+
`Host ${hostAlias}`,
|
|
5337
|
+
` User node`,
|
|
5338
|
+
` IdentityFile ${keyWin}`,
|
|
5339
|
+
` IdentitiesOnly yes`,
|
|
5340
|
+
` StrictHostKeyChecking no`,
|
|
5341
|
+
` UserKnownHostsFile NUL`,
|
|
5342
|
+
` ProxyCommand docker exec -i ${hostAlias} socat - TCP:127.0.0.1:22`
|
|
5343
|
+
].join("\n");
|
|
5344
|
+
}
|
|
5345
|
+
function escapeRegExp2(s) {
|
|
5346
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5347
|
+
}
|
|
5348
|
+
function blockMarkers(hostAlias) {
|
|
5349
|
+
return {
|
|
5350
|
+
begin: `# >>> monoceros ${hostAlias} >>>`,
|
|
5351
|
+
end: `# <<< monoceros ${hostAlias} <<<`
|
|
5352
|
+
};
|
|
5353
|
+
}
|
|
5354
|
+
async function upsertMarkedBlock(configPath, hostAlias, body) {
|
|
5355
|
+
const { begin, end } = blockMarkers(hostAlias);
|
|
5356
|
+
const section = `${begin}
|
|
5357
|
+
${body}
|
|
5358
|
+
${end}`;
|
|
5359
|
+
await fs10.mkdir(path13.dirname(configPath), { recursive: true });
|
|
5360
|
+
let existing = "";
|
|
5361
|
+
try {
|
|
5362
|
+
existing = await fs10.readFile(configPath, "utf8");
|
|
5363
|
+
} catch {
|
|
5364
|
+
existing = "";
|
|
5365
|
+
}
|
|
5366
|
+
const re = new RegExp(`${escapeRegExp2(begin)}[\\s\\S]*?${escapeRegExp2(end)}`);
|
|
5367
|
+
if (re.test(existing)) {
|
|
5368
|
+
await fs10.writeFile(configPath, existing.replace(re, section));
|
|
5369
|
+
return;
|
|
5370
|
+
}
|
|
5371
|
+
const sep = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
|
|
5372
|
+
await fs10.writeFile(configPath, `${existing}${sep}${section}
|
|
5373
|
+
`);
|
|
5374
|
+
}
|
|
5375
|
+
async function removeMarkedBlock(configPath, hostAlias) {
|
|
5376
|
+
let existing = "";
|
|
5377
|
+
try {
|
|
5378
|
+
existing = await fs10.readFile(configPath, "utf8");
|
|
5379
|
+
} catch {
|
|
5380
|
+
return;
|
|
5381
|
+
}
|
|
5382
|
+
const { begin, end } = blockMarkers(hostAlias);
|
|
5383
|
+
const re = new RegExp(
|
|
5384
|
+
`\\n?${escapeRegExp2(begin)}[\\s\\S]*?${escapeRegExp2(end)}\\n?`,
|
|
5385
|
+
"g"
|
|
5386
|
+
);
|
|
5387
|
+
await fs10.writeFile(
|
|
5388
|
+
configPath,
|
|
5389
|
+
existing.replace(re, "\n").replace(/\n{3,}/g, "\n\n")
|
|
5390
|
+
);
|
|
5391
|
+
}
|
|
5392
|
+
async function setupWindowsBridge(name, hostAlias, privateKey, deps, logger) {
|
|
5393
|
+
if (!deps.isWsl()) return;
|
|
5394
|
+
const profile = await deps.resolveProfile();
|
|
5395
|
+
if (!profile) {
|
|
5396
|
+
logger.warn(
|
|
5397
|
+
"WSL detected but the Windows user profile could not be resolved; skipping the Windows SSH bridge."
|
|
5398
|
+
);
|
|
5399
|
+
return;
|
|
5400
|
+
}
|
|
5401
|
+
const monoDir = path13.join(profile.homeWsl, ".ssh", "monoceros");
|
|
5402
|
+
await fs10.mkdir(monoDir, { recursive: true });
|
|
5403
|
+
await fs10.copyFile(privateKey, path13.join(monoDir, name));
|
|
5404
|
+
const keyWin = `${profile.homeWin}\\.ssh\\monoceros\\${name}`;
|
|
5405
|
+
await upsertMarkedBlock(
|
|
5406
|
+
path13.join(profile.homeWsl, ".ssh", "config"),
|
|
5407
|
+
hostAlias,
|
|
5408
|
+
windowsHostBlock(hostAlias, keyWin)
|
|
5409
|
+
);
|
|
5410
|
+
await deps.lockKey(keyWin, profile.user);
|
|
5411
|
+
logger.info(
|
|
5412
|
+
`Windows SSH bridge ready: \`ssh ${hostAlias}\` (Codium/Gateway too).`
|
|
5413
|
+
);
|
|
5414
|
+
}
|
|
5415
|
+
async function removeWindowsBridge(name, hostAlias, deps) {
|
|
5416
|
+
if (!deps.isWsl()) return;
|
|
5417
|
+
const profile = await deps.resolveProfile();
|
|
5418
|
+
if (!profile) return;
|
|
5419
|
+
await fs10.rm(path13.join(profile.homeWsl, ".ssh", "monoceros", name), {
|
|
5420
|
+
force: true
|
|
5421
|
+
});
|
|
5422
|
+
await removeMarkedBlock(
|
|
5423
|
+
path13.join(profile.homeWsl, ".ssh", "config"),
|
|
5424
|
+
hostAlias
|
|
5425
|
+
);
|
|
5426
|
+
}
|
|
5278
5427
|
async function setupSshAttach(opts) {
|
|
5279
5428
|
const hostAlias = `monoceros-${opts.name}`;
|
|
5280
5429
|
const logger = opts.logger ?? { info: () => {
|
|
@@ -5300,11 +5449,32 @@ async function setupSshAttach(opts) {
|
|
|
5300
5449
|
configEntryContent(opts.name, hostAlias, keys.privateKey, proxyScript)
|
|
5301
5450
|
);
|
|
5302
5451
|
await ensureInclude(userSshDir, opts.home);
|
|
5452
|
+
try {
|
|
5453
|
+
await setupWindowsBridge(
|
|
5454
|
+
opts.name,
|
|
5455
|
+
hostAlias,
|
|
5456
|
+
keys.privateKey,
|
|
5457
|
+
resolveWindowsDeps(opts.windows),
|
|
5458
|
+
logger
|
|
5459
|
+
);
|
|
5460
|
+
} catch (err) {
|
|
5461
|
+
logger.warn(
|
|
5462
|
+
`Windows SSH bridge skipped: ${err instanceof Error ? err.message : String(err)}`
|
|
5463
|
+
);
|
|
5464
|
+
}
|
|
5303
5465
|
return { hostAlias, configured: true };
|
|
5304
5466
|
}
|
|
5305
|
-
async function removeSshAttach(home, name) {
|
|
5467
|
+
async function removeSshAttach(home, name, windows) {
|
|
5306
5468
|
await fs10.rm(sshProxyScriptPath(home, name), { force: true });
|
|
5307
5469
|
await fs10.rm(sshConfigEntryPath(home, name), { force: true });
|
|
5470
|
+
try {
|
|
5471
|
+
await removeWindowsBridge(
|
|
5472
|
+
name,
|
|
5473
|
+
`monoceros-${name}`,
|
|
5474
|
+
resolveWindowsDeps(windows)
|
|
5475
|
+
);
|
|
5476
|
+
} catch {
|
|
5477
|
+
}
|
|
5308
5478
|
}
|
|
5309
5479
|
var realKeygen;
|
|
5310
5480
|
var init_ssh_attach = __esm({
|
|
@@ -6381,13 +6551,13 @@ var init_runtime_pull_hint = __esm({
|
|
|
6381
6551
|
|
|
6382
6552
|
// src/devcontainer/cli.ts
|
|
6383
6553
|
import { spawn as spawn5 } from "child_process";
|
|
6384
|
-
import { readFileSync as
|
|
6554
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
6385
6555
|
import { createRequire } from "module";
|
|
6386
6556
|
import path16 from "path";
|
|
6387
6557
|
function devcontainerCliPath() {
|
|
6388
6558
|
if (cachedBinaryPath) return cachedBinaryPath;
|
|
6389
6559
|
const pkgJsonPath = require_.resolve("@devcontainers/cli/package.json");
|
|
6390
|
-
const pkg = JSON.parse(
|
|
6560
|
+
const pkg = JSON.parse(readFileSync5(pkgJsonPath, "utf8"));
|
|
6391
6561
|
const binEntry = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.devcontainer ?? "";
|
|
6392
6562
|
if (!binEntry) {
|
|
6393
6563
|
throw new Error("Could not resolve @devcontainers/cli bin entry.");
|
|
@@ -7612,7 +7782,7 @@ var init_apply = __esm({
|
|
|
7612
7782
|
|
|
7613
7783
|
// src/devcontainer/browser-bridge.ts
|
|
7614
7784
|
import { spawn as spawn9 } from "child_process";
|
|
7615
|
-
import { existsSync as existsSync11, promises as fsp5, readFileSync as
|
|
7785
|
+
import { existsSync as existsSync11, promises as fsp5, readFileSync as readFileSync6 } from "fs";
|
|
7616
7786
|
import http from "http";
|
|
7617
7787
|
import path20 from "path";
|
|
7618
7788
|
function parseCallbackTarget(authUrl) {
|
|
@@ -7715,7 +7885,7 @@ exit 0
|
|
|
7715
7885
|
if (!existsSync11(urlFile)) return;
|
|
7716
7886
|
let content = "";
|
|
7717
7887
|
try {
|
|
7718
|
-
content =
|
|
7888
|
+
content = readFileSync6(urlFile, "utf8");
|
|
7719
7889
|
} catch {
|
|
7720
7890
|
return;
|
|
7721
7891
|
}
|
|
@@ -7898,7 +8068,7 @@ var CLI_VERSION;
|
|
|
7898
8068
|
var init_version = __esm({
|
|
7899
8069
|
"src/version.ts"() {
|
|
7900
8070
|
"use strict";
|
|
7901
|
-
CLI_VERSION = true ? "1.
|
|
8071
|
+
CLI_VERSION = true ? "1.29.0" : "dev";
|
|
7902
8072
|
}
|
|
7903
8073
|
});
|
|
7904
8074
|
|