@getmonoceros/workbench 1.35.0 → 1.36.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 +545 -179
- 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.0" : "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) {
|
|
@@ -9297,7 +9340,7 @@ async function collectDirs(dir, maxDepth) {
|
|
|
9297
9340
|
async function walk(at, rel, depth) {
|
|
9298
9341
|
let entries;
|
|
9299
9342
|
try {
|
|
9300
|
-
entries = await
|
|
9343
|
+
entries = await fs16.readdir(at, { withFileTypes: true });
|
|
9301
9344
|
} catch {
|
|
9302
9345
|
return;
|
|
9303
9346
|
}
|
|
@@ -9308,7 +9351,7 @@ async function collectDirs(dir, maxDepth) {
|
|
|
9308
9351
|
const childRel = rel ? `${rel}/${e.name}` : e.name;
|
|
9309
9352
|
out.push(childRel);
|
|
9310
9353
|
if (depth + 1 < maxDepth) {
|
|
9311
|
-
await walk(
|
|
9354
|
+
await walk(path26.join(at, e.name), childRel, depth + 1);
|
|
9312
9355
|
}
|
|
9313
9356
|
}
|
|
9314
9357
|
}
|
|
@@ -9316,9 +9359,9 @@ async function collectDirs(dir, maxDepth) {
|
|
|
9316
9359
|
return out;
|
|
9317
9360
|
}
|
|
9318
9361
|
async function listContainerWorkspaceDirs(home, name) {
|
|
9319
|
-
const root =
|
|
9362
|
+
const root = path26.join(home, "container", name);
|
|
9320
9363
|
const top = await collectDirs(root, 1);
|
|
9321
|
-
const projects = (await collectDirs(
|
|
9364
|
+
const projects = (await collectDirs(path26.join(root, "projects"), PROJECTS_DIR_MAX_DEPTH)).map((p) => `projects/${p}`);
|
|
9322
9365
|
return [.../* @__PURE__ */ new Set([...top, ...projects])].sort();
|
|
9323
9366
|
}
|
|
9324
9367
|
async function listRunInDirs(ctx) {
|
|
@@ -10164,8 +10207,8 @@ var init_generator = __esm({
|
|
|
10164
10207
|
});
|
|
10165
10208
|
|
|
10166
10209
|
// src/init/index.ts
|
|
10167
|
-
import { existsSync as existsSync16, promises as
|
|
10168
|
-
import
|
|
10210
|
+
import { existsSync as existsSync16, promises as fs17 } from "fs";
|
|
10211
|
+
import path27 from "path";
|
|
10169
10212
|
import { consola as consola16 } from "consola";
|
|
10170
10213
|
async function runInit(opts) {
|
|
10171
10214
|
const home = opts.monocerosHome ?? monocerosHome();
|
|
@@ -10184,7 +10227,7 @@ async function runInit(opts) {
|
|
|
10184
10227
|
`Config already exists: ${dest}. Delete it manually before re-running \`monoceros init\` \u2014 this protects any hand-edits.`
|
|
10185
10228
|
);
|
|
10186
10229
|
}
|
|
10187
|
-
const componentsRoot = opts.workbenchRoot ?
|
|
10230
|
+
const componentsRoot = opts.workbenchRoot ? path27.join(opts.workbenchRoot, "components") : componentsRootDir();
|
|
10188
10231
|
const catalog = await loadComponentCatalog(componentsRoot);
|
|
10189
10232
|
if (catalog.size === 0) {
|
|
10190
10233
|
throw new Error(
|
|
@@ -10250,9 +10293,9 @@ async function runInit(opts) {
|
|
|
10250
10293
|
} else {
|
|
10251
10294
|
text = generateComposedYml(opts.name, composed, lookup, repos, ports);
|
|
10252
10295
|
}
|
|
10253
|
-
await
|
|
10296
|
+
await fs17.mkdir(containerConfigsDir(home), { recursive: true });
|
|
10254
10297
|
await ensureEnvGitignored(containerConfigsDir(home));
|
|
10255
|
-
await
|
|
10298
|
+
await fs17.writeFile(dest, text, "utf8");
|
|
10256
10299
|
const envPath = containerEnvPath(opts.name, home);
|
|
10257
10300
|
const seedVars = {};
|
|
10258
10301
|
for (const f of composed.features) {
|
|
@@ -10275,8 +10318,8 @@ async function runInit(opts) {
|
|
|
10275
10318
|
}
|
|
10276
10319
|
await ensureEnvVars(envPath, opts.name, seedVars);
|
|
10277
10320
|
const documented = !anyComposed;
|
|
10278
|
-
const ymlRel =
|
|
10279
|
-
const envRel =
|
|
10321
|
+
const ymlRel = path27.relative(home, dest);
|
|
10322
|
+
const envRel = path27.relative(home, envPath);
|
|
10280
10323
|
if (documented) {
|
|
10281
10324
|
logger.success(`Wrote documented default to ${ymlRel} and ${envRel}.`);
|
|
10282
10325
|
logger.info(
|
|
@@ -10836,7 +10879,7 @@ var init_list_components = __esm({
|
|
|
10836
10879
|
|
|
10837
10880
|
// src/commands/logs.ts
|
|
10838
10881
|
import { spawn as spawn13 } from "child_process";
|
|
10839
|
-
import
|
|
10882
|
+
import path28 from "path";
|
|
10840
10883
|
import { defineCommand as defineCommand16 } from "citty";
|
|
10841
10884
|
import { consola as consola20 } from "consola";
|
|
10842
10885
|
function tailLogFile(file, follow) {
|
|
@@ -10891,7 +10934,7 @@ var init_logs = __esm({
|
|
|
10891
10934
|
const cfg = await readLaunchConfig(args.name, app);
|
|
10892
10935
|
if (cfg) {
|
|
10893
10936
|
const t = resolveTarget(cfg, target, app);
|
|
10894
|
-
const logFile =
|
|
10937
|
+
const logFile = path28.join(
|
|
10895
10938
|
containerLogsDir(args.name),
|
|
10896
10939
|
app,
|
|
10897
10940
|
`${t.name}.log`
|
|
@@ -11140,8 +11183,8 @@ var init_remove_feature = __esm({
|
|
|
11140
11183
|
});
|
|
11141
11184
|
|
|
11142
11185
|
// src/remove/index.ts
|
|
11143
|
-
import { existsSync as existsSync17, promises as
|
|
11144
|
-
import
|
|
11186
|
+
import { existsSync as existsSync17, promises as fs18 } from "fs";
|
|
11187
|
+
import path29 from "path";
|
|
11145
11188
|
import { consola as consola24 } from "consola";
|
|
11146
11189
|
async function runRemove(opts) {
|
|
11147
11190
|
const home = opts.monocerosHome ?? monocerosHome();
|
|
@@ -11186,16 +11229,16 @@ async function runRemove(opts) {
|
|
|
11186
11229
|
let backupPath = null;
|
|
11187
11230
|
if (!opts.noBackup && (hasYml || hasContainer)) {
|
|
11188
11231
|
const ts = (opts.now ?? /* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
11189
|
-
backupPath =
|
|
11190
|
-
await
|
|
11232
|
+
backupPath = path29.join(home, "container-backups", `${opts.name}-${ts}`);
|
|
11233
|
+
await fs18.mkdir(backupPath, { recursive: true });
|
|
11191
11234
|
if (hasYml) {
|
|
11192
|
-
await
|
|
11235
|
+
await fs18.copyFile(ymlPath, path29.join(backupPath, `${opts.name}.yml`));
|
|
11193
11236
|
}
|
|
11194
11237
|
if (hasEnv) {
|
|
11195
|
-
await
|
|
11238
|
+
await fs18.copyFile(envPath, path29.join(backupPath, `${opts.name}.env`));
|
|
11196
11239
|
}
|
|
11197
11240
|
if (hasContainer) {
|
|
11198
|
-
await
|
|
11241
|
+
await fs18.cp(containerPath, path29.join(backupPath, "container"), {
|
|
11199
11242
|
recursive: true
|
|
11200
11243
|
});
|
|
11201
11244
|
}
|
|
@@ -11205,14 +11248,14 @@ async function runRemove(opts) {
|
|
|
11205
11248
|
await stopBridgeDaemon(containerPath);
|
|
11206
11249
|
}
|
|
11207
11250
|
if (hasYml) {
|
|
11208
|
-
await
|
|
11251
|
+
await fs18.rm(ymlPath, { force: true });
|
|
11209
11252
|
}
|
|
11210
11253
|
if (hasEnv) {
|
|
11211
|
-
await
|
|
11254
|
+
await fs18.rm(envPath, { force: true });
|
|
11212
11255
|
}
|
|
11213
11256
|
if (hasContainer) {
|
|
11214
11257
|
try {
|
|
11215
|
-
await
|
|
11258
|
+
await fs18.rm(containerPath, { recursive: true, force: true });
|
|
11216
11259
|
} catch (err) {
|
|
11217
11260
|
const code = err.code;
|
|
11218
11261
|
if (code !== "EACCES" && code !== "EPERM") {
|
|
@@ -11234,7 +11277,7 @@ async function runRemove(opts) {
|
|
|
11234
11277
|
"-delete"
|
|
11235
11278
|
]);
|
|
11236
11279
|
try {
|
|
11237
|
-
await
|
|
11280
|
+
await fs18.rm(containerPath, { recursive: true, force: true });
|
|
11238
11281
|
} catch (err2) {
|
|
11239
11282
|
const code2 = err2.code;
|
|
11240
11283
|
throw new Error(
|
|
@@ -11369,8 +11412,8 @@ var init_remove2 = __esm({
|
|
|
11369
11412
|
});
|
|
11370
11413
|
|
|
11371
11414
|
// src/restore/index.ts
|
|
11372
|
-
import { existsSync as existsSync18, promises as
|
|
11373
|
-
import
|
|
11415
|
+
import { existsSync as existsSync18, promises as fs19 } from "fs";
|
|
11416
|
+
import path30 from "path";
|
|
11374
11417
|
import { consola as consola26 } from "consola";
|
|
11375
11418
|
async function runRestore(opts) {
|
|
11376
11419
|
const home = opts.monocerosHome ?? monocerosHome();
|
|
@@ -11378,15 +11421,15 @@ async function runRestore(opts) {
|
|
|
11378
11421
|
info: (msg) => consola26.info(msg),
|
|
11379
11422
|
success: (msg) => consola26.success(msg)
|
|
11380
11423
|
};
|
|
11381
|
-
const backup =
|
|
11424
|
+
const backup = path30.resolve(opts.backupPath);
|
|
11382
11425
|
if (!existsSync18(backup)) {
|
|
11383
11426
|
throw new Error(`Backup not found: ${backup}.`);
|
|
11384
11427
|
}
|
|
11385
|
-
const stat = await
|
|
11428
|
+
const stat = await fs19.stat(backup);
|
|
11386
11429
|
if (!stat.isDirectory()) {
|
|
11387
11430
|
throw new Error(`Backup path is not a directory: ${backup}.`);
|
|
11388
11431
|
}
|
|
11389
|
-
const entries = await
|
|
11432
|
+
const entries = await fs19.readdir(backup);
|
|
11390
11433
|
const ymlFiles = entries.filter((f) => f.endsWith(".yml"));
|
|
11391
11434
|
if (ymlFiles.length === 0) {
|
|
11392
11435
|
throw new Error(
|
|
@@ -11400,9 +11443,9 @@ async function runRestore(opts) {
|
|
|
11400
11443
|
}
|
|
11401
11444
|
const ymlFile = ymlFiles[0];
|
|
11402
11445
|
const name = ymlFile.replace(/\.yml$/, "");
|
|
11403
|
-
const containerInBackup =
|
|
11446
|
+
const containerInBackup = path30.join(backup, "container");
|
|
11404
11447
|
const hasContainer = existsSync18(containerInBackup);
|
|
11405
|
-
const envInBackup =
|
|
11448
|
+
const envInBackup = path30.join(backup, `${name}.env`);
|
|
11406
11449
|
const hasEnv = existsSync18(envInBackup);
|
|
11407
11450
|
const destYml = containerConfigPath(name, home);
|
|
11408
11451
|
const destContainer = containerDir(name, home);
|
|
@@ -11416,13 +11459,13 @@ async function runRestore(opts) {
|
|
|
11416
11459
|
`Refusing to restore: ${destContainer} already exists. Remove the current container first (\`monoceros remove ${name}\`).`
|
|
11417
11460
|
);
|
|
11418
11461
|
}
|
|
11419
|
-
await
|
|
11420
|
-
await
|
|
11462
|
+
await fs19.mkdir(containerConfigsDir(home), { recursive: true });
|
|
11463
|
+
await fs19.copyFile(path30.join(backup, ymlFile), destYml);
|
|
11421
11464
|
if (hasEnv) {
|
|
11422
|
-
await
|
|
11465
|
+
await fs19.copyFile(envInBackup, containerEnvPath(name, home));
|
|
11423
11466
|
}
|
|
11424
11467
|
if (hasContainer) {
|
|
11425
|
-
await
|
|
11468
|
+
await fs19.cp(containerInBackup, destContainer, { recursive: true });
|
|
11426
11469
|
}
|
|
11427
11470
|
logger.success(`Restored '${name}' from ${prettyPath(backup)}.`);
|
|
11428
11471
|
logger.info(
|
|
@@ -11728,14 +11771,14 @@ var init_remove_service = __esm({
|
|
|
11728
11771
|
|
|
11729
11772
|
// src/devcontainer/claude-trust.ts
|
|
11730
11773
|
import { existsSync as existsSync19, promises as fsp7 } from "fs";
|
|
11731
|
-
import
|
|
11774
|
+
import path31 from "path";
|
|
11732
11775
|
function resolveContainerCwd(name, cwd) {
|
|
11733
11776
|
const workspace = `/workspaces/${name}`;
|
|
11734
11777
|
if (!cwd) return workspace;
|
|
11735
|
-
return
|
|
11778
|
+
return path31.posix.isAbsolute(cwd) ? cwd : path31.posix.join(workspace, cwd);
|
|
11736
11779
|
}
|
|
11737
11780
|
async function preApproveClaudeProject(opts) {
|
|
11738
|
-
const file =
|
|
11781
|
+
const file = path31.join(opts.root, "home", ".claude.json");
|
|
11739
11782
|
if (!existsSync19(file)) return;
|
|
11740
11783
|
try {
|
|
11741
11784
|
const raw = await fsp7.readFile(file, "utf8");
|
|
@@ -11916,34 +11959,6 @@ var init_shell2 = __esm({
|
|
|
11916
11959
|
}
|
|
11917
11960
|
});
|
|
11918
11961
|
|
|
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
11962
|
// src/commands/start.ts
|
|
11948
11963
|
import { defineCommand as defineCommand30 } from "citty";
|
|
11949
11964
|
import { consola as consola35 } from "consola";
|
|
@@ -12076,20 +12091,360 @@ var init_start = __esm({
|
|
|
12076
12091
|
}
|
|
12077
12092
|
});
|
|
12078
12093
|
|
|
12094
|
+
// src/status/index.ts
|
|
12095
|
+
function shortFeatureName2(ref) {
|
|
12096
|
+
const withoutTag = ref.replace(/:[^:/@]+$/, "");
|
|
12097
|
+
const idx = withoutTag.lastIndexOf("/");
|
|
12098
|
+
return idx >= 0 ? withoutTag.slice(idx + 1) : withoutTag;
|
|
12099
|
+
}
|
|
12100
|
+
function cols(line) {
|
|
12101
|
+
return line.split(" ");
|
|
12102
|
+
}
|
|
12103
|
+
function nonEmptyLines(s) {
|
|
12104
|
+
return s.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
12105
|
+
}
|
|
12106
|
+
async function gatherStatus(name, opts = {}) {
|
|
12107
|
+
const docker = opts.docker ?? realDockerLookup;
|
|
12108
|
+
const root = containerDir(name, opts.home);
|
|
12109
|
+
let runtimeVersion;
|
|
12110
|
+
let languages = [];
|
|
12111
|
+
let features = [];
|
|
12112
|
+
let declaredServices = [];
|
|
12113
|
+
let declaredPorts = [];
|
|
12114
|
+
let configured = false;
|
|
12115
|
+
try {
|
|
12116
|
+
const parsed = await readConfig(containerConfigPath(name, opts.home));
|
|
12117
|
+
const createOpts = solutionConfigToCreateOptions(parsed.config);
|
|
12118
|
+
configured = true;
|
|
12119
|
+
runtimeVersion = createOpts.runtimeVersion;
|
|
12120
|
+
languages = createOpts.languages;
|
|
12121
|
+
features = Object.keys(createOpts.features ?? {}).map(shortFeatureName2);
|
|
12122
|
+
declaredServices = createOpts.services.map((s) => ({
|
|
12123
|
+
name: s.name,
|
|
12124
|
+
...typeof s.port === "number" ? { port: s.port } : {}
|
|
12125
|
+
}));
|
|
12126
|
+
declaredPorts = createOpts.ports ?? [];
|
|
12127
|
+
} catch {
|
|
12128
|
+
}
|
|
12129
|
+
let container = {
|
|
12130
|
+
exists: false,
|
|
12131
|
+
running: false,
|
|
12132
|
+
status: "",
|
|
12133
|
+
dockerName: ""
|
|
12134
|
+
};
|
|
12135
|
+
let containerId = "";
|
|
12136
|
+
let composeProject = "";
|
|
12137
|
+
const cps = await docker([
|
|
12138
|
+
"ps",
|
|
12139
|
+
"-a",
|
|
12140
|
+
"--no-trunc",
|
|
12141
|
+
"--filter",
|
|
12142
|
+
`label=devcontainer.local_folder=${root}`,
|
|
12143
|
+
"--format",
|
|
12144
|
+
'{{.ID}} {{.State}} {{.Status}} {{.Names}} {{.Label "com.docker.compose.project"}}'
|
|
12145
|
+
]);
|
|
12146
|
+
const row2 = nonEmptyLines(cps.stdout)[0];
|
|
12147
|
+
if (row2) {
|
|
12148
|
+
const [id, state, status, names, project] = cols(row2);
|
|
12149
|
+
containerId = id ?? "";
|
|
12150
|
+
composeProject = project ?? "";
|
|
12151
|
+
container = {
|
|
12152
|
+
exists: true,
|
|
12153
|
+
running: state === "running",
|
|
12154
|
+
status: status ?? "",
|
|
12155
|
+
dockerName: names ?? ""
|
|
12156
|
+
};
|
|
12157
|
+
}
|
|
12158
|
+
const services = [];
|
|
12159
|
+
if (declaredServices.length > 0) {
|
|
12160
|
+
const live = /* @__PURE__ */ new Map();
|
|
12161
|
+
if (composeProject) {
|
|
12162
|
+
const sps = await docker([
|
|
12163
|
+
"ps",
|
|
12164
|
+
"-a",
|
|
12165
|
+
"--filter",
|
|
12166
|
+
`label=com.docker.compose.project=${composeProject}`,
|
|
12167
|
+
"--format",
|
|
12168
|
+
'{{.Label "com.docker.compose.service"}} {{.State}} {{.Status}}'
|
|
12169
|
+
]);
|
|
12170
|
+
for (const l of nonEmptyLines(sps.stdout)) {
|
|
12171
|
+
const [svc, state, status] = cols(l);
|
|
12172
|
+
if (svc)
|
|
12173
|
+
live.set(svc, { running: state === "running", status: status ?? "" });
|
|
12174
|
+
}
|
|
12175
|
+
}
|
|
12176
|
+
for (const s of declaredServices) {
|
|
12177
|
+
const m = live.get(s.name);
|
|
12178
|
+
services.push({
|
|
12179
|
+
name: s.name,
|
|
12180
|
+
running: m?.running ?? false,
|
|
12181
|
+
status: m?.status ?? "not created",
|
|
12182
|
+
...typeof s.port === "number" ? { port: s.port } : {}
|
|
12183
|
+
});
|
|
12184
|
+
}
|
|
12185
|
+
}
|
|
12186
|
+
const apps = [];
|
|
12187
|
+
for (const app of await listApps(name, opts.home)) {
|
|
12188
|
+
const cfg = await readLaunchConfig(name, app, opts.home);
|
|
12189
|
+
if (!cfg) continue;
|
|
12190
|
+
for (const t of cfg.configurations) {
|
|
12191
|
+
apps.push({
|
|
12192
|
+
app,
|
|
12193
|
+
target: t.name,
|
|
12194
|
+
port: typeof t.port === "number" ? t.port : null,
|
|
12195
|
+
default: t.default === true,
|
|
12196
|
+
running: void 0,
|
|
12197
|
+
pid: null
|
|
12198
|
+
});
|
|
12199
|
+
}
|
|
12200
|
+
}
|
|
12201
|
+
const appsSupported = runtimeSupportsAppStatus(runtimeVersion);
|
|
12202
|
+
let appStateKnown = container.running && appsSupported && containerId !== "";
|
|
12203
|
+
let appStateNote;
|
|
12204
|
+
if (appStateKnown) {
|
|
12205
|
+
const res = await docker([
|
|
12206
|
+
"exec",
|
|
12207
|
+
containerId,
|
|
12208
|
+
"monoceros-ctl",
|
|
12209
|
+
"list",
|
|
12210
|
+
"--json"
|
|
12211
|
+
]);
|
|
12212
|
+
if (res.exitCode === 0) {
|
|
12213
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
12214
|
+
for (const l of nonEmptyLines(res.stdout)) {
|
|
12215
|
+
try {
|
|
12216
|
+
const o = JSON.parse(l);
|
|
12217
|
+
byKey.set(`${o.app}\0${o.target}`, {
|
|
12218
|
+
running: !!o.running,
|
|
12219
|
+
pid: o.pid ?? null
|
|
12220
|
+
});
|
|
12221
|
+
} catch {
|
|
12222
|
+
}
|
|
12223
|
+
}
|
|
12224
|
+
for (const a of apps) {
|
|
12225
|
+
const o = byKey.get(`${a.app}\0${a.target}`);
|
|
12226
|
+
if (o) {
|
|
12227
|
+
a.running = o.running;
|
|
12228
|
+
a.pid = o.pid;
|
|
12229
|
+
} else {
|
|
12230
|
+
a.running = false;
|
|
12231
|
+
}
|
|
12232
|
+
}
|
|
12233
|
+
} else {
|
|
12234
|
+
appStateKnown = false;
|
|
12235
|
+
appStateNote = `could not read run state from the runner - rebuild the runtime image, then \`monoceros upgrade ${name}\``;
|
|
12236
|
+
}
|
|
12237
|
+
}
|
|
12238
|
+
if (apps.length > 0 && !appStateKnown && !appStateNote) {
|
|
12239
|
+
appStateNote = !container.running ? `start the container to see run state (\`monoceros start ${name}\`)` : `run state needs runtime 1.6.0+ (this one: ${runtimeVersion ?? "unpinned"})`;
|
|
12240
|
+
}
|
|
12241
|
+
let hostPort = 80;
|
|
12242
|
+
try {
|
|
12243
|
+
hostPort = proxyHostPort(
|
|
12244
|
+
await readMonocerosConfig({
|
|
12245
|
+
...opts.home ? { monocerosHome: opts.home } : {}
|
|
12246
|
+
})
|
|
12247
|
+
);
|
|
12248
|
+
} catch {
|
|
12249
|
+
}
|
|
12250
|
+
const ports = proxyUrlsFor(name, declaredPorts, hostPort);
|
|
12251
|
+
return {
|
|
12252
|
+
name,
|
|
12253
|
+
configured,
|
|
12254
|
+
container,
|
|
12255
|
+
services,
|
|
12256
|
+
apps,
|
|
12257
|
+
appStateKnown,
|
|
12258
|
+
...appStateNote ? { appStateNote } : {},
|
|
12259
|
+
ports,
|
|
12260
|
+
builtIn: { languages, features }
|
|
12261
|
+
};
|
|
12262
|
+
}
|
|
12263
|
+
function row(p, marker, name, detail, pad, indent = 2) {
|
|
12264
|
+
const gap = Math.max(2, pad - name.length + 2);
|
|
12265
|
+
return `${" ".repeat(indent)}${marker} ${p.cyan(name)}${" ".repeat(gap)}${detail}`;
|
|
12266
|
+
}
|
|
12267
|
+
function liveMarker(p, running) {
|
|
12268
|
+
if (running === void 0) return " ";
|
|
12269
|
+
return running ? p.green("\u2713") : p.dim("\xB7");
|
|
12270
|
+
}
|
|
12271
|
+
function renderContainer(p, m) {
|
|
12272
|
+
const out = [p.sectionLine(m.name)];
|
|
12273
|
+
if (!m.container.exists) {
|
|
12274
|
+
out.push(
|
|
12275
|
+
row(
|
|
12276
|
+
p,
|
|
12277
|
+
p.dim("\xB7"),
|
|
12278
|
+
"(not created)",
|
|
12279
|
+
p.dim(`run \`monoceros apply ${m.name}\``),
|
|
12280
|
+
14
|
|
12281
|
+
)
|
|
12282
|
+
);
|
|
12283
|
+
return out;
|
|
12284
|
+
}
|
|
12285
|
+
const detail = m.container.running ? p.dim(m.container.status || "running") : p.dim(m.container.status || "stopped");
|
|
12286
|
+
out.push(
|
|
12287
|
+
row(
|
|
12288
|
+
p,
|
|
12289
|
+
liveMarker(p, m.container.running),
|
|
12290
|
+
m.container.dockerName,
|
|
12291
|
+
detail,
|
|
12292
|
+
14
|
|
12293
|
+
)
|
|
12294
|
+
);
|
|
12295
|
+
return out;
|
|
12296
|
+
}
|
|
12297
|
+
function renderServices(p, m) {
|
|
12298
|
+
if (m.services.length === 0) return [];
|
|
12299
|
+
const pad = Math.max(...m.services.map((s) => s.name.length));
|
|
12300
|
+
const out = ["", p.sectionLine("Services")];
|
|
12301
|
+
for (const s of m.services) {
|
|
12302
|
+
const detail = s.running ? p.dim(typeof s.port === "number" ? `running :${s.port}` : "running") : p.dim(s.status || "stopped");
|
|
12303
|
+
out.push(row(p, liveMarker(p, s.running), s.name, detail, pad));
|
|
12304
|
+
}
|
|
12305
|
+
return out;
|
|
12306
|
+
}
|
|
12307
|
+
function appTargetDetail(p, name, t) {
|
|
12308
|
+
const bits = [];
|
|
12309
|
+
if (t.running === true) {
|
|
12310
|
+
bits.push(
|
|
12311
|
+
t.port !== null ? p.dim(`http://${name}-${t.port}.localhost`) : p.dim("running")
|
|
12312
|
+
);
|
|
12313
|
+
if (t.pid !== null) bits.push(p.dim(`pid ${t.pid}`));
|
|
12314
|
+
} else if (t.running === false) {
|
|
12315
|
+
bits.push(p.dim("stopped"));
|
|
12316
|
+
}
|
|
12317
|
+
if (t.default) bits.push(p.dim("(default)"));
|
|
12318
|
+
return bits.join(" ");
|
|
12319
|
+
}
|
|
12320
|
+
function renderApps(p, m) {
|
|
12321
|
+
if (m.apps.length === 0) return [];
|
|
12322
|
+
const out = ["", p.sectionLine("Apps")];
|
|
12323
|
+
if (m.appStateNote) out.push(` ${p.dim(m.appStateNote)}`);
|
|
12324
|
+
const byApp = /* @__PURE__ */ new Map();
|
|
12325
|
+
for (const a of m.apps) {
|
|
12326
|
+
const list = byApp.get(a.app) ?? [];
|
|
12327
|
+
list.push(a);
|
|
12328
|
+
byApp.set(a.app, list);
|
|
12329
|
+
}
|
|
12330
|
+
for (const [app, targets] of byApp) {
|
|
12331
|
+
out.push(` ${p.cyan(app)}`);
|
|
12332
|
+
const pad = Math.max(...targets.map((t) => t.target.length));
|
|
12333
|
+
for (const t of targets) {
|
|
12334
|
+
out.push(
|
|
12335
|
+
row(
|
|
12336
|
+
p,
|
|
12337
|
+
liveMarker(p, t.running),
|
|
12338
|
+
t.target,
|
|
12339
|
+
appTargetDetail(p, m.name, t),
|
|
12340
|
+
pad,
|
|
12341
|
+
4
|
|
12342
|
+
)
|
|
12343
|
+
);
|
|
12344
|
+
}
|
|
12345
|
+
}
|
|
12346
|
+
return out;
|
|
12347
|
+
}
|
|
12348
|
+
function renderPorts(p, m) {
|
|
12349
|
+
if (m.ports.length === 0) return [];
|
|
12350
|
+
const pad = Math.max(...m.ports.map((r) => String(r.port).length));
|
|
12351
|
+
const out = ["", p.sectionLine("Ports")];
|
|
12352
|
+
for (const r of m.ports) {
|
|
12353
|
+
const hosts = r.isDefault ? `${m.name}.localhost \xB7 ${m.name}-${r.port}.localhost` : `${m.name}-${r.port}.localhost`;
|
|
12354
|
+
out.push(row(p, " ", String(r.port), p.dim(hosts), pad));
|
|
12355
|
+
}
|
|
12356
|
+
return out;
|
|
12357
|
+
}
|
|
12358
|
+
function renderBuiltIn(p, m) {
|
|
12359
|
+
const lines = [];
|
|
12360
|
+
if (m.builtIn.languages.length > 0)
|
|
12361
|
+
lines.push({ label: "Languages", values: m.builtIn.languages });
|
|
12362
|
+
if (m.builtIn.features.length > 0)
|
|
12363
|
+
lines.push({ label: "Features", values: m.builtIn.features });
|
|
12364
|
+
if (lines.length === 0) return [];
|
|
12365
|
+
const labelWidth = Math.max(...lines.map((l) => l.label.length));
|
|
12366
|
+
const out = ["", `${p.sectionLine("Built in")} ${p.dim("from the yml")}`];
|
|
12367
|
+
for (const l of lines) {
|
|
12368
|
+
out.push(` ${l.label.padEnd(labelWidth)} ${p.cyan(l.values.join(", "))}`);
|
|
12369
|
+
}
|
|
12370
|
+
return out;
|
|
12371
|
+
}
|
|
12372
|
+
function renderStatus(m, p) {
|
|
12373
|
+
return [
|
|
12374
|
+
...renderContainer(p, m),
|
|
12375
|
+
...renderServices(p, m),
|
|
12376
|
+
...renderApps(p, m),
|
|
12377
|
+
...renderPorts(p, m),
|
|
12378
|
+
...renderBuiltIn(p, m)
|
|
12379
|
+
].join("\n");
|
|
12380
|
+
}
|
|
12381
|
+
function renderApp(m, app, p) {
|
|
12382
|
+
const targets = m.apps.filter((a) => a.app === app);
|
|
12383
|
+
if (targets.length === 0) {
|
|
12384
|
+
const known = [...new Set(m.apps.map((a) => a.app))];
|
|
12385
|
+
throw new Error(
|
|
12386
|
+
`No app "${app}" in ${m.name} (have: ${known.join(", ") || "none"}).`
|
|
12387
|
+
);
|
|
12388
|
+
}
|
|
12389
|
+
const out = [p.sectionLine(app)];
|
|
12390
|
+
if (m.appStateNote) out.push(` ${p.dim(m.appStateNote)}`);
|
|
12391
|
+
const pad = Math.max(...targets.map((t) => t.target.length));
|
|
12392
|
+
for (const t of targets) {
|
|
12393
|
+
out.push(
|
|
12394
|
+
row(
|
|
12395
|
+
p,
|
|
12396
|
+
liveMarker(p, t.running),
|
|
12397
|
+
t.target,
|
|
12398
|
+
appTargetDetail(p, m.name, t),
|
|
12399
|
+
pad,
|
|
12400
|
+
2
|
|
12401
|
+
)
|
|
12402
|
+
);
|
|
12403
|
+
}
|
|
12404
|
+
return out.join("\n");
|
|
12405
|
+
}
|
|
12406
|
+
function renderService(m, name, p) {
|
|
12407
|
+
const s = m.services.find((svc) => svc.name === name);
|
|
12408
|
+
if (!s) {
|
|
12409
|
+
throw new Error(
|
|
12410
|
+
`No service "${name}" in ${m.name} (have: ${m.services.map((x) => x.name).join(", ") || "none"}).`
|
|
12411
|
+
);
|
|
12412
|
+
}
|
|
12413
|
+
const detail = s.running ? p.dim(typeof s.port === "number" ? `running :${s.port}` : "running") : p.dim(s.status || "stopped");
|
|
12414
|
+
return [
|
|
12415
|
+
p.sectionLine("Services"),
|
|
12416
|
+
row(p, liveMarker(p, s.running), s.name, detail, s.name.length)
|
|
12417
|
+
].join("\n");
|
|
12418
|
+
}
|
|
12419
|
+
var init_status = __esm({
|
|
12420
|
+
"src/status/index.ts"() {
|
|
12421
|
+
"use strict";
|
|
12422
|
+
init_io();
|
|
12423
|
+
init_paths();
|
|
12424
|
+
init_global();
|
|
12425
|
+
init_transform();
|
|
12426
|
+
init_launch_config();
|
|
12427
|
+
init_catalog();
|
|
12428
|
+
init_locate_running();
|
|
12429
|
+
init_dynamic();
|
|
12430
|
+
init_format();
|
|
12431
|
+
}
|
|
12432
|
+
});
|
|
12433
|
+
|
|
12079
12434
|
// src/commands/status.ts
|
|
12080
12435
|
import { defineCommand as defineCommand31 } from "citty";
|
|
12081
12436
|
var statusCommand;
|
|
12082
|
-
var
|
|
12437
|
+
var init_status2 = __esm({
|
|
12083
12438
|
"src/commands/status.ts"() {
|
|
12084
12439
|
"use strict";
|
|
12085
|
-
|
|
12086
|
-
|
|
12440
|
+
init_status();
|
|
12441
|
+
init_format();
|
|
12087
12442
|
init_dispatch();
|
|
12088
12443
|
statusCommand = defineCommand31({
|
|
12089
12444
|
meta: {
|
|
12090
12445
|
name: "status",
|
|
12091
12446
|
group: "run",
|
|
12092
|
-
description: "Show
|
|
12447
|
+
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
12448
|
},
|
|
12094
12449
|
args: {
|
|
12095
12450
|
name: {
|
|
@@ -12097,18 +12452,29 @@ var init_status = __esm({
|
|
|
12097
12452
|
description: "Container name (yml in $MONOCEROS_HOME/container-configs/).",
|
|
12098
12453
|
required: true
|
|
12099
12454
|
},
|
|
12100
|
-
|
|
12101
|
-
type: "
|
|
12102
|
-
description: "
|
|
12455
|
+
app: {
|
|
12456
|
+
type: "positional",
|
|
12457
|
+
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.",
|
|
12458
|
+
required: false
|
|
12103
12459
|
}
|
|
12104
12460
|
},
|
|
12105
12461
|
run({ args }) {
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
12462
|
+
const filter = typeof args.app === "string" ? args.app : void 0;
|
|
12463
|
+
return dispatch(async () => {
|
|
12464
|
+
const model = await gatherStatus(args.name);
|
|
12465
|
+
const p = colorsFor(process.stdout);
|
|
12466
|
+
let block;
|
|
12467
|
+
if (filter) {
|
|
12468
|
+
const isApp = model.apps.some((a) => a.app === filter);
|
|
12469
|
+
block = isApp ? renderApp(model, filter, p) : renderService(model, filter, p);
|
|
12470
|
+
} else {
|
|
12471
|
+
block = renderStatus(model, p);
|
|
12472
|
+
}
|
|
12473
|
+
process.stdout.write(`
|
|
12474
|
+
${block}
|
|
12475
|
+
`);
|
|
12476
|
+
return 0;
|
|
12477
|
+
});
|
|
12112
12478
|
}
|
|
12113
12479
|
});
|
|
12114
12480
|
}
|
|
@@ -12189,7 +12555,7 @@ var init_stop = __esm({
|
|
|
12189
12555
|
|
|
12190
12556
|
// src/tunnel/resolve.ts
|
|
12191
12557
|
import { existsSync as existsSync20 } from "fs";
|
|
12192
|
-
import
|
|
12558
|
+
import path32 from "path";
|
|
12193
12559
|
async function resolveTunnelTarget(opts) {
|
|
12194
12560
|
const ymlPath = containerConfigPath(opts.name, opts.monocerosHome);
|
|
12195
12561
|
if (!existsSync20(ymlPath)) {
|
|
@@ -12205,7 +12571,7 @@ async function resolveTunnelTarget(opts) {
|
|
|
12205
12571
|
`Container '${opts.name}' is not materialised at ${containerRoot}. Run \`monoceros apply ${opts.name}\` first.`
|
|
12206
12572
|
);
|
|
12207
12573
|
}
|
|
12208
|
-
const composePath =
|
|
12574
|
+
const composePath = path32.join(containerRoot, ".devcontainer", "compose.yaml");
|
|
12209
12575
|
const isCompose = existsSync20(composePath);
|
|
12210
12576
|
const parsedTarget = parseTargetArg(opts.target, config);
|
|
12211
12577
|
const docker = opts.docker ?? defaultDockerExec;
|
|
@@ -12686,7 +13052,7 @@ var init_prune = __esm({
|
|
|
12686
13052
|
});
|
|
12687
13053
|
|
|
12688
13054
|
// src/upgrade/index.ts
|
|
12689
|
-
import { existsSync as existsSync21, promises as
|
|
13055
|
+
import { existsSync as existsSync21, promises as fs20 } from "fs";
|
|
12690
13056
|
import { consola as consola39 } from "consola";
|
|
12691
13057
|
async function fetchRuntimeVersions() {
|
|
12692
13058
|
const tokenUrl = `https://ghcr.io/token?service=ghcr.io&scope=repository:${RUNTIME_REPO}:pull`;
|
|
@@ -12803,10 +13169,10 @@ async function runUpgrade(opts) {
|
|
|
12803
13169
|
for (const name of targets) {
|
|
12804
13170
|
const ymlPath = containerConfigPath(name, home);
|
|
12805
13171
|
if (!existsSync21(ymlPath)) continue;
|
|
12806
|
-
const raw = await
|
|
13172
|
+
const raw = await fs20.readFile(ymlPath, "utf8");
|
|
12807
13173
|
const updated = setRuntimeVersion(raw, pinVersion);
|
|
12808
13174
|
if (updated !== raw) {
|
|
12809
|
-
await
|
|
13175
|
+
await fs20.writeFile(ymlPath, updated);
|
|
12810
13176
|
bumped += 1;
|
|
12811
13177
|
logger.info(`Pinned '${name}' to runtime ${pinVersion}.`);
|
|
12812
13178
|
}
|
|
@@ -12848,7 +13214,7 @@ function formatPruneLine(prune) {
|
|
|
12848
13214
|
}
|
|
12849
13215
|
async function listContainerNames2(home) {
|
|
12850
13216
|
try {
|
|
12851
|
-
const entries = await
|
|
13217
|
+
const entries = await fs20.readdir(containerConfigsDir(home));
|
|
12852
13218
|
return entries.filter((e) => e.endsWith(".yml")).map((e) => e.slice(0, -".yml".length));
|
|
12853
13219
|
} catch {
|
|
12854
13220
|
return [];
|
|
@@ -12956,7 +13322,7 @@ var init_main = __esm({
|
|
|
12956
13322
|
init_run2();
|
|
12957
13323
|
init_shell2();
|
|
12958
13324
|
init_start();
|
|
12959
|
-
|
|
13325
|
+
init_status2();
|
|
12960
13326
|
init_stop();
|
|
12961
13327
|
init_tunnel();
|
|
12962
13328
|
init_upgrade2();
|
|
@@ -13261,25 +13627,25 @@ function detectHelpRequest(argv, main2) {
|
|
|
13261
13627
|
const separatorIdx = argv.indexOf("--");
|
|
13262
13628
|
if (helpIdx === -1) return null;
|
|
13263
13629
|
if (separatorIdx !== -1 && separatorIdx < helpIdx) return null;
|
|
13264
|
-
const
|
|
13630
|
+
const path33 = [];
|
|
13265
13631
|
const tokens = argv.slice(
|
|
13266
13632
|
0,
|
|
13267
13633
|
separatorIdx === -1 ? argv.length : separatorIdx
|
|
13268
13634
|
);
|
|
13269
13635
|
let cursor = main2;
|
|
13270
13636
|
const mainName = (main2.meta ?? {}).name ?? "monoceros";
|
|
13271
|
-
|
|
13637
|
+
path33.push(mainName);
|
|
13272
13638
|
for (const tok of tokens) {
|
|
13273
13639
|
if (tok.startsWith("-")) continue;
|
|
13274
13640
|
const subs = cursor.subCommands ?? {};
|
|
13275
13641
|
if (tok in subs) {
|
|
13276
13642
|
cursor = subs[tok];
|
|
13277
|
-
|
|
13643
|
+
path33.push(tok);
|
|
13278
13644
|
continue;
|
|
13279
13645
|
}
|
|
13280
13646
|
break;
|
|
13281
13647
|
}
|
|
13282
|
-
return { path:
|
|
13648
|
+
return { path: path33, cmd: cursor };
|
|
13283
13649
|
}
|
|
13284
13650
|
async function maybeRenderHelp(argv, main2) {
|
|
13285
13651
|
const hit = detectHelpRequest(argv, main2);
|