@getmonoceros/workbench 1.0.1 → 1.2.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
@@ -20,6 +20,13 @@ var bold = (s) => color(s, ANSI_BOLD);
20
20
  var underline = (s) => color(s, ANSI_UNDERLINE);
21
21
  var cyan = (s) => color(s, ANSI_CYAN);
22
22
  var grey = (s) => color(s, ANSI_GREY);
23
+ var GROUPS = [
24
+ { key: "lifecycle", label: "Container lifecycle" },
25
+ { key: "run", label: "Run + inspect" },
26
+ { key: "edit", label: "Edit container yml" },
27
+ { key: "discovery", label: "Discovery" },
28
+ { key: "tooling", label: "Tooling" }
29
+ ];
23
30
  function resolveArgs(argsDef) {
24
31
  if (!argsDef) return [];
25
32
  const out = [];
@@ -52,19 +59,92 @@ function renderArgDescription(arg, isRequired) {
52
59
  return parts.join(" ");
53
60
  }
54
61
  var ANSI_RE = /\x1b\[[0-9;]*m/g;
62
+ function visibleLen(s) {
63
+ return s.replace(ANSI_RE, "").length;
64
+ }
65
+ function terminalWidth() {
66
+ return process.stdout.columns && process.stdout.columns > 40 ? process.stdout.columns : 100;
67
+ }
68
+ function wrapText(text, width, continuationIndent) {
69
+ if (visibleLen(text) <= width) return text;
70
+ const words = text.split(/(\s+)/);
71
+ const lines = [];
72
+ let current = "";
73
+ for (const w of words) {
74
+ if (visibleLen(current) + visibleLen(w) <= width) {
75
+ current += w;
76
+ continue;
77
+ }
78
+ if (current.length > 0) lines.push(current.replace(/\s+$/, ""));
79
+ current = w.replace(/^\s+/, "");
80
+ }
81
+ if (current.length > 0) lines.push(current.replace(/\s+$/, ""));
82
+ return lines.map((l, i) => i === 0 ? l : continuationIndent + l).join("\n");
83
+ }
55
84
  function alignTable(rows, indent) {
56
85
  if (rows.length === 0) return "";
57
- const visibleLen = (s) => s.replace(ANSI_RE, "").length;
58
- const width = Math.max(...rows.map((r) => visibleLen(r[0])));
86
+ const labelWidth = Math.max(...rows.map((r) => visibleLen(r[0])));
87
+ const gutter = " ";
88
+ const descWidth = terminalWidth() - indent.length - labelWidth - gutter.length;
89
+ const continuationIndent = " ".repeat(
90
+ indent.length + labelWidth + gutter.length
91
+ );
59
92
  return rows.map(([left, right]) => {
60
- const pad = " ".repeat(width - visibleLen(left));
61
- return `${indent}${left}${pad} ${right}`;
93
+ const pad = " ".repeat(labelWidth - visibleLen(left));
94
+ const wrapped = wrapText(right, descWidth, continuationIndent);
95
+ return `${indent}${left}${pad}${gutter}${wrapped}`;
62
96
  }).join("\n");
63
97
  }
98
+ function collectSubCommands(cmd) {
99
+ const subs = cmd.subCommands ?? {};
100
+ const out = [];
101
+ for (const [name, sub] of Object.entries(subs)) {
102
+ const meta = sub?.meta ?? {};
103
+ if (meta.hidden) continue;
104
+ out.push({
105
+ name,
106
+ description: meta.description ?? "",
107
+ group: meta.group ?? "other"
108
+ });
109
+ }
110
+ return out;
111
+ }
112
+ function renderCommandsBlock(entries) {
113
+ if (entries.length === 0) return [];
114
+ const lines = [];
115
+ lines.push(underline(bold("COMMANDS")));
116
+ const byGroup = /* @__PURE__ */ new Map();
117
+ for (const entry2 of entries) {
118
+ const arr = byGroup.get(entry2.group) ?? [];
119
+ arr.push(entry2);
120
+ byGroup.set(entry2.group, arr);
121
+ }
122
+ const renderSection = (label, items) => {
123
+ if (items.length === 0) return;
124
+ lines.push("");
125
+ lines.push(underline(grey(label)));
126
+ lines.push("");
127
+ const rows = items.map((e) => [
128
+ cyan(e.name),
129
+ e.description
130
+ ]);
131
+ lines.push(alignTable(rows, ""));
132
+ };
133
+ for (const { key, label } of GROUPS) {
134
+ renderSection(label, byGroup.get(key) ?? []);
135
+ byGroup.delete(key);
136
+ }
137
+ for (const [groupKey, items] of byGroup) {
138
+ const label = groupKey === "other" ? "Other" : groupKey;
139
+ renderSection(label, items);
140
+ }
141
+ lines.push("");
142
+ return lines;
143
+ }
64
144
  function renderUsageBlock(cmd, commandPath) {
65
145
  const meta = cmd.meta ?? {};
66
146
  const args = resolveArgs(cmd.args ?? {});
67
- const subCommands = cmd.subCommands ?? {};
147
+ const subCommandEntries = collectSubCommands(cmd);
68
148
  const fullName = commandPath.join(" ") || meta.name || "monoceros";
69
149
  const positionals = args.filter((a) => a.type === "positional");
70
150
  const flags = args.filter((a) => a.type !== "positional");
@@ -74,17 +154,12 @@ function renderUsageBlock(cmd, commandPath) {
74
154
  const t = p.name.toUpperCase();
75
155
  usageTokens.push(isRequired ? `<${t}>` : `[${t}]`);
76
156
  }
77
- const subCommandNames = Object.keys(subCommands).filter((n) => {
78
- const sub = subCommands[n];
79
- const subMeta = sub?.meta ?? {};
80
- return !subMeta.hidden;
81
- });
82
- if (subCommandNames.length > 0) usageTokens.push(subCommandNames.join("|"));
157
+ if (subCommandEntries.length > 0) usageTokens.push("<command>");
83
158
  if (flags.length > 0) usageTokens.push("[OPTIONS]");
84
159
  const lines = [];
85
160
  const version = meta.version;
86
161
  const header = `${meta.description ?? ""} (${fullName}${version ? ` v${version}` : ""})`;
87
- lines.push(grey(header));
162
+ lines.push(grey(wrapText(header, terminalWidth(), "")));
88
163
  lines.push("");
89
164
  lines.push(
90
165
  `${underline(bold("USAGE"))} ${cyan([fullName, ...usageTokens].join(" "))}`
@@ -112,17 +187,10 @@ function renderUsageBlock(cmd, commandPath) {
112
187
  lines.push(alignTable(rows, " "));
113
188
  lines.push("");
114
189
  }
115
- if (subCommandNames.length > 0) {
116
- lines.push(underline(bold("COMMANDS")));
117
- lines.push("");
118
- const rows = [];
119
- for (const n of subCommandNames) {
120
- const sub = subCommands[n];
121
- const subMeta = sub?.meta ?? {};
122
- rows.push([cyan(n), subMeta.description ?? ""]);
190
+ if (subCommandEntries.length > 0) {
191
+ for (const line of renderCommandsBlock(subCommandEntries)) {
192
+ lines.push(line);
123
193
  }
124
- lines.push(alignTable(rows, " "));
125
- lines.push("");
126
194
  lines.push(
127
195
  `Use ${cyan(`${fullName} <command> --help`)} for more information about a command.`
128
196
  );
@@ -185,7 +253,7 @@ function getInnerArgs() {
185
253
  }
186
254
 
187
255
  // src/main.ts
188
- import { defineCommand as defineCommand24 } from "citty";
256
+ import { defineCommand as defineCommand25 } from "citty";
189
257
 
190
258
  // src/commands/add-apt-packages.ts
191
259
  import { defineCommand } from "citty";
@@ -1279,6 +1347,7 @@ var defaultConfirm = async (message) => {
1279
1347
  var addAptPackagesCommand = defineCommand({
1280
1348
  meta: {
1281
1349
  name: "add-apt-packages",
1350
+ group: "edit",
1282
1351
  description: "Add Debian/Ubuntu apt packages to the container config. Pass package names after `--` (e.g. `monoceros add-apt-packages sandbox -- make openssh-client jq`). Idempotent. No curated whitelist \u2014 invalid names surface as apt errors at container build time."
1283
1352
  },
1284
1353
  args: {
@@ -1322,6 +1391,7 @@ import { consola as consola3 } from "consola";
1322
1391
  var addFeatureCommand = defineCommand2({
1323
1392
  meta: {
1324
1393
  name: "add-feature",
1394
+ group: "edit",
1325
1395
  description: "Add a devcontainer feature by ref to the container config. Options follow `--` as `key=value` pairs. Idempotent (same ref + same options is a no-op). Adding the same ref with different options is an error."
1326
1396
  },
1327
1397
  args: {
@@ -1395,6 +1465,7 @@ import { consola as consola4 } from "consola";
1395
1465
  var addFromUrlCommand = defineCommand3({
1396
1466
  meta: {
1397
1467
  name: "add-from-url",
1468
+ group: "edit",
1398
1469
  description: "Add an https:// install URL to the container config. The URL gets piped to sh on every container rebuild. Loudly warns about remote-code execution before persisting. Idempotent."
1399
1470
  },
1400
1471
  args: {
@@ -1466,6 +1537,7 @@ import { consola as consola5 } from "consola";
1466
1537
  var addRepoCommand = defineCommand4({
1467
1538
  meta: {
1468
1539
  name: "add-repo",
1540
+ group: "edit",
1469
1541
  description: "Add a git repo to the container config. Cloned into projects/<folder>/ on container build. Idempotent \u2014 existing project subfolders are left alone. Folder name derived from URL by default; override with --as."
1470
1542
  },
1471
1543
  args: {
@@ -1517,6 +1589,7 @@ import { consola as consola6 } from "consola";
1517
1589
  var addLanguageCommand = defineCommand5({
1518
1590
  meta: {
1519
1591
  name: "add-language",
1592
+ group: "edit",
1520
1593
  description: "Add a language toolchain (devcontainer feature) to the container config. Idempotent, prints a diff before writing."
1521
1594
  },
1522
1595
  args: {
@@ -1558,6 +1631,7 @@ import { consola as consola7 } from "consola";
1558
1631
  var addServiceCommand = defineCommand6({
1559
1632
  meta: {
1560
1633
  name: "add-service",
1634
+ group: "edit",
1561
1635
  description: "Add a compose service (postgres, mysql, redis, \u2026) to the container config. Idempotent, prints a diff before writing."
1562
1636
  },
1563
1637
  args: {
@@ -2289,7 +2363,7 @@ function warnOnDeprecatedFeatureRefs(containerFeatures, globalConfig, logger) {
2289
2363
  }
2290
2364
 
2291
2365
  // src/version.ts
2292
- var CLI_VERSION = "1.0.1";
2366
+ var CLI_VERSION = "1.2.0";
2293
2367
 
2294
2368
  // src/commands/_dispatch.ts
2295
2369
  import { consola as consola11 } from "consola";
@@ -2307,6 +2381,7 @@ async function dispatch(runner) {
2307
2381
  var applyCommand = defineCommand7({
2308
2382
  meta: {
2309
2383
  name: "apply",
2384
+ group: "lifecycle",
2310
2385
  description: "Materialize a container config into $MONOCEROS_HOME/container/<name>/ and bring the dev-container up. Close any VS Code Remote Containers session for the target first \u2014 the extension auto-recreates and races with apply."
2311
2386
  },
2312
2387
  args: {
@@ -2327,8 +2402,215 @@ var applyCommand = defineCommand7({
2327
2402
  }
2328
2403
  });
2329
2404
 
2330
- // src/commands/init.ts
2405
+ // src/commands/completion.ts
2331
2406
  import { defineCommand as defineCommand8 } from "citty";
2407
+ var ALL_COMMANDS = [
2408
+ "init",
2409
+ "list-components",
2410
+ "shell",
2411
+ "run",
2412
+ "logs",
2413
+ "start",
2414
+ "stop",
2415
+ "status",
2416
+ "apply",
2417
+ "remove",
2418
+ "restore",
2419
+ "add-service",
2420
+ "add-language",
2421
+ "add-apt-packages",
2422
+ "add-feature",
2423
+ "add-from-url",
2424
+ "add-repo",
2425
+ "remove-service",
2426
+ "remove-language",
2427
+ "remove-apt-packages",
2428
+ "remove-feature",
2429
+ "remove-from-url",
2430
+ "remove-repo",
2431
+ "completion"
2432
+ ];
2433
+ var COMMANDS_WITH_CONTAINER_ARG = [
2434
+ "shell",
2435
+ "run",
2436
+ "logs",
2437
+ "start",
2438
+ "stop",
2439
+ "status",
2440
+ "apply",
2441
+ "remove",
2442
+ "add-service",
2443
+ "add-language",
2444
+ "add-apt-packages",
2445
+ "add-feature",
2446
+ "add-from-url",
2447
+ "add-repo",
2448
+ "remove-service",
2449
+ "remove-language",
2450
+ "remove-apt-packages",
2451
+ "remove-feature",
2452
+ "remove-from-url",
2453
+ "remove-repo"
2454
+ ];
2455
+ var SHELLS = ["bash", "zsh", "pwsh"];
2456
+ function renderCompletionScript(shell) {
2457
+ const commands = ALL_COMMANDS.join(" ");
2458
+ const containerCommandsRegex = COMMANDS_WITH_CONTAINER_ARG.join("|");
2459
+ if (shell === "bash") {
2460
+ return [
2461
+ "# bash completion for monoceros",
2462
+ "# install: source this file from .bashrc, e.g.",
2463
+ "# monoceros completion bash > ~/.bash_completion.d/monoceros",
2464
+ '# echo "source ~/.bash_completion.d/monoceros" >> ~/.bashrc',
2465
+ "",
2466
+ "_monoceros() {",
2467
+ " local cur prev cmd home configs_dir names",
2468
+ ' cur="${COMP_WORDS[COMP_CWORD]}"',
2469
+ "",
2470
+ " if [[ $COMP_CWORD -eq 1 ]]; then",
2471
+ ` COMPREPLY=( $(compgen -W "${commands}" -- "$cur") )`,
2472
+ " return",
2473
+ " fi",
2474
+ "",
2475
+ ' cmd="${COMP_WORDS[1]}"',
2476
+ " if [[ $COMP_CWORD -eq 2 ]]; then",
2477
+ ' case "$cmd" in',
2478
+ ` ${containerCommandsRegex})`,
2479
+ ' home="${MONOCEROS_HOME:-$HOME/.monoceros}"',
2480
+ ' configs_dir="$home/container-configs"',
2481
+ ' if [[ -d "$configs_dir" ]]; then',
2482
+ ` names=$(cd "$configs_dir" && ls *.yml 2>/dev/null | sed 's/\\.yml$//')`,
2483
+ ' COMPREPLY=( $(compgen -W "$names" -- "$cur") )',
2484
+ " fi",
2485
+ " ;;",
2486
+ " completion)",
2487
+ ` COMPREPLY=( $(compgen -W "${SHELLS.join(" ")}" -- "$cur") )`,
2488
+ " ;;",
2489
+ " esac",
2490
+ " fi",
2491
+ "}",
2492
+ "complete -F _monoceros monoceros",
2493
+ ""
2494
+ ].join("\n");
2495
+ }
2496
+ if (shell === "pwsh") {
2497
+ return [
2498
+ "# PowerShell completion for monoceros",
2499
+ "# install: dot-source this file from your $PROFILE, e.g.",
2500
+ "# monoceros completion pwsh > $HOME/.config/monoceros/completion.ps1",
2501
+ "# Add-Content $PROFILE '. $HOME/.config/monoceros/completion.ps1'",
2502
+ "",
2503
+ "Register-ArgumentCompleter -Native -CommandName monoceros -ScriptBlock {",
2504
+ " param($wordToComplete, $commandAst, $cursorPosition)",
2505
+ "",
2506
+ " $commands = @(",
2507
+ ...ALL_COMMANDS.map((c) => ` '${c}'`),
2508
+ " )",
2509
+ ` $shells = @('${SHELLS.join("', '")}')`,
2510
+ " $containerCommands = @(",
2511
+ ...COMMANDS_WITH_CONTAINER_ARG.map((c) => ` '${c}'`),
2512
+ " )",
2513
+ "",
2514
+ " $tokens = $commandAst.CommandElements",
2515
+ " $position = $tokens.Count",
2516
+ " if ($wordToComplete) { $position-- }",
2517
+ "",
2518
+ " if ($position -eq 1) {",
2519
+ ' $commands | Where-Object { $_ -like "$wordToComplete*" } |',
2520
+ ' ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_) }',
2521
+ " return",
2522
+ " }",
2523
+ "",
2524
+ " if ($position -eq 2) {",
2525
+ " $cmd = $tokens[1].Value",
2526
+ " if ($containerCommands -contains $cmd) {",
2527
+ ' $home = if ($env:MONOCEROS_HOME) { $env:MONOCEROS_HOME } else { Join-Path $env:USERPROFILE ".monoceros" }',
2528
+ ' $configsDir = Join-Path $home "container-configs"',
2529
+ " if (Test-Path $configsDir) {",
2530
+ ' Get-ChildItem -Path $configsDir -Filter "*.yml" |',
2531
+ " ForEach-Object { $_.BaseName } |",
2532
+ ' Where-Object { $_ -like "$wordToComplete*" } |',
2533
+ ' ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_) }',
2534
+ " }",
2535
+ ' } elseif ($cmd -eq "completion") {',
2536
+ ' $shells | Where-Object { $_ -like "$wordToComplete*" } |',
2537
+ ' ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_) }',
2538
+ " }",
2539
+ " }",
2540
+ "}",
2541
+ ""
2542
+ ].join("\n");
2543
+ }
2544
+ return [
2545
+ "#compdef monoceros",
2546
+ "# zsh completion for monoceros",
2547
+ "# install: drop this file somewhere on your $fpath as `_monoceros`,",
2548
+ "# then start a new shell (or run `compinit`). Example:",
2549
+ '# monoceros completion zsh > "${fpath[1]}/_monoceros"',
2550
+ "",
2551
+ "_monoceros() {",
2552
+ " local -a commands shells",
2553
+ " commands=(",
2554
+ ...ALL_COMMANDS.map((c) => ` '${c}'`),
2555
+ " )",
2556
+ ` shells=(${SHELLS.map((s) => `'${s}'`).join(" ")})`,
2557
+ "",
2558
+ " if (( CURRENT == 2 )); then",
2559
+ " _describe 'monoceros command' commands",
2560
+ " return",
2561
+ " fi",
2562
+ "",
2563
+ " local cmd=${words[2]}",
2564
+ " if (( CURRENT == 3 )); then",
2565
+ " case $cmd in",
2566
+ ` ${containerCommandsRegex})`,
2567
+ ' local home="${MONOCEROS_HOME:-$HOME/.monoceros}"',
2568
+ ' local configs_dir="$home/container-configs"',
2569
+ " if [[ -d $configs_dir ]]; then",
2570
+ " local -a names",
2571
+ " names=(${configs_dir}/*.yml(N:t:r))",
2572
+ " _describe 'container' names",
2573
+ " fi",
2574
+ " ;;",
2575
+ " completion)",
2576
+ " _describe 'shell' shells",
2577
+ " ;;",
2578
+ " esac",
2579
+ " fi",
2580
+ "}",
2581
+ "",
2582
+ '_monoceros "$@"',
2583
+ ""
2584
+ ].join("\n");
2585
+ }
2586
+ var completionCommand = defineCommand8({
2587
+ meta: {
2588
+ name: "completion",
2589
+ group: "tooling",
2590
+ description: "Print a shell completion script for bash, zsh or PowerShell to stdout. Pipe the output into a file your shell loads at startup. The install scripts (install.sh / install.ps1) call this automatically."
2591
+ },
2592
+ args: {
2593
+ shell: {
2594
+ type: "positional",
2595
+ description: "Target shell. One of: 'bash', 'zsh', 'pwsh'.",
2596
+ required: true
2597
+ }
2598
+ },
2599
+ run({ args }) {
2600
+ const shell = args.shell;
2601
+ if (shell !== "bash" && shell !== "zsh" && shell !== "pwsh") {
2602
+ process.stderr.write(
2603
+ `Unknown shell: ${JSON.stringify(shell)}. Supported: ${SHELLS.join(", ")}.
2604
+ `
2605
+ );
2606
+ process.exit(2);
2607
+ }
2608
+ process.stdout.write(renderCompletionScript(shell));
2609
+ }
2610
+ });
2611
+
2612
+ // src/commands/init.ts
2613
+ import { defineCommand as defineCommand9 } from "citty";
2332
2614
  import { consola as consola13 } from "consola";
2333
2615
 
2334
2616
  // src/init/index.ts
@@ -2788,9 +3070,10 @@ async function runInit(opts) {
2788
3070
  }
2789
3071
 
2790
3072
  // src/commands/init.ts
2791
- var initCommand = defineCommand8({
3073
+ var initCommand = defineCommand9({
2792
3074
  meta: {
2793
3075
  name: "init",
3076
+ group: "lifecycle",
2794
3077
  description: "Create a fresh container-config yml at .local/container-configs/<name>.yml. Without --with, the file is a documented default with every component commented out. With --with=<names>, the named components are composed into an active, immediately-applyable yml. Then run `monoceros apply <name>`."
2795
3078
  },
2796
3079
  args: {
@@ -2841,11 +3124,12 @@ function collectWithList(withArg, rawArgs) {
2841
3124
  }
2842
3125
 
2843
3126
  // src/commands/list-components.ts
2844
- import { defineCommand as defineCommand9 } from "citty";
3127
+ import { defineCommand as defineCommand10 } from "citty";
2845
3128
  import { consola as consola14 } from "consola";
2846
- var listComponentsCommand = defineCommand9({
3129
+ var listComponentsCommand = defineCommand10({
2847
3130
  meta: {
2848
3131
  name: "list-components",
3132
+ group: "discovery",
2849
3133
  description: "Print the components catalog used by `monoceros init --with=\u2026`. Each line is `name<TAB>category<TAB>displayName`, grouped by category for readability."
2850
3134
  },
2851
3135
  args: {},
@@ -2885,10 +3169,11 @@ var listComponentsCommand = defineCommand9({
2885
3169
  });
2886
3170
 
2887
3171
  // src/commands/logs.ts
2888
- import { defineCommand as defineCommand10 } from "citty";
2889
- var logsCommand = defineCommand10({
3172
+ import { defineCommand as defineCommand11 } from "citty";
3173
+ var logsCommand = defineCommand11({
2890
3174
  meta: {
2891
3175
  name: "logs",
3176
+ group: "run",
2892
3177
  description: "Tail logs from the compose services of the named dev-container. Pass --no-follow for a one-shot dump."
2893
3178
  },
2894
3179
  args: {
@@ -2920,11 +3205,12 @@ var logsCommand = defineCommand10({
2920
3205
  });
2921
3206
 
2922
3207
  // src/commands/remove-apt-packages.ts
2923
- import { defineCommand as defineCommand11 } from "citty";
3208
+ import { defineCommand as defineCommand12 } from "citty";
2924
3209
  import { consola as consola15 } from "consola";
2925
- var removeAptPackagesCommand = defineCommand11({
3210
+ var removeAptPackagesCommand = defineCommand12({
2926
3211
  meta: {
2927
3212
  name: "remove-apt-packages",
3213
+ group: "edit",
2928
3214
  description: "Remove apt packages from the container config. Pass package names after `--` (e.g. `monoceros remove-apt-packages sandbox -- make jq`). Idempotent, prints a diff before writing."
2929
3215
  },
2930
3216
  args: {
@@ -2963,11 +3249,12 @@ var removeAptPackagesCommand = defineCommand11({
2963
3249
  });
2964
3250
 
2965
3251
  // src/commands/remove-feature.ts
2966
- import { defineCommand as defineCommand12 } from "citty";
3252
+ import { defineCommand as defineCommand13 } from "citty";
2967
3253
  import { consola as consola16 } from "consola";
2968
- var removeFeatureCommand = defineCommand12({
3254
+ var removeFeatureCommand = defineCommand13({
2969
3255
  meta: {
2970
3256
  name: "remove-feature",
3257
+ group: "edit",
2971
3258
  description: "Remove a devcontainer feature from the container config (by its OCI ref). Idempotent, prints a diff before writing."
2972
3259
  },
2973
3260
  args: {
@@ -3004,7 +3291,7 @@ var removeFeatureCommand = defineCommand12({
3004
3291
  });
3005
3292
 
3006
3293
  // src/commands/remove.ts
3007
- import { defineCommand as defineCommand13 } from "citty";
3294
+ import { defineCommand as defineCommand14 } from "citty";
3008
3295
  import { consola as consola18 } from "consola";
3009
3296
  import { createInterface } from "readline/promises";
3010
3297
 
@@ -3090,9 +3377,10 @@ async function runRemove(opts) {
3090
3377
  }
3091
3378
 
3092
3379
  // src/commands/remove.ts
3093
- var removeCommand = defineCommand13({
3380
+ var removeCommand = defineCommand14({
3094
3381
  meta: {
3095
3382
  name: "remove",
3383
+ group: "lifecycle",
3096
3384
  description: "Wipe everything belonging to a container: stop and remove the docker objects, back up the container-configs yml + container directory (incl. home/, projects/, data/), then delete them from disk. Shared docker images stay. By default the destructive step is confirmed interactively; pass -y to skip."
3097
3385
  },
3098
3386
  args: {
@@ -3150,7 +3438,7 @@ var removeCommand = defineCommand13({
3150
3438
  });
3151
3439
 
3152
3440
  // src/commands/restore.ts
3153
- import { defineCommand as defineCommand14 } from "citty";
3441
+ import { defineCommand as defineCommand15 } from "citty";
3154
3442
  import { consola as consola20 } from "consola";
3155
3443
 
3156
3444
  // src/restore/index.ts
@@ -3218,9 +3506,10 @@ async function runRestore(opts) {
3218
3506
  }
3219
3507
 
3220
3508
  // src/commands/restore.ts
3221
- var restoreCommand = defineCommand14({
3509
+ var restoreCommand = defineCommand15({
3222
3510
  meta: {
3223
3511
  name: "restore",
3512
+ group: "lifecycle",
3224
3513
  description: "Restore a container's host-side state from a backup written by `monoceros remove`. Copies the yml and the container directory back into $MONOCEROS_HOME. Refuses to overwrite an existing config or container \u2014 remove the in-place container first if you need to clobber. Run `monoceros apply <name>` afterwards to bring it back up."
3225
3514
  },
3226
3515
  args: {
@@ -3241,11 +3530,12 @@ var restoreCommand = defineCommand14({
3241
3530
  });
3242
3531
 
3243
3532
  // src/commands/remove-from-url.ts
3244
- import { defineCommand as defineCommand15 } from "citty";
3533
+ import { defineCommand as defineCommand16 } from "citty";
3245
3534
  import { consola as consola21 } from "consola";
3246
- var removeFromUrlCommand = defineCommand15({
3535
+ var removeFromUrlCommand = defineCommand16({
3247
3536
  meta: {
3248
3537
  name: "remove-from-url",
3538
+ group: "edit",
3249
3539
  description: "Remove a previously-added install URL from the container config. Idempotent, prints a diff before writing. The URL is dropped from post-create.sh on the next `monoceros apply`."
3250
3540
  },
3251
3541
  args: {
@@ -3282,11 +3572,12 @@ var removeFromUrlCommand = defineCommand15({
3282
3572
  });
3283
3573
 
3284
3574
  // src/commands/remove-language.ts
3285
- import { defineCommand as defineCommand16 } from "citty";
3575
+ import { defineCommand as defineCommand17 } from "citty";
3286
3576
  import { consola as consola22 } from "consola";
3287
- var removeLanguageCommand = defineCommand16({
3577
+ var removeLanguageCommand = defineCommand17({
3288
3578
  meta: {
3289
3579
  name: "remove-language",
3580
+ group: "edit",
3290
3581
  description: "Remove a language toolchain from the container config. Idempotent, prints a diff before writing."
3291
3582
  },
3292
3583
  args: {
@@ -3323,11 +3614,12 @@ var removeLanguageCommand = defineCommand16({
3323
3614
  });
3324
3615
 
3325
3616
  // src/commands/remove-repo.ts
3326
- import { defineCommand as defineCommand17 } from "citty";
3617
+ import { defineCommand as defineCommand18 } from "citty";
3327
3618
  import { consola as consola23 } from "consola";
3328
- var removeRepoCommand = defineCommand17({
3619
+ var removeRepoCommand = defineCommand18({
3329
3620
  meta: {
3330
3621
  name: "remove-repo",
3622
+ group: "edit",
3331
3623
  description: "Remove a repo from the container config (matches by URL or by its projects/<folder> name). Does NOT delete the existing projects/<folder> directory \u2014 local edits are preserved; clean it up manually."
3332
3624
  },
3333
3625
  args: {
@@ -3364,11 +3656,12 @@ var removeRepoCommand = defineCommand17({
3364
3656
  });
3365
3657
 
3366
3658
  // src/commands/remove-service.ts
3367
- import { defineCommand as defineCommand18 } from "citty";
3659
+ import { defineCommand as defineCommand19 } from "citty";
3368
3660
  import { consola as consola24 } from "consola";
3369
- var removeServiceCommand = defineCommand18({
3661
+ var removeServiceCommand = defineCommand19({
3370
3662
  meta: {
3371
3663
  name: "remove-service",
3664
+ group: "edit",
3372
3665
  description: "Remove a compose service from the container config. Idempotent, prints a diff before writing. Note: data volumes (e.g. postgres-data) are NOT cleaned up automatically."
3373
3666
  },
3374
3667
  args: {
@@ -3405,7 +3698,7 @@ var removeServiceCommand = defineCommand18({
3405
3698
  });
3406
3699
 
3407
3700
  // src/commands/run.ts
3408
- import { defineCommand as defineCommand19 } from "citty";
3701
+ import { defineCommand as defineCommand20 } from "citty";
3409
3702
  import { consola as consola25 } from "consola";
3410
3703
 
3411
3704
  // src/devcontainer/shell.ts
@@ -3455,9 +3748,10 @@ async function runInContainer(opts) {
3455
3748
  }
3456
3749
 
3457
3750
  // src/commands/run.ts
3458
- var runCommand = defineCommand19({
3751
+ var runCommand = defineCommand20({
3459
3752
  meta: {
3460
3753
  name: "run",
3754
+ group: "run",
3461
3755
  description: "Run a one-off command inside the named dev-container. Use `--` to separate monoceros flags from the inner command."
3462
3756
  },
3463
3757
  args: {
@@ -3489,11 +3783,12 @@ var runCommand = defineCommand19({
3489
3783
  });
3490
3784
 
3491
3785
  // src/commands/shell.ts
3492
- import { defineCommand as defineCommand20 } from "citty";
3786
+ import { defineCommand as defineCommand21 } from "citty";
3493
3787
  import { consola as consola26 } from "consola";
3494
- var shellCommand = defineCommand20({
3788
+ var shellCommand = defineCommand21({
3495
3789
  meta: {
3496
3790
  name: "shell",
3791
+ group: "run",
3497
3792
  description: "Open an interactive bash session inside the named dev-container."
3498
3793
  },
3499
3794
  args: {
@@ -3515,10 +3810,11 @@ var shellCommand = defineCommand20({
3515
3810
  });
3516
3811
 
3517
3812
  // src/commands/start.ts
3518
- import { defineCommand as defineCommand21 } from "citty";
3519
- var startCommand = defineCommand21({
3813
+ import { defineCommand as defineCommand22 } from "citty";
3814
+ var startCommand = defineCommand22({
3520
3815
  meta: {
3521
3816
  name: "start",
3817
+ group: "run",
3522
3818
  description: "Bring the named dev-container up via `devcontainer up` (workspace + runServices, postCreate, features)."
3523
3819
  },
3524
3820
  args: {
@@ -3534,10 +3830,11 @@ var startCommand = defineCommand21({
3534
3830
  });
3535
3831
 
3536
3832
  // src/commands/status.ts
3537
- import { defineCommand as defineCommand22 } from "citty";
3538
- var statusCommand = defineCommand22({
3833
+ import { defineCommand as defineCommand23 } from "citty";
3834
+ var statusCommand = defineCommand23({
3539
3835
  meta: {
3540
3836
  name: "status",
3837
+ group: "run",
3541
3838
  description: "Show whether the compose services for the named dev-container are running."
3542
3839
  },
3543
3840
  args: {
@@ -3562,10 +3859,11 @@ var statusCommand = defineCommand22({
3562
3859
  });
3563
3860
 
3564
3861
  // src/commands/stop.ts
3565
- import { defineCommand as defineCommand23 } from "citty";
3566
- var stopCommand = defineCommand23({
3862
+ import { defineCommand as defineCommand24 } from "citty";
3863
+ var stopCommand = defineCommand24({
3567
3864
  meta: {
3568
3865
  name: "stop",
3866
+ group: "run",
3569
3867
  description: "Stop the compose services for the named dev-container. Volumes are preserved."
3570
3868
  },
3571
3869
  args: {
@@ -3590,7 +3888,7 @@ var stopCommand = defineCommand23({
3590
3888
  });
3591
3889
 
3592
3890
  // src/main.ts
3593
- var main = defineCommand24({
3891
+ var main = defineCommand25({
3594
3892
  meta: {
3595
3893
  name: "monoceros",
3596
3894
  version: CLI_VERSION,
@@ -3619,7 +3917,8 @@ var main = defineCommand24({
3619
3917
  "remove-apt-packages": removeAptPackagesCommand,
3620
3918
  "remove-feature": removeFeatureCommand,
3621
3919
  "remove-from-url": removeFromUrlCommand,
3622
- "remove-repo": removeRepoCommand
3920
+ "remove-repo": removeRepoCommand,
3921
+ completion: completionCommand
3623
3922
  }
3624
3923
  });
3625
3924