@getmonoceros/workbench 1.13.0 → 1.13.1

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
@@ -742,13 +742,20 @@ function buildEnvStub(name) {
742
742
  `;
743
743
  }
744
744
  async function ensureEnvVars(envPath, name, vars) {
745
+ const entries = Array.isArray(vars) ? vars.map((v) => [v, ""]) : Object.entries(vars);
745
746
  const exists = existsSync2(envPath);
746
747
  let content = exists ? readFileSync(envPath, "utf8") : buildEnvStub(name);
747
748
  const present = new Set(Object.keys(parseEnvFile(content)));
748
- const added = [...new Set(vars)].filter((v) => !present.has(v));
749
+ const seen = /* @__PURE__ */ new Set();
750
+ const toAdd = entries.filter(([k]) => {
751
+ if (present.has(k) || seen.has(k)) return false;
752
+ seen.add(k);
753
+ return true;
754
+ });
755
+ const added = toAdd.map(([k]) => k);
749
756
  if (!exists || added.length > 0) {
750
757
  if (content.length > 0 && !content.endsWith("\n")) content += "\n";
751
- for (const v of added) content += `${v}=
758
+ for (const [k, v] of toAdd) content += `${k}=${v}
752
759
  `;
753
760
  await fsp.mkdir(path2.dirname(envPath), { recursive: true });
754
761
  await fsp.writeFile(envPath, content);
@@ -1972,6 +1979,19 @@ var SERVICE_CATALOG = {
1972
1979
  POSTGRES_PASSWORD: "monoceros",
1973
1980
  POSTGRES_DB: "monoceros"
1974
1981
  },
1982
+ healthcheck: {
1983
+ test: [
1984
+ "CMD",
1985
+ "pg_isready",
1986
+ "-U",
1987
+ "${POSTGRES_USER}",
1988
+ "-d",
1989
+ "${POSTGRES_DB}"
1990
+ ],
1991
+ interval: "10s",
1992
+ timeout: "5s",
1993
+ retries: 5
1994
+ },
1975
1995
  // Postgres 18+ stores data under /var/lib/postgresql/<major>/, so
1976
1996
  // the recommended mount is the parent directory; pre-18 used
1977
1997
  // /var/lib/postgresql/data directly. See
@@ -1986,12 +2006,33 @@ var SERVICE_CATALOG = {
1986
2006
  MYSQL_ROOT_PASSWORD: "monoceros",
1987
2007
  MYSQL_DATABASE: "monoceros"
1988
2008
  },
2009
+ healthcheck: {
2010
+ test: [
2011
+ "CMD",
2012
+ "mysqladmin",
2013
+ "ping",
2014
+ "-h",
2015
+ "127.0.0.1",
2016
+ "-u",
2017
+ "root",
2018
+ "-p${MYSQL_ROOT_PASSWORD}"
2019
+ ],
2020
+ interval: "10s",
2021
+ timeout: "5s",
2022
+ retries: 5
2023
+ },
1989
2024
  dataMount: "/var/lib/mysql",
1990
2025
  defaultPort: 3306
1991
2026
  },
1992
2027
  redis: {
1993
2028
  id: "redis",
1994
2029
  image: "redis:8",
2030
+ healthcheck: {
2031
+ test: ["CMD", "redis-cli", "ping"],
2032
+ interval: "10s",
2033
+ timeout: "5s",
2034
+ retries: 5
2035
+ },
1995
2036
  dataMount: "/data",
1996
2037
  defaultPort: 6379
1997
2038
  }
@@ -2028,10 +2069,20 @@ function expandCuratedService(name) {
2028
2069
  name: def.id,
2029
2070
  image: def.image,
2030
2071
  port: def.defaultPort,
2031
- ...def.env ? { env: { ...def.env } } : {},
2032
- ...def.dataMount ? { volumes: [`data:${def.dataMount}`] } : {}
2072
+ ...def.env ? {
2073
+ env: Object.fromEntries(
2074
+ Object.keys(def.env).map((k) => [k, `\${${k}}`])
2075
+ )
2076
+ } : {},
2077
+ ...def.dataMount ? { volumes: [`data:${def.dataMount}`] } : {},
2078
+ ...def.healthcheck ? { healthcheck: def.healthcheck } : {},
2079
+ restart: "unless-stopped"
2033
2080
  };
