@getmonoceros/workbench 1.38.20 → 1.39.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
@@ -9138,7 +9138,7 @@ var CLI_VERSION;
9138
9138
  var init_version = __esm({
9139
9139
  "src/version.ts"() {
9140
9140
  "use strict";
9141
- CLI_VERSION = true ? "1.38.20" : "dev";
9141
+ CLI_VERSION = true ? "1.39.0" : "dev";
9142
9142
  }
9143
9143
  });
9144
9144
 
@@ -9213,164 +9213,6 @@ var init_apply2 = __esm({
9213
9213
  }
9214
9214
  });
9215
9215
 
9216
- // src/commands/completion.ts
9217
- import { defineCommand as defineCommand9 } from "citty";
9218
- function renderCompletionScript(shell) {
9219
- if (shell === "bash") {
9220
- return [
9221
- "# bash completion for monoceros",
9222
- "# install: source this file from .bashrc, e.g.",
9223
- "# monoceros completion bash > ~/.bash_completion.d/monoceros",
9224
- '# echo "source ~/.bash_completion.d/monoceros" >> ~/.bashrc',
9225
- "#",
9226
- "# The work is done by `monoceros __complete --line --point`; this",
9227
- "# shell wrapper only forwards the cursor view.",
9228
- "",
9229
- "_monoceros() {",
9230
- " local IFS=$'\\n'",
9231
- " local candidates",
9232
- ' candidates=$(monoceros __complete --line "$COMP_LINE" --point "$COMP_POINT" 2>/dev/null)',
9233
- ' local cur="${COMP_WORDS[COMP_CWORD]}"',
9234
- ' COMPREPLY=( $(compgen -W "$candidates" -- "$cur") )',
9235
- " # Suppress the trailing space when bash narrowed the candidate",
9236
- " # set to a single token that ends with `=` \u2014 those are value-",
9237
- " # flags (`--with-features=`, `--with-ports=`, \u2026) where the user types the",
9238
- " # value immediately after.",
9239
- ' if [[ ${#COMPREPLY[@]} -eq 1 && "${COMPREPLY[0]}" == *= ]]; then',
9240
- " compopt -o nospace",
9241
- " fi",
9242
- "}",
9243
- "complete -F _monoceros monoceros",
9244
- ""
9245
- ].join("\n");
9246
- }
9247
- if (shell === "pwsh") {
9248
- return [
9249
- "# PowerShell completion for monoceros",
9250
- "# install: dot-source this file from your $PROFILE, e.g.",
9251
- "# monoceros completion pwsh > $HOME/.config/monoceros/completion.ps1",
9252
- "# Add-Content $PROFILE '. $HOME/.config/monoceros/completion.ps1'",
9253
- "#",
9254
- "# The work is done by `monoceros __complete --line --point`; this",
9255
- "# shell wrapper only forwards the cursor view.",
9256
- "",
9257
- "Register-ArgumentCompleter -Native -CommandName monoceros -ScriptBlock {",
9258
- " param($wordToComplete, $commandAst, $cursorPosition)",
9259
- " $line = $commandAst.Extent.Text",
9260
- " $point = $cursorPosition - $commandAst.Extent.StartOffset",
9261
- " if ($point -lt 0) { $point = 0 }",
9262
- " $raw = & monoceros __complete --line $line --point $point 2>$null",
9263
- " if (-not $raw) { return }",
9264
- ' $raw -split "`n" |',
9265
- ' Where-Object { $_.Length -gt 0 -and $_ -like "$wordToComplete*" } |',
9266
- ' ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_) }',
9267
- "}",
9268
- ""
9269
- ].join("\n");
9270
- }
9271
- return [
9272
- "#compdef monoceros",
9273
- "# zsh completion for monoceros",
9274
- "# install: drop this file somewhere on your $fpath as `_monoceros`,",
9275
- "# then start a new shell (or run `compinit`). Example:",
9276
- '# monoceros completion zsh > "${fpath[1]}/_monoceros"',
9277
- "#",
9278
- "# The work is done by `monoceros __complete --line --point`; this",
9279
- "# shell wrapper only forwards the cursor view.",
9280
- "",
9281
- "_monoceros() {",
9282
- ' local line="$BUFFER"',
9283
- ' local point="$CURSOR"',
9284
- " local -a candidates with_eq without_eq",
9285
- ' candidates=("${(@f)$(monoceros __complete --line "$line" --point "$point" 2>/dev/null)}")',
9286
- ' candidates=("${(@)candidates:#}")',
9287
- ' # Split candidates into "ends with `=`" (value-flags \u2014 no suffix',
9288
- " # space wanted because the user types the value immediately) and",
9289
- ' # "everything else" (positional values, boolean flags \u2014 default',
9290
- " # space behaviour).",
9291
- ' for cand in "${candidates[@]}"; do',
9292
- ' if [[ "$cand" == *= ]]; then',
9293
- ' with_eq+=("$cand")',
9294
- " else",
9295
- ' without_eq+=("$cand")',
9296
- " fi",
9297
- " done",
9298
- " (( ${#with_eq[@]} )) && compadd -S '' -- \"${with_eq[@]}\"",
9299
- ' (( ${#without_eq[@]} )) && compadd -- "${without_eq[@]}"',
9300
- "}",
9301
- "",
9302
- '_monoceros "$@"',
9303
- ""
9304
- ].join("\n");
9305
- }
9306
- var SHELLS, completionCommand;
9307
- var init_completion = __esm({
9308
- "src/commands/completion.ts"() {
9309
- "use strict";
9310
- SHELLS = ["bash", "zsh", "pwsh"];
9311
- completionCommand = defineCommand9({
9312
- meta: {
9313
- name: "completion",
9314
- group: "tooling",
9315
- // Hidden from `monoceros --help`: the install scripts wire up
9316
- // completion automatically; manual setup is documented at
9317
- // getmonoceros.build/docs/reference/utilities/completion. Still runnable directly.
9318
- hidden: true,
9319
- 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."
9320
- },
9321
- args: {
9322
- shell: {
9323
- type: "positional",
9324
- description: "Target shell. One of: 'bash', 'zsh', 'pwsh'.",
9325
- required: true
9326
- }
9327
- },
9328
- run({ args }) {
9329
- const shell = args.shell;
9330
- if (shell !== "bash" && shell !== "zsh" && shell !== "pwsh") {
9331
- process.stderr.write(
9332
- `Unknown shell: ${JSON.stringify(shell)}. Supported: ${SHELLS.join(", ")}.
9333
- `
9334
- );
9335
- process.exit(2);
9336
- }
9337
- process.stdout.write(renderCompletionScript(shell));
9338
- }
9339
- });
9340
- }
9341
- });
9342
-
9343
- // src/commands/__bridge.ts
9344
- import { defineCommand as defineCommand10 } from "citty";
9345
- var __bridgeCommand;
9346
- var init_bridge = __esm({
9347
- "src/commands/__bridge.ts"() {
9348
- "use strict";
9349
- init_bridge_daemon();
9350
- __bridgeCommand = defineCommand10({
9351
- meta: {
9352
- name: "__bridge",
9353
- group: "internal",
9354
- hidden: true,
9355
- description: "Internal: host-side browser-bridge daemon (background)."
9356
- },
9357
- args: {
9358
- root: {
9359
- type: "positional",
9360
- description: "Materialized container root ($MONOCEROS_HOME/container/<name>/).",
9361
- required: true
9362
- }
9363
- },
9364
- async run({ args }) {
9365
- try {
9366
- await runBridgeDaemon({ root: args.root });
9367
- } catch {
9368
- }
9369
- }
9370
- });
9371
- }
9372
- });
9373
-
9374
9216
  // src/config/launch-config.ts
