@getmonoceros/workbench 1.36.4 → 1.36.6

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
@@ -2154,67 +2154,59 @@ async function containersPublishing(docker, hostPort) {
2154
2154
  if (ps.exitCode !== 0) return [];
2155
2155
  return ps.stdout.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
2156
2156
  }
2157
+ function hostPortFallbackLines(hostPort) {
2158
+ return [
2159
+ dim("Or set a different proxy port in ") + cyan2("~/.monoceros/monoceros-config.yml") + dim(":"),
2160
+ " " + cyan2("schemaVersion: 1"),
2161
+ " " + cyan2("routing:"),
2162
+ " " + cyan2(" hostPort: 8080"),
2163
+ "",
2164
+ dim(
2165
+ `Aborting. Re-run once port ${hostPort} is free or a different port is set.`
2166
+ )
2167
+ ];
2168
+ }
2157
2169
  function formatLiveContainerError(hostPort, containers) {
2158
2170
  const firstName = containers[0].split(" ")[0];
2159
2171
  return [
2160
2172
  `Host port ${hostPort} is in use: it is published by a running container.`,
2161
2173
  "",
2162
- `Monoceros needs that port for its Traefik proxy. The container(s) holding it:`,
2163
- ...containers.map((c) => ` - ${c}`),
2174
+ dim("Held by:"),
2175
+ ...containers.map((c) => " " + cyan2(c)),
2164
2176
  "",
2165
- `Stop or re-map it, then re-run, e.g.:`,
2177
+ dim("Stop or re-map it, then re-run:"),
2178
+ " " + cyan2(`docker stop ${firstName}`),
2166
2179
  "",
2167
- ` docker stop ${firstName}`,
2168
- "",
2169
- `Or move Monoceros off the port: set \`routing.hostPort\` in`,
2170
- `~/.monoceros/monoceros-config.yml.`,
2171
- "",
2172
- `Aborting. Re-run after the conflict is resolved.`
2180
+ ...hostPortFallbackLines(hostPort)
2173
2181
  ].join("\n");
2174
2182
  }
2175
2183
  function formatLeftoverHolderError(hostPort) {
2176
2184
  return [
2177
- `Host port ${hostPort} is in use, but no Docker container in the active`,
2178
- `engine publishes it.`,
2179
- "",
2180
- `This is almost always a leftover Docker port-forwarder (docker-proxy)`,
2181
- `whose container is already gone. It is left behind when a native Docker`,
2182
- `daemon is restarted while a container held the port, which is common with`,
2183
- `dockerd-via-systemd inside WSL (WSL restarts it on every shutdown). The`,
2184
- `forwarder keeps the port bound with nothing behind it. Two ways out:`,
2185
- "",
2186
- ` 1) Recommended: reap the leftover by restarting the Docker daemon`,
2187
- ` (harmless, it just clears stale forwarders):`,
2188
- ` WSL / native dockerd: sudo systemctl restart docker`,
2189
- ` Docker Desktop: restart it from its menu`,
2190
- ` Then re-run.`,
2185
+ `Host port ${hostPort} is in use, but no running container publishes it.`,
2191
2186
  "",
2192
- ` 2) Or move Monoceros off port ${hostPort}. Edit (or create)`,
2193
- ` ~/.monoceros/monoceros-config.yml and add:`,
2187
+ dim("Most likely a leftover docker-proxy whose container is already gone"),
2188
+ dim("(a native dockerd in WSL strands these on restart), or a holder in"),
2189
+ dim("another Docker engine. Fix it one of two ways, then re-run:"),
2194
2190
  "",
2195
- ` schemaVersion: 1`,
2196
- ` routing:`,
2197
- ` hostPort: 8080 # any free port`,
2191
+ dim("Reap the leftover by restarting the Docker daemon (harmless):"),
2192
+ " " + cyan2("sudo systemctl restart docker"),
2198
2193
  "",
2199
- ` URLs then become http://<name>.localhost:8080/.`,
2200
- "",
2201
- `Aborting. Re-run after the conflict is resolved.`
2194
+ ...hostPortFallbackLines(hostPort)
2202
2195
  ].join("\n");
2203
2196
  }
