@getmonoceros/workbench 1.38.0 → 1.38.2
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 +100 -73
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -4593,75 +4593,87 @@ function generateAgentsMd(input) {
|
|
|
4593
4593
|
" DataGrip) to one of the services."
|
|
4594
4594
|
);
|
|
4595
4595
|
lines.push("");
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
"Declare it in the app's own launch config at",
|
|
4608
|
-
"`projects/<app>/.monoceros/launch.json`, then start it with",
|
|
4609
|
-
"`monoceros-ctl`. Add or update an entry whenever you set up a",
|
|
4610
|
-
"long-running server. The file travels with the app, so the human can",
|
|
4611
|
-
"restart it later without knowing your start command:"
|
|
4612
|
-
);
|
|
4613
|
-
lines.push("");
|
|
4614
|
-
lines.push("```json");
|
|
4615
|
-
lines.push("{");
|
|
4616
|
-
lines.push(' "configurations": [');
|
|
4617
|
-
lines.push(
|
|
4618
|
-
` { "name": "web", "command": "<the project's start command>", "port": ${input.ports[0]}, "default": true }`
|
|
4619
|
-
);
|
|
4620
|
-
lines.push(" ]");
|
|
4621
|
-
lines.push("}");
|
|
4622
|
-
lines.push("```");
|
|
4623
|
-
lines.push("");
|
|
4596
|
+
const examplePort = input.ports.length > 0 ? String(input.ports[0]) : "<port>";
|
|
4597
|
+
lines.push("## Running a long-running server");
|
|
4598
|
+
lines.push("");
|
|
4599
|
+
lines.push(
|
|
4600
|
+
"When you build something that serves on a port (a web app, an API),",
|
|
4601
|
+
"it must keep running after this session ends. A plain `npm start` (or",
|
|
4602
|
+
"any foreground start) dies the moment the user exits you or closes the",
|
|
4603
|
+
input.ports.length > 0 ? `terminal, and then \`${input.containerName}.localhost${portSuffix}\` returns 502 Bad Gateway.` : "terminal, and the app stops responding."
|
|
4604
|
+
);
|
|
4605
|
+
lines.push("");
|
|
4606
|
+
if (input.ports.length === 0) {
|
|
4624
4607
|
lines.push(
|
|
4625
|
-
"
|
|
4626
|
-
"
|
|
4627
|
-
"
|
|
4628
|
-
"`projects/`; `port` must be a port already exposed on the container."
|
|
4608
|
+
"This container exposes **no ports yet**, so a server has nothing to be",
|
|
4609
|
+
"reached on. Before serving one, ask the user to add a port on the host",
|
|
4610
|
+
"and re-apply - you cannot do this from inside:"
|
|
4629
4611
|
);
|
|
4630
4612
|
lines.push("");
|
|
4631
|
-
lines.push("Start it, stop it, tail its log:");
|
|
4632
|
-
lines.push("");
|
|
4633
4613
|
lines.push("```");
|
|
4634
|
-
lines.push(
|
|
4635
|
-
lines.push(
|
|
4636
|
-
lines.push("monoceros-ctl logs <app>");
|
|
4614
|
+
lines.push(`monoceros add-port ${input.containerName} <port>`);
|
|
4615
|
+
lines.push(`monoceros apply ${input.containerName}`);
|
|
4637
4616
|
lines.push("```");
|
|
4638
4617
|
lines.push("");
|
|
4639
|
-
lines.push(
|
|
4640
|
-
"`start` launches it detached (it survives your session) and, when a",
|
|
4641
|
-
"`port` is set, waits until it actually listens before returning. The",
|
|
4642
|
-
"human can do the same from the host with",
|
|
4643
|
-
`\`monoceros start ${input.containerName} <app>\` / \`monoceros stop ${input.containerName} <app>\`,`,
|
|
4644
|
-
`and follow output with \`monoceros logs ${input.containerName} <app>\`.`
|
|
4645
|
-
);
|
|
4646
|
-
lines.push("");
|
|
4647
|
-
lines.push(
|
|
4648
|
-
"An app can declare several servers (e.g. an API and a web frontend).",
|
|
4649
|
-
'Mark every server that should come up together with `"default": true`;',
|
|
4650
|
-
"`monoceros-ctl start <app>` (no `--target`) then starts the whole default",
|
|
4651
|
-
"set in the order the entries appear in the file, waiting for each",
|
|
4652
|
-
"server's `port` to listen before starting the next - so order an entry",
|
|
4653
|
-
"before anything that depends on it. If one fails to come up, the rest are",
|
|
4654
|
-
"not started. Pass `--target <name>` to start or stop a single one."
|
|
4655
|
-
);
|
|
4656
|
-
lines.push("");
|
|
4657
|
-
lines.push(
|
|
4658
|
-
"The server must listen on `0.0.0.0` (not `127.0.0.1`) on the exposed",
|
|
4659
|
-
"port, or Traefik cannot reach it. You only have the ports already",
|
|
4660
|
-
"declared on the container; if you need another, ask the human to add it",
|
|
4661
|
-
`on the host (\`monoceros add-port ${input.containerName} <port>\`) and re-apply.`
|
|
4662
|
-
);
|
|
4663
|
-
lines.push("");
|
|
4664
4618
|
}
|
|
4619
|
+
lines.push(
|
|
4620
|
+
"Declare the server in the app's own launch config at",
|
|
4621
|
+
"`projects/<app>/.monoceros/launch.json`, then start it with",
|
|
4622
|
+
"`monoceros-ctl`. Add or update an entry whenever you set up a",
|
|
4623
|
+
"long-running server. The file travels with the app, so the human can",
|
|
4624
|
+
"restart it later without knowing your start command:"
|
|
4625
|
+
);
|
|
4626
|
+
lines.push("");
|
|
4627
|
+
lines.push("```json");
|
|
4628
|
+
lines.push("{");
|
|
4629
|
+
lines.push(' "configurations": [');
|
|
4630
|
+
lines.push(
|
|
4631
|
+
` { "name": "web", "command": "<the project's start command>", "port": ${examplePort}, "default": true }`
|
|
4632
|
+
);
|
|
4633
|
+
lines.push(" ]");
|
|
4634
|
+
lines.push("}");
|
|
4635
|
+
lines.push("```");
|
|
4636
|
+
lines.push("");
|
|
4637
|
+
lines.push(
|
|
4638
|
+
"Use whatever start command the project actually uses (`npm run dev`,",
|
|
4639
|
+
"`./mvnw spring-boot:run`, `python manage.py runserver`, `go run .`, \u2026).",
|
|
4640
|
+
"Do not force a language-specific one. `<app>` is the path under",
|
|
4641
|
+
"`projects/`; `port` must be a port exposed on the container."
|
|
4642
|
+
);
|
|
4643
|
+
lines.push("");
|
|
4644
|
+
lines.push("Start it, stop it, tail its log:");
|
|
4645
|
+
lines.push("");
|
|
4646
|
+
lines.push("```");
|
|
4647
|
+
lines.push("monoceros-ctl start <app>");
|
|
4648
|
+
lines.push("monoceros-ctl stop <app>");
|
|
4649
|
+
lines.push("monoceros-ctl logs <app>");
|
|
4650
|
+
lines.push("```");
|
|
4651
|
+
lines.push("");
|
|
4652
|
+
lines.push(
|
|
4653
|
+
"`start` launches it detached (it survives your session) and, when a",
|
|
4654
|
+
"`port` is set, waits until it actually listens before returning. The",
|
|
4655
|
+
"human can do the same from the host with",
|
|
4656
|
+
`\`monoceros start ${input.containerName} <app>\` / \`monoceros stop ${input.containerName} <app>\`,`,
|
|
4657
|
+
`and follow output with \`monoceros logs ${input.containerName} <app>\`.`
|
|
4658
|
+
);
|
|
4659
|
+
lines.push("");
|
|
4660
|
+
lines.push(
|
|
4661
|
+
"An app can declare several servers (e.g. an API and a web frontend).",
|
|
4662
|
+
'Mark every server that should come up together with `"default": true`;',
|
|
4663
|
+
"`monoceros-ctl start <app>` (no `--target`) then starts the whole default",
|
|
4664
|
+
"set in the order the entries appear in the file, waiting for each",
|
|
4665
|
+
"server's `port` to listen before starting the next - so order an entry",
|
|
4666
|
+
"before anything that depends on it. If one fails to come up, the rest are",
|
|
4667
|
+
"not started. Pass `--target <name>` to start or stop a single one."
|
|
4668
|
+
);
|
|
4669
|
+
lines.push("");
|
|
4670
|
+
lines.push(
|
|
4671
|
+
"The server must listen on `0.0.0.0` (not `127.0.0.1`) on the exposed",
|
|
4672
|
+
"port, or Traefik cannot reach it. You only have the ports already",
|
|
4673
|
+
"declared on the container; if you need another, ask the human to add it",
|
|
4674
|
+
`on the host (\`monoceros add-port ${input.containerName} <port>\`) and re-apply.`
|
|
4675
|
+
);
|
|
4676
|
+
lines.push("");
|
|
4665
4677
|
lines.push("## Command reference");
|
|
4666
4678
|
lines.push("");
|
|
4667
4679
|
lines.push(
|
|
@@ -6169,7 +6181,7 @@ var init_add_apt_packages = __esm({
|
|
|
6169
6181
|
meta: {
|
|
6170
6182
|
name: "add-apt-packages",
|
|
6171
6183
|
group: "edit",
|
|
6172
|
-
description: "Add Debian/Ubuntu apt packages to the container config. Pass package names
|
|
6184
|
+
description: "Add Debian/Ubuntu apt packages to the container config. Pass package names as arguments (e.g. `monoceros add-apt-packages sandbox make openssh-client jq`). Idempotent. No curated whitelist \u2014 invalid names surface as apt errors at container build time."
|
|
6173
6185
|
},
|
|
6174
6186
|
args: {
|
|
6175
6187
|
name: {
|
|
@@ -6177,6 +6189,11 @@ var init_add_apt_packages = __esm({
|
|
|
6177
6189
|
description: "Container name (yml in $MONOCEROS_HOME/container-configs/).",
|
|
6178
6190
|
required: true
|
|
6179
6191
|
},
|
|
6192
|
+
packages: {
|
|
6193
|
+
type: "positional",
|
|
6194
|
+
description: "One or more Debian/Ubuntu apt package names (e.g. `make jq`). At least one is required.",
|
|
6195
|
+
required: false
|
|
6196
|
+
},
|
|
6180
6197
|
yes: {
|
|
6181
6198
|
type: "boolean",
|
|
6182
6199
|
description: "Skip the interactive confirmation and apply the diff.",
|
|
@@ -6185,10 +6202,10 @@ var init_add_apt_packages = __esm({
|
|
|
6185
6202
|
}
|
|
6186
6203
|
},
|
|
6187
6204
|
async run({ args }) {
|
|
6188
|
-
const packages = [...getInnerArgs()];
|
|
6205
|
+
const packages = [...args._.slice(1).map(String), ...getInnerArgs()];
|
|
6189
6206
|
if (packages.length === 0) {
|
|
6190
6207
|
consola3.error(
|
|
6191
|
-
"No package names given. Usage: `monoceros add-apt-packages <containername> [--yes]
|
|
6208
|
+
"No package names given. Usage: `monoceros add-apt-packages <containername> [--yes] <pkg> [<pkg> \u2026]`."
|
|
6192
6209
|
);
|
|
6193
6210
|
process.exit(1);
|
|
6194
6211
|
}
|
|
@@ -6504,7 +6521,7 @@ var init_add_port = __esm({
|
|
|
6504
6521
|
meta: {
|
|
6505
6522
|
name: "add-port",
|
|
6506
6523
|
group: "edit",
|
|
6507
|
-
description: "Add one or more ports to the container config so they become reachable from the host via Traefik (`<container>.localhost` / `<container>-<port>.localhost`). Pass port numbers
|
|
6524
|
+
description: "Add one or more ports to the container config so they become reachable from the host via Traefik (`<container>.localhost` / `<container>-<port>.localhost`). Pass port numbers as arguments (e.g. `monoceros add-port sandbox 3000 5173 6006`). Idempotent. Persisted in the yml so later `monoceros apply` runs restore the routes. Pass `--default` together with a single port to make it the bare `<container>.localhost` route \u2014 the port is inserted at position 0 (or moved there if it already exists)."
|
|
6508
6525
|
},
|
|
6509
6526
|
args: {
|
|
6510
6527
|
name: {
|
|
@@ -6512,6 +6529,11 @@ var init_add_port = __esm({
|
|
|
6512
6529
|
description: "Container name (yml in $MONOCEROS_HOME/container-configs/).",
|
|
6513
6530
|
required: true
|
|
6514
6531
|
},
|
|
6532
|
+
ports: {
|
|
6533
|
+
type: "positional",
|
|
6534
|
+
description: "One or more port numbers to expose (e.g. `3000 5173`). At least one is required.",
|
|
6535
|
+
required: false
|
|
6536
|
+
},
|
|
6515
6537
|
yes: {
|
|
6516
6538
|
type: "boolean",
|
|
6517
6539
|
description: "Skip the interactive confirmation and apply the diff.",
|
|
@@ -6525,10 +6547,10 @@ var init_add_port = __esm({
|
|
|
6525
6547
|
}
|
|
6526
6548
|
},
|
|
6527
6549
|
async run({ args }) {
|
|
6528
|
-
const tokens = [...getInnerArgs()];
|
|
6550
|
+
const tokens = [...args._.slice(1).map(String), ...getInnerArgs()];
|
|
6529
6551
|
if (tokens.length === 0) {
|
|
6530
6552
|
consola8.error(
|
|
6531
|
-
"No ports given. Usage: `monoceros add-port <containername> [--
|
|
6553
|
+
"No ports given. Usage: `monoceros add-port <containername> [--default] [--yes] <port> [<port> \u2026]`."
|
|
6532
6554
|
);
|
|
6533
6555
|
process.exit(1);
|
|
6534
6556
|
}
|
|
@@ -8974,7 +8996,7 @@ var CLI_VERSION;
|
|
|
8974
8996
|
var init_version = __esm({
|
|
8975
8997
|
"src/version.ts"() {
|
|
8976
8998
|
"use strict";
|
|
8977
|
-
CLI_VERSION = true ? "1.38.
|
|
8999
|
+
CLI_VERSION = true ? "1.38.2" : "dev";
|
|
8978
9000
|
}
|
|
8979
9001
|
});
|
|
8980
9002
|
|
|
@@ -12372,6 +12394,7 @@ var init_run3 = __esm({
|
|
|
12372
12394
|
|
|
12373
12395
|
// src/tls/ca.ts
|
|
12374
12396
|
import { promises as fs21 } from "fs";
|
|
12397
|
+
import os3 from "os";
|
|
12375
12398
|
import path33 from "path";
|
|
12376
12399
|
import forge from "node-forge";
|
|
12377
12400
|
function homeDir(monocerosHome2) {
|
|
@@ -12380,6 +12403,10 @@ function homeDir(monocerosHome2) {
|
|
|
12380
12403
|
function randomSerial() {
|
|
12381
12404
|
return "00" + forge.util.bytesToHex(forge.random.getBytesSync(16));
|
|
12382
12405
|
}
|
|
12406
|
+
function caCommonName() {
|
|
12407
|
+
const host = os3.hostname().replace(/\.local$/, "").trim();
|
|
12408
|
+
return host ? `Monoceros Local CA (${host})` : "Monoceros Local CA";
|
|
12409
|
+
}
|
|
12383
12410
|
async function fileExists(p) {
|
|
12384
12411
|
try {
|
|
12385
12412
|
await fs21.access(p);
|
|
@@ -12409,7 +12436,7 @@ async function loadOrCreateCa(monocerosHome2) {
|
|
|
12409
12436
|
cert.validity.notAfter = new Date(
|
|
12410
12437
|
cert.validity.notBefore.getTime() + CA_DAYS * 24 * 60 * 60 * 1e3
|
|
12411
12438
|
);
|
|
12412
|
-
const attrs = [{ name: "commonName", value:
|
|
12439
|
+
const attrs = [{ name: "commonName", value: caCommonName() }];
|
|
12413
12440
|
cert.setSubject(attrs);
|
|
12414
12441
|
cert.setIssuer(attrs);
|
|
12415
12442
|
cert.setExtensions([
|
|
@@ -12571,14 +12598,14 @@ var init_caddy = __esm({
|
|
|
12571
12598
|
});
|
|
12572
12599
|
|
|
12573
12600
|
// src/share/run.ts
|
|
12574
|
-
import
|
|
12601
|
+
import os4 from "os";
|
|
12575
12602
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
12576
12603
|
import { consola as consola35 } from "consola";
|
|
12577
12604
|
import { promises as fs22 } from "fs";
|
|
12578
12605
|
import path34 from "path";
|
|
12579
12606
|
function realHostAddresses() {
|
|
12580
12607
|
let ip;
|
|
12581
|
-
for (const list of Object.values(
|
|
12608
|
+
for (const list of Object.values(os4.networkInterfaces())) {
|
|
12582
12609
|
for (const addr of list ?? []) {
|
|
12583
12610
|
if (addr.family === "IPv4" && !addr.internal) {
|
|
12584
12611
|
ip = addr.address;
|
|
@@ -12597,7 +12624,7 @@ function mdnsHostName() {
|
|
|
12597
12624
|
const name = res.status === 0 ? res.stdout.trim() : "";
|
|
12598
12625
|
if (name) return `${name}.local`;
|
|
12599
12626
|
}
|
|
12600
|
-
const hn =
|
|
12627
|
+
const hn = os4.hostname();
|
|
12601
12628
|
return hn.endsWith(".local") ? hn : `${hn}.local`;
|
|
12602
12629
|
}
|
|
12603
12630
|
async function runShare(opts) {
|