@getmonoceros/workbench 1.17.1 → 1.18.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 CHANGED
@@ -3216,8 +3216,8 @@ function removeRepoFromDoc(doc, urlOrPath) {
3216
3216
  if (!isMap2(item)) return false;
3217
3217
  const url = item.get("url");
3218
3218
  if (url === urlOrPath) return true;
3219
- const path22 = item.get("path");
3220
- const effectivePath = typeof path22 === "string" ? path22 : typeof url === "string" ? deriveRepoName(url) : void 0;
3219
+ const path23 = item.get("path");
3220
+ const effectivePath = typeof path23 === "string" ? path23 : typeof url === "string" ? deriveRepoName(url) : void 0;
3221
3221
  return effectivePath === urlOrPath;
3222
3222
  });
3223
3223
  if (idx < 0) return false;
@@ -3329,7 +3329,7 @@ async function runAddRepo(input) {
3329
3329
  "Missing repo URL. Usage: monoceros add-repo <containername> <url>."
3330
3330
  );
3331
3331
  }
3332
- const path22 = (input.path ?? deriveRepoName(url)).trim();
3332
+ const path23 = (input.path ?? deriveRepoName(url)).trim();
3333
3333
  const hasName = typeof input.gitName === "string" && input.gitName.trim().length > 0;
3334
3334
  const hasEmail = typeof input.gitEmail === "string" && input.gitEmail.trim().length > 0;