2204
2197
  function formatHostPortHeldError(hostPort, _code, systemMessage) {
2205
2198
  return [
2206
2199
  `Cannot reach host port ${hostPort}: ${systemMessage}`,
2207
2200
  "",
2208
- `This is not the typical "port already in use" case.`,
2209
- `Monoceros's pre-flight uses a TCP-connect probe (not a bind), so`,
2210
- `EACCES / privileged-port errors normally don't appear here. Most`,
2211
- `likely something on your host network stack (firewall, network`,
2212
- `namespace, \u2026) is interfering with loopback connects.`,
2201
+ dim('This is not the typical "port already in use" case. The pre-flight'),
2202
+ dim("uses a TCP-connect probe (not a bind), so EACCES / privileged-port"),
2203
+ dim("errors normally do not appear here. Most likely something on your"),
2204
+ dim("host network stack (firewall, network namespace) is interfering with"),
2205
+ dim("loopback connects."),
2213
2206
  "",
2214
- "Workaround: move Monoceros off this port by setting",
2215
- "`routing.hostPort` in ~/.monoceros/monoceros-config.yml.",
2207
+ dim("Workaround: move Monoceros off this port by setting ") + cyan2("routing.hostPort") + dim(" in ") + cyan2("~/.monoceros/monoceros-config.yml") + dim("."),
2216
2208
  "",
2217
- `Aborting. Re-run after the issue is resolved.`
2209
+ dim("Aborting. Re-run after the issue is resolved.")
2218
2210
  ].join("\n");
2219
2211
  }
2220
2212
  var CONNECT_TIMEOUT_MS, realPortProbe;
@@ -2222,6 +2214,7 @@ var init_port_check = __esm({
2222
2214
  "src/proxy/port-check.ts"() {
2223
2215
  "use strict";
2224
2216
  init_proxy();
2217
+ init_format();
2225
2218
  CONNECT_TIMEOUT_MS = 750;
2226
2219
  realPortProbe = (port) => {
2227
2220
  return new Promise((resolve) => {
@@ -3762,6 +3755,25 @@ function composeVolumeSource(spec, serviceName) {
3762
3755
  const relative = src.startsWith("./") ? src.slice(2) : src;
3763
3756
  return `../${relative}:${rest}`;
3764
3757
  }
3758
+ function serviceVolumeHostDirs(services, repos = []) {
3759
+ const cloneTargets = repos.map((r) => `projects/${r.path}`);
3760
+ const dirs = /* @__PURE__ */ new Set();
3761
+ for (const svc of services) {
3762
+ for (const vol of svc.volumes) {
3763
+ const src = vol.split(":")[0];
3764
+ if (src === "data") continue;
3765
+ const rel = src.startsWith("./") ? src.slice(2) : src;
3766
+ if (cloneTargets.some((t) => rel === t || rel.startsWith(`${t}/`))) {
3767
+ continue;
3768
+ }
3769
+ const slash = rel.lastIndexOf("/");
3770
+ const lastSeg = slash === -1 ? rel : rel.slice(slash + 1);
3771
+ const dir = lastSeg.includes(".") ? slash === -1 ? "" : rel.slice(0, slash) : rel;
3772
+ if (dir) dirs.add(dir);
3773
+ }
3774
+ }
3775
+ return [...dirs];
3776
+ }
3765
3777
  function buildComposeYaml(opts, dockerMode = "rootful") {
3766
3778
  void dockerMode;
3767
3779
  const hasPorts = (opts.ports?.length ?? 0) > 0;
@@ -4115,6 +4127,9 @@ async function writeScaffold(opts, targetDir, scaffoldOpts = {}) {
4115
4127
  await fs8.mkdir(path11.join(dataDir, svc.name), { recursive: true });
4116
4128
  }
4117
4129
  }
4130
+ for (const dir of serviceVolumeHostDirs(opts.services, opts.repos)) {
4131
+ await fs8.mkdir(path11.join(targetDir, dir), { recursive: true });
4132
+ }
4118
4133
  }
4119
4134
  const containerGitignore = path11.join(targetDir, ".gitignore");
4120
4135
  await fs8.writeFile(
@@ -8857,7 +8872,7 @@ var CLI_VERSION;
8857
8872
  var init_version = __esm({
8858
8873
  "src/version.ts"() {
8859
8874
  "use strict";
8860
- CLI_VERSION = true ? "1.36.4" : "dev";
8875
+ CLI_VERSION = true ? "1.36.6" : "dev";
8861
8876
  }
8862
8877
  });
8863
8878