@getmonoceros/workbench 1.18.0 → 1.19.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
@@ -1903,6 +1903,41 @@ function curatedServiceEnvDefaults(name) {
1903
1903
  const def = SERVICE_CATALOG[name];
1904
1904
  return def?.env ? { ...def.env } : {};
1905
1905
  }
1906
+ function serviceConnectionEnv(services) {
1907
+ const env = {};
1908
+ for (const svc of services) {
1909
+ if (!isCuratedService(svc.name)) continue;
1910
+ const host = svc.name;
1911
+ if (svc.name === "postgres") {
1912
+ const user = svc.env.POSTGRES_USER ?? "postgres";
1913
+ const pass = svc.env.POSTGRES_PASSWORD ?? "";
1914
+ const db = svc.env.POSTGRES_DB ?? user;
1915
+ const port = svc.port ?? 5432;
1916
+ env.PGHOST = host;
1917
+ env.PGPORT = String(port);
1918
+ env.PGUSER = user;
1919
+ env.PGPASSWORD = pass;
1920
+ env.PGDATABASE = db;
1921
+ env.DATABASE_URL = `postgresql://${user}:${pass}@${host}:${port}/${db}`;
1922
+ } else if (svc.name === "mysql") {
1923
+ const pass = svc.env.MYSQL_ROOT_PASSWORD ?? "";
1924
+ const db = svc.env.MYSQL_DATABASE ?? "";
1925
+ const port = svc.port ?? 3306;
1926
+ env.MYSQL_HOST = host;
1927
+ env.MYSQL_PORT = String(port);
1928
+ env.MYSQL_USER = "root";
1929
+ env.MYSQL_PASSWORD = pass;
1930
+ env.MYSQL_DATABASE = db;
1931
+ if (env.DATABASE_URL === void 0) {
1932
+ env.DATABASE_URL = `mysql://root:${pass}@${host}:${port}/${db}`;
1933
+ }
1934
+ } else if (svc.name === "redis") {
1935
+ const port = svc.port ?? 6379;
1936
+ env.REDIS_URL = `redis://${host}:${port}`;
1937
+ }
1938
+ }
1939
+ return env;
1940
+ }
1906
1941
  function deriveServiceName(image) {
1907
1942
  const lastSegment = image.split("/").pop() ?? image;
1908
1943
  const noTag = lastSegment.split("@")[0].split(":")[0];
@@ -2438,6 +2473,14 @@ function buildComposeYaml(opts, dockerMode = "rootful") {
2438
2473
  for (const v of ideVolumes) {
2439
2474
  lines.push(` - ${v.volume}:${v.target}`);
2440
2475
  }
2476
+ const wsEnv = serviceConnectionEnv(opts.services);
2477
+ const wsEnvKeys = Object.keys(wsEnv);
2478
+ if (wsEnvKeys.length > 0) {
2479
+ lines.push(" environment:");
2480
+ for (const k of wsEnvKeys) {
2481
+ lines.push(` ${k}: ${composeScalar(wsEnv[k])}`);
2482
+ }
2483
+ }
2441
2484
  for (const svc of opts.services) {
2442
2485
  lines.push(` ${svc.name}:`);
2443
2486
  lines.push(` image: ${svc.image}`);
@@ -3216,8 +3259,8 @@ function removeRepoFromDoc(doc, urlOrPath) {
3216
3259
  if (!isMap2(item)) return false;
3217
3260
  const url = item.get("url");
3218
3261
  if (url === urlOrPath) return true;
3219
- const path23 = item.get("path");
3220
- const effectivePath = typeof path23 === "string" ? path23 : typeof url === "string" ? deriveRepoName(url) : void 0;
3262
+ const path24 = item.get("path");
3263
+ const effectivePath = typeof path24 === "string" ? path24 : typeof url === "string" ? deriveRepoName(url) : void 0;
3221
3264
  return effectivePath === urlOrPath;
3222
3265
  });
3223
3266
  if (idx < 0) return false;
@@ -3329,7 +3372,7 @@ async function runAddRepo(input) {
3329
3372
  "Missing repo URL. Usage: monoceros add-repo <containername> <url>."
3330
3373
  );
3331
3374
  }
3332
- const path23 = (input.path ?? deriveRepoName(url)).trim();
3375
+ const path24 = (input.path ?? deriveRepoName(url)).trim();
3333
3376
  const hasName = typeof input.gitName === "string" && input.gitName.trim().length > 0;
3334
3377
  const hasEmail = typeof input.gitEmail === "string" && input.gitEmail.trim().length > 0;
3335
3378
  if (hasName !== hasEmail) {
@@ -3366,7 +3409,7 @@ async function runAddRepo(input) {
3366
3409
  const providerToWrite = !canonical && explicitProvider ? explicitProvider : void 0;
3367
3410
  const entry2 = {
3368
3411
  url,
3369
- path: path23,
3412
+ path: path24,
3370
3413
  ...hasName && hasEmail ? {
3371
3414
  gitUser: {
3372
3415
  name: input.gitName.trim(),
@@ -4767,22 +4810,42 @@ function generateAgentsMd(input) {
4767
4810
  lines.push(formatServiceLine(svc));
4768
4811
  }
4769
4812
  lines.push("");
4770
- lines.push(
4771
- "Credentials for these services are intentionally not stored in this",
4772
- "file. If you need to connect from code or from the command line, ask",
4773
- "the user in the current chat; they will paste the values directly.",
4774
- "Do not commit credentials provided this way into any file in the",
4775
- "repo \u2014 they belong in the user's `.env` on the host, not in source",
4776
- "control."
4777
- );
4813
+ const connEnv = serviceConnectionEnv(input.services);
4814
+ if (Object.keys(connEnv).length > 0) {
4815
+ lines.push(
4816
+ "Connection details for the curated services above are already set as",
4817
+ "environment variables in this container. Read them from the",
4818
+ "environment \u2014 do not ask the user for credentials, and do not",
4819
+ "hardcode them:"
4820
+ );
4821
+ lines.push("");
4822
+ if (connEnv.DATABASE_URL !== void 0) {
4823
+ lines.push(
4824
+ "- `DATABASE_URL` \u2014 the SQL database. Engine-specific variables are",
4825
+ " set too (`PGHOST`/`PGPORT`/`PGUSER`/`PGPASSWORD`/`PGDATABASE` for",
4826
+ " Postgres, `MYSQL_*` for MySQL)."
4827
+ );
4828
+ }
4829
+ if (connEnv.REDIS_URL !== void 0) {
4830
+ lines.push("- `REDIS_URL` \u2014 Redis.");
4831
+ }
4832
+ lines.push("");
4833
+ lines.push(
4834
+ "These are dev-only defaults for the local container, fine to use",
4835
+ "directly. Prefer reading the variable (e.g. `process.env.DATABASE_URL`)",
4836
+ "over copying its value into code."
4837
+ );
4838
+ }
4778
4839
  const hasCustom = input.services.some((s) => !isCuratedService(s.name));
4779
4840
  if (hasCustom) {
4780
4841
  lines.push("");
4781
4842
  lines.push(
4782
4843
  "For custom-image services, Monoceros does not know the service's",
4783
- "configuration (env vars, ports beyond the primary one, required",
4784
- "volumes). Treat such a service as a black box reachable at the",
4785
- "listed address; if you need more, ask the user."
4844
+ "configuration or credentials (env vars, ports beyond the primary one,",
4845
+ "required volumes). Treat such a service as a black box reachable at",
4846
+ "the listed address; if you need to connect, ask the user in the",
4847
+ "current chat. Do not commit credentials into the repo \u2014 they belong",
4848
+ "in the user's `.env` on the host."
4786
4849
  );
4787
4850
  }
4788
4851
  lines.push("");
@@ -4866,6 +4929,54 @@ function generateAgentsMd(input) {
4866
4929
  " DataGrip) to one of the services."
4867
4930
  );
4868
4931
  lines.push("");
4932
+ if (input.ports.length > 0) {
4933
+ lines.push("## Running a long-running server");
4934
+ lines.push("");
4935
+ lines.push(
4936
+ "When you build something that serves on a port (a web app, an API),",
4937
+ "start it as a **detached** background process so it keeps running after",
4938
+ "this session ends. A plain `npm start` (or any foreground start) dies",
4939
+ "the moment the user exits you or closes the terminal \u2014 and then",
4940
+ `\`${input.containerName}.localhost\` returns 502 Bad Gateway.`
4941
+ );
4942
+ lines.push("");
4943
+ lines.push(
4944
+ "Launch it in a new session with `setsid`, using the project's own",
4945
+ "start command, and record the process-group PID + log under the",
4946
+ "container's logs directory:"
4947
+ );
4948
+ lines.push("");
4949
+ lines.push("```");
4950
+ lines.push(
4951
+ `setsid sh -c 'echo $$ >/workspaces/${input.containerName}/logs/<app>.pid; \\`
4952
+ );
4953
+ lines.push(
4954
+ ` exec <the project's start command> >/workspaces/${input.containerName}/logs/<app>.log 2>&1' </dev/null &`
4955
+ );
4956
+ lines.push("```");
4957
+ lines.push("");
4958
+ lines.push(
4959
+ "Use whatever start command the project actually uses (`npm start`,",
4960
+ "`./mvnw spring-boot:run`, `python app.py`, `go run .`, \u2026) \u2014 do not force",
4961
+ "a language-specific one. `<app>` is a short name you choose."
4962
+ );
4963
+ lines.push("");
4964
+ lines.push("To stop it, kill the whole process group (also stops children");
4965
+ lines.push("like node under npm or java under maven):");
4966
+ lines.push("");
4967
+ lines.push("```");
4968
+ lines.push(
4969
+ `kill -TERM -$(cat /workspaces/${input.containerName}/logs/<app>.pid)`
4970
+ );
4971
+ lines.push("```");
4972
+ lines.push("");
4973
+ lines.push(
4974
+ `The user can follow the output with \`monoceros logs ${input.containerName} <app>\``,
4975
+ "on the host. The server must listen on `0.0.0.0` (not `127.0.0.1`) on",
4976
+ "the exposed port, or Traefik cannot reach it."
4977
+ );
4978
+ lines.push("");
4979
+ }
4869
4980
  lines.push("## Command reference");
4870
4981
  lines.push("");
4871
4982
  lines.push(
@@ -5373,10 +5484,12 @@ var init_cli = __esm({
5373
5484
  cachedBinaryPath = null;
5374
5485
  spawnDevcontainer = (args, cwd, options = {}) => {
5375
5486
  const binPath = devcontainerCliPath();
5487
+ const env = { ...process.env, DOCKER_CLI_HINTS: "false" };
5376
5488
  return new Promise((resolve, reject) => {
5377
5489
  if (options.interactive) {
5378
5490
  const child2 = spawn4(process.execPath, [binPath, ...args], {
5379
5491
  cwd,
5492
+ env,
5380
5493
  stdio: "inherit"
5381
5494
  });
5382
5495
  child2.on("error", reject);
@@ -5385,6 +5498,7 @@ var init_cli = __esm({
5385
5498
  }
5386
5499
  const child = spawn4(process.execPath, [binPath, ...args], {
5387
5500
  cwd,
5501
+ env,
5388
5502
  stdio: ["ignore", "pipe", "pipe"]
5389
5503
  });
5390
5504
  if (options.quiet) {
@@ -6293,7 +6407,7 @@ var CLI_VERSION;
6293
6407
  var init_version = __esm({
6294
6408
  "src/version.ts"() {
6295
6409
  "use strict";
6296
- CLI_VERSION = true ? "1.18.0" : "dev";
6410
+ CLI_VERSION = true ? "1.19.0" : "dev";
6297
6411
  }
6298
6412
  });
6299
6413
 
@@ -7992,7 +8106,11 @@ exit 0
7992
8106
  "-lc",
7993
8107
  `export PATH="/workspaces/${name}/${RELAY_DIRNAME}:$PATH"; exec claude`
7994
8108
  ],
7995
- { cwd: root, stdio: "inherit" }
8109
+ {
8110
+ cwd: root,
8111
+ env: { ...process.env, DOCKER_CLI_HINTS: "false" },
8112
+ stdio: "inherit"
8113
+ }
7996
8114
  );
7997
8115
  const code = await new Promise((resolve) => {
7998
8116
  child.on("error", () => resolve(1));
@@ -8064,7 +8182,18 @@ var init_login2 = __esm({
8064
8182
  });
8065
8183
 
8066
8184
  // src/commands/logs.ts
8185
+ import { spawn as spawn9 } from "child_process";
8186
+ import { existsSync as existsSync12 } from "fs";
8187
+ import path20 from "path";
8067
8188
  import { defineCommand as defineCommand14 } from "citty";
8189
+ function tailLogFile(file, follow) {
8190
+ const [cmd, args] = follow ? ["tail", ["-F", file]] : ["cat", [file]];
8191
+ return new Promise((resolve, reject) => {
8192
+ const child = spawn9(cmd, args, { stdio: "inherit" });
8193
+ child.on("error", reject);
8194
+ child.on("exit", (code) => resolve(code ?? 0));
8195
+ });
8196
+ }
8068
8197
  var logsCommand;
8069
8198
  var init_logs = __esm({
8070
8199
  "src/commands/logs.ts"() {
@@ -8076,7 +8205,7 @@ var init_logs = __esm({
8076
8205
  meta: {
8077
8206
  name: "logs",
8078
8207
  group: "run",
8079
- description: "Tail logs from the compose services of the named dev-container. Pass --no-follow for a one-shot dump."
8208
+ description: "Tail logs from a compose service of the named dev-container, or from a long-running app started inside it (logs/<app>.log). Pass --no-follow for a one-shot dump."
8080
8209
  },
8081
8210
  args: {
8082
8211
  name: {
@@ -8086,7 +8215,7 @@ var init_logs = __esm({
8086
8215
  },
8087
8216
  service: {
8088
8217
  type: "string",
8089
- description: "Restrict to a single compose service (e.g. postgres). Defaults to all."
8218
+ description: "A compose service (e.g. postgres) or an app whose log is at logs/<service>.log. Defaults to all compose services."
8090
8219
  },
8091
8220
  follow: {
8092
8221
  type: "boolean",
@@ -8096,10 +8225,17 @@ var init_logs = __esm({
8096
8225
  }
8097
8226
  },
8098
8227
  run({ args }) {
8228
+ const service = typeof args.service === "string" ? args.service : void 0;
8229
+ if (service) {
8230
+ const logFile = path20.join(containerLogsDir(args.name), `${service}.log`);
8231
+ if (existsSync12(logFile)) {
8232
+ return dispatch(() => tailLogFile(logFile, args.follow));
8233
+ }
8234
+ }
8099
8235
  return dispatch(
8100
8236
  () => runLogs({
8101
8237
  root: containerDir(args.name),
8102
- ...typeof args.service === "string" ? { service: args.service } : {},
8238
+ ...service ? { service } : {},
8103
8239
  follow: args.follow
8104
8240
  })
8105
8241
  );
@@ -8299,8 +8435,8 @@ var init_remove_feature = __esm({
8299
8435
  });
8300
8436
 
8301
8437
  // src/remove/index.ts
8302
- import { existsSync as existsSync12, promises as fs15 } from "fs";
8303
- import path20 from "path";
8438
+ import { existsSync as existsSync13, promises as fs15 } from "fs";
8439
+ import path21 from "path";
8304
8440
  import { consola as consola21 } from "consola";
8305
8441
  async function runRemove(opts) {
8306
8442
  const home = opts.monocerosHome ?? monocerosHome();
@@ -8317,9 +8453,9 @@ async function runRemove(opts) {
8317
8453
  const ymlPath = containerConfigPath(opts.name, home);
8318
8454
  const envPath = containerEnvPath(opts.name, home);
8319
8455
  const containerPath = containerDir(opts.name, home);
8320
- const hasYml = existsSync12(ymlPath);
8321
- const hasEnv = existsSync12(envPath);
8322
- const hasContainer = existsSync12(containerPath);
8456
+ const hasYml = existsSync13(ymlPath);
8457
+ const hasEnv = existsSync13(envPath);
8458
+ const hasContainer = existsSync13(containerPath);
8323
8459
  if (!hasYml && !hasContainer) {
8324
8460
  throw new Error(
8325
8461
  `Nothing to remove for '${opts.name}': neither ${ymlPath} nor ${containerPath} exists.`
@@ -8345,16 +8481,16 @@ async function runRemove(opts) {
8345
8481
  let backupPath = null;
8346
8482
  if (!opts.noBackup && (hasYml || hasContainer)) {
8347
8483
  const ts = (opts.now ?? /* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8348
- backupPath = path20.join(home, "container-backups", `${opts.name}-${ts}`);
8484
+ backupPath = path21.join(home, "container-backups", `${opts.name}-${ts}`);
8349
8485
  await fs15.mkdir(backupPath, { recursive: true });
8350
8486
  if (hasYml) {
8351
- await fs15.copyFile(ymlPath, path20.join(backupPath, `${opts.name}.yml`));
8487
+ await fs15.copyFile(ymlPath, path21.join(backupPath, `${opts.name}.yml`));
8352
8488
  }
8353
8489
  if (hasEnv) {
8354
- await fs15.copyFile(envPath, path20.join(backupPath, `${opts.name}.env`));
8490
+ await fs15.copyFile(envPath, path21.join(backupPath, `${opts.name}.env`));
8355
8491
  }
8356
8492
  if (hasContainer) {
8357
- await fs15.cp(containerPath, path20.join(backupPath, "container"), {
8493
+ await fs15.cp(containerPath, path21.join(backupPath, "container"), {
8358
8494
  recursive: true
8359
8495
  });
8360
8496
  }
@@ -8514,8 +8650,8 @@ var init_remove2 = __esm({
8514
8650
  });
8515
8651
 
8516
8652
  // src/restore/index.ts
8517
- import { existsSync as existsSync13, promises as fs16 } from "fs";
8518
- import path21 from "path";
8653
+ import { existsSync as existsSync14, promises as fs16 } from "fs";
8654
+ import path22 from "path";
8519
8655
  import { consola as consola23 } from "consola";
8520
8656
  async function runRestore(opts) {
8521
8657
  const home = opts.monocerosHome ?? monocerosHome();
@@ -8523,8 +8659,8 @@ async function runRestore(opts) {
8523
8659
  info: (msg) => consola23.info(msg),
8524
8660
  success: (msg) => consola23.success(msg)
8525
8661
  };
8526
- const backup = path21.resolve(opts.backupPath);
8527
- if (!existsSync13(backup)) {
8662
+ const backup = path22.resolve(opts.backupPath);
8663
+ if (!existsSync14(backup)) {
8528
8664
  throw new Error(`Backup not found: ${backup}.`);
8529
8665
  }
8530
8666
  const stat = await fs16.stat(backup);
@@ -8545,24 +8681,24 @@ async function runRestore(opts) {
8545
8681
  }
8546
8682
  const ymlFile = ymlFiles[0];
8547
8683
  const name = ymlFile.replace(/\.yml$/, "");
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);
8684
+ const containerInBackup = path22.join(backup, "container");
8685
+ const hasContainer = existsSync14(containerInBackup);
8686
+ const envInBackup = path22.join(backup, `${name}.env`);
8687
+ const hasEnv = existsSync14(envInBackup);
8552
8688
  const destYml = containerConfigPath(name, home);
8553
8689
  const destContainer = containerDir(name, home);
8554
- if (existsSync13(destYml)) {
8690
+ if (existsSync14(destYml)) {
8555
8691
  throw new Error(
8556
8692
  `Refusing to restore: ${destYml} already exists. Remove the current container first (\`monoceros remove ${name}\`) or rename the existing config.`
8557
8693
  );
8558
8694
  }
8559
- if (hasContainer && existsSync13(destContainer)) {
8695
+ if (hasContainer && existsSync14(destContainer)) {
8560
8696
  throw new Error(
8561
8697
  `Refusing to restore: ${destContainer} already exists. Remove the current container first (\`monoceros remove ${name}\`).`
8562
8698
  );
8563
8699
  }
8564
8700
  await fs16.mkdir(containerConfigsDir(home), { recursive: true });
8565
- await fs16.copyFile(path21.join(backup, ymlFile), destYml);
8701
+ await fs16.copyFile(path22.join(backup, ymlFile), destYml);
8566
8702
  if (hasEnv) {
8567
8703
  await fs16.copyFile(envInBackup, containerEnvPath(name, home));
8568
8704
  }
@@ -9143,11 +9279,11 @@ var init_stop = __esm({
9143
9279
  });
9144
9280
 
9145
9281
  // src/tunnel/resolve.ts
9146
- import { existsSync as existsSync14 } from "fs";
9147
- import path22 from "path";
9282
+ import { existsSync as existsSync15 } from "fs";
9283
+ import path23 from "path";
9148
9284
  async function resolveTunnelTarget(opts) {
9149
9285
  const ymlPath = containerConfigPath(opts.name, opts.monocerosHome);
9150
- if (!existsSync14(ymlPath)) {
9286
+ if (!existsSync15(ymlPath)) {
9151
9287
  throw new Error(
9152
9288
  `No yml profile for '${opts.name}' at ${ymlPath}. Run \`monoceros init ${opts.name}\` first.`
9153
9289
  );
@@ -9155,13 +9291,13 @@ async function resolveTunnelTarget(opts) {
9155
9291
  const parsed = await readConfig(ymlPath);
9156
9292
  const config = parsed.config;
9157
9293
  const containerRoot = containerDir(opts.name, opts.monocerosHome);
9158
- if (!existsSync14(containerRoot)) {
9294
+ if (!existsSync15(containerRoot)) {
9159
9295
  throw new Error(
9160
9296
  `Container '${opts.name}' is not materialised at ${containerRoot}. Run \`monoceros apply ${opts.name}\` first.`
9161
9297
  );
9162
9298
  }
9163
- const composePath = path22.join(containerRoot, ".devcontainer", "compose.yaml");
9164
- const isCompose = existsSync14(composePath);
9299
+ const composePath = path23.join(containerRoot, ".devcontainer", "compose.yaml");
9300
+ const isCompose = existsSync15(composePath);
9165
9301
  const parsedTarget = parseTargetArg(opts.target, config);
9166
9302
  const docker = opts.docker ?? defaultDockerExec;
9167
9303
  if (isCompose) {
@@ -9396,7 +9532,7 @@ var init_port_check2 = __esm({
9396
9532
  });
9397
9533
 
9398
9534
  // src/tunnel/run.ts
9399
- import { spawn as spawn9 } from "child_process";
9535
+ import { spawn as spawn10 } from "child_process";
9400
9536
  import { consola as consola34 } from "consola";
9401
9537
  function signalNumber(signal) {
9402
9538
  switch (signal) {
@@ -9486,7 +9622,7 @@ var init_run3 = __esm({
9486
9622
  init_port_check2();
9487
9623
  SOCAT_IMAGE = "alpine/socat:1.8.0.3";
9488
9624
  defaultDockerSpawn = (args) => {
9489
- const child = spawn9("docker", args, {
9625
+ const child = spawn10("docker", args, {
9490
9626
  stdio: "inherit"
9491
9627
  });
9492
9628
  const exited = new Promise((resolve, reject) => {
@@ -9580,7 +9716,7 @@ var init_tunnel = __esm({
9580
9716
  });
9581
9717
 
9582
9718
  // src/upgrade/index.ts
9583
- import { existsSync as existsSync15, promises as fs17 } from "fs";
9719
+ import { existsSync as existsSync16, promises as fs17 } from "fs";
9584
9720
  import { consola as consola36 } from "consola";
9585
9721
  async function fetchRuntimeVersions() {
9586
9722
  const tokenUrl = `https://ghcr.io/token?service=ghcr.io&scope=repository:${RUNTIME_REPO}:pull`;
@@ -9639,7 +9775,7 @@ async function runUpgrade(opts) {
9639
9775
  );
9640
9776
  }
9641
9777
  const ymlPath = containerConfigPath(opts.name, home);
9642
- if (!existsSync15(ymlPath)) {
9778
+ if (!existsSync16(ymlPath)) {
9643
9779
  throw new Error(
9644
9780
  `No such config: ${ymlPath}. Run \`monoceros init <template> ${opts.name}\` first.`
9645
9781
  );
@@ -10071,25 +10207,25 @@ function detectHelpRequest(argv, main2) {
10071
10207
  const separatorIdx = argv.indexOf("--");
10072
10208
  if (helpIdx === -1) return null;
10073
10209
  if (separatorIdx !== -1 && separatorIdx < helpIdx) return null;
10074
- const path23 = [];
10210
+ const path24 = [];
10075
10211
  const tokens = argv.slice(
10076
10212
  0,
10077
10213
  separatorIdx === -1 ? argv.length : separatorIdx
10078
10214
  );
10079
10215
  let cursor = main2;
10080
10216
  const mainName = (main2.meta ?? {}).name ?? "monoceros";
10081
- path23.push(mainName);
10217
+ path24.push(mainName);
10082
10218
  for (const tok of tokens) {
10083
10219
  if (tok.startsWith("-")) continue;
10084
10220
  const subs = cursor.subCommands ?? {};
10085
10221
  if (tok in subs) {
10086
10222
  cursor = subs[tok];
10087
- path23.push(tok);
10223
+ path24.push(tok);
10088
10224
  continue;
10089
10225
  }
10090
10226
  break;
10091
10227
  }
10092
- return { path: path23, cmd: cursor };
10228
+ return { path: path24, cmd: cursor };
10093
10229
  }
10094
10230
  async function maybeRenderHelp(argv, main2) {
10095
10231
  const hit = detectHelpRequest(argv, main2);