@getmonoceros/workbench 1.35.0 → 1.36.1
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 +566 -180
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -1166,6 +1166,7 @@ function makePalette(isTty2) {
|
|
|
1166
1166
|
bold: (s) => wrap(s, ANSI_BOLD2),
|
|
1167
1167
|
underline: (s) => wrap(s, ANSI_UNDERLINE2),
|
|
1168
1168
|
cyan: (s) => wrap(s, ANSI_CYAN2),
|
|
1169
|
+
green: (s) => wrap(s, ANSI_GREEN),
|
|
1169
1170
|
dim: (s) => wrap(s, ANSI_GREY2),
|
|
1170
1171
|
sectionLine: (label) => wrap(`\u25B8 ${label}`, ANSI_BOLD2, ANSI_UNDERLINE2)
|
|
1171
1172
|
};
|
|
@@ -1173,7 +1174,7 @@ function makePalette(isTty2) {
|
|
|
1173
1174
|
function colorsFor(stream) {
|
|
1174
1175
|
return makePalette(stream.isTTY ?? false);
|
|
1175
1176
|
}
|
|
1176
|
-
var ESC, ANSI_BOLD2, ANSI_UNDERLINE2, ANSI_CYAN2, ANSI_GREY2, ANSI_RESET2, ANSI_RE2, stderrPalette, bold2, underline2, cyan2, dim, sectionLine;
|
|
1177
|
+
var ESC, ANSI_BOLD2, ANSI_UNDERLINE2, ANSI_CYAN2, ANSI_GREEN, ANSI_GREY2, ANSI_RESET2, ANSI_RE2, stderrPalette, bold2, underline2, cyan2, green, dim, sectionLine;
|
|
1177
1178
|
var init_format = __esm({
|
|
1178
1179
|
"src/util/format.ts"() {
|
|
1179
1180
|
"use strict";
|
|
@@ -1181,6 +1182,7 @@ var init_format = __esm({
|
|
|
1181
1182
|
ANSI_BOLD2 = `${ESC}1m`;
|
|
1182
1183
|
ANSI_UNDERLINE2 = `${ESC}4m`;
|
|
1183
1184
|
ANSI_CYAN2 = `${ESC}36m`;
|
|
1185
|
+
ANSI_GREEN = `${ESC}32m`;
|
|
1184
1186
|
ANSI_GREY2 = `${ESC}90m`;
|
|
1185
1187
|
ANSI_RESET2 = `${ESC}0m`;
|
|
1186
1188
|
ANSI_RE2 = /\x1b\[[0-9;]*m/g;
|
|
@@ -1188,6 +1190,7 @@ var init_format = __esm({
|
|
|
1188
1190
|
bold2 = stderrPalette.bold;
|
|
1189
1191
|
underline2 = stderrPalette.underline;
|
|
1190
1192
|
cyan2 = stderrPalette.cyan;
|
|
1193
|
+
green = stderrPalette.green;
|
|
1191
1194
|
dim = stderrPalette.dim;
|
|
1192
1195
|
sectionLine = stderrPalette.sectionLine;
|
|
1193
1196
|
}
|
|
@@ -2255,6 +2258,14 @@ function runtimeSupportsEntrypointSshd(version) {
|
|
|
2255
2258
|
if (!version) return false;
|
|
2256
2259
|
return compareRuntimeVersions(version, MIN_RUNTIME_FOR_ENTRYPOINT_SSHD) >= 0;
|
|
2257
2260
|
}
|
|
2261
|
+
function runtimeSupportsAppRestart(version) {
|
|
2262
|
+
if (!version) return false;
|
|
2263
|
+
return compareRuntimeVersions(version, MIN_RUNTIME_FOR_APP_RESTART) >= 0;
|
|
2264
|
+
}
|
|
2265
|
+
function runtimeSupportsAppStatus(version) {
|
|
2266
|
+
if (!version) return false;
|
|
2267
|
+
return compareRuntimeVersions(version, MIN_RUNTIME_FOR_APP_STATUS) >= 0;
|
|
2268
|
+
}
|
|
2258
2269
|
function descriptorOptionDefaults(options) {
|
|
2259
2270
|
const out = {};
|
|
2260
2271
|
for (const [key, spec] of Object.entries(options)) {
|
|
@@ -2387,7 +2398,7 @@ function deriveServiceName(image) {
|
|
|
2387
2398
|
const noTag = lastSegment.split("@")[0].split(":")[0];
|
|
2388
2399
|
return noTag.toLowerCase().replace(/[^a-z0-9_-]/g, "-");
|
|
2389
2400
|
}
|
|
2390
|
-
var DEFAULT_BASE_IMAGE, override, BASE_IMAGE, RUNTIME_IMAGE_REPO, DEFAULT_RUNTIME_VERSION, MIN_RUNTIME_FOR_SSH_ATTACH, MIN_RUNTIME_FOR_HOST_KEY_PINNING, MIN_RUNTIME_FOR_ENTRYPOINT_SSHD, MIN_RUNTIME_FOR_BROWSER_BRIDGE, DESCRIPTORS, BUILTIN_LANGUAGES, LANGUAGE_CATALOG, LANGUAGE_SPEC_RE, SERVICE_CATALOG, DEFERRED_SERVICE_PROFILE;
|
|
2401
|
+
var DEFAULT_BASE_IMAGE, override, BASE_IMAGE, RUNTIME_IMAGE_REPO, DEFAULT_RUNTIME_VERSION, MIN_RUNTIME_FOR_SSH_ATTACH, MIN_RUNTIME_FOR_HOST_KEY_PINNING, MIN_RUNTIME_FOR_ENTRYPOINT_SSHD, MIN_RUNTIME_FOR_BROWSER_BRIDGE, MIN_RUNTIME_FOR_APP_RESTART, MIN_RUNTIME_FOR_APP_STATUS, DESCRIPTORS, BUILTIN_LANGUAGES, LANGUAGE_CATALOG, LANGUAGE_SPEC_RE, SERVICE_CATALOG, DEFERRED_SERVICE_PROFILE;
|
|
2391
2402
|
var init_catalog = __esm({
|
|
2392
2403
|
"src/create/catalog.ts"() {
|
|
2393
2404
|
"use strict";
|
|
@@ -2396,7 +2407,7 @@ var init_catalog = __esm({
|
|
|
2396
2407
|
override = process.env.MONOCEROS_BASE_IMAGE_OVERRIDE?.trim();
|
|
2397
2408
|
BASE_IMAGE = override && override.length > 0 ? override : DEFAULT_BASE_IMAGE;
|
|
2398
2409
|
RUNTIME_IMAGE_REPO = "ghcr.io/getmonoceros/monoceros-runtime";
|
|
2399
|
-
DEFAULT_RUNTIME_VERSION = true ? "1.
|
|
2410
|
+
DEFAULT_RUNTIME_VERSION = true ? "1.6.0" : readFileSync3(
|
|
2400
2411
|
fileURLToPath2(
|
|
2401
2412
|
new URL("../../../../images/runtime/VERSION", import.meta.url)
|
|
2402
2413
|
),
|
|
@@ -2406,6 +2417,8 @@ var init_catalog = __esm({
|
|
|
2406
2417
|
MIN_RUNTIME_FOR_HOST_KEY_PINNING = "1.3.5";
|
|
2407
2418
|
MIN_RUNTIME_FOR_ENTRYPOINT_SSHD = "1.3.6";
|
|
2408
2419
|
MIN_RUNTIME_FOR_BROWSER_BRIDGE = "1.3.3";
|
|
2420
|
+
MIN_RUNTIME_FOR_APP_RESTART = "1.6.0";
|
|
2421
|
+
MIN_RUNTIME_FOR_APP_STATUS = "1.6.0";
|
|
2409
2422
|
DESCRIPTORS = loadDescriptorCatalogSync();
|
|
2410
2423
|
BUILTIN_LANGUAGES = new Set(
|
|
2411
2424
|
[...DESCRIPTORS.values()].filter((c) => c.category === "language" && c.descriptor.language?.builtin).map(descriptorSelector)
|
|
@@ -5386,8 +5399,8 @@ function removeRepoFromDoc(doc, urlOrPath) {
|
|
|
5386
5399
|
if (!isMap2(item)) return false;
|
|
5387
5400
|
const url = item.get("url");
|
|
5388
5401
|
if (url === urlOrPath) return true;
|
|
5389
|
-
const
|
|
5390
|
-
const effectivePath = typeof
|
|
5402
|
+
const path33 = item.get("path");
|
|
5403
|
+
const effectivePath = typeof path33 === "string" ? path33 : typeof url === "string" ? deriveRepoName(url) : void 0;
|
|
5391
5404
|
return effectivePath === urlOrPath;
|
|
5392
5405
|
});
|
|
5393
5406
|
if (idx < 0) return false;
|
|
@@ -5531,7 +5544,7 @@ async function runAddRepo(input) {
|
|
|
5531
5544
|
"Missing repo URL. Usage: monoceros add-repo <containername> <url>."
|
|
5532
5545
|
);
|
|
5533
5546
|
}
|
|
5534
|
-
const
|
|
5547
|
+
const path33 = (input.path ?? deriveRepoName(url)).trim();
|
|
5535
5548
|
const hasName = typeof input.gitName === "string" && input.gitName.trim().length > 0;
|
|
5536
5549
|
const hasEmail = typeof input.gitEmail === "string" && input.gitEmail.trim().length > 0;
|
|
5537
5550
|
if (hasName !== hasEmail) {
|
|
@@ -5568,7 +5581,7 @@ async function runAddRepo(input) {
|
|
|
5568
5581
|
const providerToWrite = !canonical && explicitProvider ? explicitProvider : void 0;
|
|
5569
5582
|
const entry2 = {
|
|
5570
5583
|
url,
|
|
5571
|
-
path:
|
|
5584
|
+
path: path33,
|
|
5572
5585
|
...hasName && hasEmail ? {
|
|
5573
5586
|
gitUser: {
|
|
5574
5587
|
name: input.gitName.trim(),
|
|
@@ -6536,16 +6549,66 @@ var init_state = __esm({
|
|
|
6536
6549
|
}
|
|
6537
6550
|
});
|
|
6538
6551
|
|
|
6552
|
+
// src/devcontainer/app-control.ts
|
|
6553
|
+
import { promises as fs12 } from "fs";
|
|
6554
|
+
import path15 from "path";
|
|
6555
|
+
function findRunningContainer(name, opts = {}) {
|
|
6556
|
+
return findRunningContainerByLocalFolder(containerDir(name), {
|
|
6557
|
+
...opts.docker ? { docker: opts.docker } : {}
|
|
6558
|
+
});
|
|
6559
|
+
}
|
|
6560
|
+
async function runAppCtl(name, ctlArgs2, opts = {}) {
|
|
6561
|
+
const id = await findRunningContainer(name, opts);
|
|
6562
|
+
if (!id) {
|
|
6563
|
+
throw new Error(
|
|
6564
|
+
`Container "${name}" is not running. Run \`monoceros start ${name}\` first.`
|
|
6565
|
+
);
|
|
6566
|
+
}
|
|
6567
|
+
const exec = opts.exec ?? realContainerExec;
|
|
6568
|
+
const result = await exec(id, ["monoceros-ctl", ...ctlArgs2]);
|
|
6569
|
+
return result.exitCode;
|
|
6570
|
+
}
|
|
6571
|
+
async function hasWantedApps(name, home) {
|
|
6572
|
+
const runRoot = path15.join(containerDir(name, home), ".monoceros", "run");
|
|
6573
|
+
async function anyPid(dir) {
|
|
6574
|
+
let entries;
|
|
6575
|
+
try {
|
|
6576
|
+
entries = await fs12.readdir(dir, { withFileTypes: true });
|
|
6577
|
+
} catch {
|
|
6578
|
+
return false;
|
|
6579
|
+
}
|
|
6580
|
+
for (const e of entries) {
|
|
6581
|
+
if (e.isDirectory()) {
|
|
6582
|
+
if (await anyPid(path15.join(dir, e.name))) return true;
|
|
6583
|
+
} else if (e.isFile() && e.name.endsWith(".pid")) {
|
|
6584
|
+
return true;
|
|
6585
|
+
}
|
|
6586
|
+
}
|
|
6587
|
+
return false;
|
|
6588
|
+
}
|
|
6589
|
+
return anyPid(runRoot);
|
|
6590
|
+
}
|
|
6591
|
+
function ctlArgs(sub, app, target, extra = []) {
|
|
6592
|
+
return [sub, app, ...target ? ["--target", target] : [], ...extra];
|
|
6593
|
+
}
|
|
6594
|
+
var init_app_control = __esm({
|
|
6595
|
+
"src/devcontainer/app-control.ts"() {
|
|
6596
|
+
"use strict";
|
|
6597
|
+
init_paths();
|
|
6598
|
+
init_locate_running();
|
|
6599
|
+
}
|
|
6600
|
+
});
|
|
6601
|
+
|
|
6539
6602
|
// src/devcontainer/browser-bridge.ts
|
|
6540
6603
|
import { spawn as spawn5 } from "child_process";
|
|
6541
6604
|
import { existsSync as existsSync9, promises as fsp4, readFileSync as readFileSync5 } from "fs";
|
|
6542
6605
|
import http from "http";
|
|
6543
|
-
import
|
|
6606
|
+
import path16 from "path";
|
|
6544
6607
|
function relayDir(root) {
|
|
6545
|
-
return
|
|
6608
|
+
return path16.join(root, RELAY_DIRNAME);
|
|
6546
6609
|
}
|
|
6547
6610
|
function relayUrlFile(root) {
|
|
6548
|
-
return
|
|
6611
|
+
return path16.join(relayDir(root), "url");
|
|
6549
6612
|
}
|
|
6550
6613
|
function parseCallbackTarget(authUrl) {
|
|
6551
6614
|
try {
|
|
@@ -6599,7 +6662,7 @@ function openInBrowser(url) {
|
|
|
6599
6662
|
}
|
|
6600
6663
|
async function startBrowserBridge(opts) {
|
|
6601
6664
|
const dir = relayDir(opts.root);
|
|
6602
|
-
const relayScript =
|
|
6665
|
+
const relayScript = path16.join(dir, "xdg-open");
|
|
6603
6666
|
const urlFile = relayUrlFile(opts.root);
|
|
6604
6667
|
await fsp4.mkdir(dir, { recursive: true });
|
|
6605
6668
|
await fsp4.rm(urlFile, { force: true });
|
|
@@ -6796,7 +6859,7 @@ var init_runtime_pull_hint = __esm({
|
|
|
6796
6859
|
import { spawn as spawn6 } from "child_process";
|
|
6797
6860
|
import { readFileSync as readFileSync6 } from "fs";
|
|
6798
6861
|
import { createRequire } from "module";
|
|
6799
|
-
import
|
|
6862
|
+
import path17 from "path";
|
|
6800
6863
|
function devcontainerCliPath() {
|
|
6801
6864
|
if (cachedBinaryPath) return cachedBinaryPath;
|
|
6802
6865
|
const pkgJsonPath = require_.resolve("@devcontainers/cli/package.json");
|
|
@@ -6805,7 +6868,7 @@ function devcontainerCliPath() {
|
|
|
6805
6868
|
if (!binEntry) {
|
|
6806
6869
|
throw new Error("Could not resolve @devcontainers/cli bin entry.");
|
|
6807
6870
|
}
|
|
6808
|
-
cachedBinaryPath =
|
|
6871
|
+
cachedBinaryPath = path17.resolve(path17.dirname(pkgJsonPath), binEntry);
|
|
6809
6872
|
return cachedBinaryPath;
|
|
6810
6873
|
}
|
|
6811
6874
|
var require_, cachedBinaryPath, spawnDevcontainer;
|
|
@@ -6880,7 +6943,7 @@ var init_cli = __esm({
|
|
|
6880
6943
|
// src/devcontainer/compose.ts
|
|
6881
6944
|
import { spawn as spawn7 } from "child_process";
|
|
6882
6945
|
import { existsSync as existsSync10 } from "fs";
|
|
6883
|
-
import
|
|
6946
|
+
import path18 from "path";
|
|
6884
6947
|
import { Writable } from "stream";
|
|
6885
6948
|
import { consola as consola10 } from "consola";
|
|
6886
6949
|
function spawnDockerComposeTo(opts) {
|
|
@@ -6949,21 +7012,21 @@ async function cleanupDockerObjects(opts) {
|
|
|
6949
7012
|
return { exitCode: rmExit, removedIds: ids };
|
|
6950
7013
|
}
|
|
6951
7014
|
function composeProjectName(root) {
|
|
6952
|
-
return `${
|
|
7015
|
+
return `${path18.basename(root)}_devcontainer`;
|
|
6953
7016
|
}
|
|
6954
7017
|
function assertDevcontainer(root) {
|
|
6955
|
-
if (!existsSync10(
|
|
7018
|
+
if (!existsSync10(path18.join(root, ".devcontainer"))) {
|
|
6956
7019
|
throw new Error(
|
|
6957
7020
|
`No .devcontainer/ at ${root}. Run \`monoceros apply <name>\` first.`
|
|
6958
7021
|
);
|
|
6959
7022
|
}
|
|
6960
7023
|
}
|
|
6961
7024
|
function isComposeMode(root) {
|
|
6962
|
-
return existsSync10(
|
|
7025
|
+
return existsSync10(path18.join(root, ".devcontainer", "compose.yaml"));
|
|
6963
7026
|
}
|
|
6964
7027
|
function resolveCompose(root) {
|
|
6965
7028
|
assertDevcontainer(root);
|
|
6966
|
-
const composeFile =
|
|
7029
|
+
const composeFile = path18.join(root, ".devcontainer", "compose.yaml");
|
|
6967
7030
|
if (!existsSync10(composeFile)) {
|
|
6968
7031
|
throw new Error(
|
|
6969
7032
|
`No compose.yaml at ${composeFile}. \`monoceros logs\` tails compose service logs, which require services configured via \`monoceros add-service <name> <svc>\`. For a bare container, use \`monoceros shell <name>\` or read logs/<app>.log.`
|
|
@@ -7156,23 +7219,13 @@ function runStop(opts) {
|
|
|
7156
7219
|
}
|
|
7157
7220
|
return stopImageContainer(opts);
|
|
7158
7221
|
}
|
|
7159
|
-
function runStatus(opts) {
|
|
7160
|
-
assertDevcontainer(opts.root);
|
|
7161
|
-
if (isComposeMode(opts.root)) {
|
|
7162
|
-
return runComposeAction(
|
|
7163
|
-
(service) => ["ps", ...service ? [service] : []],
|
|
7164
|
-
opts
|
|
7165
|
-
);
|
|
7166
|
-
}
|
|
7167
|
-
return statusImageContainer(opts);
|
|
7168
|
-
}
|
|
7169
7222
|
function imageContainerFilter(root) {
|
|
7170
7223
|
return `label=devcontainer.local_folder=${root}`;
|
|
7171
7224
|
}
|
|
7172
7225
|
async function stopImageContainer(opts) {
|
|
7173
7226
|
const exec = opts.dockerExec ?? spawnDocker;
|
|
7174
7227
|
const logger = opts.logger ?? { info: (msg) => consola10.info(msg) };
|
|
7175
|
-
const name =
|
|
7228
|
+
const name = path18.basename(opts.root);
|
|
7176
7229
|
const ps = await exec([
|
|
7177
7230
|
"ps",
|
|
7178
7231
|
"-q",
|
|
@@ -7190,29 +7243,6 @@ async function stopImageContainer(opts) {
|
|
|
7190
7243
|
if (res.exitCode === 0) logger.info(`Stopped '${name}'.`);
|
|
7191
7244
|
return res.exitCode;
|
|
7192
7245
|
}
|
|
7193
|
-
async function statusImageContainer(opts) {
|
|
7194
|
-
const exec = opts.dockerExec ?? spawnDocker;
|
|
7195
|
-
const logger = opts.logger ?? { info: (msg) => consola10.info(msg) };
|
|
7196
|
-
const name = path17.basename(opts.root);
|
|
7197
|
-
const res = await exec([
|
|
7198
|
-
"ps",
|
|
7199
|
-
"-a",
|
|
7200
|
-
"--filter",
|
|
7201
|
-
imageContainerFilter(opts.root)
|
|
7202
|
-
]);
|
|
7203
|
-
const rows = res.stdout.split("\n").filter((l) => l.trim().length > 0);
|
|
7204
|
-
if (rows.length <= 1) {
|
|
7205
|
-
logger.info(
|
|
7206
|
-
`Container '${name}' does not exist. Run \`monoceros apply ${name}\`.`
|
|
7207
|
-
);
|
|
7208
|
-
return 0;
|
|
7209
|
-
}
|
|
7210
|
-
process.stdout.write(
|
|
7211
|
-
res.stdout.endsWith("\n") ? res.stdout : `${res.stdout}
|
|
7212
|
-
`
|
|
7213
|
-
);
|
|
7214
|
-
return res.exitCode;
|
|
7215
|
-
}
|
|
7216
7246
|
function runLogs(opts) {
|
|
7217
7247
|
const follow = opts.follow ?? true;
|
|
7218
7248
|
return runComposeAction(
|
|
@@ -7280,9 +7310,9 @@ import {
|
|
|
7280
7310
|
readFileSync as readFileSync7,
|
|
7281
7311
|
writeFileSync
|
|
7282
7312
|
} from "fs";
|
|
7283
|
-
import
|
|
7313
|
+
import path19 from "path";
|
|
7284
7314
|
function bridgePidFile(root) {
|
|
7285
|
-
return
|
|
7315
|
+
return path19.join(relayDir(root), "daemon.pid");
|
|
7286
7316
|
}
|
|
7287
7317
|
function pidAlive(pid) {
|
|
7288
7318
|
try {
|
|
@@ -7386,7 +7416,7 @@ var init_bridge_daemon = __esm({
|
|
|
7386
7416
|
|
|
7387
7417
|
// src/apply/apply-log.ts
|
|
7388
7418
|
import { createWriteStream, mkdirSync as mkdirSync2 } from "fs";
|
|
7389
|
-
import
|
|
7419
|
+
import path20 from "path";
|
|
7390
7420
|
import { Writable as Writable2 } from "stream";
|
|
7391
7421
|
function safeIsoStamp(d) {
|
|
7392
7422
|
return d.toISOString().replace(/[:.]/g, "-");
|
|
@@ -7396,7 +7426,7 @@ function createApplyLog(opts) {
|
|
|
7396
7426
|
const dir = containerLogsDir(opts.name, opts.home);
|
|
7397
7427
|
mkdirSync2(dir, { recursive: true });
|
|
7398
7428
|
const file = `apply-${opts.name}-${safeIsoStamp(now)}.log`;
|
|
7399
|
-
const fullPath =
|
|
7429
|
+
const fullPath = path20.join(dir, file);
|
|
7400
7430
|
const stream = createWriteStream(fullPath, { flags: "w" });
|
|
7401
7431
|
const header = [
|
|
7402
7432
|
`# monoceros apply log`,
|
|
@@ -7733,9 +7763,9 @@ var init_images = __esm({
|
|
|
7733
7763
|
|
|
7734
7764
|
// src/config/machine-state.ts
|
|
7735
7765
|
import { promises as fsp6, readFileSync as readFileSync8 } from "fs";
|
|
7736
|
-
import
|
|
7766
|
+
import path21 from "path";
|
|
7737
7767
|
function machineStatePath(home = monocerosHome()) {
|
|
7738
|
-
return
|
|
7768
|
+
return path21.join(home, ".machine-state.json");
|
|
7739
7769
|
}
|
|
7740
7770
|
async function readMachineState(home = monocerosHome()) {
|
|
7741
7771
|
try {
|
|
@@ -7878,8 +7908,8 @@ var init_docker_mode = __esm({
|
|
|
7878
7908
|
|
|
7879
7909
|
// src/devcontainer/identity.ts
|
|
7880
7910
|
import { spawn as spawn10 } from "child_process";
|
|
7881
|
-
import { promises as
|
|
7882
|
-
import
|
|
7911
|
+
import { promises as fs13 } from "fs";
|
|
7912
|
+
import path22 from "path";
|
|
7883
7913
|
import { consola as consola11 } from "consola";
|
|
7884
7914
|
async function resolveIdentityWithPrompt(options = {}) {
|
|
7885
7915
|
const spawnFn = options.spawn ?? realGitConfigGet;
|
|
@@ -7935,8 +7965,8 @@ async function resolveIdentityWithPrompt(options = {}) {
|
|
|
7935
7965
|
};
|
|
7936
7966
|
}
|
|
7937
7967
|
async function collectGitIdentity(devContainerRoot, options = {}) {
|
|
7938
|
-
const gitconfigDir =
|
|
7939
|
-
const gitconfigPath =
|
|
7968
|
+
const gitconfigDir = path22.join(devContainerRoot, ".monoceros");
|
|
7969
|
+
const gitconfigPath = path22.join(gitconfigDir, "gitconfig");
|
|
7940
7970
|
const logger = options.logger ?? { info: () => {
|
|
7941
7971
|
}, warn: () => {
|
|
7942
7972
|
} };
|
|
@@ -7949,8 +7979,8 @@ async function collectGitIdentity(devContainerRoot, options = {}) {
|
|
|
7949
7979
|
const lines = ["[user]"];
|
|
7950
7980
|
if (resolved.name !== void 0) lines.push(` name = ${resolved.name}`);
|
|
7951
7981
|
if (resolved.email !== void 0) lines.push(` email = ${resolved.email}`);
|
|
7952
|
-
await
|
|
7953
|
-
await
|
|
7982
|
+
await fs13.mkdir(gitconfigDir, { recursive: true });
|
|
7983
|
+
await fs13.writeFile(gitconfigPath, lines.join("\n") + "\n");
|
|
7954
7984
|
return {
|
|
7955
7985
|
...resolved.name !== void 0 ? { name: resolved.name } : {},
|
|
7956
7986
|
...resolved.email !== void 0 ? { email: resolved.email } : {},
|
|
@@ -7993,7 +8023,7 @@ async function readKeyFromHost(spawnFn, key, logger) {
|
|
|
7993
8023
|
}
|
|
7994
8024
|
async function readExistingGitconfig(filePath) {
|
|
7995
8025
|
try {
|
|
7996
|
-
const content = await
|
|
8026
|
+
const content = await fs13.readFile(filePath, "utf8");
|
|
7997
8027
|
const result = {};
|
|
7998
8028
|
const nameMatch = /^\s*name\s*=\s*(.+?)\s*$/m.exec(content);
|
|
7999
8029
|
const emailMatch = /^\s*email\s*=\s*(.+?)\s*$/m.exec(content);
|
|
@@ -8070,7 +8100,7 @@ var init_identity = __esm({
|
|
|
8070
8100
|
});
|
|
8071
8101
|
|
|
8072
8102
|
// src/apply/index.ts
|
|
8073
|
-
import { existsSync as existsSync12, promises as
|
|
8103
|
+
import { existsSync as existsSync12, promises as fs14 } from "fs";
|
|
8074
8104
|
import { consola as consola12 } from "consola";
|
|
8075
8105
|
async function runApply(opts) {
|
|
8076
8106
|
const home = opts.monocerosHome ?? monocerosHome();
|
|
@@ -8210,7 +8240,7 @@ Fix the value in the env file (or the yml).`
|
|
|
8210
8240
|
if (dockerMode === "rootless") {
|
|
8211
8241
|
throw new Error(formatRootlessNotSupportedError());
|
|
8212
8242
|
}
|
|
8213
|
-
await
|
|
8243
|
+
await fs14.mkdir(targetDir, { recursive: true });
|
|
8214
8244
|
await writeScaffold(createOpts, targetDir, { dockerMode });
|
|
8215
8245
|
await writeStateFile(
|
|
8216
8246
|
targetDir,
|
|
@@ -8382,6 +8412,18 @@ Fix the value in the env file (or the yml).`
|
|
|
8382
8412
|
);
|
|
8383
8413
|
}
|
|
8384
8414
|
}
|
|
8415
|
+
if (runtimeSupportsAppRestart(createOpts.runtimeVersion) && await hasWantedApps(opts.name, home)) {
|
|
8416
|
+
progressOut.write(`
|
|
8417
|
+
${dim("restoring apps that were running\u2026")}
|
|
8418
|
+
`);
|
|
8419
|
+
try {
|
|
8420
|
+
await runAppCtl(opts.name, ["reconcile"]);
|
|
8421
|
+
} catch (err) {
|
|
8422
|
+
(logger.warn ?? logger.info)(
|
|
8423
|
+
`Restoring running apps skipped: ${err instanceof Error ? err.message : String(err)}. Bring them back with \`monoceros start ${opts.name} <app>\`.`
|
|
8424
|
+
);
|
|
8425
|
+
}
|
|
8426
|
+
}
|
|
8385
8427
|
const summaryLines = buildApplySummary(createOpts);
|
|
8386
8428
|
if (summaryLines.length > 0) {
|
|
8387
8429
|
const formatted = formatApplySummary(summaryLines);
|
|
@@ -8432,7 +8474,7 @@ ${stripAnsi(formatted)}
|
|
|
8432
8474
|
}
|
|
8433
8475
|
async function assertSafeTargetDir(targetDir, expectedOrigin) {
|
|
8434
8476
|
if (!existsSync12(targetDir)) return;
|
|
8435
|
-
const entries = await
|
|
8477
|
+
const entries = await fs14.readdir(targetDir);
|
|
8436
8478
|
if (entries.length === 0) return;
|
|
8437
8479
|
const state = await readStateFile(targetDir);
|
|
8438
8480
|
if (state) {
|
|
@@ -8502,7 +8544,7 @@ async function persistPromptedIdentity(prompted, ymlPath, home, logger) {
|
|
|
8502
8544
|
}
|
|
8503
8545
|
if (wantContainer) {
|
|
8504
8546
|
try {
|
|
8505
|
-
const text = await
|
|
8547
|
+
const text = await fs14.readFile(ymlPath, "utf8");
|
|
8506
8548
|
const parsed = parseConfig(text, ymlPath);
|
|
8507
8549
|
const changed = setContainerGitUserInDoc(parsed.doc, {
|
|
8508
8550
|
name: prompted.name,
|
|
@@ -8510,7 +8552,7 @@ async function persistPromptedIdentity(prompted, ymlPath, home, logger) {
|
|
|
8510
8552
|
});
|
|
8511
8553
|
if (changed) {
|
|
8512
8554
|
const out = stringifyConfig(parsed.doc);
|
|
8513
|
-
await
|
|
8555
|
+
await fs14.writeFile(ymlPath, out, "utf8");
|
|
8514
8556
|
logger.info(
|
|
8515
8557
|
`Saved identity in this container \u2014 wrote git.user into ${prettyPath(ymlPath)}.`
|
|
8516
8558
|
);
|
|
@@ -8533,6 +8575,7 @@ var init_apply = __esm({
|
|
|
8533
8575
|
init_state();
|
|
8534
8576
|
init_transform();
|
|
8535
8577
|
init_catalog();
|
|
8578
|
+
init_app_control();
|
|
8536
8579
|
init_bridge_daemon();
|
|
8537
8580
|
init_ssh_attach();
|
|
8538
8581
|
init_scaffold();
|
|
@@ -8560,7 +8603,7 @@ var init_apply = __esm({
|
|
|
8560
8603
|
|
|
8561
8604
|
// src/devcontainer/shell.ts
|
|
8562
8605
|
import { existsSync as existsSync13 } from "fs";
|
|
8563
|
-
import
|
|
8606
|
+
import path23 from "path";
|
|
8564
8607
|
async function runShell(opts) {
|
|
8565
8608
|
assertContainerExists(opts.root);
|
|
8566
8609
|
const spawnFn = opts.spawn ?? spawnDevcontainer;
|
|
@@ -8570,7 +8613,7 @@ async function runShell(opts) {
|
|
|
8570
8613
|
{ quiet: true }
|
|
8571
8614
|
);
|
|
8572
8615
|
if (upCode !== 0) return upCode;
|
|
8573
|
-
const name = opts.name ??
|
|
8616
|
+
const name = opts.name ?? path23.basename(opts.root);
|
|
8574
8617
|
const isTty2 = opts.isTty ?? process.stdout.isTTY;
|
|
8575
8618
|
const bridge = isTty2 ? await startBrowserBridge({ name, root: opts.root, spawn: spawnFn }) : null;
|
|
8576
8619
|
try {
|
|
@@ -8594,7 +8637,7 @@ async function runShell(opts) {
|
|
|
8594
8637
|
}
|
|
8595
8638
|
}
|
|
8596
8639
|
function assertContainerExists(root) {
|
|
8597
|
-
if (!existsSync13(
|
|
8640
|
+
if (!existsSync13(path23.join(root, ".devcontainer"))) {
|
|
8598
8641
|
throw new Error(
|
|
8599
8642
|
`No .devcontainer/ at ${root}. Run \`monoceros apply <name>\` first.`
|
|
8600
8643
|
);
|
|
@@ -8611,12 +8654,12 @@ var init_shell = __esm({
|
|
|
8611
8654
|
// src/open/index.ts
|
|
8612
8655
|
import { spawn as spawn11 } from "child_process";
|
|
8613
8656
|
import { accessSync, constants, existsSync as existsSync14 } from "fs";
|
|
8614
|
-
import
|
|
8657
|
+
import path24 from "path";
|
|
8615
8658
|
import { consola as consola13 } from "consola";
|
|
8616
8659
|
function resolveOnPath(bin) {
|
|
8617
|
-
const dirs = (process.env.PATH ?? "").split(
|
|
8660
|
+
const dirs = (process.env.PATH ?? "").split(path24.delimiter).filter(Boolean);
|
|
8618
8661
|
for (const dir of dirs) {
|
|
8619
|
-
const candidate =
|
|
8662
|
+
const candidate = path24.join(dir, bin);
|
|
8620
8663
|
try {
|
|
8621
8664
|
accessSync(candidate, constants.X_OK);
|
|
8622
8665
|
return candidate;
|
|
@@ -8729,7 +8772,7 @@ var CLI_VERSION;
|
|
|
8729
8772
|
var init_version = __esm({
|
|
8730
8773
|
"src/version.ts"() {
|
|
8731
8774
|
"use strict";
|
|
8732
|
-
CLI_VERSION = true ? "1.
|
|
8775
|
+
CLI_VERSION = true ? "1.36.1" : "dev";
|
|
8733
8776
|
}
|
|
8734
8777
|
});
|
|
8735
8778
|
|
|
@@ -8963,10 +9006,10 @@ var init_bridge = __esm({
|
|
|
8963
9006
|
});
|
|
8964
9007
|
|
|
8965
9008
|
// src/config/launch-config.ts
|
|
8966
|
-
import { promises as
|
|
8967
|
-
import
|
|
9009
|
+
import { promises as fs15 } from "fs";
|
|
9010
|
+
import path25 from "path";
|
|
8968
9011
|
function launchConfigPath(name, appRel, home) {
|
|
8969
|
-
return
|
|
9012
|
+
return path25.join(
|
|
8970
9013
|
containerDir(name, home),
|
|
8971
9014
|
"projects",
|
|
8972
9015
|
appRel,
|
|
@@ -9016,7 +9059,7 @@ async function readLaunchConfig(name, appRel, home) {
|
|
|
9016
9059
|
const file = launchConfigPath(name, appRel, home);
|
|
9017
9060
|
let content;
|
|
9018
9061
|
try {
|
|
9019
|
-
content = await
|
|
9062
|
+
content = await fs15.readFile(file, "utf8");
|
|
9020
9063
|
} catch {
|
|
9021
9064
|
return void 0;
|
|
9022
9065
|
}
|
|
@@ -9053,12 +9096,12 @@ function resolveTarget(config, targetName, appRel) {
|
|
|
9053
9096
|
);
|
|
9054
9097
|
}
|
|
9055
9098
|
async function listApps(name, home) {
|
|
9056
|
-
const projectsRoot =
|
|
9099
|
+
const projectsRoot = path25.join(containerDir(name, home), "projects");
|
|
9057
9100
|
const out = [];
|
|
9058
9101
|
async function walk(at, rel, depth) {
|
|
9059
9102
|
let entries;
|
|
9060
9103
|
try {
|
|
9061
|
-
entries = await
|
|
9104
|
+
entries = await fs15.readdir(at, { withFileTypes: true });
|
|
9062
9105
|
} catch {
|
|
9063
9106
|
return;
|
|
9064
9107
|
}
|
|
@@ -9067,7 +9110,7 @@ async function listApps(name, home) {
|
|
|
9067
9110
|
);
|
|
9068
9111
|
if (hasLaunch) {
|
|
9069
9112
|
try {
|
|
9070
|
-
await
|
|
9113
|
+
await fs15.access(path25.join(at, LAUNCH_DIRNAME, LAUNCH_FILENAME));
|
|
9071
9114
|
if (rel) out.push(rel);
|
|
9072
9115
|
} catch {
|
|
9073
9116
|
}
|
|
@@ -9077,7 +9120,7 @@ async function listApps(name, home) {
|
|
|
9077
9120
|
if (!e.isDirectory()) continue;
|
|
9078
9121
|
if (e.name.startsWith(".")) continue;
|
|
9079
9122
|
await walk(
|
|
9080
|
-
|
|
9123
|
+
path25.join(at, e.name),
|
|
9081
9124
|
rel ? `${rel}/${e.name}` : e.name,
|
|
9082
9125
|
depth + 1
|
|
9083
9126
|
);
|
|
@@ -9098,8 +9141,8 @@ var init_launch_config = __esm({
|
|
|
9098
9141
|
});
|
|
9099
9142
|
|
|
9100
9143
|
// src/completion/resolve.ts
|
|
9101
|
-
import { existsSync as existsSync15, promises as
|
|
9102
|
-
import
|
|
9144
|
+
import { existsSync as existsSync15, promises as fs16 } from "fs";
|
|
9145
|
+
import path26 from "path";
|
|
9103
9146
|
async function resolveCompletions(line, point, opts = {}) {
|
|
9104
9147
|
const { prev, current } = parseCompletionLine(line, point);
|
|
9105
9148
|
const ctx = { prev, current, opts };
|
|
@@ -9248,9 +9291,9 @@ function filterPrefix(values, fragment) {
|
|
|
9248
9291
|
}
|
|
9249
9292
|
async function listContainerNames(ctx) {
|
|
9250
9293
|
const home = ctx.opts.monocerosHome ?? monocerosHome();
|
|
9251
|
-
const dir =
|
|
9294
|
+
const dir = path26.join(home, "container-configs");
|
|
9252
9295
|
if (!existsSync15(dir)) return [];
|
|
9253
|
-
const entries = await
|
|
9296
|
+
const entries = await fs16.readdir(dir);
|
|
9254
9297
|
return entries.filter((e) => e.endsWith(".yml")).map((e) => e.slice(0, -".yml".length)).sort();
|
|
9255
9298
|
}
|
|
9256
9299
|
function containerNameFromCtx(ctx) {
|
|
@@ -9281,6 +9324,22 @@ async function listAppCandidates(ctx) {
|
|
|
9281
9324
|
return [];
|
|
9282
9325
|
}
|
|
9283
9326
|
}
|
|
9327
|
+
async function listAppOrServiceCandidates(ctx) {
|
|
9328
|
+
const name = containerNameFromCtx(ctx);
|
|
9329
|
+
if (!name) return [];
|
|
9330
|
+
const apps = await listApps(name, ctx.opts.monocerosHome).catch(() => []);
|
|
9331
|
+
let services = [];
|
|
9332
|
+
try {
|
|
9333
|
+
const parsed = await readConfig(
|
|
9334
|
+
containerConfigPath(name, ctx.opts.monocerosHome)
|
|
9335
|
+
);
|
|
9336
|
+
services = solutionConfigToCreateOptions(parsed.config).services.map(
|
|
9337
|
+
(s) => s.name
|
|
9338
|
+
);
|
|
9339
|
+
} catch {
|
|
9340
|
+
}
|
|
9341
|
+
return [.../* @__PURE__ */ new Set([...apps, ...services])].sort();
|
|
9342
|
+
}
|
|
9284
9343
|
async function listTargetCandidates(ctx) {
|
|
9285
9344
|
const name = containerNameFromCtx(ctx);
|
|
9286
9345
|
const app = positionalFromCtx(ctx, 1);
|
|
@@ -9297,7 +9356,7 @@ async function collectDirs(dir, maxDepth) {
|
|
|
9297
9356
|
async function walk(at, rel, depth) {
|
|
9298
9357
|
let entries;
|
|
9299
9358
|
try {
|
|
9300
|
-
entries = await
|
|
9359
|
+
entries = await fs16.readdir(at, { withFileTypes: true });
|
|
9301
9360
|
} catch {
|
|
9302
9361
|
return;
|
|
9303
9362
|
}
|
|
@@ -9308,7 +9367,7 @@ async function collectDirs(dir, maxDepth) {
|
|
|
9308
9367
|
const childRel = rel ? `${rel}/${e.name}` : e.name;
|
|
9309
9368
|
out.push(childRel);
|
|
9310
9369
|
if (depth + 1 < maxDepth) {
|
|
9311
|
-
await walk(
|
|
9370
|
+
await walk(path26.join(at, e.name), childRel, depth + 1);
|
|
9312
9371
|
}
|
|
9313
9372
|
}
|
|
9314
9373
|
}
|
|
@@ -9316,9 +9375,9 @@ async function collectDirs(dir, maxDepth) {
|
|
|
9316
9375
|
return out;
|
|
9317
9376
|
}
|
|
9318
9377
|
async function listContainerWorkspaceDirs(home, name) {
|
|
9319
|
-
const root =
|
|
9378
|
+
const root = path26.join(home, "container", name);
|
|
9320
9379
|
const top = await collectDirs(root, 1);
|
|
9321
|
-
const projects = (await collectDirs(
|
|
9380
|
+
const projects = (await collectDirs(path26.join(root, "projects"), PROJECTS_DIR_MAX_DEPTH)).map((p) => `projects/${p}`);
|
|
9322
9381
|
return [.../* @__PURE__ */ new Set([...top, ...projects])].sort();
|
|
9323
9382
|
}
|
|
9324
9383
|
async function listRunInDirs(ctx) {
|
|
@@ -9394,6 +9453,8 @@ var init_resolve = __esm({
|
|
|
9394
9453
|
"src/completion/resolve.ts"() {
|
|
9395
9454
|
"use strict";
|
|
9396
9455
|
init_paths();
|
|
9456
|
+
init_io();
|
|
9457
|
+
init_transform();
|
|
9397
9458
|
init_launch_config();
|
|
9398
9459
|
init_components();
|
|
9399
9460
|
init_manifest();
|
|
@@ -9500,7 +9561,9 @@ var init_resolve = __esm({
|
|
|
9500
9561
|
"--target": { type: "value", values: (ctx) => listTargetCandidates(ctx) }
|
|
9501
9562
|
}
|
|
9502
9563
|
},
|
|
9503
|
-
status: {
|
|
9564
|
+
status: {
|
|
9565
|
+
positionals: [containerName, (ctx) => listAppOrServiceCandidates(ctx)]
|
|
9566
|
+
},
|
|
9504
9567
|
"list-apps": { positionals: [containerName] },
|
|
9505
9568
|
"add-language": {
|
|
9506
9569
|
positionals: [containerName, () => listLanguageNames()]
|
|
@@ -10164,8 +10227,8 @@ var init_generator = __esm({
|
|
|
10164
10227
|
});
|
|
10165
10228
|
|
|
10166
10229
|
// src/init/index.ts
|
|
10167
|
-
import { existsSync as existsSync16, promises as
|
|
10168
|
-
import
|
|
10230
|
+
import { existsSync as existsSync16, promises as fs17 } from "fs";
|
|
10231
|
+
import path27 from "path";
|
|
10169
10232
|
import { consola as consola16 } from "consola";
|
|
10170
10233
|
async function runInit(opts) {
|
|
10171
10234
|
const home = opts.monocerosHome ?? monocerosHome();
|
|
@@ -10184,7 +10247,7 @@ async function runInit(opts) {
|
|
|
10184
10247
|
`Config already exists: ${dest}. Delete it manually before re-running \`monoceros init\` \u2014 this protects any hand-edits.`
|
|
10185
10248
|
);
|
|
10186
10249
|
}
|
|
10187
|
-
const componentsRoot = opts.workbenchRoot ?
|
|
10250
|
+
const componentsRoot = opts.workbenchRoot ? path27.join(opts.workbenchRoot, "components") : componentsRootDir();
|
|
10188
10251
|
const catalog = await loadComponentCatalog(componentsRoot);
|
|
10189
10252
|
if (catalog.size === 0) {
|
|
10190
10253
|
throw new Error(
|
|
@@ -10250,9 +10313,9 @@ async function runInit(opts) {
|
|
|
10250
10313
|
} else {
|
|
10251
10314
|
text = generateComposedYml(opts.name, composed, lookup, repos, ports);
|
|
10252
10315
|
}
|
|
10253
|
-
await
|
|
10316
|
+
await fs17.mkdir(containerConfigsDir(home), { recursive: true });
|
|
10254
10317
|
await ensureEnvGitignored(containerConfigsDir(home));
|
|
10255
|
-
await
|
|
10318
|
+
await fs17.writeFile(dest, text, "utf8");
|
|
10256
10319
|
const envPath = containerEnvPath(opts.name, home);
|
|
10257
10320
|
const seedVars = {};
|
|
10258
10321
|
for (const f of composed.features) {
|
|
@@ -10275,8 +10338,8 @@ async function runInit(opts) {
|
|
|
10275
10338
|
}
|
|
10276
10339
|
await ensureEnvVars(envPath, opts.name, seedVars);
|
|
10277
10340
|
const documented = !anyComposed;
|
|
10278
|
-
const ymlRel =
|
|
10279
|
-
const envRel =
|
|
10341
|
+
const ymlRel = path27.relative(home, dest);
|
|
10342
|
+
const envRel = path27.relative(home, envPath);
|
|
10280
10343
|
if (documented) {
|
|
10281
10344
|
logger.success(`Wrote documented default to ${ymlRel} and ${envRel}.`);
|
|
10282
10345
|
logger.info(
|
|
@@ -10836,7 +10899,7 @@ var init_list_components = __esm({
|
|
|
10836
10899
|
|
|
10837
10900
|
// src/commands/logs.ts
|
|
10838
10901
|
import { spawn as spawn13 } from "child_process";
|
|
10839
|
-
import
|
|
10902
|
+
import path28 from "path";
|
|
10840
10903
|
import { defineCommand as defineCommand16 } from "citty";
|
|
10841
10904
|
import { consola as consola20 } from "consola";
|
|
10842
10905
|
function tailLogFile(file, follow) {
|
|
@@ -10891,7 +10954,7 @@ var init_logs = __esm({
|
|
|
10891
10954
|
const cfg = await readLaunchConfig(args.name, app);
|
|
10892
10955
|
if (cfg) {
|
|
10893
10956
|
const t = resolveTarget(cfg, target, app);
|
|
10894
|
-
const logFile =
|
|
10957
|
+
const logFile = path28.join(
|
|
10895
10958
|
containerLogsDir(args.name),
|
|
10896
10959
|
app,
|
|
10897
10960
|
`${t.name}.log`
|
|
@@ -11140,8 +11203,8 @@ var init_remove_feature = __esm({
|
|
|
11140
11203
|
});
|
|
11141
11204
|
|
|
11142
11205
|
// src/remove/index.ts
|
|
11143
|
-
import { existsSync as existsSync17, promises as
|
|
11144
|
-
import
|
|
11206
|
+
import { existsSync as existsSync17, promises as fs18 } from "fs";
|
|
11207
|
+
import path29 from "path";
|
|
11145
11208
|
import { consola as consola24 } from "consola";
|
|
11146
11209
|
async function runRemove(opts) {
|
|
11147
11210
|
const home = opts.monocerosHome ?? monocerosHome();
|
|
@@ -11186,16 +11249,16 @@ async function runRemove(opts) {
|
|
|
11186
11249
|
let backupPath = null;
|
|
11187
11250
|
if (!opts.noBackup && (hasYml || hasContainer)) {
|
|
11188
11251
|
const ts = (opts.now ?? /* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
11189
|
-
backupPath =
|
|
11190
|
-
await
|
|
11252
|
+
backupPath = path29.join(home, "container-backups", `${opts.name}-${ts}`);
|
|
11253
|
+
await fs18.mkdir(backupPath, { recursive: true });
|
|
11191
11254
|
if (hasYml) {
|
|
11192
|
-
await
|
|
11255
|
+
await fs18.copyFile(ymlPath, path29.join(backupPath, `${opts.name}.yml`));
|
|
11193
11256
|
}
|
|
11194
11257
|
if (hasEnv) {
|
|
11195
|
-
await
|
|
11258
|
+
await fs18.copyFile(envPath, path29.join(backupPath, `${opts.name}.env`));
|
|
11196
11259
|
}
|
|
11197
11260
|
if (hasContainer) {
|
|
11198
|
-
await
|
|
11261
|
+
await fs18.cp(containerPath, path29.join(backupPath, "container"), {
|
|
11199
11262
|
recursive: true
|
|
11200
11263
|
});
|
|
11201
11264
|
}
|
|
@@ -11205,14 +11268,14 @@ async function runRemove(opts) {
|
|
|
11205
11268
|
await stopBridgeDaemon(containerPath);
|
|
11206
11269
|
}
|
|
11207
11270
|
if (hasYml) {
|
|
11208
|
-
await
|
|
11271
|
+
await fs18.rm(ymlPath, { force: true });
|
|
11209
11272
|
}
|
|
11210
11273
|
if (hasEnv) {
|
|
11211
|
-
await
|
|
11274
|
+
await fs18.rm(envPath, { force: true });
|
|
11212
11275
|
}
|
|
11213
11276
|
if (hasContainer) {
|
|
11214
11277
|
try {
|
|
11215
|
-
await
|
|
11278
|
+
await fs18.rm(containerPath, { recursive: true, force: true });
|
|
11216
11279
|
} catch (err) {
|
|
11217
11280
|
const code = err.code;
|
|
11218
11281
|
if (code !== "EACCES" && code !== "EPERM") {
|
|
@@ -11234,7 +11297,7 @@ async function runRemove(opts) {
|
|
|
11234
11297
|
"-delete"
|
|
11235
11298
|
]);
|
|
11236
11299
|
try {
|
|
11237
|
-
await
|
|
11300
|
+
await fs18.rm(containerPath, { recursive: true, force: true });
|
|
11238
11301
|
} catch (err2) {
|
|
11239
11302
|
const code2 = err2.code;
|
|
11240
11303
|
throw new Error(
|
|
@@ -11369,8 +11432,8 @@ var init_remove2 = __esm({
|
|
|
11369
11432
|
});
|
|
11370
11433
|
|
|
11371
11434
|
// src/restore/index.ts
|
|
11372
|
-
import { existsSync as existsSync18, promises as
|
|
11373
|
-
import
|
|
11435
|
+
import { existsSync as existsSync18, promises as fs19 } from "fs";
|
|
11436
|
+
import path30 from "path";
|
|
11374
11437
|
import { consola as consola26 } from "consola";
|
|
11375
11438
|
async function runRestore(opts) {
|
|
11376
11439
|
const home = opts.monocerosHome ?? monocerosHome();
|
|
@@ -11378,15 +11441,15 @@ async function runRestore(opts) {
|
|
|
11378
11441
|
info: (msg) => consola26.info(msg),
|
|
11379
11442
|
success: (msg) => consola26.success(msg)
|
|
11380
11443
|
};
|
|
11381
|
-
const backup =
|
|
11444
|
+
const backup = path30.resolve(opts.backupPath);
|
|
11382
11445
|
if (!existsSync18(backup)) {
|
|
11383
11446
|
throw new Error(`Backup not found: ${backup}.`);
|
|
11384
11447
|
}
|
|
11385
|
-
const stat = await
|
|
11448
|
+
const stat = await fs19.stat(backup);
|
|
11386
11449
|
if (!stat.isDirectory()) {
|
|
11387
11450
|
throw new Error(`Backup path is not a directory: ${backup}.`);
|
|
11388
11451
|
}
|
|
11389
|
-
const entries = await
|
|
11452
|
+
const entries = await fs19.readdir(backup);
|
|
11390
11453
|
const ymlFiles = entries.filter((f) => f.endsWith(".yml"));
|
|
11391
11454
|
if (ymlFiles.length === 0) {
|
|
11392
11455
|
throw new Error(
|
|
@@ -11400,9 +11463,9 @@ async function runRestore(opts) {
|
|
|
11400
11463
|
}
|
|
11401
11464
|
const ymlFile = ymlFiles[0];
|
|
11402
11465
|
const name = ymlFile.replace(/\.yml$/, "");
|
|
11403
|
-
const containerInBackup =
|
|
11466
|
+
const containerInBackup = path30.join(backup, "container");
|
|
11404
11467
|
const hasContainer = existsSync18(containerInBackup);
|
|
11405
|
-
const envInBackup =
|
|
11468
|
+
const envInBackup = path30.join(backup, `${name}.env`);
|
|
11406
11469
|
const hasEnv = existsSync18(envInBackup);
|
|
11407
11470
|
const destYml = containerConfigPath(name, home);
|
|
11408
11471
|
const destContainer = containerDir(name, home);
|
|
@@ -11416,13 +11479,13 @@ async function runRestore(opts) {
|
|
|
11416
11479
|
`Refusing to restore: ${destContainer} already exists. Remove the current container first (\`monoceros remove ${name}\`).`
|
|
11417
11480
|
);
|
|
11418
11481
|
}
|
|
11419
|
-
await
|
|
11420
|
-
await
|
|
11482
|
+
await fs19.mkdir(containerConfigsDir(home), { recursive: true });
|
|
11483
|
+
await fs19.copyFile(path30.join(backup, ymlFile), destYml);
|
|
11421
11484
|
if (hasEnv) {
|
|
11422
|
-
await
|
|
11485
|
+
await fs19.copyFile(envInBackup, containerEnvPath(name, home));
|
|
11423
11486
|
}
|
|
11424
11487
|
if (hasContainer) {
|
|
11425
|
-
await
|
|
11488
|
+
await fs19.cp(containerInBackup, destContainer, { recursive: true });
|
|
11426
11489
|
}
|
|
11427
11490
|
logger.success(`Restored '${name}' from ${prettyPath(backup)}.`);
|
|
11428
11491
|
logger.info(
|
|
@@ -11728,14 +11791,14 @@ var init_remove_service = __esm({
|
|
|
11728
11791
|
|
|
11729
11792
|
// src/devcontainer/claude-trust.ts
|
|
11730
11793
|
import { existsSync as existsSync19, promises as fsp7 } from "fs";
|
|
11731
|
-
import
|
|
11794
|
+
import path31 from "path";
|
|
11732
11795
|
function resolveContainerCwd(name, cwd) {
|
|
11733
11796
|
const workspace = `/workspaces/${name}`;
|
|
11734
11797
|
if (!cwd) return workspace;
|
|
11735
|
-
return
|
|
11798
|
+
return path31.posix.isAbsolute(cwd) ? cwd : path31.posix.join(workspace, cwd);
|
|
11736
11799
|
}
|
|
11737
11800
|
async function preApproveClaudeProject(opts) {
|
|
11738
|
-
const file =
|
|
11801
|
+
const file = path31.join(opts.root, "home", ".claude.json");
|
|
11739
11802
|
if (!existsSync19(file)) return;
|
|
11740
11803
|
try {
|
|
11741
11804
|
const raw = await fsp7.readFile(file, "utf8");
|
|
@@ -11916,34 +11979,6 @@ var init_shell2 = __esm({
|
|
|
11916
11979
|
}
|
|
11917
11980
|
});
|
|
11918
11981
|
|
|
11919
|
-
// src/devcontainer/app-control.ts
|
|
11920
|
-
function findRunningContainer(name, opts = {}) {
|
|
11921
|
-
return findRunningContainerByLocalFolder(containerDir(name), {
|
|
11922
|
-
...opts.docker ? { docker: opts.docker } : {}
|
|
11923
|
-
});
|
|
11924
|
-
}
|
|
11925
|
-
async function runAppCtl(name, ctlArgs2, opts = {}) {
|
|
11926
|
-
const id = await findRunningContainer(name, opts);
|
|
11927
|
-
if (!id) {
|
|
11928
|
-
throw new Error(
|
|
11929
|
-
`Container "${name}" is not running. Run \`monoceros start ${name}\` first.`
|
|
11930
|
-
);
|
|
11931
|
-
}
|
|
11932
|
-
const exec = opts.exec ?? realContainerExec;
|
|
11933
|
-
const result = await exec(id, ["monoceros-ctl", ...ctlArgs2]);
|
|
11934
|
-
return result.exitCode;
|
|
11935
|
-
}
|
|
11936
|
-
function ctlArgs(sub, app, target, extra = []) {
|
|
11937
|
-
return [sub, app, ...target ? ["--target", target] : [], ...extra];
|
|
11938
|
-
}
|
|
11939
|
-
var init_app_control = __esm({
|
|
11940
|
-
"src/devcontainer/app-control.ts"() {
|
|
11941
|
-
"use strict";
|
|
11942
|
-
init_paths();
|
|
11943
|
-
init_locate_running();
|
|
11944
|
-
}
|
|
11945
|
-
});
|
|
11946
|
-
|
|
11947
11982
|
// src/commands/start.ts
|
|
11948
11983
|
import { defineCommand as defineCommand30 } from "citty";
|
|
11949
11984
|
import { consola as consola35 } from "consola";
|
|
@@ -12076,20 +12111,360 @@ var init_start = __esm({
|
|
|
12076
12111
|
}
|
|
12077
12112
|
});
|
|
12078
12113
|
|
|
12114
|
+
// src/status/index.ts
|
|
12115
|
+
function shortFeatureName2(ref) {
|
|
12116
|
+
const withoutTag = ref.replace(/:[^:/@]+$/, "");
|
|
12117
|
+
const idx = withoutTag.lastIndexOf("/");
|
|
12118
|
+
return idx >= 0 ? withoutTag.slice(idx + 1) : withoutTag;
|
|
12119
|
+
}
|
|
12120
|
+
function cols(line) {
|
|
12121
|
+
return line.split(" ");
|
|
12122
|
+
}
|
|
12123
|
+
function nonEmptyLines(s) {
|
|
12124
|
+
return s.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
12125
|
+
}
|
|
12126
|
+
async function gatherStatus(name, opts = {}) {
|
|
12127
|
+
const docker = opts.docker ?? realDockerLookup;
|
|
12128
|
+
const root = containerDir(name, opts.home);
|
|
12129
|
+
let runtimeVersion;
|
|
12130
|
+
let languages = [];
|
|
12131
|
+
let features = [];
|
|
12132
|
+
let declaredServices = [];
|
|
12133
|
+
let declaredPorts = [];
|
|
12134
|
+
let configured = false;
|
|
12135
|
+
try {
|
|
12136
|
+
const parsed = await readConfig(containerConfigPath(name, opts.home));
|
|
12137
|
+
const createOpts = solutionConfigToCreateOptions(parsed.config);
|
|
12138
|
+
configured = true;
|
|
12139
|
+
runtimeVersion = createOpts.runtimeVersion;
|
|
12140
|
+
languages = createOpts.languages;
|
|
12141
|
+
features = Object.keys(createOpts.features ?? {}).map(shortFeatureName2);
|
|
12142
|
+
declaredServices = createOpts.services.map((s) => ({
|
|
12143
|
+
name: s.name,
|
|
12144
|
+
...typeof s.port === "number" ? { port: s.port } : {}
|
|
12145
|
+
}));
|
|
12146
|
+
declaredPorts = createOpts.ports ?? [];
|
|
12147
|
+
} catch {
|
|
12148
|
+
}
|
|
12149
|
+
let container = {
|
|
12150
|
+
exists: false,
|
|
12151
|
+
running: false,
|
|
12152
|
+
status: "",
|
|
12153
|
+
dockerName: ""
|
|
12154
|
+
};
|
|
12155
|
+
let containerId = "";
|
|
12156
|
+
let composeProject = "";
|
|
12157
|
+
const cps = await docker([
|
|
12158
|
+
"ps",
|
|
12159
|
+
"-a",
|
|
12160
|
+
"--no-trunc",
|
|
12161
|
+
"--filter",
|
|
12162
|
+
`label=devcontainer.local_folder=${root}`,
|
|
12163
|
+
"--format",
|
|
12164
|
+
'{{.ID}} {{.State}} {{.Status}} {{.Names}} {{.Label "com.docker.compose.project"}}'
|
|
12165
|
+
]);
|
|
12166
|
+
const row2 = nonEmptyLines(cps.stdout)[0];
|
|
12167
|
+
if (row2) {
|
|
12168
|
+
const [id, state, status, names, project] = cols(row2);
|
|
12169
|
+
containerId = id ?? "";
|
|
12170
|
+
composeProject = project ?? "";
|
|
12171
|
+
container = {
|
|
12172
|
+
exists: true,
|
|
12173
|
+
running: state === "running",
|
|
12174
|
+
status: status ?? "",
|
|
12175
|
+
dockerName: names ?? ""
|
|
12176
|
+
};
|
|
12177
|
+
}
|
|
12178
|
+
const services = [];
|
|
12179
|
+
if (declaredServices.length > 0) {
|
|
12180
|
+
const live = /* @__PURE__ */ new Map();
|
|
12181
|
+
if (composeProject) {
|
|
12182
|
+
const sps = await docker([
|
|
12183
|
+
"ps",
|
|
12184
|
+
"-a",
|
|
12185
|
+
"--filter",
|
|
12186
|
+
`label=com.docker.compose.project=${composeProject}`,
|
|
12187
|
+
"--format",
|
|
12188
|
+
'{{.Label "com.docker.compose.service"}} {{.State}} {{.Status}}'
|
|
12189
|
+
]);
|
|
12190
|
+
for (const l of nonEmptyLines(sps.stdout)) {
|
|
12191
|
+
const [svc, state, status] = cols(l);
|
|
12192
|
+
if (svc)
|
|
12193
|
+
live.set(svc, { running: state === "running", status: status ?? "" });
|
|
12194
|
+
}
|
|
12195
|
+
}
|
|
12196
|
+
for (const s of declaredServices) {
|
|
12197
|
+
const m = live.get(s.name);
|
|
12198
|
+
services.push({
|
|
12199
|
+
name: s.name,
|
|
12200
|
+
running: m?.running ?? false,
|
|
12201
|
+
status: m?.status ?? "not created",
|
|
12202
|
+
...typeof s.port === "number" ? { port: s.port } : {}
|
|
12203
|
+
});
|
|
12204
|
+
}
|
|
12205
|
+
}
|
|
12206
|
+
const apps = [];
|
|
12207
|
+
for (const app of await listApps(name, opts.home)) {
|
|
12208
|
+
const cfg = await readLaunchConfig(name, app, opts.home);
|
|
12209
|
+
if (!cfg) continue;
|
|
12210
|
+
for (const t of cfg.configurations) {
|
|
12211
|
+
apps.push({
|
|
12212
|
+
app,
|
|
12213
|
+
target: t.name,
|
|
12214
|
+
port: typeof t.port === "number" ? t.port : null,
|
|
12215
|
+
default: t.default === true,
|
|
12216
|
+
running: void 0,
|
|
12217
|
+
pid: null
|
|
12218
|
+
});
|
|
12219
|
+
}
|
|
12220
|
+
}
|
|
12221
|
+
const appsSupported = runtimeSupportsAppStatus(runtimeVersion);
|
|
12222
|
+
let appStateKnown = container.running && appsSupported && containerId !== "";
|
|
12223
|
+
let appStateNote;
|
|
12224
|
+
if (appStateKnown) {
|
|
12225
|
+
const res = await docker([
|
|
12226
|
+
"exec",
|
|
12227
|
+
containerId,
|
|
12228
|
+
"monoceros-ctl",
|
|
12229
|
+
"list",
|
|
12230
|
+
"--json"
|
|
12231
|
+
]);
|
|
12232
|
+
if (res.exitCode === 0) {
|
|
12233
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
12234
|
+
for (const l of nonEmptyLines(res.stdout)) {
|
|
12235
|
+
try {
|
|
12236
|
+
const o = JSON.parse(l);
|
|
12237
|
+
byKey.set(`${o.app}\0${o.target}`, {
|
|
12238
|
+
running: !!o.running,
|
|
12239
|
+
pid: o.pid ?? null
|
|
12240
|
+
});
|
|
12241
|
+
} catch {
|
|
12242
|
+
}
|
|
12243
|
+
}
|
|
12244
|
+
for (const a of apps) {
|
|
12245
|
+
const o = byKey.get(`${a.app}\0${a.target}`);
|
|
12246
|
+
if (o) {
|
|
12247
|
+
a.running = o.running;
|
|
12248
|
+
a.pid = o.pid;
|
|
12249
|
+
} else {
|
|
12250
|
+
a.running = false;
|
|
12251
|
+
}
|
|
12252
|
+
}
|
|
12253
|
+
} else {
|
|
12254
|
+
appStateKnown = false;
|
|
12255
|
+
appStateNote = `could not read run state from the runner - rebuild the runtime image, then \`monoceros upgrade ${name}\``;
|
|
12256
|
+
}
|
|
12257
|
+
}
|
|
12258
|
+
if (apps.length > 0 && !appStateKnown && !appStateNote) {
|
|
12259
|
+
appStateNote = !container.running ? `start the container to see run state (\`monoceros start ${name}\`)` : `run state needs runtime 1.6.0+ (this one: ${runtimeVersion ?? "unpinned"})`;
|
|
12260
|
+
}
|
|
12261
|
+
let hostPort = 80;
|
|
12262
|
+
try {
|
|
12263
|
+
hostPort = proxyHostPort(
|
|
12264
|
+
await readMonocerosConfig({
|
|
12265
|
+
...opts.home ? { monocerosHome: opts.home } : {}
|
|
12266
|
+
})
|
|
12267
|
+
);
|
|
12268
|
+
} catch {
|
|
12269
|
+
}
|
|
12270
|
+
const ports = proxyUrlsFor(name, declaredPorts, hostPort);
|
|
12271
|
+
return {
|
|
12272
|
+
name,
|
|
12273
|
+
configured,
|
|
12274
|
+
container,
|
|
12275
|
+
services,
|
|
12276
|
+
apps,
|
|
12277
|
+
appStateKnown,
|
|
12278
|
+
...appStateNote ? { appStateNote } : {},
|
|
12279
|
+
ports,
|
|
12280
|
+
builtIn: { languages, features }
|
|
12281
|
+
};
|
|
12282
|
+
}
|
|
12283
|
+
function row(p, marker, name, detail, pad, indent = 2) {
|
|
12284
|
+
const gap = Math.max(2, pad - name.length + 2);
|
|
12285
|
+
return `${" ".repeat(indent)}${marker} ${p.cyan(name)}${" ".repeat(gap)}${detail}`;
|
|
12286
|
+
}
|
|
12287
|
+
function liveMarker(p, running) {
|
|
12288
|
+
if (running === void 0) return " ";
|
|
12289
|
+
return running ? p.green("\u2713") : p.dim("\xB7");
|
|
12290
|
+
}
|
|
12291
|
+
function renderContainer(p, m) {
|
|
12292
|
+
const out = [p.sectionLine(m.name)];
|
|
12293
|
+
if (!m.container.exists) {
|
|
12294
|
+
out.push(
|
|
12295
|
+
row(
|
|
12296
|
+
p,
|
|
12297
|
+
p.dim("\xB7"),
|
|
12298
|
+
"(not created)",
|
|
12299
|
+
p.dim(`run \`monoceros apply ${m.name}\``),
|
|
12300
|
+
14
|
|
12301
|
+
)
|
|
12302
|
+
);
|
|
12303
|
+
return out;
|
|
12304
|
+
}
|
|
12305
|
+
const detail = m.container.running ? p.dim(m.container.status || "running") : p.dim(m.container.status || "stopped");
|
|
12306
|
+
out.push(
|
|
12307
|
+
row(
|
|
12308
|
+
p,
|
|
12309
|
+
liveMarker(p, m.container.running),
|
|
12310
|
+
m.container.dockerName,
|
|
12311
|
+
detail,
|
|
12312
|
+
14
|
|
12313
|
+
)
|
|
12314
|
+
);
|
|
12315
|
+
return out;
|
|
12316
|
+
}
|
|
12317
|
+
function renderServices(p, m) {
|
|
12318
|
+
if (m.services.length === 0) return [];
|
|
12319
|
+
const pad = Math.max(...m.services.map((s) => s.name.length));
|
|
12320
|
+
const out = ["", p.sectionLine("Services")];
|
|
12321
|
+
for (const s of m.services) {
|
|
12322
|
+
const detail = s.running ? p.dim(typeof s.port === "number" ? `running :${s.port}` : "running") : p.dim(s.status || "stopped");
|
|
12323
|
+
out.push(row(p, liveMarker(p, s.running), s.name, detail, pad));
|
|
12324
|
+
}
|
|
12325
|
+
return out;
|
|
12326
|
+
}
|
|
12327
|
+
function appTargetDetail(p, name, t) {
|
|
12328
|
+
const bits = [];
|
|
12329
|
+
if (t.running === true) {
|
|
12330
|
+
bits.push(
|
|
12331
|
+
t.port !== null ? p.dim(`http://${name}-${t.port}.localhost`) : p.dim("running")
|
|
12332
|
+
);
|
|
12333
|
+
if (t.pid !== null) bits.push(p.dim(`pid ${t.pid}`));
|
|
12334
|
+
} else if (t.running === false) {
|
|
12335
|
+
bits.push(p.dim("stopped"));
|
|
12336
|
+
}
|
|
12337
|
+
if (t.default) bits.push(p.dim("(default)"));
|
|
12338
|
+
return bits.join(" ");
|
|
12339
|
+
}
|
|
12340
|
+
function renderApps(p, m) {
|
|
12341
|
+
if (m.apps.length === 0) return [];
|
|
12342
|
+
const out = ["", p.sectionLine("Apps")];
|
|
12343
|
+
if (m.appStateNote) out.push(` ${p.dim(m.appStateNote)}`);
|
|
12344
|
+
const byApp = /* @__PURE__ */ new Map();
|
|
12345
|
+
for (const a of m.apps) {
|
|
12346
|
+
const list = byApp.get(a.app) ?? [];
|
|
12347
|
+
list.push(a);
|
|
12348
|
+
byApp.set(a.app, list);
|
|
12349
|
+
}
|
|
12350
|
+
for (const [app, targets] of byApp) {
|
|
12351
|
+
out.push(` ${p.cyan(app)}`);
|
|
12352
|
+
const pad = Math.max(...targets.map((t) => t.target.length));
|
|
12353
|
+
for (const t of targets) {
|
|
12354
|
+
out.push(
|
|
12355
|
+
row(
|
|
12356
|
+
p,
|
|
12357
|
+
liveMarker(p, t.running),
|
|
12358
|
+
t.target,
|
|
12359
|
+
appTargetDetail(p, m.name, t),
|
|
12360
|
+
pad,
|
|
12361
|
+
4
|
|
12362
|
+
)
|
|
12363
|
+
);
|
|
12364
|
+
}
|
|
12365
|
+
}
|
|
12366
|
+
return out;
|
|
12367
|
+
}
|
|
12368
|
+
function renderPorts(p, m) {
|
|
12369
|
+
if (m.ports.length === 0) return [];
|
|
12370
|
+
const pad = Math.max(...m.ports.map((r) => String(r.port).length));
|
|
12371
|
+
const out = ["", p.sectionLine("Ports")];
|
|
12372
|
+
for (const r of m.ports) {
|
|
12373
|
+
const hosts = r.isDefault ? `${m.name}.localhost \xB7 ${m.name}-${r.port}.localhost` : `${m.name}-${r.port}.localhost`;
|
|
12374
|
+
out.push(row(p, " ", String(r.port), p.dim(hosts), pad));
|
|
12375
|
+
}
|
|
12376
|
+
return out;
|
|
12377
|
+
}
|
|
12378
|
+
function renderBuiltIn(p, m) {
|
|
12379
|
+
const lines = [];
|
|
12380
|
+
if (m.builtIn.languages.length > 0)
|
|
12381
|
+
lines.push({ label: "Languages", values: m.builtIn.languages });
|
|
12382
|
+
if (m.builtIn.features.length > 0)
|
|
12383
|
+
lines.push({ label: "Features", values: m.builtIn.features });
|
|
12384
|
+
if (lines.length === 0) return [];
|
|
12385
|
+
const labelWidth = Math.max(...lines.map((l) => l.label.length));
|
|
12386
|
+
const out = ["", `${p.sectionLine("Built in")} ${p.dim("from the yml")}`];
|
|
12387
|
+
for (const l of lines) {
|
|
12388
|
+
out.push(` ${l.label.padEnd(labelWidth)} ${p.cyan(l.values.join(", "))}`);
|
|
12389
|
+
}
|
|
12390
|
+
return out;
|
|
12391
|
+
}
|
|
12392
|
+
function renderStatus(m, p) {
|
|
12393
|
+
return [
|
|
12394
|
+
...renderContainer(p, m),
|
|
12395
|
+
...renderServices(p, m),
|
|
12396
|
+
...renderApps(p, m),
|
|
12397
|
+
...renderPorts(p, m),
|
|
12398
|
+
...renderBuiltIn(p, m)
|
|
12399
|
+
].join("\n");
|
|
12400
|
+
}
|
|
12401
|
+
function renderApp(m, app, p) {
|
|
12402
|
+
const targets = m.apps.filter((a) => a.app === app);
|
|
12403
|
+
if (targets.length === 0) {
|
|
12404
|
+
const known = [...new Set(m.apps.map((a) => a.app))];
|
|
12405
|
+
throw new Error(
|
|
12406
|
+
`No app "${app}" in ${m.name} (have: ${known.join(", ") || "none"}).`
|
|
12407
|
+
);
|
|
12408
|
+
}
|
|
12409
|
+
const out = [p.sectionLine(app)];
|
|
12410
|
+
if (m.appStateNote) out.push(` ${p.dim(m.appStateNote)}`);
|
|
12411
|
+
const pad = Math.max(...targets.map((t) => t.target.length));
|
|
12412
|
+
for (const t of targets) {
|
|
12413
|
+
out.push(
|
|
12414
|
+
row(
|
|
12415
|
+
p,
|
|
12416
|
+
liveMarker(p, t.running),
|
|
12417
|
+
t.target,
|
|
12418
|
+
appTargetDetail(p, m.name, t),
|
|
12419
|
+
pad,
|
|
12420
|
+
2
|
|
12421
|
+
)
|
|
12422
|
+
);
|
|
12423
|
+
}
|
|
12424
|
+
return out.join("\n");
|
|
12425
|
+
}
|
|
12426
|
+
function renderService(m, name, p) {
|
|
12427
|
+
const s = m.services.find((svc) => svc.name === name);
|
|
12428
|
+
if (!s) {
|
|
12429
|
+
throw new Error(
|
|
12430
|
+
`No service "${name}" in ${m.name} (have: ${m.services.map((x) => x.name).join(", ") || "none"}).`
|
|
12431
|
+
);
|
|
12432
|
+
}
|
|
12433
|
+
const detail = s.running ? p.dim(typeof s.port === "number" ? `running :${s.port}` : "running") : p.dim(s.status || "stopped");
|
|
12434
|
+
return [
|
|
12435
|
+
p.sectionLine("Services"),
|
|
12436
|
+
row(p, liveMarker(p, s.running), s.name, detail, s.name.length)
|
|
12437
|
+
].join("\n");
|
|
12438
|
+
}
|
|
12439
|
+
var init_status = __esm({
|
|
12440
|
+
"src/status/index.ts"() {
|
|
12441
|
+
"use strict";
|
|
12442
|
+
init_io();
|
|
12443
|
+
init_paths();
|
|
12444
|
+
init_global();
|
|
12445
|
+
init_transform();
|
|
12446
|
+
init_launch_config();
|
|
12447
|
+
init_catalog();
|
|
12448
|
+
init_locate_running();
|
|
12449
|
+
init_dynamic();
|
|
12450
|
+
init_format();
|
|
12451
|
+
}
|
|
12452
|
+
});
|
|
12453
|
+
|
|
12079
12454
|
// src/commands/status.ts
|
|
12080
12455
|
import { defineCommand as defineCommand31 } from "citty";
|
|
12081
12456
|
var statusCommand;
|
|
12082
|
-
var
|
|
12457
|
+
var init_status2 = __esm({
|
|
12083
12458
|
"src/commands/status.ts"() {
|
|
12084
12459
|
"use strict";
|
|
12085
|
-
|
|
12086
|
-
|
|
12460
|
+
init_status();
|
|
12461
|
+
init_format();
|
|
12087
12462
|
init_dispatch();
|
|
12088
12463
|
statusCommand = defineCommand31({
|
|
12089
12464
|
meta: {
|
|
12090
12465
|
name: "status",
|
|
12091
12466
|
group: "run",
|
|
12092
|
-
description: "Show
|
|
12467
|
+
description: "Show the dev-container at a glance: container, services and apps (up/down), the ports it routes, and what the yml built in. With an <app> (or a service name), narrow to just that."
|
|
12093
12468
|
},
|
|
12094
12469
|
args: {
|
|
12095
12470
|
name: {
|
|
@@ -12097,18 +12472,29 @@ var init_status = __esm({
|
|
|
12097
12472
|
description: "Container name (yml in $MONOCEROS_HOME/container-configs/).",
|
|
12098
12473
|
required: true
|
|
12099
12474
|
},
|
|
12100
|
-
|
|
12101
|
-
type: "
|
|
12102
|
-
description: "
|
|
12475
|
+
app: {
|
|
12476
|
+
type: "positional",
|
|
12477
|
+
description: "Narrow to one app (a path under projects/ with .monoceros/launch.json) or one compose service (e.g. postgres). Omit for the whole stack.",
|
|
12478
|
+
required: false
|
|
12103
12479
|
}
|
|
12104
12480
|
},
|
|
12105
12481
|
run({ args }) {
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
12482
|
+
const filter = typeof args.app === "string" ? args.app : void 0;
|
|
12483
|
+
return dispatch(async () => {
|
|
12484
|
+
const model = await gatherStatus(args.name);
|
|
12485
|
+
const p = colorsFor(process.stdout);
|
|
12486
|
+
let block;
|
|
12487
|
+
if (filter) {
|
|
12488
|
+
const isApp = model.apps.some((a) => a.app === filter);
|
|
12489
|
+
block = isApp ? renderApp(model, filter, p) : renderService(model, filter, p);
|
|
12490
|
+
} else {
|
|
12491
|
+
block = renderStatus(model, p);
|
|
12492
|
+
}
|
|
12493
|
+
process.stdout.write(`
|
|
12494
|
+
${block}
|
|
12495
|
+
`);
|
|
12496
|
+
return 0;
|
|
12497
|
+
});
|
|
12112
12498
|
}
|
|
12113
12499
|
});
|
|
12114
12500
|
}
|
|
@@ -12189,7 +12575,7 @@ var init_stop = __esm({
|
|
|
12189
12575
|
|
|
12190
12576
|
// src/tunnel/resolve.ts
|
|
12191
12577
|
import { existsSync as existsSync20 } from "fs";
|
|
12192
|
-
import
|
|
12578
|
+
import path32 from "path";
|
|
12193
12579
|
async function resolveTunnelTarget(opts) {
|
|
12194
12580
|
const ymlPath = containerConfigPath(opts.name, opts.monocerosHome);
|
|
12195
12581
|
if (!existsSync20(ymlPath)) {
|
|
@@ -12205,7 +12591,7 @@ async function resolveTunnelTarget(opts) {
|
|
|
12205
12591
|
`Container '${opts.name}' is not materialised at ${containerRoot}. Run \`monoceros apply ${opts.name}\` first.`
|
|
12206
12592
|
);
|
|
12207
12593
|
}
|
|
12208
|
-
const composePath =
|
|
12594
|
+
const composePath = path32.join(containerRoot, ".devcontainer", "compose.yaml");
|
|
12209
12595
|
const isCompose = existsSync20(composePath);
|
|
12210
12596
|
const parsedTarget = parseTargetArg(opts.target, config);
|
|
12211
12597
|
const docker = opts.docker ?? defaultDockerExec;
|
|
@@ -12686,7 +13072,7 @@ var init_prune = __esm({
|
|
|
12686
13072
|
});
|
|
12687
13073
|
|
|
12688
13074
|
// src/upgrade/index.ts
|
|
12689
|
-
import { existsSync as existsSync21, promises as
|
|
13075
|
+
import { existsSync as existsSync21, promises as fs20 } from "fs";
|
|
12690
13076
|
import { consola as consola39 } from "consola";
|
|
12691
13077
|
async function fetchRuntimeVersions() {
|
|
12692
13078
|
const tokenUrl = `https://ghcr.io/token?service=ghcr.io&scope=repository:${RUNTIME_REPO}:pull`;
|
|
@@ -12803,10 +13189,10 @@ async function runUpgrade(opts) {
|
|
|
12803
13189
|
for (const name of targets) {
|
|
12804
13190
|
const ymlPath = containerConfigPath(name, home);
|
|
12805
13191
|
if (!existsSync21(ymlPath)) continue;
|
|
12806
|
-
const raw = await
|
|
13192
|
+
const raw = await fs20.readFile(ymlPath, "utf8");
|
|
12807
13193
|
const updated = setRuntimeVersion(raw, pinVersion);
|
|
12808
13194
|
if (updated !== raw) {
|
|
12809
|
-
await
|
|
13195
|
+
await fs20.writeFile(ymlPath, updated);
|
|
12810
13196
|
bumped += 1;
|
|
12811
13197
|
logger.info(`Pinned '${name}' to runtime ${pinVersion}.`);
|
|
12812
13198
|
}
|
|
@@ -12848,7 +13234,7 @@ function formatPruneLine(prune) {
|
|
|
12848
13234
|
}
|
|
12849
13235
|
async function listContainerNames2(home) {
|
|
12850
13236
|
try {
|
|
12851
|
-
const entries = await
|
|
13237
|
+
const entries = await fs20.readdir(containerConfigsDir(home));
|
|
12852
13238
|
return entries.filter((e) => e.endsWith(".yml")).map((e) => e.slice(0, -".yml".length));
|
|
12853
13239
|
} catch {
|
|
12854
13240
|
return [];
|
|
@@ -12956,7 +13342,7 @@ var init_main = __esm({
|
|
|
12956
13342
|
init_run2();
|
|
12957
13343
|
init_shell2();
|
|
12958
13344
|
init_start();
|
|
12959
|
-
|
|
13345
|
+
init_status2();
|
|
12960
13346
|
init_stop();
|
|
12961
13347
|
init_tunnel();
|
|
12962
13348
|
init_upgrade2();
|
|
@@ -13261,25 +13647,25 @@ function detectHelpRequest(argv, main2) {
|
|
|
13261
13647
|
const separatorIdx = argv.indexOf("--");
|
|
13262
13648
|
if (helpIdx === -1) return null;
|
|
13263
13649
|
if (separatorIdx !== -1 && separatorIdx < helpIdx) return null;
|
|
13264
|
-
const
|
|
13650
|
+
const path33 = [];
|
|
13265
13651
|
const tokens = argv.slice(
|
|
13266
13652
|
0,
|
|
13267
13653
|
separatorIdx === -1 ? argv.length : separatorIdx
|
|
13268
13654
|
);
|
|
13269
13655
|
let cursor = main2;
|
|
13270
13656
|
const mainName = (main2.meta ?? {}).name ?? "monoceros";
|
|
13271
|
-
|
|
13657
|
+
path33.push(mainName);
|
|
13272
13658
|
for (const tok of tokens) {
|
|
13273
13659
|
if (tok.startsWith("-")) continue;
|
|
13274
13660
|
const subs = cursor.subCommands ?? {};
|
|
13275
13661
|
if (tok in subs) {
|
|
13276
13662
|
cursor = subs[tok];
|
|
13277
|
-
|
|
13663
|
+
path33.push(tok);
|
|
13278
13664
|
continue;
|
|
13279
13665
|
}
|
|
13280
13666
|
break;
|
|
13281
13667
|
}
|
|
13282
|
-
return { path:
|
|
13668
|
+
return { path: path33, cmd: cursor };
|
|
13283
13669
|
}
|
|
13284
13670
|
async function maybeRenderHelp(argv, main2) {
|
|
13285
13671
|
const hit = detectHelpRequest(argv, main2);
|