@getmonoceros/workbench 1.38.18 → 1.38.20

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/README.md CHANGED
@@ -18,12 +18,12 @@ this up front and print platform-specific guidance.
18
18
 
19
19
  ```sh
20
20
  # macOS / Linux
21
- curl -fsSL https://raw.githubusercontent.com/getmonoceros/workbench/main/install.sh | bash
21
+ curl -fsSL https://raw.githubusercontent.com/getmonoceros/workbench/main/installer/install.sh | bash
22
22
  ```
23
23
 
24
24
  ```powershell
25
25
  # Windows (PowerShell)
26
- iwr -useb https://raw.githubusercontent.com/getmonoceros/workbench/main/install.ps1 | iex
26
+ irm https://raw.githubusercontent.com/getmonoceros/workbench/main/installer/install.ps1 | iex
27
27
  ```
28
28
 
29
29
  The script checks Docker + Node, installs the package globally via
package/dist/bin.js CHANGED
@@ -479,6 +479,18 @@ function expandEnvRefs(env) {
479
479
  }
480
480
  return out;
481
481
  }
482
+ function mergeEnvLayers(...layers) {
483
+ const out = {};
484
+ for (const layer of layers) {
485
+ for (const [key, value] of Object.entries(layer)) {
486
+ const incomingEmpty = value.trim() === "";
487
+ const haveNonEmpty = out[key] !== void 0 && out[key].trim() !== "";
488
+ if (incomingEmpty && haveNonEmpty) continue;
489
+ out[key] = value;
490
+ }
491
+ }
492
+ return out;
493
+ }
482
494
  function interpolateServices(services, vars) {
483
495
  const missing = [];
484
496
  const resolved = services.map((svc) => {
@@ -1439,10 +1451,10 @@ function resolveRepoTokens(config, catalog, envVars) {
1439
1451
  async function resolveContainerRepoTokens(name, home, catalog) {
1440
1452
  const ymlPath = containerConfigPath(name, home);
1441
1453
  const { config } = parseConfig(await fs4.readFile(ymlPath, "utf8"), ymlPath);
1442
- const envVars = {
1443
- ...readEnvFile(globalEnvPath(home)),
1444
- ...readEnvFile(containerEnvPath(name, home))
1445
- };
1454
+ const envVars = mergeEnvLayers(
1455
+ readEnvFile(globalEnvPath(home)),
1456
+ readEnvFile(containerEnvPath(name, home))
1457
+ );
1446
1458
  return resolveRepoTokens(config, catalog, envVars);
1447
1459
  }
1448
1460
  function formatTokenUse(use) {
@@ -4452,6 +4464,9 @@ function generateAgentsMd(input) {
4452
4464
  lines.push(sub ? ` ${sub}` : "");
4453
4465
  }
4454
4466
  }
4467
+ for (const mountLine of formatServiceMounts(svc)) {
4468
+ lines.push(mountLine);
4469
+ }
4455
4470
  }
4456
4471
  lines.push("");
4457
4472
  const connEnv = serviceConnectionEnv(input.services);
@@ -4630,6 +4645,7 @@ function generateAgentsMd(input) {
4630
4645
  );
4631
4646
  lines.push("");
4632
4647
  const examplePort = input.ports.length > 0 ? String(input.ports[0]) : "<port>";
4648
+ const secondPort = input.ports.length > 1 ? String(input.ports[1]) : "<port>";
4633
4649
  lines.push("## Running a long-running server");
4634
4650
  lines.push("");
4635
4651
  lines.push(
@@ -4664,7 +4680,10 @@ function generateAgentsMd(input) {
4664
4680
  lines.push("{");
4665
4681
  lines.push(' "targets": [');
4666
4682
  lines.push(
4667
- ` { "name": "web", "command": "<the project's start command>", "port": ${examplePort}, "default": true }`
4683
+ ` { "name": "api", "command": "<the API's start command>", "port": ${examplePort}, "default": true },`
4684
+ );
4685
+ lines.push(
4686
+ ` { "name": "web", "command": "<the web start command>", "port": ${secondPort}, "default": true }`
4668
4687
  );
4669
4688
  lines.push(" ]");
4670
4689
  lines.push("}");
@@ -4703,6 +4722,17 @@ function generateAgentsMd(input) {
4703
4722
  "not started. Pass `--target <name>` to start or stop a single one."
4704
4723
  );
4705
4724
  lines.push("");
4725
+ lines.push(
4726
+ "When you add a server in a later session, revisit the existing",
4727
+ "`launch.json` instead of assuming its current `default` set is complete.",
4728
+ "If the new server belongs to the app that should come up together (a",
4729
+ "backend the frontend calls, a worker the app relies on), give it",
4730
+ '`"default": true` too and place its entry before whatever depends on it.',
4731
+ "A single pre-existing default entry does not mean later servers should",
4732
+ "stay non-default - most servers that make up the running app belong in",
4733
+ "the default set."
4734
+ );
4735
+ lines.push("");
4706
4736
  lines.push(
4707
4737
  "The server must listen on `0.0.0.0` (not `127.0.0.1`) on the exposed",
4708
4738
  "port, or Traefik cannot reach it. You only have the ports already",
@@ -4740,6 +4770,42 @@ function formatServiceLine(svc) {
4740
4770
  }
4741
4771
  return `- **${svc.name}** (custom image \`${svc.image}\`) \u2014 reachable at \`${reach}\``;
4742
4772
  }
4773
+ function formatServiceMounts(svc) {
4774
+ const byProject = /* @__PURE__ */ new Map();
4775
+ for (const spec of svc.volumes) {
4776
+ const mount = parseBindMount(spec);
4777
+ if (!mount) continue;
4778
+ const project = projectOf(mount.source);
4779
+ if (!project) continue;
4780
+ const readOnly = mount.mode === "ro" ? " (read-only)" : "";
4781
+ const bucket = byProject.get(project) ?? [];
4782
+ bucket.push(` - \`${mount.source}\` \u2192 \`${mount.target}\`${readOnly}`);
4783
+ byProject.set(project, bucket);
4784
+ }
4785
+ if (byProject.size === 0) return [];
4786
+ const out = [" Workspace mounts (edit these on the host, then re-apply):"];
4787
+ for (const [project, entries] of byProject) {
4788
+ out.push(` - ${project}:`);
4789
+ out.push(...entries);
4790
+ }
4791
+ return out;
4792
+ }
4793
+ function parseBindMount(spec) {
4794
+ const parts = spec.split(":");
4795
+ if (parts.length < 2) return null;
4796
+ const source = parts[0];
4797
+ let mode;
4798
+ const last = parts[parts.length - 1];
4799
+ if (parts.length >= 3 && !last.includes("/")) {
4800
+ mode = parts.pop();
4801
+ }
4802
+ return { source, target: parts.slice(1).join(":"), mode };
4803
+ }
4804
+ function projectOf(source) {
4805
+ const segments = source.split("/");
4806
+ if (segments[0] !== "projects" || segments.length < 2) return null;
4807
+ return segments[1] ?? null;
4808
+ }
4743
4809
  function agentsMdInputFromCreateOptions(opts, featureDisplayMap2, manifestLoader, hostPort = 80) {
4744
4810
  const features = [];
4745
4811
  for (const [ref, userOptions] of Object.entries(opts.features ?? {})) {
@@ -8355,11 +8421,13 @@ ${sectionLine(label)}
8355
8421
  warnOnDeprecatedFeatureRefs(parsed.config.features, globalConfig, logger);
8356
8422
  const envPath = containerEnvPath(opts.name, home);
8357
8423
  await ensureEnvGitignored(containerConfigsDir(home));
8358
- const envVars = expandEnvRefs({
8359
- ...readEnvFile(globalEnvPath(home)),
8360
- ...readEnvFile(envPath),
8361
- ...opts.env ?? {}
8362
- });
8424
+ const envVars = expandEnvRefs(
8425
+ mergeEnvLayers(
8426
+ readEnvFile(globalEnvPath(home)),
8427
+ readEnvFile(envPath),
8428
+ opts.env ?? {}
8429
+ )
8430
+ );
8363
8431
  const catalog = await loadComponentCatalog();
8364
8432
  const repoTokens = resolveRepoTokens(parsed.config, catalog, envVars);
8365
8433
  const featureTokenPrompt = opts.featureTokenPrompt ?? defaultFeatureTokenPrompt;
@@ -9070,7 +9138,7 @@ var CLI_VERSION;
9070
9138
  var init_version = __esm({
9071
9139
  "src/version.ts"() {
9072
9140
  "use strict";
9073
- CLI_VERSION = true ? "1.38.18" : "dev";
9141
+ CLI_VERSION = true ? "1.38.20" : "dev";
9074
9142
  }
9075
9143
  });
9076
9144
 
@@ -12815,7 +12883,7 @@ async function runShare(opts) {
12815
12883
  if (addresses.length === 0) addresses.push("<host-ip>");
12816
12884
  const caPath = await caTrustDisplayPath(tls.caCertPath, home);
12817
12885
  const banner = [
12818
- `Sharing ${opts.name}/${opts.app} on the local network (Ctrl+C to stop):`
12886
+ `Sharing ${opts.name}/${opts.app} on the local network:`
12819
12887
  ];
12820
12888
  for (const t of ported) {
12821
12889
  banner.push("", ` ${cyan2(t.name)}`);
@@ -12826,7 +12894,9 @@ async function runShare(opts) {
12826
12894
  banner.push(
12827
12895
  "",
12828
12896
  dim(" Trust the local CA once (first device) for warning-free HTTPS:"),
12829
- dim(` ${caPath}`)
12897
+ dim(` ${caPath}`),
12898
+ "",
12899
+ "Press Ctrl+C to stop sharing."
12830
12900
  );
12831
12901
  log.info(banner.join("\n"));
12832
12902
  const dockerSpawn = opts.dockerSpawn ?? defaultDockerSpawn;