@getmonoceros/workbench 1.25.0 → 1.26.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.
@@ -0,0 +1,17 @@
1
+ id: mailpit
2
+ category: service
3
+ displayName: Mailpit
4
+ description: 'SMTP catcher for local dev — apps send mail to it and nothing leaves the machine. SMTP on `mailpit:1025`; web UI + API on 8025 (reach via `monoceros tunnel <name> mailpit:8025`).'
5
+ service:
6
+ image: axllent/mailpit:latest
7
+ defaultPort: 1025
8
+ healthcheck:
9
+ # Mailpit ships its own readiness probe in the image — no curl/wget needed.
10
+ test: [CMD, /mailpit, readyz]
11
+ interval: 15s
12
+ timeout: 5s
13
+ retries: 5
14
+ connectionEnv:
15
+ URL: smtp://${host}:${port}
16
+ HOST: ${host}
17
+ PORT: ${port}
@@ -0,0 +1,36 @@
1
+ id: mongodb
2
+ category: service
3
+ displayName: MongoDB
4
+ description: 'MongoDB with seeded dev credentials and a readiness healthcheck. Reachable in-container as host `mongodb`.'
5
+ service:
6
+ image: mongo:8
7
+ defaultPort: 27017
8
+ dataMount: /data/db
9
+ healthcheck:
10
+ test: [CMD, mongosh, --quiet, --eval, 'db.adminCommand({ ping: 1 }).ok']
11
+ interval: 10s
12
+ timeout: 5s
13
+ retries: 5
14
+ vscodeExtensions: [mongodb.mongodb-vscode]
15
+ client:
16
+ npm: [mongosh]
17
+ connectionEnv:
18
+ URL: mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@${host}:${port}/${MONGO_INITDB_DATABASE}?authSource=admin
19
+ HOST: ${host}
20
+ PORT: ${port}
21
+ USER: ${MONGO_INITDB_ROOT_USERNAME}
22
+ PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
23
+ DB: ${MONGO_INITDB_DATABASE}
24
+ options:
25
+ MONGO_INITDB_ROOT_USERNAME:
26
+ type: string
27
+ default: monoceros
28
+ surface: env
29
+ MONGO_INITDB_ROOT_PASSWORD:
30
+ type: string
31
+ default: monoceros
32
+ surface: env
33
+ MONGO_INITDB_DATABASE:
34
+ type: string
35
+ default: monoceros
36
+ surface: env
@@ -22,6 +22,8 @@ service:
22
22
  timeout: 5s
23
23
  retries: 5
24
24
  vscodeExtensions: [cweijan.vscode-database-client2]
25
+ client:
26
+ apt: [default-mysql-client]
25
27
  connectionEnv:
26
28
  URL: mysql://root:${MYSQL_ROOT_PASSWORD}@${host}:${port}/${MYSQL_DATABASE}
27
29
  HOST: ${host}
@@ -0,0 +1,36 @@
1
+ id: pgvector
2
+ category: service
3
+ displayName: pgvector (PostgreSQL + vectors)
4
+ description: 'PostgreSQL with the pgvector extension for embeddings / vector search — a drop-in Postgres. Reachable in-container as host `pgvector`. Enable the extension once with `CREATE EXTENSION vector;` (or in your migration).'
5
+ service:
6
+ image: pgvector/pgvector:pg18
7
+ defaultPort: 5432
8
+ dataMount: /var/lib/postgresql
9
+ healthcheck:
10
+ test: [CMD, pg_isready, -U, '${POSTGRES_USER}', -d, '${POSTGRES_DB}']
11
+ interval: 10s
12
+ timeout: 5s
13
+ retries: 5
14
+ vscodeExtensions: [cweijan.vscode-database-client2]
15
+ client:
16
+ apt: [postgresql-client]
17
+ connectionEnv:
18
+ URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${host}:${port}/${POSTGRES_DB}
19
+ HOST: ${host}
20
+ PORT: ${port}
21
+ USER: ${POSTGRES_USER}
22
+ PASSWORD: ${POSTGRES_PASSWORD}
23
+ DB: ${POSTGRES_DB}
24
+ options:
25
+ POSTGRES_USER:
26
+ type: string
27
+ default: monoceros
28
+ surface: env
29
+ POSTGRES_PASSWORD:
30
+ type: string
31
+ default: monoceros
32
+ surface: env
33
+ POSTGRES_DB:
34
+ type: string
35
+ default: monoceros
36
+ surface: env
@@ -12,6 +12,8 @@ service:
12
12
  timeout: 5s