2034
2081
  }
2082
+ function curatedServiceEnvDefaults(name) {
2083
+ const def = SERVICE_CATALOG[name];
2084
+ return def?.env ? { ...def.env } : {};
2085
+ }
2035
2086
  function deriveServiceName(image) {
2036
2087
  const lastSegment = image.split("/").pop() ?? image;
2037
2088
  const noTag = lastSegment.split("@")[0].split(":")[0];
@@ -3137,8 +3188,26 @@ async function runAddService(input) {
3137
3188
  }
3138
3189
  return r.outcome === "added";
3139
3190
  });
3140
- if (result.status === "updated" && !curated) {
3141
- (input.logger ?? defaultLogger()).info(customServiceHint(name));
3191
+ if (result.status === "updated") {
3192
+ if (curated) {
3193
+ const defaults = curatedServiceEnvDefaults(arg);
3194
+ if (Object.keys(defaults).length > 0) {
3195
+ const home = input.monocerosHome ?? monocerosHome();
3196
+ await ensureEnvGitignored(containerConfigsDir(home));
3197
+ const seeded = await ensureEnvVars(
3198
+ containerEnvPath(input.name, home),
3199
+ input.name,
3200
+ defaults
3201
+ );
3202
+ if (seeded.added.length > 0) {
3203
+ (input.logger ?? defaultLogger()).info(
3204
+ `Seeded ${seeded.added.join(", ")} into ${input.name}.env (dev-defaults \u2014 change them there if needed).`
3205
+ );
3206
+ }
3207
+ }
3208
+ } else {
3209
+ (input.logger ?? defaultLogger()).info(customServiceHint(name));
3210
+ }
3142
3211
  }
3143
3212
  return result;
3144
3213
  }
@@ -5193,7 +5262,7 @@ async function persistPromptedIdentity(prompted, ymlPath, home, logger) {
5193
5262
  }
5194
5263
 
5195
5264
  // src/version.ts
5196
- var CLI_VERSION = true ? "1.13.0" : "dev";
5265
+ var CLI_VERSION = true ? "1.13.1" : "dev";
5197
5266
 
5198
5267
  // src/commands/_dispatch.ts
5199
5268
  import { consola as consola12 } from "consola";
@@ -6196,12 +6265,22 @@ async function runInit(opts) {
6196
6265
  await ensureEnvGitignored(containerConfigsDir(home));
6197
6266
  await fs14.writeFile(dest, text, "utf8");
6198
6267
  const envPath = containerEnvPath(opts.name, home);
6199
- const featureVars = composed.features.flatMap(
6200
- (f) => featureOptionHints(lookup(f.ref), f.ref, Object.keys(f.options ?? {})).map(
6201
- (h) => h.envVar
6202
- )
6203
- );
6204
- await ensureEnvVars(envPath, opts.name, featureVars);
6268
+ const seedVars = {};
6269
+ for (const f of composed.features) {
6270
+ for (const h of featureOptionHints(
6271
+ lookup(f.ref),
6272
+ f.ref,
6273
+ Object.keys(f.options ?? {})
6274
+ )) {
6275
+ if (!(h.envVar in seedVars)) seedVars[h.envVar] = "";
6276
+ }
6277
+ }
6278
+ for (const svc of composed.services) {
6279
+ if (svc.kind === "curated") {
6280
+ Object.assign(seedVars, curatedServiceEnvDefaults(svc.name));
6281
+ }
6282
+ }
6283
+ await ensureEnvVars(envPath, opts.name, seedVars);
6205
6284
  if (promptedIdentity?.prompted) {
6206
6285
  const { name, email, scope } = promptedIdentity.prompted;
6207
6286
  if (scope === "g" || scope === "b") {