@mesh-tech/mesh-cli 0.31.1 → 0.32.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.
- package/dist/bin/mesh.js +71 -27
- package/dist/bin/mesh.js.map +1 -1
- package/dist/build-info.json +2 -2
- package/dist/src/commands/hub/index.d.ts +6 -1
- package/dist/src/commands/hub/index.js +67 -26
- package/package.json +1 -1
- package/skills/core/SKILL.md +3 -2
package/dist/bin/mesh.js
CHANGED
|
@@ -16931,6 +16931,31 @@ import * as net12 from "node:net";
|
|
|
16931
16931
|
import * as os9 from "node:os";
|
|
16932
16932
|
import * as path36 from "node:path";
|
|
16933
16933
|
import chalk3 from "chalk";
|
|
16934
|
+
function hubSessionName(apiPort) {
|
|
16935
|
+
return `${HUB_SESSION_PREFIX}-${apiPort}`;
|
|
16936
|
+
}
|
|
16937
|
+
function isHubSession(name) {
|
|
16938
|
+
return HUB_SESSION_RE.test(name);
|
|
16939
|
+
}
|
|
16940
|
+
function listHubSessions() {
|
|
16941
|
+
try {
|
|
16942
|
+
return execFileSync24("tmux", ["list-sessions", "-F", "#{session_name}"], {
|
|
16943
|
+
encoding: "utf8",
|
|
16944
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
16945
|
+
}).split("\n").map((line) => line.trim()).filter(isHubSession);
|
|
16946
|
+
} catch {
|
|
16947
|
+
return [];
|
|
16948
|
+
}
|
|
16949
|
+
}
|
|
16950
|
+
function killTargets(live, named) {
|
|
16951
|
+
return named ? live.filter((name) => name === named) : live;
|
|
16952
|
+
}
|
|
16953
|
+
function killInstructions(targets) {
|
|
16954
|
+
return targets.map((name) => {
|
|
16955
|
+
const port = name.slice(HUB_SESSION_PREFIX.length + 1);
|
|
16956
|
+
return port ? ` ${name}: mesh hub dev --kill --api-port ${port}` : ` ${name}: tmux kill-session -t ${name}`;
|
|
16957
|
+
});
|
|
16958
|
+
}
|
|
16934
16959
|
function devSessionsDir() {
|
|
16935
16960
|
return path36.join(os9.tmpdir(), "mesh-dev-sessions");
|
|
16936
16961
|
}
|
|
@@ -17158,8 +17183,8 @@ function isPortListening2(port) {
|
|
|
17158
17183
|
socket.once("error", () => done(false));
|
|
17159
17184
|
});
|
|
17160
17185
|
}
|
|
17161
|
-
function hubEnvDir() {
|
|
17162
|
-
return path36.join(os9.tmpdir(), "mesh-dev-sessions",
|
|
17186
|
+
function hubEnvDir(sessionName) {
|
|
17187
|
+
return path36.join(os9.tmpdir(), "mesh-dev-sessions", sessionName);
|
|
17163
17188
|
}
|
|
17164
17189
|
function parsePort(raw, fallback, source) {
|
|
17165
17190
|
if (raw === void 0) return fallback;
|
|
@@ -17181,17 +17206,28 @@ function redactEnv(env) {
|
|
|
17181
17206
|
}
|
|
17182
17207
|
async function hubDevAction(opts) {
|
|
17183
17208
|
if (opts.kill) {
|
|
17184
|
-
|
|
17185
|
-
|
|
17186
|
-
|
|
17187
|
-
|
|
17188
|
-
|
|
17189
|
-
|
|
17209
|
+
const namedPort = opts.apiPort || process.env.MESH_HUB_DEV_API_PORT;
|
|
17210
|
+
const named = namedPort ? hubSessionName(parsePort(namedPort, DEFAULT_HUB_API_PORT, opts.apiPort ? "--api-port" : "MESH_HUB_DEV_API_PORT")) : null;
|
|
17211
|
+
const targets = killTargets(listHubSessions(), named);
|
|
17212
|
+
if (targets.length === 0) {
|
|
17213
|
+
logInfo(named ? `No '${named}' tmux session running.` : "No `mesh hub dev` session running.");
|
|
17214
|
+
return;
|
|
17190
17215
|
}
|
|
17216
|
+
if (targets.length > 1) {
|
|
17217
|
+
throw new MeshCliError(
|
|
17218
|
+
`${targets.length} Hub sessions are running \u2014 name the one to stop.
|
|
17219
|
+
${killInstructions(targets).join("\n")}`,
|
|
17220
|
+
{ remediation: { command: "mesh hub dev --kill --api-port <port> # the API port that Hub was started on" } }
|
|
17221
|
+
);
|
|
17222
|
+
}
|
|
17223
|
+
const target = targets[0];
|
|
17224
|
+
execFileSync24("tmux", ["kill-session", "-t", target], { stdio: "ignore" });
|
|
17225
|
+
fs29.rmSync(hubEnvDir(target), { recursive: true, force: true });
|
|
17226
|
+
logSuccess(`Killed Hub session '${target}'.`);
|
|
17191
17227
|
return;
|
|
17192
17228
|
}
|
|
17193
17229
|
const uiPort = opts.port ? parsePort(opts.port, DEFAULT_HUB_UI_PORT, "--port") : parsePort(process.env.MESH_HUB_DEV_PORT, DEFAULT_HUB_UI_PORT, "MESH_HUB_DEV_PORT");
|
|
17194
|
-
const apiPort = parsePort(opts.apiPort, DEFAULT_HUB_API_PORT, "--api-port");
|
|
17230
|
+
const apiPort = opts.apiPort ? parsePort(opts.apiPort, DEFAULT_HUB_API_PORT, "--api-port") : parsePort(process.env.MESH_HUB_DEV_API_PORT, DEFAULT_HUB_API_PORT, "MESH_HUB_DEV_API_PORT");
|
|
17195
17231
|
const platformDir = resolvePlatformDir(opts.platformDir, process.cwd());
|
|
17196
17232
|
const cwdAppRoot = findAppRoot(process.cwd());
|
|
17197
17233
|
const session = pickDevSession(listDevSessions(), { session: opts.session, cwdAppRoot });
|
|
@@ -17218,9 +17254,10 @@ async function hubDevAction(opts) {
|
|
|
17218
17254
|
for (const [k, v] of Object.entries(redactEnv(assembled.uiEnv))) console.log(` ${k}=${v}`);
|
|
17219
17255
|
return;
|
|
17220
17256
|
}
|
|
17221
|
-
|
|
17222
|
-
|
|
17223
|
-
|
|
17257
|
+
const hubSession = hubSessionName(apiPort);
|
|
17258
|
+
if (tmuxSessionExists(hubSession)) {
|
|
17259
|
+
throw new MeshCliError(`A '${hubSession}' tmux session is already running.`, {
|
|
17260
|
+
remediation: { command: `mesh hub dev --kill --api-port ${apiPort} # then re-run` }
|
|
17224
17261
|
});
|
|
17225
17262
|
}
|
|
17226
17263
|
for (const [label, port, flag] of [
|
|
@@ -17245,20 +17282,20 @@ async function hubDevAction(opts) {
|
|
|
17245
17282
|
for (const warning of assembled.warnings) logWarn(warning);
|
|
17246
17283
|
const apiDir = path36.join(platformDir, "apps", "hub", "api");
|
|
17247
17284
|
const uiDir = path36.join(platformDir, "apps", "hub", "ui");
|
|
17248
|
-
execFileSync24("tmux", ["new-session", "-d", "-s",
|
|
17285
|
+
execFileSync24("tmux", ["new-session", "-d", "-s", hubSession, "-n", "api", "-c", apiDir]);
|
|
17249
17286
|
if (!assembled.apiEnv.DEV_USER_TOKEN_URL && assembled.apiEnv.DEV_USER_ID_TOKEN) {
|
|
17250
17287
|
const platform = session.state.devOutput.platform;
|
|
17251
17288
|
const credContext = `mesh.${platform.env}`;
|
|
17252
17289
|
const tokenPort = await findFreePort4();
|
|
17253
17290
|
const tokenUrl = `http://127.0.0.1:${tokenPort}`;
|
|
17254
|
-
execFileSync24("tmux", ["new-window", "-t",
|
|
17255
|
-
execFileSync24("tmux", ["set-option", "-t", `${
|
|
17291
|
+
execFileSync24("tmux", ["new-window", "-t", hubSession, "-n", "token-server", "-c", platformDir]);
|
|
17292
|
+
execFileSync24("tmux", ["set-option", "-t", `${hubSession}:token-server`, "remain-on-exit", "on"], {
|
|
17256
17293
|
stdio: "ignore"
|
|
17257
17294
|
});
|
|
17258
17295
|
execFileSync24("tmux", [
|
|
17259
17296
|
"send-keys",
|
|
17260
17297
|
"-t",
|
|
17261
|
-
`${
|
|
17298
|
+
`${hubSession}:token-server`,
|
|
17262
17299
|
`npx mesh dev __token-server ${tokenPort} ${credContext}`,
|
|
17263
17300
|
"Enter"
|
|
17264
17301
|
]);
|
|
@@ -17270,15 +17307,15 @@ async function hubDevAction(opts) {
|
|
|
17270
17307
|
logSuccess(`Dev-user token-server: ${tokenUrl} (context ${credContext})`);
|
|
17271
17308
|
}
|
|
17272
17309
|
const launch = (window, dir, env, cmd, createWindow) => {
|
|
17273
|
-
const envFile = path36.join(hubEnvDir(), `${window}.env.sh`);
|
|
17310
|
+
const envFile = path36.join(hubEnvDir(hubSession), `${window}.env.sh`);
|
|
17274
17311
|
writeEnvFile(envFile, env);
|
|
17275
17312
|
if (createWindow) {
|
|
17276
|
-
execFileSync24("tmux", ["new-window", "-t",
|
|
17313
|
+
execFileSync24("tmux", ["new-window", "-t", hubSession, "-n", window, "-c", dir]);
|
|
17277
17314
|
}
|
|
17278
|
-
execFileSync24("tmux", ["set-option", "-t", `${
|
|
17315
|
+
execFileSync24("tmux", ["set-option", "-t", `${hubSession}:${window}`, "remain-on-exit", "on"], {
|
|
17279
17316
|
stdio: "ignore"
|
|
17280
17317
|
});
|
|
17281
|
-
execFileSync24("tmux", ["send-keys", "-t", `${
|
|
17318
|
+
execFileSync24("tmux", ["send-keys", "-t", `${hubSession}:${window}`, buildLaunchCommand(envFile, dir, cmd), "Enter"]);
|
|
17282
17319
|
};
|
|
17283
17320
|
launch("api", apiDir, assembled.apiEnv, "pnpm dev", false);
|
|
17284
17321
|
launch("ui", uiDir, assembled.uiEnv, `pnpm dev --port ${uiPort} --strictPort`, true);
|
|
@@ -17288,15 +17325,15 @@ async function hubDevAction(opts) {
|
|
|
17288
17325
|
if (!apiUp || !uiUp) {
|
|
17289
17326
|
throw new MeshCliError(
|
|
17290
17327
|
`Hub ${apiUp ? "UI" : "API"} did not start listening (api :${apiPort}, ui :${uiPort}).`,
|
|
17291
|
-
{ remediation: { command: `tmux attach -t ${
|
|
17328
|
+
{ remediation: { command: `tmux attach -t ${hubSession} # inspect the ${apiUp ? "ui" : "api"} window` } }
|
|
17292
17329
|
);
|
|
17293
17330
|
}
|
|
17294
17331
|
console.log("");
|
|
17295
17332
|
logSuccess(`Mesh Hub (dev-local scope ${assembled.scope.scopeTenants.join(",")} @ ${assembled.scope.scopeEnv})`);
|
|
17296
17333
|
console.log(` ${chalk3.bold.cyan(`http://localhost:${uiPort}`)} (also reachable on your tailnet)`);
|
|
17297
17334
|
console.log(` api http://localhost:${apiPort}`);
|
|
17298
|
-
console.log(` logs tmux attach -t ${
|
|
17299
|
-
console.log(` stop mesh hub dev --kill`);
|
|
17335
|
+
console.log(` logs tmux attach -t ${hubSession}`);
|
|
17336
|
+
console.log(` stop mesh hub dev --kill --api-port ${apiPort}`);
|
|
17300
17337
|
}
|
|
17301
17338
|
function registerHubCommands(program2) {
|
|
17302
17339
|
const hub = program2.command("hub").description("Local Hub over dev-local stacks");
|
|
@@ -17305,9 +17342,15 @@ function registerHubCommands(program2) {
|
|
|
17305
17342
|
).option("--session <name>", "dev session to observe (default: auto-detect from cwd)").option("--tenants <list>", "comma-separated HUB_SCOPE_TENANTS override (default: the session's tenant)").option(
|
|
17306
17343
|
"--audience <who>",
|
|
17307
17344
|
"who the Hub renders for: `operator` (platform staff \u2014 the default here) or `tenant` (a client's operators). Anything else reads as `tenant`"
|
|
17308
|
-
).option("--port <port>", `Hub UI host port (default: $MESH_HUB_DEV_PORT or ${DEFAULT_HUB_UI_PORT})`).option(
|
|
17309
|
-
|
|
17310
|
-
|
|
17345
|
+
).option("--port <port>", `Hub UI host port (default: $MESH_HUB_DEV_PORT or ${DEFAULT_HUB_UI_PORT})`).option(
|
|
17346
|
+
"--api-port <port>",
|
|
17347
|
+
`Hub API port, and the key its tmux session is named after \u2014 several Hubs coexist on different ones (default: $MESH_HUB_DEV_API_PORT or ${DEFAULT_HUB_API_PORT})`
|
|
17348
|
+
).option("--platform-dir <dir>", "mesh-platform checkout to run the Hub from (default: $MESH_PLATFORM_DIR or walk up from cwd)").option("--print-env", "print the assembled env (secrets redacted) and exit without launching").option(
|
|
17349
|
+
"--kill",
|
|
17350
|
+
"tear down a running Hub session; with several up, name it with --api-port (or $MESH_HUB_DEV_API_PORT)"
|
|
17351
|
+
).action(hubDevAction);
|
|
17352
|
+
}
|
|
17353
|
+
var HUB_SESSION_PREFIX, HUB_SESSION_RE, DEFAULT_HUB_UI_PORT, DEFAULT_HUB_API_PORT, FORWARD_PREFIXES, localPlatformEnv2, SENSITIVE_RE;
|
|
17311
17354
|
var init_hub = __esm({
|
|
17312
17355
|
"libs/mesh-cli/src/commands/hub/index.ts"() {
|
|
17313
17356
|
"use strict";
|
|
@@ -17317,7 +17360,8 @@ var init_hub = __esm({
|
|
|
17317
17360
|
init_stack();
|
|
17318
17361
|
init_log();
|
|
17319
17362
|
init_pulumi();
|
|
17320
|
-
|
|
17363
|
+
HUB_SESSION_PREFIX = "mesh-hub-dev";
|
|
17364
|
+
HUB_SESSION_RE = new RegExp(`^${HUB_SESSION_PREFIX}(-\\d+)?$`);
|
|
17321
17365
|
DEFAULT_HUB_UI_PORT = Number(DEFAULT_HUB_PORT);
|
|
17322
17366
|
DEFAULT_HUB_API_PORT = 3002;
|
|
17323
17367
|
FORWARD_PREFIXES = ["AWS_", "DEV_USER_"];
|