13
13
  retries: 5
14
14
  vscodeExtensions: [cweijan.vscode-database-client2]
15
+ client:
16
+ apt: [postgresql-client]
15
17
  connectionEnv:
16
18
  URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${host}:${port}/${POSTGRES_DB}
17
19
  HOST: ${host}
@@ -12,6 +12,8 @@ service:
12
12
  timeout: 5s
13
13
  retries: 5
14
14
  vscodeExtensions: [cweijan.vscode-database-client2]
15
+ client:
16
+ apt: [redis-tools]
15
17
  connectionEnv:
16
18
  URL: redis://${host}:${port}
17
19
  HOST: ${host}
@@ -0,0 +1,28 @@
1
+ id: rustfs
2
+ category: service
3
+ displayName: RustFS
4
+ description: 'S3-compatible object storage (MinIO-compatible API). S3 API on `rustfs:9000`; web console on 9001 (enable with `RUSTFS_CONSOLE_ENABLE=true`, reach via `monoceros tunnel <name> rustfs:9001`).'
5
+ service:
6
+ image: rustfs/rustfs:latest
7
+ defaultPort: 9000
8
+ dataMount: /data
9
+ healthcheck:
10
+ test: [CMD, curl, -f, 'http://localhost:9000/minio/health/live']
11
+ interval: 10s
12
+ timeout: 5s
13
+ retries: 5
14
+ connectionEnv:
15
+ URL: http://${host}:${port}
16
+ HOST: ${host}
17
+ PORT: ${port}
18
+ ACCESS_KEY: ${RUSTFS_ACCESS_KEY}
19
+ SECRET_KEY: ${RUSTFS_SECRET_KEY}
20
+ options:
21
+ RUSTFS_ACCESS_KEY:
22
+ type: string
23
+ default: rustfsadmin
24
+ surface: env
25
+ RUSTFS_SECRET_KEY:
26
+ type: string
27
+ default: rustfsadmin
28
+ surface: env
package/dist/bin.js CHANGED
@@ -740,6 +740,19 @@ var init_descriptor = __esm({
740
740
  * HOST: ${host}
741
741
  */
742
742
  connectionEnv: z2.record(z2.string(), z2.string()).optional(),
743
+ /**
744
+ * CLI client tool(s) for this service, installed into the WORKSPACE
745
+ * container at apply so the dev/agent can use them (the service runs in its
746
+ * own container; the workspace has no client otherwise). `apt` packages are
747
+ * merged into the workspace's apt-packages feature (build-time, cached);
748
+ * `npm` packages are installed globally in post-create (guarded, so it's a
749
+ * no-op once present). E.g. postgres → apt `postgresql-client` (`psql`),
750
+ * mongodb → npm `mongosh`. See ADR 0020.
751
+ */
752
+ client: z2.object({
753
+ apt: z2.array(z2.string()).optional(),
754
+ npm: z2.array(z2.string()).optional()
755
+ }).optional(),
743
756
  vscodeExtensions: z2.array(z2.string()).optional()
744
757
  });