3335
3335
  if (hasName !== hasEmail) {
@@ -3366,7 +3366,7 @@ async function runAddRepo(input) {
3366
3366
  const providerToWrite = !canonical && explicitProvider ? explicitProvider : void 0;
3367
3367
  const entry2 = {
3368
3368
  url,
3369
- path: path22,
3369
+ path: path23,
3370
3370
  ...hasName && hasEmail ? {
3371
3371
  gitUser: {
3372
3372
  name: input.gitName.trim(),
@@ -6293,7 +6293,7 @@ var CLI_VERSION;
6293
6293
  var init_version = __esm({
6294
6294
  "src/version.ts"() {
6295
6295
  "use strict";
6296
- CLI_VERSION = true ? "1.17.1" : "dev";
6296
+ CLI_VERSION = true ? "1.18.0" : "dev";
6297
6297
  }
6298
6298
  });
6299
6299
 
@@ -6482,6 +6482,43 @@ var init_completion = __esm({
6482
6482
  }
6483
6483
  });
6484
6484
 
6485
+ // src/login/services.ts
6486
+ function featureLeaf(ref) {
6487
+ const noTag = ref.replace(/:[^/:]*$/, "");
6488
+ return noTag.slice(noTag.lastIndexOf("/") + 1);
6489
+ }
6490
+ function loginCapableServices(refs) {
6491
+ const out = [];
6492
+ for (const ref of refs) {
6493
+ const service = LOGIN_SERVICE_BY_LEAF[featureLeaf(ref)];
6494
+ if (service && !out.includes(service)) out.push(service);
6495
+ }
6496
+ return out;
6497
+ }
6498
+ function parseCallbackTarget(authUrl) {
6499
+ try {
6500
+ const u = new URL(authUrl);
6501
+ const redirect = u.searchParams.get("redirect_uri");
6502
+ if (!redirect) return null;
6503
+ const r = new URL(redirect);
6504
+ if (r.hostname !== "localhost" && r.hostname !== "127.0.0.1") return null;
6505
+ const port = Number(r.port);
6506
+ if (!Number.isInteger(port) || port <= 0) return null;
6507
+ return { port, pathname: r.pathname };
6508
+ } catch {
6509
+ return null;
6510
+ }
6511
+ }
6512
+ var LOGIN_SERVICE_BY_LEAF;
6513
+ var init_services = __esm({
6514
+ "src/login/services.ts"() {
6515
+ "use strict";
6516
+ LOGIN_SERVICE_BY_LEAF = {
6517
+ "claude-code": "claude"
6518
+ };
6519
+ }
6520
+ });
6521
+
6485
6522
  // src/completion/resolve.ts
6486
6523
  import { existsSync as existsSync8, promises as fs13 } from "fs";
6487
6524
  import path16 from "path";
@@ -6638,6 +6675,20 @@ async function listContainerNames(ctx) {
6638
6675
  const entries = await fs13.readdir(dir);
6639
6676
  return entries.filter((e) => e.endsWith(".yml")).map((e) => e.slice(0, -".yml".length)).sort();
6640
6677
  }
6678
+ async function listLoginServices(ctx) {
6679
+ const after = ctx.prev.slice(2);
6680
+ const name = after.find((t) => !t.startsWith("-"));
6681
+ if (!name) return [];
6682
+ const home = ctx.opts.monocerosHome ?? monocerosHome();
6683
+ const cfgPath = path16.join(home, "container-configs", `${name}.yml`);
6684
+ if (!existsSync8(cfgPath)) return [];
6685
+ try {
6686
+ const { config } = await readConfig(cfgPath);
6687
+ return loginCapableServices(config.features.map((f) => f.ref));
6688
+ } catch {
6689
+ return [];
6690
+ }
6691
+ }
6641
6692
  async function listFeatureComponents() {
6642
6693
  const catalog = await loadComponentCatalog();
6643
6694
  return [...catalog.values()].filter((c) => c.file.category === "feature").map((c) => c.name).sort();
@@ -6705,15 +6756,18 @@ var init_resolve = __esm({
6705
6756
  "src/completion/resolve.ts"() {
6706
6757
  "use strict";
6707
6758
  init_paths();
6759
+ init_io();
6708
6760
  init_components();
6709
6761
  init_manifest();
6710
6762
  init_catalog();
6763
+ init_services();
6711
6764
  init_schema();
6712
6765
  ALL_COMMANDS = [
6713
6766
  "init",
6714
6767
  "list-components",
6715
6768
  "shell",
6716
6769
  "run",
6770
+ "login",
6717
6771
  "logs",
6718
6772
  "start",
6719
6773
  "stop",
@@ -6782,6 +6836,7 @@ var init_resolve = __esm({
6782
6836
  positionals: [containerName],
6783
6837
  flags: { "--in": { type: "value" } }
6784
6838
  },
6839
+ login: { positionals: [containerName, (ctx) => listLoginServices(ctx)] },
6785
6840
  logs: { positionals: [containerName] },
6786
6841
  start: { positionals: [containerName] },
6787
6842
  stop: { positionals: [containerName] },
@@ -7754,8 +7809,262 @@ var init_list_components = __esm({
7754
7809
  }
7755
7810
  });
7756
7811
 
7757
- // src/commands/logs.ts
7812
+ // src/devcontainer/shell.ts
7813
+ import { existsSync as existsSync10 } from "fs";
7814
+ import path18 from "path";
7815
+ async function runShell(opts) {
7816
+ assertContainerExists(opts.root);
7817
+ const spawnFn = opts.spawn ?? spawnDevcontainer;
7818
+ const upCode = await spawnFn(
7819
+ ["up", "--workspace-folder", opts.root, "--mount-workspace-git-root=false"],
7820
+ opts.root,
7821
+ { quiet: true }
7822
+ );
7823
+ if (upCode !== 0) return upCode;
7824
+ return spawnFn(
7825
+ [
7826
+ "exec",
7827
+ "--workspace-folder",
7828
+ opts.root,
7829
+ "--mount-workspace-git-root=false",
7830
+ "bash"
7831
+ ],
7832
+ opts.root,
7833
+ { interactive: true }
7834
+ );
7835
+ }
7836
+ function assertContainerExists(root) {
7837
+ if (!existsSync10(path18.join(root, ".devcontainer"))) {
7838
+ throw new Error(
7839
+ `No .devcontainer/ at ${root}. Run \`monoceros apply <name>\` first.`
7840
+ );
7841
+ }
7842
+ }
7843
+ var init_shell = __esm({
7844
+ "src/devcontainer/shell.ts"() {
7845
+ "use strict";
7846
+ init_cli();
7847
+ }
7848
+ });
7849
+
7850
+ // src/login/index.ts
7851
+ import { spawn as spawn8 } from "child_process";
7852
+ import { existsSync as existsSync11, promises as fsp2, readFileSync as readFileSync6 } from "fs";
7853
+ import http from "http";
7854
+ import path19 from "path";
7855
+ import { consola as consola16 } from "consola";
7856
+ function openInBrowser(url) {
7857
+ const platform = process.platform;
7858
+ const [cmd, args] = platform === "darwin" ? ["open", [url]] : platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
7859
+ try {
7860
+ const child = spawn8(cmd, args, {
7861
+ stdio: "ignore",
7862
+ detached: true
7863
+ });
7864
+ child.on("error", () => {
7865
+ });
7866
+ child.unref();
7867
+ } catch {
7868
+ }
7869
+ }
7870
+ async function runLogin(opts) {
7871
+ const root = containerDir(opts.name);
7872
+ assertContainerExists(root);
7873
+ const { config } = await readConfig(containerConfigPath(opts.name));
7874
+ const capable = loginCapableServices(config.features.map((f) => f.ref));
7875
+ if (capable.length === 0) {
7876
+ consola16.error(
7877
+ `Container "${opts.name}" has no tool with a Monoceros login. (Supported today: claude.)`
7878
+ );
7879
+ return 1;
7880
+ }
7881
+ if (!opts.feature) {
7882
+ consola16.info(
7883
+ `Login-capable tools in "${opts.name}": ${capable.join(", ")}.`
7884
+ );
7885
+ consola16.info(`Log one in with: monoceros login ${opts.name} <tool>`);
7886
+ return 0;
7887
+ }
7888
+ const service = opts.feature;
7889
+ if (!capable.includes(service)) {
7890
+ consola16.error(
7891
+ `"${service}" is not a login-capable tool in "${opts.name}". Available: ${capable.join(", ")}.`
7892
+ );
7893
+ return 1;
7894
+ }
7895
+ if (service !== "claude") {
7896
+ consola16.error(
7897
+ `Login for "${service}" is not implemented yet (only claude).`
7898
+ );
7899
+ return 1;
7900
+ }
7901
+ return runClaudeLogin(opts.name, root, opts.spawn ?? spawnDevcontainer);
7902
+ }
7903
+ async function runClaudeLogin(name, root, spawnFn) {
7904
+ const credFile = path19.join(root, "home", ".claude", ".credentials.json");
7905
+ if (existsSync11(credFile)) {
7906
+ consola16.success(
7907
+ `Claude is already logged in for "${name}". Re-apply or remove the credential to log in again.`
7908
+ );
7909
+ return 0;
7910
+ }
7911
+ const upCode = await spawnFn(
7912
+ ["up", "--workspace-folder", root, "--mount-workspace-git-root=false"],
7913
+ root,
7914
+ { quiet: true }
7915
+ );
7916
+ if (upCode !== 0) return upCode;
7917
+ const relayDir = path19.join(root, RELAY_DIRNAME);
7918
+ const relayScript = path19.join(relayDir, "xdg-open");
7919
+ const urlFile = path19.join(relayDir, "url");
7920
+ await fsp2.mkdir(relayDir, { recursive: true });
7921
+ await fsp2.rm(urlFile, { force: true });
7922
+ await fsp2.writeFile(
7923
+ relayScript,
7924
+ `#!/bin/sh
7925
+ printf '%s\\n' "$1" > "$(dirname "$0")/url"
7926
+ exit 0
7927
+ `,
7928
+ { mode: 493 }
7929
+ );
7930
+ await fsp2.chmod(relayScript, 493);
7931
+ const servers = [];
7932
+ let handledUrl = false;
7933
+ const onAuthUrl = (authUrl) => {
7934
+ consola16.info("Opening the Claude sign-in page in your browser\u2026");
7935
+ openInBrowser(authUrl);
7936
+ const target = parseCallbackTarget(authUrl);
7937
+ if (!target) {
7938
+ return;
7939
+ }
7940
+ const server = http.createServer((req, res) => {
7941
+ const reqUrl = req.url ?? target.pathname;
7942
+ res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
7943
+ res.end(
7944
+ '<html><body style="font-family:sans-serif;padding:3rem">You are signed in. You can close this tab and return to the terminal.</body></html>'
7945
+ );
7946
+ void spawnFn(
7947
+ [
7948
+ "exec",
7949
+ "--workspace-folder",
7950
+ root,
7951
+ "--mount-workspace-git-root=false",
7952
+ "curl",
7953
+ "-fsS",
7954
+ `http://localhost:${target.port}${reqUrl}`
7955
+ ],
7956
+ root,
7957
+ { quiet: true }
7958
+ );
7959
+ });
7960
+ server.on("error", (err) => {
7961
+ consola16.warn(
7962
+ `Could not start the local callback helper on port ${target.port} (${err.message}). If the browser shows a code, paste it into the terminal instead.`
7963
+ );
7964
+ });
7965
+ server.listen(target.port, "127.0.0.1");
7966
+ servers.push(server);
7967
+ };
7968
+ const poll = setInterval(() => {
7969
+ if (handledUrl || !existsSync11(urlFile)) return;
7970
+ let content = "";
7971
+ try {
7972
+ content = readFileSync6(urlFile, "utf8");
7973
+ } catch {
7974
+ return;
7975
+ }
7976
+ if (!content.trim()) return;
7977
+ handledUrl = true;
7978
+ onAuthUrl(content.trim());
7979
+ }, 250);
7980
+ consola16.info(
7981
+ "Starting Claude login. Pick your account in Claude's menu \u2014 the browser opens for you, no copying."
7982
+ );
7983
+ const child = spawn8(
7984
+ process.execPath,
7985
+ [
7986
+ devcontainerCliPath(),
7987
+ "exec",
7988
+ "--workspace-folder",
7989
+ root,
7990
+ "--mount-workspace-git-root=false",
7991
+ "bash",
7992
+ "-lc",
7993
+ `export PATH="/workspaces/${name}/${RELAY_DIRNAME}:$PATH"; exec claude`
7994
+ ],
7995
+ { cwd: root, stdio: "inherit" }
7996
+ );
7997
+ const code = await new Promise((resolve) => {
7998
+ child.on("error", () => resolve(1));
7999
+ child.on("exit", (c) => resolve(c ?? 0));
8000
+ });
8001
+ clearInterval(poll);
8002
+ for (const s of servers) s.close();
8003
+ await fsp2.rm(relayDir, { recursive: true, force: true });
8004
+ if (existsSync11(credFile)) {
8005
+ consola16.success(
8006
+ `Claude is logged in for "${name}". The credential persists across rebuilds.`
8007
+ );
8008
+ }
8009
+ return code;
8010
+ }
8011
+ var RELAY_DIRNAME;
8012
+ var init_login = __esm({
8013
+ "src/login/index.ts"() {
8014
+ "use strict";
8015
+ init_io();
8016
+ init_paths();
8017
+ init_cli();
8018
+ init_shell();
8019
+ init_services();
8020
+ RELAY_DIRNAME = ".monoceros-login";
8021
+ }
8022
+ });
8023
+
8024
+ // src/commands/login.ts
7758
8025
  import { defineCommand as defineCommand13 } from "citty";
8026
+ import { consola as consola17 } from "consola";
8027
+ var loginCommand;
8028
+ var init_login2 = __esm({
8029
+ "src/commands/login.ts"() {
8030
+ "use strict";
8031
+ init_login();
8032
+ loginCommand = defineCommand13({
8033
+ meta: {
8034
+ name: "login",
8035
+ group: "lifecycle",
8036
+ description: "Log a curated tool in inside the container. Opens the sign-in page in your browser for you \u2014 no copying URLs. Today: Claude."
8037
+ },
8038
+ args: {
8039
+ name: {
8040
+ type: "positional",
8041
+ description: "Container name.",
8042
+ required: true
8043
+ },
8044
+ feature: {
8045
+ type: "positional",
8046
+ description: "Which tool to log in (e.g. `claude`). Optional when the container has only one login-capable tool.",
8047
+ required: false
8048
+ }
8049
+ },
8050
+ async run({ args }) {
8051
+ try {
8052
+ const code = await runLogin({
8053
+ name: args.name,
8054
+ ...args.feature ? { feature: args.feature } : {}
8055
+ });
8056
+ process.exit(code);
8057
+ } catch (err) {
8058
+ consola17.error(err instanceof Error ? err.message : String(err));
8059
+ process.exit(1);
8060
+ }
8061
+ }
8062
+ });
8063
+ }
8064
+ });
8065
+
8066
+ // src/commands/logs.ts
8067
+ import { defineCommand as defineCommand14 } from "citty";
7759
8068
  var logsCommand;
7760
8069
  var init_logs = __esm({
7761
8070
  "src/commands/logs.ts"() {
@@ -7763,7 +8072,7 @@ var init_logs = __esm({
7763
8072
  init_paths();
7764
8073
  init_compose();
7765
8074
  init_dispatch();
7766
- logsCommand = defineCommand13({
8075
+ logsCommand = defineCommand14({
7767
8076
  meta: {
7768
8077
  name: "logs",
7769
8078
  group: "run",
@@ -7800,11 +8109,11 @@ var init_logs = __esm({
7800
8109
  });
7801
8110
 
7802
8111
  // src/commands/port.ts
7803
- import { defineCommand as defineCommand14 } from "citty";
7804
- import { consola as consola16 } from "consola";
8112
+ import { defineCommand as defineCommand15 } from "citty";
8113
+ import { consola as consola18 } from "consola";
7805
8114
  async function runPortListing(opts) {
7806
8115
  const out = opts.out ?? process.stdout;
7807
- const info = opts.info ?? ((m) => consola16.info(m));
8116
+ const info = opts.info ?? ((m) => consola18.info(m));
7808
8117
  const parsed = await readConfig(
7809
8118
  containerConfigPath(opts.name, opts.monocerosHome)
7810
8119
  );
@@ -7862,7 +8171,7 @@ var init_port = __esm({
7862
8171
  init_schema();
7863
8172
  init_dynamic();
7864
8173
  init_format();
7865
- portCommand = defineCommand14({
8174
+ portCommand = defineCommand15({
7866
8175
  meta: {
7867
8176
  name: "port",
7868
8177
  group: "discovery",
@@ -7880,7 +8189,7 @@ var init_port = __esm({
7880
8189
  const code = await runPortListing({ name: args.name });
7881
8190
  process.exit(code);
7882
8191
  } catch (err) {
7883
- consola16.error(err instanceof Error ? err.message : String(err));
8192
+ consola18.error(err instanceof Error ? err.message : String(err));
7884
8193
  process.exit(1);
7885
8194
  }
7886
8195
  }
@@ -7889,15 +8198,15 @@ var init_port = __esm({
7889
8198
  });
7890
8199
 
7891
8200
  // src/commands/remove-apt-packages.ts
7892
- import { defineCommand as defineCommand15 } from "citty";
7893
- import { consola as consola17 } from "consola";
8201
+ import { defineCommand as defineCommand16 } from "citty";
8202
+ import { consola as consola19 } from "consola";
7894
8203
  var removeAptPackagesCommand;
7895
8204
  var init_remove_apt_packages = __esm({
7896
8205
  "src/commands/remove-apt-packages.ts"() {
7897
8206
  "use strict";
7898
8207
  init_inner_args();
7899
8208
  init_modify();
7900
- removeAptPackagesCommand = defineCommand15({
8209
+ removeAptPackagesCommand = defineCommand16({
7901
8210
  meta: {
7902
8211
  name: "remove-apt-packages",
7903
8212
  group: "edit",
@@ -7919,7 +8228,7 @@ var init_remove_apt_packages = __esm({
7919
8228
  async run({ args }) {
7920
8229
  const packages = [...getInnerArgs()];
7921
8230
  if (packages.length === 0) {
7922
- consola17.error(
8231
+ consola19.error(
7923
8232
  "No package names given. Usage: `monoceros remove-apt-packages <containername> [--yes] -- <pkg> [<pkg> \u2026]`."
7924
8233
  );
7925
8234
  process.exit(1);
@@ -7932,7 +8241,7 @@ var init_remove_apt_packages = __esm({
7932
8241
  });
7933
8242
  process.exit(result.status === "aborted" ? 1 : 0);
7934
8243
  } catch (err) {
7935
- consola17.error(err instanceof Error ? err.message : String(err));
8244
+ consola19.error(err instanceof Error ? err.message : String(err));
7936
8245
  process.exit(1);
7937
8246
  }
7938
8247
  }
@@ -7941,14 +8250,14 @@ var init_remove_apt_packages = __esm({
7941
8250
  });
7942
8251
 
7943
8252
  // src/commands/remove-feature.ts
7944
- import { defineCommand as defineCommand16 } from "citty";
7945
- import { consola as consola18 } from "consola";
8253
+ import { defineCommand as defineCommand17 } from "citty";
8254
+ import { consola as consola20 } from "consola";
7946
8255
  var removeFeatureCommand;
7947
8256
  var init_remove_feature = __esm({
7948
8257
  "src/commands/remove-feature.ts"() {
7949
8258
  "use strict";
7950
8259
  init_modify();
7951
- removeFeatureCommand = defineCommand16({
8260
+ removeFeatureCommand = defineCommand17({
7952
8261
  meta: {
7953
8262
  name: "remove-feature",
7954
8263
  group: "edit",
@@ -7981,7 +8290,7 @@ var init_remove_feature = __esm({
7981
8290
  });
7982
8291
  process.exit(result.status === "aborted" ? 1 : 0);
7983
8292
  } catch (err) {
7984
- consola18.error(err instanceof Error ? err.message : String(err));
8293
+ consola20.error(err instanceof Error ? err.message : String(err));
7985
8294
  process.exit(1);
7986
8295
  }
7987
8296
  }
@@ -7990,15 +8299,15 @@ var init_remove_feature = __esm({
7990
8299
  });
7991
8300
 
7992
8301
  // src/remove/index.ts
7993
- import { existsSync as existsSync10, promises as fs15 } from "fs";
7994
- import path18 from "path";
7995
- import { consola as consola19 } from "consola";
8302
+ import { existsSync as existsSync12, promises as fs15 } from "fs";
8303
+ import path20 from "path";
8304
+ import { consola as consola21 } from "consola";
7996
8305
  async function runRemove(opts) {
7997
8306
  const home = opts.monocerosHome ?? monocerosHome();
7998
8307
  const logger = opts.logger ?? {
7999
- info: (msg) => consola19.info(msg),
8000
- success: (msg) => consola19.success(msg),
8001
- warn: (msg) => consola19.warn(msg)
8308
+ info: (msg) => consola21.info(msg),
8309
+ success: (msg) => consola21.success(msg),
8310
+ warn: (msg) => consola21.warn(msg)
8002
8311
  };
8003
8312
  if (!REGEX.solutionName.test(opts.name)) {
8004
8313
  throw new Error(
@@ -8008,9 +8317,9 @@ async function runRemove(opts) {
8008
8317
  const ymlPath = containerConfigPath(opts.name, home);
8009
8318
  const envPath = containerEnvPath(opts.name, home);
8010
8319
  const containerPath = containerDir(opts.name, home);
8011
- const hasYml = existsSync10(ymlPath);
8012
- const hasEnv = existsSync10(envPath);
8013
- const hasContainer = existsSync10(containerPath);
8320
+ const hasYml = existsSync12(ymlPath);
8321
+ const hasEnv = existsSync12(envPath);
8322
+ const hasContainer = existsSync12(containerPath);
8014
8323
  if (!hasYml && !hasContainer) {
8015
8324
  throw new Error(
8016
8325
  `Nothing to remove for '${opts.name}': neither ${ymlPath} nor ${containerPath} exists.`
@@ -8036,16 +8345,16 @@ async function runRemove(opts) {
8036
8345
  let backupPath = null;
8037
8346
  if (!opts.noBackup && (hasYml || hasContainer)) {
8038
8347
  const ts = (opts.now ?? /* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8039
- backupPath = path18.join(home, "container-backups", `${opts.name}-${ts}`);
8348
+ backupPath = path20.join(home, "container-backups", `${opts.name}-${ts}`);
8040
8349
  await fs15.mkdir(backupPath, { recursive: true });
8041
8350
  if (hasYml) {
8042
- await fs15.copyFile(ymlPath, path18.join(backupPath, `${opts.name}.yml`));
8351
+ await fs15.copyFile(ymlPath, path20.join(backupPath, `${opts.name}.yml`));
8043
8352
  }
8044
8353
  if (hasEnv) {
8045
- await fs15.copyFile(envPath, path18.join(backupPath, `${opts.name}.env`));
8354
+ await fs15.copyFile(envPath, path20.join(backupPath, `${opts.name}.env`));
8046
8355
  }
8047
8356
  if (hasContainer) {
8048
- await fs15.cp(containerPath, path18.join(backupPath, "container"), {
8357
+ await fs15.cp(containerPath, path20.join(backupPath, "container"), {
8049
8358
  recursive: true
8050
8359
  });
8051
8360
  }
@@ -8134,15 +8443,15 @@ var init_remove = __esm({
8134
8443
  });
8135
8444
 
8136
8445
  // src/commands/remove.ts
8137
- import { defineCommand as defineCommand17 } from "citty";
8138
- import { consola as consola20 } from "consola";
8446
+ import { defineCommand as defineCommand18 } from "citty";
8447
+ import { consola as consola22 } from "consola";
8139
8448
  import { createInterface } from "readline/promises";
8140
8449
  var removeCommand;
8141
8450
  var init_remove2 = __esm({
8142
8451
  "src/commands/remove.ts"() {
8143
8452
  "use strict";
8144
8453
  init_remove();
8145
- removeCommand = defineCommand17({
8454
+ removeCommand = defineCommand18({
8146
8455
  meta: {
8147
8456
  name: "remove",
8148
8457
  group: "lifecycle",
@@ -8179,7 +8488,7 @@ var init_remove2 = __esm({
8179
8488
  const skipPrompt = args.yes === true;
8180
8489
  if (!skipPrompt) {
8181
8490
  const warning = noBackup ? `About to remove '${args.name}' WITHOUT a backup. Docker objects, container-configs entry, and container directory will all be deleted.` : `About to remove '${args.name}'. A backup will be written to container-backups/ first, then docker objects, container-configs entry, and container directory will all be deleted.`;
8182
- consola20.warn(warning);
8491
+ consola22.warn(warning);
8183
8492
  const rl = createInterface({
8184
8493
  input: process.stdin,
8185
8494
  output: process.stdout
@@ -8187,7 +8496,7 @@ var init_remove2 = __esm({
8187
8496
  const answer = await rl.question("Continue? [y/N] ");
8188
8497
  rl.close();
8189
8498
  if (!/^y(es)?$/i.test(answer.trim())) {
8190
- consola20.info("Aborted. Nothing changed.");
8499
+ consola22.info("Aborted. Nothing changed.");
8191
8500
  process.exit(0);
8192
8501
  }
8193
8502
  }
@@ -8196,7 +8505,7 @@ var init_remove2 = __esm({
8196
8505
  ...noBackup ? { noBackup: true } : {}
8197
8506
  });
8198
8507
  } catch (err) {
8199
- consola20.error(err instanceof Error ? err.message : String(err));
8508
+ consola22.error(err instanceof Error ? err.message : String(err));
8200
8509
  process.exit(1);
8201
8510
  }
8202
8511
  }
@@ -8205,17 +8514,17 @@ var init_remove2 = __esm({
8205
8514
  });
8206
8515
 
8207
8516
  // src/restore/index.ts
8208
- import { existsSync as existsSync11, promises as fs16 } from "fs";
8209
- import path19 from "path";
8210
- import { consola as consola21 } from "consola";
8517
+ import { existsSync as existsSync13, promises as fs16 } from "fs";
8518
+ import path21 from "path";
8519
+ import { consola as consola23 } from "consola";
8211
8520
  async function runRestore(opts) {
8212
8521
  const home = opts.monocerosHome ?? monocerosHome();
8213
8522
  const logger = opts.logger ?? {
8214
- info: (msg) => consola21.info(msg),
8215
- success: (msg) => consola21.success(msg)
8523
+ info: (msg) => consola23.info(msg),
8524
+ success: (msg) => consola23.success(msg)
8216
8525
  };
8217
- const backup = path19.resolve(opts.backupPath);
8218
- if (!existsSync11(backup)) {
8526
+ const backup = path21.resolve(opts.backupPath);
8527
+ if (!existsSync13(backup)) {
8219
8528
  throw new Error(`Backup not found: ${backup}.`);
8220
8529
  }
8221
8530
  const stat = await fs16.stat(backup);
@@ -8236,24 +8545,24 @@ async function runRestore(opts) {
8236
8545
  }
8237
8546
  const ymlFile = ymlFiles[0];
8238
8547
  const name = ymlFile.replace(/\.yml$/, "");
8239
- const containerInBackup = path19.join(backup, "container");
8240
- const hasContainer = existsSync11(containerInBackup);
8241
- const envInBackup = path19.join(backup, `${name}.env`);
8242
- const hasEnv = existsSync11(envInBackup);
8548
+ const containerInBackup = path21.join(backup, "container");
8549
+ const hasContainer = existsSync13(containerInBackup);
8550
+ const envInBackup = path21.join(backup, `${name}.env`);
8551
+ const hasEnv = existsSync13(envInBackup);
8243
8552
  const destYml = containerConfigPath(name, home);
8244
8553
  const destContainer = containerDir(name, home);
8245
- if (existsSync11(destYml)) {
8554
+ if (existsSync13(destYml)) {
8246
8555
  throw new Error(
8247
8556
  `Refusing to restore: ${destYml} already exists. Remove the current container first (\`monoceros remove ${name}\`) or rename the existing config.`
8248
8557
  );
8249
8558
  }
8250
- if (hasContainer && existsSync11(destContainer)) {
8559
+ if (hasContainer && existsSync13(destContainer)) {
8251
8560
  throw new Error(
8252
8561
  `Refusing to restore: ${destContainer} already exists. Remove the current container first (\`monoceros remove ${name}\`).`
8253
8562
  );
8254
8563
  }
8255
8564
  await fs16.mkdir(containerConfigsDir(home), { recursive: true });
8256
- await fs16.copyFile(path19.join(backup, ymlFile), destYml);
8565
+ await fs16.copyFile(path21.join(backup, ymlFile), destYml);
8257
8566
  if (hasEnv) {
8258
8567
  await fs16.copyFile(envInBackup, containerEnvPath(name, home));
8259
8568
  }
@@ -8278,14 +8587,14 @@ var init_restore = __esm({
8278
8587
  });
8279
8588
 
8280
8589
  // src/commands/restore.ts
8281
- import { defineCommand as defineCommand18 } from "citty";
8282
- import { consola as consola22 } from "consola";
8590
+ import { defineCommand as defineCommand19 } from "citty";
8591
+ import { consola as consola24 } from "consola";
8283
8592
  var restoreCommand;
8284
8593
  var init_restore2 = __esm({
8285
8594
  "src/commands/restore.ts"() {
8286
8595
  "use strict";
8287
8596
  init_restore();
8288
- restoreCommand = defineCommand18({
8597
+ restoreCommand = defineCommand19({
8289
8598
  meta: {
8290
8599
  name: "restore",
8291
8600
  group: "lifecycle",
@@ -8302,7 +8611,7 @@ var init_restore2 = __esm({
8302
8611
  try {
8303
8612
  await runRestore({ backupPath: args["backup-path"] });
8304
8613
  } catch (err) {
8305
- consola22.error(err instanceof Error ? err.message : String(err));
8614
+ consola24.error(err instanceof Error ? err.message : String(err));
8306
8615
  process.exit(1);
8307
8616
  }
8308
8617
  }
@@ -8311,14 +8620,14 @@ var init_restore2 = __esm({
8311
8620
  });
8312
8621
 
8313
8622
  // src/commands/remove-from-url.ts
8314
- import { defineCommand as defineCommand19 } from "citty";
8315
- import { consola as consola23 } from "consola";
8623
+ import { defineCommand as defineCommand20 } from "citty";
8624
+ import { consola as consola25 } from "consola";
8316
8625
  var removeFromUrlCommand;
8317
8626
  var init_remove_from_url = __esm({
8318
8627
  "src/commands/remove-from-url.ts"() {
8319
8628
  "use strict";
8320
8629
  init_modify();
8321
- removeFromUrlCommand = defineCommand19({
8630
+ removeFromUrlCommand = defineCommand20({
8322
8631
  meta: {
8323
8632
  name: "remove-from-url",
8324
8633
  group: "edit",
@@ -8351,7 +8660,7 @@ var init_remove_from_url = __esm({
8351
8660
  });
8352
8661
  process.exit(result.status === "aborted" ? 1 : 0);
8353
8662
  } catch (err) {
8354
- consola23.error(err instanceof Error ? err.message : String(err));
8663
+ consola25.error(err instanceof Error ? err.message : String(err));
8355
8664
  process.exit(1);
8356
8665
  }
8357
8666
  }
@@ -8360,14 +8669,14 @@ var init_remove_from_url = __esm({
8360
8669
  });
8361
8670
 
8362
8671
  // src/commands/remove-language.ts
8363
- import { defineCommand as defineCommand20 } from "citty";
8364
- import { consola as consola24 } from "consola";
8672
+ import { defineCommand as defineCommand21 } from "citty";
8673
+ import { consola as consola26 } from "consola";
8365
8674
  var removeLanguageCommand;
8366
8675
  var init_remove_language = __esm({
8367
8676
  "src/commands/remove-language.ts"() {
8368
8677
  "use strict";
8369
8678
  init_modify();
8370
- removeLanguageCommand = defineCommand20({
8679
+ removeLanguageCommand = defineCommand21({
8371
8680
  meta: {
8372
8681
  name: "remove-language",
8373
8682
  group: "edit",
@@ -8400,7 +8709,7 @@ var init_remove_language = __esm({
8400
8709
  });
8401
8710
  process.exit(result.status === "aborted" ? 1 : 0);
8402
8711
  } catch (err) {
8403
- consola24.error(err instanceof Error ? err.message : String(err));
8712
+ consola26.error(err instanceof Error ? err.message : String(err));
8404
8713
  process.exit(1);
8405
8714
  }
8406
8715
  }
@@ -8409,8 +8718,8 @@ var init_remove_language = __esm({
8409
8718
  });
8410
8719
 
8411
8720
  // src/commands/remove-port.ts
8412
- import { defineCommand as defineCommand21 } from "citty";
8413
- import { consola as consola25 } from "consola";
8721
+ import { defineCommand as defineCommand22 } from "citty";
8722
+ import { consola as consola27 } from "consola";
8414
8723
  function coerceToken2(raw) {
8415
8724
  const n = Number(raw);
8416
8725
  return Number.isFinite(n) ? n : raw;
@@ -8421,7 +8730,7 @@ var init_remove_port = __esm({
8421
8730
  "use strict";
8422
8731
  init_inner_args();
8423
8732
  init_modify();
8424
- removePortCommand = defineCommand21({
8733
+ removePortCommand = defineCommand22({
8425
8734
  meta: {
8426
8735
  name: "remove-port",
8427
8736
  group: "edit",
@@ -8443,7 +8752,7 @@ var init_remove_port = __esm({
8443
8752
  async run({ args }) {
8444
8753
  const tokens = [...getInnerArgs()];
8445
8754
  if (tokens.length === 0) {
8446
- consola25.error(
8755
+ consola27.error(
8447
8756
  "No ports given. Usage: `monoceros remove-port <containername> [--yes] -- <port> [<port> \u2026]`."
8448
8757
  );
8449
8758
  process.exit(1);
@@ -8456,7 +8765,7 @@ var init_remove_port = __esm({
8456
8765
  });
8457
8766
  process.exit(result.status === "aborted" ? 1 : 0);
8458
8767
  } catch (err) {
8459
- consola25.error(err instanceof Error ? err.message : String(err));
8768
+ consola27.error(err instanceof Error ? err.message : String(err));
8460
8769
  process.exit(1);
8461
8770
  }
8462
8771
  }
@@ -8465,14 +8774,14 @@ var init_remove_port = __esm({
8465
8774
  });
8466
8775
 
8467
8776
  // src/commands/remove-repo.ts
8468
- import { defineCommand as defineCommand22 } from "citty";
8469
- import { consola as consola26 } from "consola";
8777
+ import { defineCommand as defineCommand23 } from "citty";
8778
+ import { consola as consola28 } from "consola";
8470
8779
  var removeRepoCommand;
8471
8780
  var init_remove_repo = __esm({
8472
8781
  "src/commands/remove-repo.ts"() {
8473
8782
  "use strict";
8474
8783
  init_modify();
8475
- removeRepoCommand = defineCommand22({
8784
+ removeRepoCommand = defineCommand23({
8476
8785
  meta: {
8477
8786
  name: "remove-repo",
8478
8787
  group: "edit",
@@ -8505,7 +8814,7 @@ var init_remove_repo = __esm({
8505
8814
  });
8506
8815
  process.exit(result.status === "aborted" ? 1 : 0);
8507
8816
  } catch (err) {
8508
- consola26.error(err instanceof Error ? err.message : String(err));
8817
+ consola28.error(err instanceof Error ? err.message : String(err));
8509
8818
  process.exit(1);
8510
8819
  }
8511
8820
  }
@@ -8514,14 +8823,14 @@ var init_remove_repo = __esm({
8514
8823
  });
8515
8824
 
8516
8825
  // src/commands/remove-service.ts
8517
- import { defineCommand as defineCommand23 } from "citty";
8518
- import { consola as consola27 } from "consola";
8826
+ import { defineCommand as defineCommand24 } from "citty";
8827
+ import { consola as consola29 } from "consola";
8519
8828
  var removeServiceCommand;
8520
8829
  var init_remove_service = __esm({
8521
8830
  "src/commands/remove-service.ts"() {
8522
8831
  "use strict";
8523
8832
  init_modify();
8524
- removeServiceCommand = defineCommand23({
8833
+ removeServiceCommand = defineCommand24({
8525
8834
  meta: {
8526
8835
  name: "remove-service",
8527
8836
  group: "edit",
@@ -8554,7 +8863,7 @@ var init_remove_service = __esm({
8554
8863
  });
8555
8864
  process.exit(result.status === "aborted" ? 1 : 0);
8556
8865
  } catch (err) {
8557
- consola27.error(err instanceof Error ? err.message : String(err));
8866
+ consola29.error(err instanceof Error ? err.message : String(err));
8558
8867
  process.exit(1);
8559
8868
  }
8560
8869
  }
@@ -8562,44 +8871,6 @@ var init_remove_service = __esm({
8562
8871
  }
8563
8872
  });
8564
8873
 
8565
- // src/devcontainer/shell.ts
8566
- import { existsSync as existsSync12 } from "fs";
8567
- import path20 from "path";
8568
- async function runShell(opts) {
8569
- assertContainerExists(opts.root);
8570
- const spawnFn = opts.spawn ?? spawnDevcontainer;
8571
- const upCode = await spawnFn(
8572
- ["up", "--workspace-folder", opts.root, "--mount-workspace-git-root=false"],
8573
- opts.root,
8574
- { quiet: true }
8575
- );
8576
- if (upCode !== 0) return upCode;
8577
- return spawnFn(
8578
- [
8579
- "exec",
8580
- "--workspace-folder",
8581
- opts.root,
8582
- "--mount-workspace-git-root=false",
8583
- "bash"
8584
- ],
8585
- opts.root,
8586
- { interactive: true }
8587
- );
8588
- }
8589
- function assertContainerExists(root) {
8590
- if (!existsSync12(path20.join(root, ".devcontainer"))) {
8591
- throw new Error(
8592
- `No .devcontainer/ at ${root}. Run \`monoceros apply <name>\` first.`
8593
- );
8594
- }
8595
- }
8596
- var init_shell = __esm({
8597
- "src/devcontainer/shell.ts"() {
8598
- "use strict";
8599
- init_cli();
8600
- }
8601
- });
8602
-
8603
8874
  // src/devcontainer/run.ts
8604
8875
  async function runInContainer(opts) {
8605
8876
  if (opts.command.length === 0) {
@@ -8644,8 +8915,8 @@ var init_run = __esm({
8644
8915
  });
8645
8916
 
8646
8917
  // src/commands/run.ts
8647
- import { defineCommand as defineCommand24 } from "citty";
8648
- import { consola as consola28 } from "consola";
8918
+ import { defineCommand as defineCommand25 } from "citty";
8919
+ import { consola as consola30 } from "consola";
8649
8920
  var runCommand;
8650
8921
  var init_run2 = __esm({
8651
8922
  "src/commands/run.ts"() {
@@ -8653,7 +8924,7 @@ var init_run2 = __esm({
8653
8924
  init_paths();
8654
8925
  init_run();
8655
8926
  init_inner_args();
8656
- runCommand = defineCommand24({
8927
+ runCommand = defineCommand25({
8657
8928
  meta: {
8658
8929
  name: "run",
8659
8930
  group: "run",
@@ -8673,7 +8944,7 @@ var init_run2 = __esm({
8673
8944
  async run({ args }) {
8674
8945
  const command = [...getInnerArgs()];
8675
8946
  if (command.length === 0) {
8676
- consola28.error(
8947
+ consola30.error(
8677
8948
  "No command provided. Usage: `monoceros run <containername> -- <cmd> [args\u2026]`."
8678
8949
  );
8679
8950
  process.exit(1);
@@ -8686,7 +8957,7 @@ var init_run2 = __esm({
8686
8957
  });
8687
8958
  process.exit(exitCode);
8688
8959
  } catch (err) {
8689
- consola28.error(err instanceof Error ? err.message : String(err));
8960
+ consola30.error(err instanceof Error ? err.message : String(err));
8690
8961
  process.exit(1);
8691
8962
  }
8692
8963
  }
@@ -8695,15 +8966,15 @@ var init_run2 = __esm({
8695
8966
  });
8696
8967
 
8697
8968
  // src/commands/shell.ts
8698
- import { defineCommand as defineCommand25 } from "citty";
8699
- import { consola as consola29 } from "consola";
8969
+ import { defineCommand as defineCommand26 } from "citty";
8970
+ import { consola as consola31 } from "consola";
8700
8971
  var shellCommand;
8701
8972
  var init_shell2 = __esm({
8702
8973
  "src/commands/shell.ts"() {
8703
8974
  "use strict";
8704
8975
  init_paths();
8705
8976
  init_shell();
8706
- shellCommand = defineCommand25({
8977
+ shellCommand = defineCommand26({
8707
8978
  meta: {
8708
8979
  name: "shell",
8709
8980
  group: "run",
@@ -8721,7 +8992,7 @@ var init_shell2 = __esm({
8721
8992
  const exitCode = await runShell({ root: containerDir(args.name) });
8722
8993
  process.exit(exitCode);
8723
8994
  } catch (err) {
8724
- consola29.error(err instanceof Error ? err.message : String(err));
8995
+ consola31.error(err instanceof Error ? err.message : String(err));
8725
8996
  process.exit(1);
8726
8997
  }
8727
8998
  }
@@ -8730,8 +9001,8 @@ var init_shell2 = __esm({
8730
9001
  });
8731
9002
 
8732
9003
  // src/commands/start.ts
8733
- import { defineCommand as defineCommand26 } from "citty";
8734
- import { consola as consola30 } from "consola";
9004
+ import { defineCommand as defineCommand27 } from "citty";
9005
+ import { consola as consola32 } from "consola";
8735
9006
  var startCommand;
8736
9007
  var init_start = __esm({
8737
9008
  "src/commands/start.ts"() {
@@ -8743,7 +9014,7 @@ var init_start = __esm({
8743
9014
  init_proxy();
8744
9015
  init_port_check();
8745
9016
  init_dispatch();
8746
- startCommand = defineCommand26({
9017
+ startCommand = defineCommand27({
8747
9018
  meta: {
8748
9019
  name: "start",
8749
9020
  group: "run",
@@ -8768,7 +9039,7 @@ var init_start = __esm({
8768
9039
  hostPort = proxyHostPort(global);
8769
9040
  }
8770
9041
  } catch (err) {
8771
- consola30.warn(
9042
+ consola32.warn(
8772
9043
  `Could not read container yml ahead of start: ${err instanceof Error ? err.message : String(err)}. Skipping Traefik pre-flight.`
8773
9044
  );
8774
9045
  }
@@ -8784,7 +9055,7 @@ var init_start = __esm({
8784
9055
  });
8785
9056
 
8786
9057
  // src/commands/status.ts
8787
- import { defineCommand as defineCommand27 } from "citty";
9058
+ import { defineCommand as defineCommand28 } from "citty";
8788
9059
  var statusCommand;
8789
9060
  var init_status = __esm({
8790
9061
  "src/commands/status.ts"() {
@@ -8792,7 +9063,7 @@ var init_status = __esm({
8792
9063
  init_paths();
8793
9064
  init_compose();
8794
9065
  init_dispatch();
8795
- statusCommand = defineCommand27({
9066
+ statusCommand = defineCommand28({
8796
9067
  meta: {
8797
9068
  name: "status",
8798
9069
  group: "run",
@@ -8822,8 +9093,8 @@ var init_status = __esm({
8822
9093
  });
8823
9094
 
8824
9095
  // src/commands/stop.ts
8825
- import { defineCommand as defineCommand28 } from "citty";
8826
- import { consola as consola31 } from "consola";
9096
+ import { defineCommand as defineCommand29 } from "citty";
9097
+ import { consola as consola33 } from "consola";
8827
9098
  var stopCommand;
8828
9099
  var init_stop = __esm({
8829
9100
  "src/commands/stop.ts"() {
@@ -8832,7 +9103,7 @@ var init_stop = __esm({
8832
9103
  init_compose();
8833
9104
  init_proxy();
8834
9105
  init_dispatch();
8835
- stopCommand = defineCommand28({
9106
+ stopCommand = defineCommand29({
8836
9107
  meta: {
8837
9108
  name: "stop",
8838
9109
  group: "run",
@@ -8857,10 +9128,10 @@ var init_stop = __esm({
8857
9128
  });
8858
9129
  try {
8859
9130
  await maybeStopProxy({
8860
- logger: { info: (msg) => consola31.info(msg) }
9131
+ logger: { info: (msg) => consola33.info(msg) }
8861
9132
  });
8862
9133
  } catch (err) {
8863
- consola31.warn(
9134
+ consola33.warn(
8864
9135
  `Could not tear down the Traefik proxy: ${err instanceof Error ? err.message : String(err)}. Ignored.`
8865
9136
  );
8866
9137
  }
@@ -8872,11 +9143,11 @@ var init_stop = __esm({
8872
9143
  });
8873
9144
 
8874
9145
  // src/tunnel/resolve.ts
8875
- import { existsSync as existsSync13 } from "fs";
8876
- import path21 from "path";
9146
+ import { existsSync as existsSync14 } from "fs";
9147
+ import path22 from "path";
8877
9148
  async function resolveTunnelTarget(opts) {
8878
9149
  const ymlPath = containerConfigPath(opts.name, opts.monocerosHome);
8879
- if (!existsSync13(ymlPath)) {
9150
+ if (!existsSync14(ymlPath)) {
8880
9151
  throw new Error(
8881
9152
  `No yml profile for '${opts.name}' at ${ymlPath}. Run \`monoceros init ${opts.name}\` first.`
8882
9153
  );
@@ -8884,13 +9155,13 @@ async function resolveTunnelTarget(opts) {
8884
9155
  const parsed = await readConfig(ymlPath);
8885
9156
  const config = parsed.config;
8886
9157
  const containerRoot = containerDir(opts.name, opts.monocerosHome);
8887
- if (!existsSync13(containerRoot)) {
9158
+ if (!existsSync14(containerRoot)) {
8888
9159
  throw new Error(
8889
9160
  `Container '${opts.name}' is not materialised at ${containerRoot}. Run \`monoceros apply ${opts.name}\` first.`
8890
9161
  );
8891
9162
  }
8892
- const composePath = path21.join(containerRoot, ".devcontainer", "compose.yaml");
8893
- const isCompose = existsSync13(composePath);
9163
+ const composePath = path22.join(containerRoot, ".devcontainer", "compose.yaml");
9164
+ const isCompose = existsSync14(composePath);
8894
9165
  const parsedTarget = parseTargetArg(opts.target, config);
8895
9166
  const docker = opts.docker ?? defaultDockerExec;
8896
9167
  if (isCompose) {
@@ -9125,8 +9396,8 @@ var init_port_check2 = __esm({
9125
9396
  });
9126
9397
 
9127
9398
  // src/tunnel/run.ts
9128
- import { spawn as spawn8 } from "child_process";
9129
- import { consola as consola32 } from "consola";
9399
+ import { spawn as spawn9 } from "child_process";
9400
+ import { consola as consola34 } from "consola";
9130
9401
  function signalNumber(signal) {
9131
9402
  switch (signal) {
9132
9403
  case "SIGINT":
@@ -9139,8 +9410,8 @@ function signalNumber(signal) {
9139
9410
  }
9140
9411
  async function runTunnel(opts) {
9141
9412
  const log = opts.logger ?? {
9142
- info: (m) => consola32.info(m),
9143
- warn: (m) => consola32.warn(m)
9413
+ info: (m) => consola34.info(m),
9414
+ warn: (m) => consola34.warn(m)
9144
9415
  };
9145
9416
  const resolve = opts.resolve ?? resolveTunnelTarget;
9146
9417
  const resolveArgs3 = {
@@ -9215,7 +9486,7 @@ var init_run3 = __esm({
9215
9486
  init_port_check2();
9216
9487
  SOCAT_IMAGE = "alpine/socat:1.8.0.3";
9217
9488
  defaultDockerSpawn = (args) => {
9218
- const child = spawn8("docker", args, {
9489
+ const child = spawn9("docker", args, {
9219
9490
  stdio: "inherit"
9220
9491
  });
9221
9492
  const exited = new Promise((resolve, reject) => {
@@ -9246,8 +9517,8 @@ var init_run3 = __esm({
9246
9517
  });
9247
9518
 
9248
9519
  // src/commands/tunnel.ts
9249
- import { defineCommand as defineCommand29 } from "citty";
9250
- import { consola as consola33 } from "consola";
9520
+ import { defineCommand as defineCommand30 } from "citty";
9521
+ import { consola as consola35 } from "consola";
9251
9522
  function parseLocalPort(raw) {
9252
9523
  if (raw === void 0) return void 0;
9253
9524
  const n = Number(raw);
@@ -9263,7 +9534,7 @@ var init_tunnel = __esm({
9263
9534
  "src/commands/tunnel.ts"() {
9264
9535
  "use strict";
9265
9536
  init_run3();
9266
- tunnelCommand = defineCommand29({
9537
+ tunnelCommand = defineCommand30({
9267
9538
  meta: {
9268
9539
  name: "tunnel",
9269
9540
  group: "discovery",
@@ -9300,7 +9571,7 @@ var init_tunnel = __esm({
9300
9571
  });
9301
9572
  process.exit(exitCode);
9302
9573
  } catch (err) {
9303
- consola33.error(err instanceof Error ? err.message : String(err));
9574
+ consola35.error(err instanceof Error ? err.message : String(err));
9304
9575
  process.exit(1);
9305
9576
  }
9306
9577
  }
@@ -9309,8 +9580,8 @@ var init_tunnel = __esm({
9309
9580
  });
9310
9581
 
9311
9582
  // src/upgrade/index.ts
9312
- import { existsSync as existsSync14, promises as fs17 } from "fs";
9313
- import { consola as consola34 } from "consola";
9583
+ import { existsSync as existsSync15, promises as fs17 } from "fs";
9584
+ import { consola as consola36 } from "consola";
9314
9585
  async function fetchRuntimeVersions() {
9315
9586
  const tokenUrl = `https://ghcr.io/token?service=ghcr.io&scope=repository:${RUNTIME_REPO}:pull`;
9316
9587
  const tokenRes = await fetch(tokenUrl);
@@ -9348,7 +9619,7 @@ ${yml}`;
9348
9619
  }
9349
9620
  async function runUpgrade(opts) {
9350
9621
  const home = opts.monocerosHome ?? monocerosHome();
9351
- const logger = opts.logger ?? consola34;
9622
+ const logger = opts.logger ?? consola36;
9352
9623
  const fetchVersions = opts.fetchVersions ?? fetchRuntimeVersions;
9353
9624
  if (opts.list) {
9354
9625
  const versions = await fetchVersions();
@@ -9368,7 +9639,7 @@ async function runUpgrade(opts) {
9368
9639
  );
9369
9640
  }
9370
9641
  const ymlPath = containerConfigPath(opts.name, home);
9371
- if (!existsSync14(ymlPath)) {
9642
+ if (!existsSync15(ymlPath)) {
9372
9643
  throw new Error(
9373
9644
  `No such config: ${ymlPath}. Run \`monoceros init <template> ${opts.name}\` first.`
9374
9645
  );
@@ -9416,7 +9687,7 @@ var init_upgrade = __esm({
9416
9687
  });
9417
9688
 
9418
9689
  // src/commands/upgrade.ts
9419
- import { defineCommand as defineCommand30 } from "citty";
9690
+ import { defineCommand as defineCommand31 } from "citty";
9420
9691
  var upgradeCommand;
9421
9692
  var init_upgrade2 = __esm({
9422
9693
  "src/commands/upgrade.ts"() {
@@ -9424,7 +9695,7 @@ var init_upgrade2 = __esm({
9424
9695
  init_upgrade();
9425
9696
  init_version();
9426
9697
  init_dispatch();
9427
- upgradeCommand = defineCommand30({
9698
+ upgradeCommand = defineCommand31({
9428
9699
  meta: {
9429
9700
  name: "upgrade",
9430
9701
  group: "lifecycle",
@@ -9466,7 +9737,7 @@ var main_exports = {};
9466
9737
  __export(main_exports, {
9467
9738
  main: () => main
9468
9739
  });
9469
- import { defineCommand as defineCommand31 } from "citty";
9740
+ import { defineCommand as defineCommand32 } from "citty";
9470
9741
  var main;
9471
9742
  var init_main = __esm({
9472
9743
  "src/main.ts"() {
@@ -9483,6 +9754,7 @@ var init_main = __esm({
9483
9754
  init_complete();
9484
9755
  init_init2();
9485
9756
  init_list_components();
9757
+ init_login2();
9486
9758
  init_logs();
9487
9759
  init_port();
9488
9760
  init_remove_apt_packages();
@@ -9502,7 +9774,7 @@ var init_main = __esm({
9502
9774
  init_tunnel();
9503
9775
  init_upgrade2();
9504
9776
  init_version();
9505
- main = defineCommand31({
9777
+ main = defineCommand32({
9506
9778
  meta: {
9507
9779
  name: "monoceros",
9508
9780
  version: CLI_VERSION,
@@ -9513,6 +9785,7 @@ var init_main = __esm({
9513
9785
  "list-components": listComponentsCommand,
9514
9786
  shell: shellCommand,
9515
9787
  run: runCommand,
9788
+ login: loginCommand,
9516
9789
  logs: logsCommand,
9517
9790
  start: startCommand,
9518
9791
  stop: stopCommand,
@@ -9798,25 +10071,25 @@ function detectHelpRequest(argv, main2) {
9798
10071
  const separatorIdx = argv.indexOf("--");
9799
10072
  if (helpIdx === -1) return null;
9800
10073
  if (separatorIdx !== -1 && separatorIdx < helpIdx) return null;
9801
- const path22 = [];
10074
+ const path23 = [];
9802
10075
  const tokens = argv.slice(
9803
10076
  0,
9804
10077
  separatorIdx === -1 ? argv.length : separatorIdx
9805
10078
  );
9806
10079
  let cursor = main2;
9807
10080
  const mainName = (main2.meta ?? {}).name ?? "monoceros";
9808
- path22.push(mainName);
10081
+ path23.push(mainName);
9809
10082
  for (const tok of tokens) {
9810
10083
  if (tok.startsWith("-")) continue;
9811
10084
  const subs = cursor.subCommands ?? {};
9812
10085
  if (tok in subs) {
9813
10086
  cursor = subs[tok];
9814
- path22.push(tok);
10087
+ path23.push(tok);
9815
10088
  continue;
9816
10089
  }
9817
10090
  break;
9818
10091
  }
9819
- return { path: path22, cmd: cursor };
10092
+ return { path: path23, cmd: cursor };
9820
10093
  }
9821
10094
  async function maybeRenderHelp(argv, main2) {
9822
10095
  const hit = detectHelpRequest(argv, main2);