9375
9217
  import { promises as fs16 } from "fs";
9376
9218
  import path25 from "path";
@@ -9569,6 +9411,14 @@ function tokenize(text) {
9569
9411
  function isShellWhitespace(ch) {
9570
9412
  return ch === " " || ch === " ";
9571
9413
  }
9414
+ function staticSource(fn) {
9415
+ pwshMeta.set(fn, { static: true });
9416
+ return fn;
9417
+ }
9418
+ function dynamicSource(kind, fn) {
9419
+ pwshMeta.set(fn, { static: false, kind });
9420
+ return fn;
9421
+ }
9572
9422
  function dispatchCommand(spec, argTokens, ctx) {
9573
9423
  const dashDashIdx = argTokens.indexOf("--");
9574
9424
  const preDash = dashDashIdx < 0 ? argTokens : argTokens.slice(0, dashDashIdx);
@@ -9815,7 +9665,36 @@ async function resolveFeatureRefForCompletion(token) {
9815
9665
  const f = c.file.contributes.features?.[0];
9816
9666
  return f?.ref;
9817
9667
  }
9818
- var WORKSPACE_DIR_SKIP, PROJECTS_DIR_MAX_DEPTH, ALL_COMMANDS, containerName, COMMAND_SPECS, COMPLETION_COMMAND_SPEC_KEYS;
9668
+ async function describeSource(src) {
9669
+ if (!src) return {};
9670
+ const meta = pwshMeta.get(src);
9671
+ if (!meta) return {};
9672
+ if (meta.static) return { values: await src(EMPTY_CTX) };
9673
+ return { kind: meta.kind };
9674
+ }
9675
+ async function buildPwshCompletionModel() {
9676
+ const specs = {};
9677
+ for (const [name, spec] of Object.entries(COMMAND_SPECS)) {
9678
+ const posSources = spec.positionals ?? [];
9679
+ const positionalCount = spec.positionalCount ?? posSources.length;
9680
+ const positionals = [];
9681
+ for (const src of posSources) positionals.push(await describeSource(src));
9682
+ const flags = {};
9683
+ for (const [flag, fspec] of Object.entries(spec.flags ?? {})) {
9684
+ const entry2 = {
9685
+ type: fspec.type,
9686
+ aliases: fspec.aliases ?? []
9687
+ };
9688
+ if (fspec.type === "value" && fspec.values) {
9689
+ entry2.value = await describeSource(fspec.values);
9690
+ }
9691
+ flags[flag] = entry2;
9692
+ }
9693
+ specs[name] = { positionals, positionalCount, flags };
9694
+ }
9695
+ return { commands: [...ALL_COMMANDS], specs };
9696
+ }
9697
+ var pwshMeta, WORKSPACE_DIR_SKIP, PROJECTS_DIR_MAX_DEPTH, ALL_COMMANDS, containerName, appCandidates, appOrServiceCandidates, targetCandidates, runInDirs, languageValues, serviceValues, featureValues, providerValues, shellValues, openToolValues, COMMAND_SPECS, COMPLETION_COMMAND_SPEC_KEYS, EMPTY_CTX;
9819
9698
  var init_resolve = __esm({
9820
9699
  "src/completion/resolve.ts"() {
9821
9700
  "use strict";
@@ -9828,6 +9707,7 @@ var init_resolve = __esm({
9828
9707
  init_catalog();
9829
9708
  init_schema();
9830
9709
  init_open();
9710
+ pwshMeta = /* @__PURE__ */ new WeakMap();
9831
9711
  WORKSPACE_DIR_SKIP = /* @__PURE__ */ new Set(["node_modules"]);
9832
9712
  PROJECTS_DIR_MAX_DEPTH = 4;
9833
9713
  ALL_COMMANDS = [
@@ -9864,7 +9744,26 @@ var init_resolve = __esm({
9864
9744
  "share",
9865
9745
  "completion"
9866
9746
  ];
9867
- containerName = (ctx) => listContainerNames(ctx);
9747
+ containerName = dynamicSource(
9748
+ "containerName",
9749
+ (ctx) => listContainerNames(ctx)
9750
+ );
9751
+ appCandidates = dynamicSource("app", (ctx) => listAppCandidates(ctx));
9752
+ appOrServiceCandidates = dynamicSource(
9753
+ "appOrService",
9754
+ (ctx) => listAppOrServiceCandidates(ctx)
9755
+ );
9756
+ targetCandidates = dynamicSource(
9757
+ "target",
9758
+ (ctx) => listTargetCandidates(ctx)
9759
+ );
9760
+ runInDirs = dynamicSource("runInDir", (ctx) => listRunInDirs(ctx));
9761
+ languageValues = staticSource(() => listLanguageNames());
9762
+ serviceValues = staticSource(() => listServiceNames());
9763
+ featureValues = staticSource(() => listFeatureComponents());
9764
+ providerValues = staticSource(() => listProviders());
9765
+ shellValues = staticSource(() => listShellNames());
9766
+ openToolValues = staticSource(() => [...OPEN_TOOLS]);
9868
9767
  COMMAND_SPECS = {
9869
9768
  init: {
9870
9769
  // First positional is a FRESH name → no suggestion source, but
@@ -9873,12 +9772,9 @@ var init_resolve = __esm({
9873
9772
  // flag suggestions.
9874
9773
  positionalCount: 1,
9875
9774
  flags: {
9876
- "--with-languages": { type: "value", values: () => listLanguageNames() },
9877
- "--with-features": {
9878
- type: "value",
9879
- values: () => listFeatureComponents()
9880
- },
9881
- "--with-services": { type: "value", values: () => listServiceNames() },
9775
+ "--with-languages": { type: "value", values: languageValues },
9776
+ "--with-features": { type: "value", values: featureValues },
9777
+ "--with-services": { type: "value", values: serviceValues },
9882
9778
  "--with-apt-packages": { type: "value" },
9883
9779
  "--with-repos": { type: "value" },
9884
9780
  "--with-ports": { type: "value" }
@@ -9888,7 +9784,7 @@ var init_resolve = __esm({
9888
9784
  positionals: [containerName],
9889
9785
  flags: {
9890
9786
  "--yes": { type: "boolean", aliases: ["-y"] },
9891
- "--open": { type: "value", values: () => [...OPEN_TOOLS] }
9787
+ "--open": { type: "value", values: openToolValues }
9892
9788
  }
9893
9789
  },
9894
9790
  upgrade: {
@@ -9905,39 +9801,39 @@ var init_resolve = __esm({
9905
9801
  }
9906
9802
  },
9907
9803
  shell: { positionals: [containerName] },
9908
- open: { positionals: [containerName, () => [...OPEN_TOOLS]] },
9804
+ open: { positionals: [containerName, openToolValues] },
9909
9805
  run: {
9910
9806
  positionals: [containerName],
9911
- flags: { "--in": { type: "value", values: (ctx) => listRunInDirs(ctx) } }
9807
+ flags: { "--in": { type: "value", values: runInDirs } }
9912
9808
  },
9913
9809
  logs: {
9914
- positionals: [containerName, (ctx) => listAppCandidates(ctx)],
9810
+ positionals: [containerName, appCandidates],
9915
9811
  flags: {
9916
- "--target": { type: "value", values: (ctx) => listTargetCandidates(ctx) }
9812
+ "--target": { type: "value", values: targetCandidates }
9917
9813
  }
9918
9814
  },
9919
9815
  start: {
9920
- positionals: [containerName, (ctx) => listAppCandidates(ctx)],
9816
+ positionals: [containerName, appCandidates],
9921
9817
  flags: {
9922
- "--target": { type: "value", values: (ctx) => listTargetCandidates(ctx) },
9923
- "--open": { type: "value", values: () => [...OPEN_TOOLS] }
9818
+ "--target": { type: "value", values: targetCandidates },
9819
+ "--open": { type: "value", values: openToolValues }
9924
9820
  }
9925
9821
  },
9926
9822
  stop: {
9927
- positionals: [containerName, (ctx) => listAppCandidates(ctx)],
9823
+ positionals: [containerName, appCandidates],
9928
9824
  flags: {
9929
- "--target": { type: "value", values: (ctx) => listTargetCandidates(ctx) }
9825
+ "--target": { type: "value", values: targetCandidates }
9930
9826
  }
9931
9827
  },
9932
9828
  status: {
9933
- positionals: [containerName, (ctx) => listAppOrServiceCandidates(ctx)]
9829
+ positionals: [containerName, appOrServiceCandidates]
9934
9830
  },
9935
9831
  "list-apps": { positionals: [containerName] },
9936
9832
  "add-language": {
9937
- positionals: [containerName, () => listLanguageNames()]
9833
+ positionals: [containerName, languageValues]
9938
9834
  },
9939
9835
  "add-service": {
9940
- positionals: [containerName, () => listServiceNames()]
9836
+ positionals: [containerName, serviceValues]
9941
9837
  },
9942
9838
  "add-apt-packages": {
9943
9839
  positionals: [containerName],
@@ -9945,7 +9841,7 @@ var init_resolve = __esm({
9945
9841
  // freeform package names — no useful suggestion list
9946
9842
  },
9947
9843
  "add-feature": {
9948
- positionals: [containerName, () => listFeatureComponents()],
9844
+ positionals: [containerName, featureValues],
9949
9845
  flags: { "--yes": { type: "boolean", aliases: ["-y"] } },
9950
9846
  innerArgs: (ctx) => listFeatureOptionInnerArgs(ctx)
9951
9847
  },
@@ -9956,7 +9852,7 @@ var init_resolve = __esm({
9956
9852
  "--path": { type: "value" },
9957
9853
  "--git-name": { type: "value" },
9958
9854
  "--git-email": { type: "value" },
9959
- "--provider": { type: "value", values: () => listProviders() },
9855
+ "--provider": { type: "value", values: providerValues },
9960
9856
  "--yes": { type: "boolean", aliases: ["-y"] }
9961
9857
  }
9962
9858
  },
@@ -9969,17 +9865,17 @@ var init_resolve = __esm({
9969
9865
  innerArgs: () => []
9970
9866
  },
9971
9867
  "remove-language": {
9972
- positionals: [containerName, () => listLanguageNames()]
9868
+ positionals: [containerName, languageValues]
9973
9869
  },
9974
9870
  "remove-service": {
9975
- positionals: [containerName, () => listServiceNames()]
9871
+ positionals: [containerName, serviceValues]
9976
9872
  },
9977
9873
  "remove-apt-packages": {
9978
9874
  positionals: [containerName],
9979
9875
  innerArgs: () => []
9980
9876
  },
9981
9877
  "remove-feature": {
9982
- positionals: [containerName, () => listFeatureComponents()],
9878
+ positionals: [containerName, featureValues],
9983
9879
  flags: { "--yes": { type: "boolean", aliases: ["-y"] } }
9984
9880
  },
9985
9881
  "remove-from-url": { positionals: [containerName] },
@@ -9995,17 +9891,17 @@ var init_resolve = __esm({
9995
9891
  innerArgs: () => []
9996
9892
  },
9997
9893
  tunnel: {
9998
- positionals: [containerName, () => listServiceNames()],
9894
+ positionals: [containerName, serviceValues],
9999
9895
  flags: {
10000
9896
  "--local-port": { type: "value" },
10001
9897
  "--local-address": { type: "value" }
10002
9898
  }
10003
9899
  },
10004
9900
  share: {
10005
- positionals: [containerName, (ctx) => listAppCandidates(ctx)]
9901
+ positionals: [containerName, appCandidates]
10006
9902
  },
10007
9903
  completion: {
10008
- positionals: [() => listShellNames()]
9904
+ positionals: [shellValues]
10009
9905
  },
10010
9906
  "list-components": {},
10011
9907
  restore: {
@@ -10016,6 +9912,401 @@ var init_resolve = __esm({
10016
9912
  }
10017
9913
  };
10018
9914
  COMPLETION_COMMAND_SPEC_KEYS = Object.keys(COMMAND_SPECS);
9915
+ EMPTY_CTX = { prev: [], current: "", opts: {} };
9916
+ }
9917
+ });
9918
+
9919
+ // src/commands/completion.ts
9920
+ import { defineCommand as defineCommand9 } from "citty";
9921
+ function renderBashScript() {
9922
+ return [
9923
+ "# bash completion for monoceros",
9924
+ "# install: source this file from .bashrc, e.g.",
9925
+ "# monoceros completion bash > ~/.bash_completion.d/monoceros",
9926
+ '# echo "source ~/.bash_completion.d/monoceros" >> ~/.bashrc',
9927
+ "#",
9928
+ "# The work is done by `monoceros __complete --line --point`; this",
9929
+ "# shell wrapper only forwards the cursor view.",
9930
+ "",
9931
+ "_monoceros() {",
9932
+ " local IFS=$'\\n'",
9933
+ " local candidates",
9934
+ ' candidates=$(monoceros __complete --line "$COMP_LINE" --point "$COMP_POINT" 2>/dev/null)',
9935
+ ' local cur="${COMP_WORDS[COMP_CWORD]}"',
9936
+ ' COMPREPLY=( $(compgen -W "$candidates" -- "$cur") )',
9937
+ " # Suppress the trailing space when bash narrowed the candidate",
9938
+ " # set to a single token that ends with `=` \u2014 those are value-",
9939
+ " # flags (`--with-features=`, `--with-ports=`, \u2026) where the user types the",
9940
+ " # value immediately after.",
9941
+ ' if [[ ${#COMPREPLY[@]} -eq 1 && "${COMPREPLY[0]}" == *= ]]; then',
9942
+ " compopt -o nospace",
9943
+ " fi",
9944
+ "}",
9945
+ "complete -F _monoceros monoceros",
9946
+ ""
9947
+ ].join("\n");
9948
+ }
9949
+ function renderZshScript() {
9950
+ return [
9951
+ "#compdef monoceros",
9952
+ "# zsh completion for monoceros",
9953
+ "# install: drop this file somewhere on your $fpath as `_monoceros`,",
9954
+ "# then start a new shell (or run `compinit`). Example:",
9955
+ '# monoceros completion zsh > "${fpath[1]}/_monoceros"',
9956
+ "#",
9957
+ "# The work is done by `monoceros __complete --line --point`; this",
9958
+ "# shell wrapper only forwards the cursor view.",
9959
+ "",
9960
+ "_monoceros() {",
9961
+ ' local line="$BUFFER"',
9962
+ ' local point="$CURSOR"',
9963
+ " local -a candidates with_eq without_eq",
9964
+ ' candidates=("${(@f)$(monoceros __complete --line "$line" --point "$point" 2>/dev/null)}")',
9965
+ ' candidates=("${(@)candidates:#}")',
9966
+ ' # Split candidates into "ends with `=`" (value-flags \u2014 no suffix',
9967
+ " # space wanted because the user types the value immediately) and",
9968
+ ' # "everything else" (positional values, boolean flags \u2014 default',
9969
+ " # space behaviour).",
9970
+ ' for cand in "${candidates[@]}"; do',
9971
+ ' if [[ "$cand" == *= ]]; then',
9972
+ ' with_eq+=("$cand")',
9973
+ " else",
9974
+ ' without_eq+=("$cand")',
9975
+ " fi",
9976
+ " done",
9977
+ " (( ${#with_eq[@]} )) && compadd -S '' -- \"${with_eq[@]}\"",
9978
+ ' (( ${#without_eq[@]} )) && compadd -- "${without_eq[@]}"',
9979
+ "}",
9980
+ "",
9981
+ '_monoceros "$@"',
9982
+ ""
9983
+ ].join("\n");
9984
+ }
9985
+ async function renderPwshScript() {
9986
+ const model = await buildPwshCompletionModel();
9987
+ const json = JSON.stringify(model);
9988
+ return `# PowerShell completion for monoceros (self-contained).
9989
+ # install: dot-source this file from your $PROFILE, e.g.
9990
+ # monoceros completion pwsh > $HOME/.config/monoceros/completion.ps1
9991
+ # Add-Content $PROFILE '. $HOME/.config/monoceros/completion.ps1'
9992
+ #
9993
+ # Unlike the bash/zsh wrappers this never calls back into the CLI per
9994
+ # Tab (on Windows that would be a WSL round-trip each keystroke).
9995
+ # The static candidates are baked in below; the dynamic ones (container
9996
+ # names, apps, workspace dirs, launch targets) are read straight off the
9997
+ # host filesystem via the %USERPROFILE%\\.monoceros symlink.
9998
+
9999
+ $global:MonocerosModel = @'
10000
+ ${json}
10001
+ '@ | ConvertFrom-Json
10002
+
10003
+ function __Monoceros_Home {
10004
+ if ($env:MONOCEROS_HOME) { return $env:MONOCEROS_HOME }
10005
+ return (Join-Path $env:USERPROFILE '.monoceros')
10006
+ }
10007
+
10008
+ function __Monoceros_ContainerNames {
10009
+ $dir = Join-Path (__Monoceros_Home) 'container-configs'
10010
+ if (-not (Test-Path -LiteralPath $dir)) { return @() }
10011
+ @(Get-ChildItem -LiteralPath $dir -Filter '*.yml' -File -ErrorAction SilentlyContinue |
10012
+ ForEach-Object { $_.BaseName } | Sort-Object)
10013
+ }
10014
+
10015
+ # Recursively collect directory paths under $at, relative to it, capped
10016
+ # at $maxDepth. Skips dot-dirs, node_modules, and symlinked dirs \u2014 the
10017
+ # host-side mirror of collectDirs() in completion/resolve.ts.
10018
+ function __Monoceros_CollectDirs($maxDepth, $acc, $at, $rel, $depth) {
10019
+ $entries = Get-ChildItem -LiteralPath $at -Directory -Force -ErrorAction SilentlyContinue
10020
+ foreach ($e in $entries) {
10021
+ if ($e.Name.StartsWith('.')) { continue }
10022
+ if ($e.Name -eq 'node_modules') { continue }
10023
+ if ($e.LinkType) { continue }
10024
+ $childRel = if ($rel) { "$rel/$($e.Name)" } else { $e.Name }
10025
+ [void]$acc.Add($childRel)
10026
+ if (($depth + 1) -lt $maxDepth) {
10027
+ __Monoceros_CollectDirs $maxDepth $acc $e.FullName $childRel ($depth + 1)
10028
+ }
10029
+ }
10030
+ }
10031
+
10032
+ function __Monoceros_WorkspaceDirs($name) {
10033
+ if (-not $name) { return @() }
10034
+ $root = Join-Path (Join-Path (__Monoceros_Home) 'container') $name
10035
+ if (-not (Test-Path -LiteralPath $root)) { return @() }
10036
+ $acc = New-Object System.Collections.Generic.List[string]
10037
+ __Monoceros_CollectDirs 1 $acc $root '' 0
10038
+ $projects = Join-Path $root 'projects'
10039
+ if (Test-Path -LiteralPath $projects) {
10040
+ $pacc = New-Object System.Collections.Generic.List[string]
10041
+ __Monoceros_CollectDirs 4 $pacc $projects '' 0
10042
+ foreach ($p in $pacc) { [void]$acc.Add("projects/$p") }
10043
+ }
10044
+ @($acc | Sort-Object -Unique)
10045
+ }
10046
+
10047
+ # App-relative paths under projects/ carrying .monoceros/launch.json.
10048
+ function __Monoceros_WalkApps($at, $rel, $depth, $acc) {
10049
+ if ($rel -and (Test-Path -LiteralPath (Join-Path (Join-Path $at '.monoceros') 'launch.json'))) {
10050
+ [void]$acc.Add($rel)
10051
+ }
10052
+ if ($depth -ge 4) { return }
10053
+ $entries = Get-ChildItem -LiteralPath $at -Directory -Force -ErrorAction SilentlyContinue
10054
+ foreach ($e in $entries) {
10055
+ if ($e.Name.StartsWith('.')) { continue }
10056
+ $childRel = if ($rel) { "$rel/$($e.Name)" } else { $e.Name }
10057
+ __Monoceros_WalkApps $e.FullName $childRel ($depth + 1) $acc
10058
+ }
10059
+ }
10060
+
10061
+ function __Monoceros_Apps($name) {
10062
+ if (-not $name) { return @() }
10063
+ $root = Join-Path (Join-Path (Join-Path (__Monoceros_Home) 'container') $name) 'projects'
10064
+ if (-not (Test-Path -LiteralPath $root)) { return @() }
10065
+ $acc = New-Object System.Collections.Generic.List[string]
10066
+ __Monoceros_WalkApps $root '' 0 $acc
10067
+ @($acc | Sort-Object)
10068
+ }
10069
+
10070
+ function __Monoceros_Targets($name, $app) {
10071
+ if (-not $name -or -not $app) { return @() }
10072
+ $appPath = $app -replace '/', '\\'
10073
+ $file = Join-Path (Join-Path (Join-Path (Join-Path (__Monoceros_Home) 'container') $name) 'projects') (Join-Path $appPath (Join-Path '.monoceros' 'launch.json'))
10074
+ if (-not (Test-Path -LiteralPath $file)) { return @() }
10075
+ try { $json = Get-Content -LiteralPath $file -Raw | ConvertFrom-Json } catch { return @() }
10076
+ $list = if ($json.targets) { $json.targets } elseif ($json.configurations) { $json.configurations } else { $null }
10077
+ if (-not $list) { return @() }
10078
+ @($list | ForEach-Object { $_.name } | Where-Object { $_ })
10079
+ }
10080
+
10081
+ # The positional tokens (skipping flags) after \`monoceros <cmd>\`.
10082
+ function __Monoceros_Positionals($argTokens) {
10083
+ $out = @()
10084
+ foreach ($t in $argTokens) {
10085
+ if ($t -eq '--') { break }
10086
+ if ($t.StartsWith('-')) { continue }
10087
+ $out += $t
10088
+ }
10089
+ ,$out
10090
+ }
10091
+
10092
+ # Resolve a value descriptor ({values:[...]} static, or {kind:...}
10093
+ # dynamic) to its candidate list.
10094
+ function __Monoceros_Values($desc, $argTokens) {
10095
+ if (-not $desc) { return @() }
10096
+ if ($null -ne $desc.values) { return @($desc.values) }
10097
+ if ($desc.kind) {
10098
+ $pos = __Monoceros_Positionals $argTokens
10099
+ $name = if ($pos.Count -gt 0) { $pos[0] } else { $null }
10100
+ $app = if ($pos.Count -gt 1) { $pos[1] } else { $null }
10101
+ switch ($desc.kind) {
10102
+ 'containerName' { return (__Monoceros_ContainerNames) }
10103
+ 'app' { return (__Monoceros_Apps $name) }
10104
+ 'appOrService' { return (__Monoceros_Apps $name) }
10105
+ 'runInDir' { return (__Monoceros_WorkspaceDirs $name) }
10106
+ 'target' { return (__Monoceros_Targets $name $app) }
10107
+ }
10108
+ }
10109
+ return @()
10110
+ }
10111
+
10112
+ # Comma-aware prefix filter \u2014 mirrors resolveValues() so
10113
+ # \`--with-features=a,b<TAB>\` completes after the last comma.
10114
+ function __Monoceros_Filter($values, $fragment) {
10115
+ if (-not $values) { return @() }
10116
+ $commaIdx = $fragment.LastIndexOf(',')
10117
+ if ($commaIdx -lt 0) {
10118
+ return @($values | Where-Object { $_.StartsWith($fragment) })
10119
+ }
10120
+ $prefix = $fragment.Substring(0, $commaIdx + 1)
10121
+ $tail = $fragment.Substring($commaIdx + 1)
10122
+ @($values | Where-Object { $_.StartsWith($tail) } | ForEach-Object { "$prefix$_" })
10123
+ }
10124
+
10125
+ function __Monoceros_LookupFlag($flags, $token) {
10126
+ if (-not $flags) { return $null }
10127
+ $direct = $flags.PSObject.Properties[$token]
10128
+ if ($direct) { return $direct.Value }
10129
+ foreach ($p in $flags.PSObject.Properties) {
10130
+ if ($p.Value.aliases -contains $token) { return $p.Value }
10131
+ }
10132
+ return $null
10133
+ }
10134
+
10135
+ # Value flags are offered with a trailing '=' (so no space is wanted
10136
+ # after Tab); boolean flags and aliases as bare names.
10137
+ function __Monoceros_FlagNames($flags, $fragment) {
10138
+ if (-not $flags) { return @() }
10139
+ $names = @()
10140
+ foreach ($p in $flags.PSObject.Properties) {
10141
+ if ($p.Value.type -eq 'value') { $names += "$($p.Name)=" } else { $names += $p.Name }
10142
+ foreach ($a in $p.Value.aliases) { $names += $a }
10143
+ }
10144
+ @($names | Where-Object { $_.StartsWith($fragment) })
10145
+ }
10146
+
10147
+ function __Monoceros_CountPositionals($argTokens, $flags) {
10148
+ $count = 0
10149
+ for ($i = 0; $i -lt $argTokens.Count; $i++) {
10150
+ $t = $argTokens[$i]
10151
+ if ($t -like '--*' -and $t.Contains('=')) { continue }
10152
+ if ($t.StartsWith('-')) {
10153
+ $flag = __Monoceros_LookupFlag $flags $t
10154
+ if ($flag -and $flag.type -eq 'value' -and ($i + 1) -lt $argTokens.Count) { $i++ }
10155
+ continue
10156
+ }
10157
+ $count++
10158
+ }
10159
+ $count
10160
+ }
10161
+
10162
+ function __Monoceros_Emit($candidates) {
10163
+ @($candidates | ForEach-Object {
10164
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
10165
+ })
10166
+ }
10167
+
10168
+ Register-ArgumentCompleter -Native -CommandName @('monoceros', 'monoceros.cmd', 'monoceros.exe') -ScriptBlock {
10169
+ param($wordToComplete, $commandAst, $cursorPosition)
10170
+
10171
+ $model = $global:MonocerosModel
10172
+ $current = if ($wordToComplete) { $wordToComplete } else { '' }
10173
+
10174
+ # Tokens already complete on the line. When the current word is
10175
+ # non-empty it is the last command element \u2014 drop it from "prev".
10176
+ $elements = @($commandAst.CommandElements | ForEach-Object { $_.Extent.Text })
10177
+ if ($current -ne '' -and $elements.Count -gt 0 -and $elements[-1] -eq $current) {
10178
+ $prev = if ($elements.Count -gt 1) { @($elements[0..($elements.Count - 2)]) } else { @() }
10179
+ } else {
10180
+ $prev = $elements
10181
+ }
10182
+ # Strip the program name (prev[0]).
10183
+ $tokens = if ($prev.Count -gt 1) { @($prev[1..($prev.Count - 1)]) } else { @() }
10184
+
10185
+ # No subcommand yet \u2192 complete the subcommand list.
10186
+ if ($tokens.Count -eq 0) {
10187
+ return (__Monoceros_Emit (@($model.commands | Where-Object { $_.StartsWith($current) })))
10188
+ }
10189
+
10190
+ $command = $tokens[0]
10191
+ $spec = $model.specs.PSObject.Properties[$command]
10192
+ if (-not $spec) { return }
10193
+ $spec = $spec.Value
10194
+ $argTokens = if ($tokens.Count -gt 1) { @($tokens[1..($tokens.Count - 1)]) } else { @() }
10195
+
10196
+ # Everything after \`--\` is the inner command \u2014 not ours to complete.
10197
+ if ($argTokens -contains '--') { return }
10198
+
10199
+ # Case A: current is \`--flag=fragment\` \u2192 that flag's values.
10200
+ if ($current -like '--*' -and $current.Contains('=')) {
10201
+ $eq = $current.IndexOf('=')
10202
+ $flagName = $current.Substring(0, $eq)
10203
+ $frag = $current.Substring($eq + 1)
10204
+ $flag = if ($spec.flags) { $spec.flags.PSObject.Properties[$flagName] } else { $null }
10205
+ if (-not $flag -or $flag.Value.type -ne 'value') { return }
10206
+ $vals = __Monoceros_Values $flag.Value.value $argTokens
10207
+ return (__Monoceros_Emit (@(__Monoceros_Filter $vals $frag | ForEach-Object { "$flagName=$_" })))
10208
+ }
10209
+
10210
+ # Case B: current is an incomplete flag name.
10211
+ if ($current.StartsWith('-')) {
10212
+ return (__Monoceros_Emit (__Monoceros_FlagNames $spec.flags $current))
10213
+ }
10214
+
10215
+ # Case C: previous token was a value flag expecting a value.
10216
+ $lastPrev = if ($argTokens.Count -gt 0) { $argTokens[-1] } else { $null }
10217
+ if ($lastPrev -and $lastPrev -like '--*' -and -not $lastPrev.Contains('=')) {
10218
+ $flag = if ($spec.flags) { $spec.flags.PSObject.Properties[$lastPrev] } else { $null }
10219
+ if ($flag -and $flag.Value.type -eq 'value' -and $flag.Value.value) {
10220
+ $vals = __Monoceros_Values $flag.Value.value $argTokens
10221
+ return (__Monoceros_Emit (__Monoceros_Filter $vals $current))
10222
+ }
10223
+ }
10224
+
10225
+ # Case D: a positional slot.
10226
+ $positionalIdx = __Monoceros_CountPositionals $argTokens $spec.flags
10227
+ $positionals = @($spec.positionals)
10228
+ $expected = $spec.positionalCount
10229
+ if ($positionalIdx -lt $positionals.Count) {
10230
+ $vals = __Monoceros_Values $positionals[$positionalIdx] $argTokens
10231
+ return (__Monoceros_Emit (__Monoceros_Filter $vals $current))
10232
+ }
10233
+ if ($positionalIdx -ge $expected) {
10234
+ return (__Monoceros_Emit (__Monoceros_FlagNames $spec.flags $current))
10235
+ }
10236
+ }
10237
+ `;
10238
+ }
10239
+ async function renderCompletionScript(shell) {
10240
+ if (shell === "bash") return renderBashScript();
10241
+ if (shell === "zsh") return renderZshScript();
10242
+ return renderPwshScript();
10243
+ }
10244
+ var SHELLS, completionCommand;
10245
+ var init_completion = __esm({
10246
+ "src/commands/completion.ts"() {
10247
+ "use strict";
10248
+ init_resolve();
10249
+ SHELLS = ["bash", "zsh", "pwsh"];
10250
+ completionCommand = defineCommand9({
10251
+ meta: {
10252
+ name: "completion",
10253
+ group: "tooling",
10254
+ // Hidden from `monoceros --help`: the install scripts wire up
10255
+ // completion automatically; manual setup is documented at
10256
+ // getmonoceros.build/docs/reference/utilities/completion. Still runnable directly.
10257
+ hidden: true,
10258
+ 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."
10259
+ },
10260
+ args: {
10261
+ shell: {
10262
+ type: "positional",
10263
+ description: "Target shell. One of: 'bash', 'zsh', 'pwsh'.",
10264
+ required: true
10265
+ }
10266
+ },
10267
+ async run({ args }) {
10268
+ const shell = args.shell;
10269
+ if (shell !== "bash" && shell !== "zsh" && shell !== "pwsh") {
10270
+ process.stderr.write(
10271
+ `Unknown shell: ${JSON.stringify(shell)}. Supported: ${SHELLS.join(", ")}.
10272
+ `
10273
+ );
10274
+ process.exit(2);
10275
+ }
10276
+ process.stdout.write(await renderCompletionScript(shell));
10277
+ }
10278
+ });
10279
+ }
10280
+ });
10281
+
10282
+ // src/commands/__bridge.ts
10283
+ import { defineCommand as defineCommand10 } from "citty";
10284
+ var __bridgeCommand;
10285
+ var init_bridge = __esm({
10286
+ "src/commands/__bridge.ts"() {
10287
+ "use strict";
10288
+ init_bridge_daemon();
10289
+ __bridgeCommand = defineCommand10({
10290
+ meta: {
10291
+ name: "__bridge",
10292
+ group: "internal",
10293
+ hidden: true,
10294
+ description: "Internal: host-side browser-bridge daemon (background)."
10295
+ },
10296
+ args: {
10297
+ root: {
10298
+ type: "positional",
10299
+ description: "Materialized container root ($MONOCEROS_HOME/container/<name>/).",
10300
+ required: true
10301
+ }
10302
+ },
10303
+ async run({ args }) {
10304
+ try {
10305
+ await runBridgeDaemon({ root: args.root });
10306
+ } catch {
10307
+ }
10308
+ }
10309
+ });
10019
10310
  }
10020
10311
  });
10021
10312