745
758
  PersistentHomeFileSchema = z2.object({
@@ -2208,7 +2221,7 @@ function curatedServiceEnvDefaults(name) {
2208
2221
  function serviceConnectionEnv(services) {
2209
2222
  const env = {};
2210
2223
  for (const svc of services) {
2211
- const conn = svc.connectionEnv;
2224
+ const conn = svc.connectionEnv ?? SERVICE_CATALOG[svc.name]?.connectionEnv;
2212
2225
  if (!conn || Object.keys(conn).length === 0) continue;
2213
2226
  const prefix = svc.name.replace(/[^A-Za-z0-9]+/g, "_").toUpperCase();
2214
2227
  const host = svc.name;
@@ -2224,6 +2237,24 @@ function serviceConnectionEnv(services) {
2224
2237
  }
2225
2238
  return env;
2226
2239
  }
2240
+ function serviceClientAptPackages(services) {
2241
+ const pkgs = /* @__PURE__ */ new Set();
2242
+ for (const svc of services) {
2243
+ for (const pkg of SERVICE_CATALOG[svc.name]?.client?.apt ?? []) {
2244
+ pkgs.add(pkg);
2245
+ }
2246
+ }
2247
+ return [...pkgs].sort();
2248
+ }
2249
+ function serviceClientNpmPackages(services) {
2250
+ const pkgs = /* @__PURE__ */ new Set();
2251
+ for (const svc of services) {
2252
+ for (const pkg of SERVICE_CATALOG[svc.name]?.client?.npm ?? []) {
2253
+ pkgs.add(pkg);
2254
+ }
2255
+ }
2256
+ return [...pkgs].sort();
2257
+ }
2227
2258
  function deriveServiceName(image) {
2228
2259
  const lastSegment = image.split("/").pop() ?? image;
2229
2260
  const noTag = lastSegment.split("@")[0].split(":")[0];
@@ -2283,7 +2314,8 @@ var init_catalog = __esm({
2283
2314
  ...svc.dataMount ? { dataMount: svc.dataMount } : {},
2284
2315
  defaultPort: svc.defaultPort,
2285
2316
  ...svc.vscodeExtensions ? { vscodeExtensions: svc.vscodeExtensions } : {},
2286
- ...svc.connectionEnv ? { connectionEnv: svc.connectionEnv } : {}
2317
+ ...svc.connectionEnv ? { connectionEnv: svc.connectionEnv } : {},
2318
+ ...svc.client ? { client: svc.client } : {}
2287
2319
  };
2288
2320
  return [key, entry2];
2289
2321
  })
@@ -2800,10 +2832,16 @@ function resolveFeatures(opts) {
2800
2832
  persistentHomeFiles: []
2801
2833
  });
2802
2834
  }
2803
- if (opts.aptPackages && opts.aptPackages.length > 0) {
2835
+ const aptPackages = [
2836
+ .../* @__PURE__ */ new Set([
2837
+ ...opts.aptPackages ?? [],
2838
+ ...serviceClientAptPackages(opts.services)
2839
+ ])
2840
+ ].sort();
2841
+ if (aptPackages.length > 0) {
2804
2842
  resolved.push({
2805
2843
  devcontainerKey: "ghcr.io/devcontainers-contrib/features/apt-packages:1",
2806
- options: { packages: opts.aptPackages.join(",") },
2844
+ options: { packages: aptPackages.join(",") },
2807
2845
  persistentHomePaths: [],
2808
2846
  persistentHomeFiles: []
2809
2847
  });
@@ -3197,6 +3235,18 @@ function buildPostCreateScript(opts) {
3197
3235
  " pnpm install",
3198
3236
  "fi"
3199
3237
  ];
3238
+ const clientNpm = serviceClientNpmPackages(opts.services);
3239
+ if (clientNpm.length > 0) {
3240
+ lines.push(
3241
+ "",
3242
+ "# CLI clients for the curated services (global npm installs)."
3243
+ );
3244
+ for (const pkg of clientNpm) {
3245
+ lines.push(
3246
+ `command -v ${pkg} >/dev/null 2>&1 || npm install -g --no-audit --no-fund ${pkg}`
3247
+ );
3248
+ }
3249
+ }
3200
3250
  if (opts.installUrls && opts.installUrls.length > 0) {
3201
3251
  lines.push(
3202
3252
  "",
@@ -7260,7 +7310,7 @@ var CLI_VERSION;
7260
7310
  var init_version = __esm({
7261
7311
  "src/version.ts"() {
7262
7312
  "use strict";
7263
- CLI_VERSION = true ? "1.25.0" : "dev";
7313
+ CLI_VERSION = true ? "1.26.0" : "dev";
7264
7314
  }
7265
7315
  });
7266
7316