@mesh-tech/mesh-cli 0.26.0 → 0.27.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 +1056 -778
- package/dist/bin/mesh.js.map +3 -3
- package/dist/build-info.json +2 -2
- package/dist/src/commands/local/index.d.ts +5 -3
- package/dist/src/commands/local/index.js +61 -23
- package/dist/src/commands/local/mock-idps.d.ts +48 -0
- package/dist/src/commands/local/mock-idps.js +119 -0
- package/dist/src/commands/local/seed-zitadel.d.ts +6 -0
- package/dist/src/commands/local/seed-zitadel.js +76 -0
- package/dist/src/commands/local/stack.d.ts +11 -3
- package/dist/src/commands/local/stack.js +29 -15
- package/dist/src/commands/temporal.js +10 -0
- package/dist/src/commands/temporal.js.map +2 -2
- package/package.json +2 -2
- package/skills/core/SKILL.md +1 -1
- package/stack/docker-compose.idps.yml +104 -0
- package/stack/idps/dex.yaml +53 -0
package/dist/bin/mesh.js
CHANGED
|
@@ -1251,9 +1251,11 @@ var init_cache_home = __esm({
|
|
|
1251
1251
|
// libs/mesh-cli/src/commands/local/stack.ts
|
|
1252
1252
|
var stack_exports = {};
|
|
1253
1253
|
__export(stack_exports, {
|
|
1254
|
+
BASE_COMPOSE_FILE: () => BASE_COMPOSE_FILE,
|
|
1254
1255
|
COMPOSE_PROJECT: () => COMPOSE_PROJECT,
|
|
1255
1256
|
DEFAULT_HUB_PORT: () => DEFAULT_HUB_PORT,
|
|
1256
1257
|
HUB_OVERLAY_FILE: () => HUB_OVERLAY_FILE,
|
|
1258
|
+
IDPS_OVERLAY_FILE: () => IDPS_OVERLAY_FILE,
|
|
1257
1259
|
ONE_SHOT_SERVICES: () => ONE_SHOT_SERVICES,
|
|
1258
1260
|
STACK_ENDPOINTS: () => STACK_ENDPOINTS,
|
|
1259
1261
|
compose: () => compose,
|
|
@@ -1264,11 +1266,12 @@ __export(stack_exports, {
|
|
|
1264
1266
|
findPackageRoot: () => findPackageRoot,
|
|
1265
1267
|
hubApiRunning: () => hubApiRunning,
|
|
1266
1268
|
hubEndpoints: () => hubEndpoints,
|
|
1267
|
-
hubOverlayRunning: () => hubOverlayRunning,
|
|
1268
1269
|
hubOverlayServices: () => hubOverlayServices,
|
|
1269
1270
|
hubPort: () => hubPort,
|
|
1271
|
+
idpsOverlayServices: () => idpsOverlayServices,
|
|
1270
1272
|
localLogsDir: () => localLogsDir,
|
|
1271
1273
|
localProbesDir: () => localProbesDir,
|
|
1274
|
+
overlayRunning: () => overlayRunning,
|
|
1272
1275
|
parseComposePs: () => parseComposePs,
|
|
1273
1276
|
parseComposeServiceNames: () => parseComposeServiceNames,
|
|
1274
1277
|
probeEndpoint: () => probeEndpoint,
|
|
@@ -1368,17 +1371,29 @@ function parseComposeServiceNames(yamlText) {
|
|
|
1368
1371
|
const doc = parseYaml(yamlText);
|
|
1369
1372
|
return Object.keys(doc?.services ?? {});
|
|
1370
1373
|
}
|
|
1371
|
-
function
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
hubOverlayServicesCache = new Set(parseComposeServiceNames(fs5.readFileSync(file, "utf-8")));
|
|
1374
|
+
function overlayServicesOf(overlayFile) {
|
|
1375
|
+
const cached = overlayServicesCache.get(overlayFile);
|
|
1376
|
+
if (cached) return cached;
|
|
1377
|
+
const file = path5.join(stackDir(), overlayFile);
|
|
1378
|
+
if (!fs5.existsSync(file)) {
|
|
1379
|
+
throw new MeshCliError(`Local stack assets are incomplete: ${file} is missing.`, {
|
|
1380
|
+
remediation: { command: "npm install -g @mesh-tech/mesh-cli" }
|
|
1381
|
+
});
|
|
1380
1382
|
}
|
|
1381
|
-
|
|
1383
|
+
const base = new Set(
|
|
1384
|
+
parseComposeServiceNames(fs5.readFileSync(path5.join(stackDir(), BASE_COMPOSE_FILE), "utf-8"))
|
|
1385
|
+
);
|
|
1386
|
+
const names = new Set(
|
|
1387
|
+
parseComposeServiceNames(fs5.readFileSync(file, "utf-8")).filter((n) => !base.has(n))
|
|
1388
|
+
);
|
|
1389
|
+
overlayServicesCache.set(overlayFile, names);
|
|
1390
|
+
return names;
|
|
1391
|
+
}
|
|
1392
|
+
function hubOverlayServices() {
|
|
1393
|
+
return overlayServicesOf(HUB_OVERLAY_FILE);
|
|
1394
|
+
}
|
|
1395
|
+
function idpsOverlayServices() {
|
|
1396
|
+
return overlayServicesOf(IDPS_OVERLAY_FILE);
|
|
1382
1397
|
}
|
|
1383
1398
|
function stackOwnedElsewhere() {
|
|
1384
1399
|
try {
|
|
@@ -1416,6 +1431,7 @@ function compose(args, opts = {}) {
|
|
|
1416
1431
|
const dir = stackDir();
|
|
1417
1432
|
const files = ["-f", path5.join(dir, "docker-compose.yml")];
|
|
1418
1433
|
if (opts.hub) files.push("-f", path5.join(dir, "docker-compose.hub.yml"));
|
|
1434
|
+
if (opts.idps) files.push("-f", path5.join(dir, IDPS_OVERLAY_FILE));
|
|
1419
1435
|
const fullArgs = ["compose", "-p", COMPOSE_PROJECT, ...files, ...args];
|
|
1420
1436
|
return execFileSync4("docker", fullArgs, {
|
|
1421
1437
|
cwd: dir,
|
|
@@ -1451,6 +1467,7 @@ async function composeStreamed(args, opts = {}) {
|
|
|
1451
1467
|
const dir = stackDir();
|
|
1452
1468
|
const files = ["-f", path5.join(dir, "docker-compose.yml")];
|
|
1453
1469
|
if (opts.hub) files.push("-f", path5.join(dir, "docker-compose.hub.yml"));
|
|
1470
|
+
if (opts.idps) files.push("-f", path5.join(dir, IDPS_OVERLAY_FILE));
|
|
1454
1471
|
const fullArgs = ["compose", "-p", COMPOSE_PROJECT, ...files, ...args];
|
|
1455
1472
|
const env = {
|
|
1456
1473
|
...process.env,
|
|
@@ -1539,11 +1556,14 @@ function stackServices() {
|
|
|
1539
1556
|
return parseComposePs(compose(["ps", "-a", "--format", "json"], { hub: true }));
|
|
1540
1557
|
}
|
|
1541
1558
|
function crashedServices(services, opts) {
|
|
1559
|
+
const dormant = new Set(
|
|
1560
|
+
opts.overlays.filter((o) => !o.started).flatMap((o) => [...o.services])
|
|
1561
|
+
);
|
|
1542
1562
|
return services.filter(
|
|
1543
|
-
(s) => s.state === "exited" && !ONE_SHOT_SERVICES.has(s.name) &&
|
|
1563
|
+
(s) => s.state === "exited" && !ONE_SHOT_SERVICES.has(s.name) && !dormant.has(s.name)
|
|
1544
1564
|
);
|
|
1545
1565
|
}
|
|
1546
|
-
function
|
|
1566
|
+
function overlayRunning(services, overlayServices) {
|
|
1547
1567
|
return services.some((s) => overlayServices.has(s.name) && s.state === "running");
|
|
1548
1568
|
}
|
|
1549
1569
|
function hubApiRunning(services) {
|
|
@@ -1563,7 +1583,7 @@ async function probeEndpoint(endpoint) {
|
|
|
1563
1583
|
}
|
|
1564
1584
|
return true;
|
|
1565
1585
|
}
|
|
1566
|
-
var COMPOSE_PROJECT, STACK_ENDPOINTS, DEFAULT_HUB_PORT, HUB_OVERLAY_FILE,
|
|
1586
|
+
var COMPOSE_PROJECT, STACK_ENDPOINTS, DEFAULT_HUB_PORT, BASE_COMPOSE_FILE, HUB_OVERLAY_FILE, IDPS_OVERLAY_FILE, overlayServicesCache, ONE_SHOT_SERVICES;
|
|
1567
1587
|
var init_stack = __esm({
|
|
1568
1588
|
"libs/mesh-cli/src/commands/local/stack.ts"() {
|
|
1569
1589
|
"use strict";
|
|
@@ -1668,7 +1688,10 @@ var init_stack = __esm({
|
|
|
1668
1688
|
}
|
|
1669
1689
|
];
|
|
1670
1690
|
DEFAULT_HUB_PORT = "9000";
|
|
1691
|
+
BASE_COMPOSE_FILE = "docker-compose.yml";
|
|
1671
1692
|
HUB_OVERLAY_FILE = "docker-compose.hub.yml";
|
|
1693
|
+
IDPS_OVERLAY_FILE = "docker-compose.idps.yml";
|
|
1694
|
+
overlayServicesCache = /* @__PURE__ */ new Map();
|
|
1672
1695
|
ONE_SHOT_SERVICES = /* @__PURE__ */ new Set(["spicedb-migrate", "zitadel-machinekey-init"]);
|
|
1673
1696
|
}
|
|
1674
1697
|
});
|
|
@@ -3803,11 +3826,11 @@ function readAllCredentials() {
|
|
|
3803
3826
|
function readCredentials(context) {
|
|
3804
3827
|
return readAllCredentials()[context] ?? null;
|
|
3805
3828
|
}
|
|
3806
|
-
function atomicWriteFileSync(
|
|
3807
|
-
const tmpPath = `${
|
|
3829
|
+
function atomicWriteFileSync(path48, data, mode) {
|
|
3830
|
+
const tmpPath = `${path48}.${process.pid}.${atomicWriteCounter++}.tmp`;
|
|
3808
3831
|
try {
|
|
3809
3832
|
fs10.writeFileSync(tmpPath, data, { mode });
|
|
3810
|
-
fs10.renameSync(tmpPath,
|
|
3833
|
+
fs10.renameSync(tmpPath, path48);
|
|
3811
3834
|
} catch (err) {
|
|
3812
3835
|
try {
|
|
3813
3836
|
fs10.unlinkSync(tmpPath);
|
|
@@ -6674,10 +6697,143 @@ var init_src = __esm({
|
|
|
6674
6697
|
}
|
|
6675
6698
|
});
|
|
6676
6699
|
|
|
6677
|
-
// libs/mesh-cli/src/commands/local/
|
|
6700
|
+
// libs/mesh-cli/src/commands/local/mock-idps.ts
|
|
6701
|
+
import { execFileSync as execFileSync13 } from "child_process";
|
|
6678
6702
|
import * as fs16 from "fs";
|
|
6679
|
-
import * as os5 from "os";
|
|
6680
6703
|
import * as path16 from "path";
|
|
6704
|
+
function ensureMockSamlSigningKey() {
|
|
6705
|
+
const dir = keyDir();
|
|
6706
|
+
const certPath = path16.join(dir, "cert.pem");
|
|
6707
|
+
const keyPath = path16.join(dir, "key.pem");
|
|
6708
|
+
if (!fs16.existsSync(certPath) || !fs16.existsSync(keyPath)) {
|
|
6709
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
6710
|
+
try {
|
|
6711
|
+
execFileSync13(
|
|
6712
|
+
"openssl",
|
|
6713
|
+
[
|
|
6714
|
+
"req",
|
|
6715
|
+
"-x509",
|
|
6716
|
+
"-newkey",
|
|
6717
|
+
"rsa:2048",
|
|
6718
|
+
"-keyout",
|
|
6719
|
+
keyPath,
|
|
6720
|
+
"-out",
|
|
6721
|
+
certPath,
|
|
6722
|
+
"-days",
|
|
6723
|
+
"3650",
|
|
6724
|
+
"-nodes",
|
|
6725
|
+
"-subj",
|
|
6726
|
+
"/CN=mesh-local-mock-saml"
|
|
6727
|
+
],
|
|
6728
|
+
{ stdio: "ignore" }
|
|
6729
|
+
);
|
|
6730
|
+
} catch (cause) {
|
|
6731
|
+
throw new MeshCliError("Could not generate the mock SAML signing key.", {
|
|
6732
|
+
remediation: {
|
|
6733
|
+
command: "openssl version # openssl must be on PATH for --with-idps"
|
|
6734
|
+
},
|
|
6735
|
+
cause
|
|
6736
|
+
});
|
|
6737
|
+
}
|
|
6738
|
+
}
|
|
6739
|
+
return {
|
|
6740
|
+
publicKeyB64: fs16.readFileSync(certPath).toString("base64"),
|
|
6741
|
+
privateKeyB64: fs16.readFileSync(keyPath).toString("base64")
|
|
6742
|
+
};
|
|
6743
|
+
}
|
|
6744
|
+
var MOCK_SAML_PORT, MOCK_OIDC_PORT, MOCK_OIDC_SERVICE, idpEndpoints, MOCK_SAML_IDP_NAME, MOCK_OIDC_IDP_NAME, MOCK_OIDC_CLIENT_ID, MOCK_OIDC_CLIENT_SECRET, mockSamlMetadataUrl, mockOidcEndpoints, keyDir, mockIdpComposeEnv, buildMockSamlIdpBody, buildMockOauthIdpBody, missingLoginPolicyIdps;
|
|
6745
|
+
var init_mock_idps = __esm({
|
|
6746
|
+
"libs/mesh-cli/src/commands/local/mock-idps.ts"() {
|
|
6747
|
+
"use strict";
|
|
6748
|
+
init_cache_home();
|
|
6749
|
+
init_errors();
|
|
6750
|
+
MOCK_SAML_PORT = 4569;
|
|
6751
|
+
MOCK_OIDC_PORT = 5556;
|
|
6752
|
+
MOCK_OIDC_SERVICE = "mock-oidc";
|
|
6753
|
+
idpEndpoints = () => [
|
|
6754
|
+
{
|
|
6755
|
+
service: "mock-saml",
|
|
6756
|
+
label: "Mock SAML IdP",
|
|
6757
|
+
url: `http://localhost:${MOCK_SAML_PORT}`,
|
|
6758
|
+
probe: { kind: "http", url: mockSamlMetadataUrl() },
|
|
6759
|
+
hint: "sign in as any email you type; federation metadata at /api/saml/metadata"
|
|
6760
|
+
},
|
|
6761
|
+
{
|
|
6762
|
+
service: MOCK_OIDC_SERVICE,
|
|
6763
|
+
label: "Mock OIDC IdP",
|
|
6764
|
+
url: `http://localhost:${MOCK_OIDC_PORT}/dex`,
|
|
6765
|
+
probe: {
|
|
6766
|
+
kind: "http",
|
|
6767
|
+
url: `http://localhost:${MOCK_OIDC_PORT}/dex/.well-known/openid-configuration`
|
|
6768
|
+
},
|
|
6769
|
+
hint: "dev@local.mesh or ops@local.mesh / password"
|
|
6770
|
+
}
|
|
6771
|
+
];
|
|
6772
|
+
MOCK_SAML_IDP_NAME = "Mock SAML (local)";
|
|
6773
|
+
MOCK_OIDC_IDP_NAME = "Mock OIDC (local)";
|
|
6774
|
+
MOCK_OIDC_CLIENT_ID = "mesh-local";
|
|
6775
|
+
MOCK_OIDC_CLIENT_SECRET = "mesh-local-secret";
|
|
6776
|
+
mockSamlMetadataUrl = () => `http://localhost:${MOCK_SAML_PORT}/api/saml/metadata`;
|
|
6777
|
+
mockOidcEndpoints = () => ({
|
|
6778
|
+
authorization: `http://localhost:${MOCK_OIDC_PORT}/dex/auth`,
|
|
6779
|
+
token: `http://${MOCK_OIDC_SERVICE}:${MOCK_OIDC_PORT}/dex/token`,
|
|
6780
|
+
user: `http://${MOCK_OIDC_SERVICE}:${MOCK_OIDC_PORT}/dex/userinfo`
|
|
6781
|
+
});
|
|
6782
|
+
keyDir = () => path16.join(meshCacheDir("mesh-local"), "mock-idp");
|
|
6783
|
+
mockIdpComposeEnv = () => {
|
|
6784
|
+
const { publicKeyB64, privateKeyB64 } = ensureMockSamlSigningKey();
|
|
6785
|
+
return {
|
|
6786
|
+
MESH_MOCK_SAML_PUBLIC_KEY: publicKeyB64,
|
|
6787
|
+
MESH_MOCK_SAML_PRIVATE_KEY: privateKeyB64
|
|
6788
|
+
};
|
|
6789
|
+
};
|
|
6790
|
+
buildMockSamlIdpBody = (metadataXml) => ({
|
|
6791
|
+
name: MOCK_SAML_IDP_NAME,
|
|
6792
|
+
metadataXml: Buffer.from(metadataXml, "utf-8").toString("base64"),
|
|
6793
|
+
binding: "SAML_BINDING_POST",
|
|
6794
|
+
withSignedRequest: true,
|
|
6795
|
+
providerOptions: {
|
|
6796
|
+
isLinkingAllowed: true,
|
|
6797
|
+
isCreationAllowed: true,
|
|
6798
|
+
isAutoCreation: true,
|
|
6799
|
+
isAutoUpdate: true,
|
|
6800
|
+
// Matches the component's default: without it a federated sign-in for an
|
|
6801
|
+
// address that already has a Zitadel account fails as a duplicate
|
|
6802
|
+
// instead of linking, which is the behaviour worth being able to see.
|
|
6803
|
+
autoLinking: "AUTO_LINKING_OPTION_EMAIL"
|
|
6804
|
+
}
|
|
6805
|
+
});
|
|
6806
|
+
buildMockOauthIdpBody = () => {
|
|
6807
|
+
const endpoints = mockOidcEndpoints();
|
|
6808
|
+
return {
|
|
6809
|
+
name: MOCK_OIDC_IDP_NAME,
|
|
6810
|
+
clientId: MOCK_OIDC_CLIENT_ID,
|
|
6811
|
+
clientSecret: MOCK_OIDC_CLIENT_SECRET,
|
|
6812
|
+
authorizationEndpoint: endpoints.authorization,
|
|
6813
|
+
tokenEndpoint: endpoints.token,
|
|
6814
|
+
userEndpoint: endpoints.user,
|
|
6815
|
+
scopes: ["openid", "profile", "email"],
|
|
6816
|
+
idAttribute: "sub",
|
|
6817
|
+
providerOptions: {
|
|
6818
|
+
isLinkingAllowed: true,
|
|
6819
|
+
isCreationAllowed: true,
|
|
6820
|
+
isAutoCreation: true,
|
|
6821
|
+
isAutoUpdate: true,
|
|
6822
|
+
autoLinking: "AUTO_LINKING_OPTION_EMAIL"
|
|
6823
|
+
}
|
|
6824
|
+
};
|
|
6825
|
+
};
|
|
6826
|
+
missingLoginPolicyIdps = (attached, wanted) => {
|
|
6827
|
+
const have = new Set(attached);
|
|
6828
|
+
return [...new Set(wanted)].filter((id) => !have.has(id));
|
|
6829
|
+
};
|
|
6830
|
+
}
|
|
6831
|
+
});
|
|
6832
|
+
|
|
6833
|
+
// libs/mesh-cli/src/commands/local/seed-zitadel.ts
|
|
6834
|
+
import * as fs17 from "fs";
|
|
6835
|
+
import * as os5 from "os";
|
|
6836
|
+
import * as path17 from "path";
|
|
6681
6837
|
function buildCliAppPayload() {
|
|
6682
6838
|
return {
|
|
6683
6839
|
name: CLI_APP_NAME,
|
|
@@ -6694,10 +6850,10 @@ function buildCliAppPayload() {
|
|
|
6694
6850
|
};
|
|
6695
6851
|
}
|
|
6696
6852
|
function readSeederPat() {
|
|
6697
|
-
const tmp =
|
|
6853
|
+
const tmp = path17.join(fs17.mkdtempSync(path17.join(os5.tmpdir(), "mesh-zitadel-")), "pat.txt");
|
|
6698
6854
|
try {
|
|
6699
6855
|
compose(["cp", "zitadel:/machinekey/pat.txt", tmp]);
|
|
6700
|
-
const pat =
|
|
6856
|
+
const pat = fs17.readFileSync(tmp, "utf-8").trim();
|
|
6701
6857
|
if (!pat) throw new Error("empty PAT file");
|
|
6702
6858
|
return pat;
|
|
6703
6859
|
} catch {
|
|
@@ -6706,7 +6862,7 @@ function readSeederPat() {
|
|
|
6706
6862
|
{ remediation: { command: "mesh stop --destroy && mesh start" } }
|
|
6707
6863
|
);
|
|
6708
6864
|
} finally {
|
|
6709
|
-
|
|
6865
|
+
fs17.rmSync(path17.dirname(tmp), { recursive: true, force: true });
|
|
6710
6866
|
}
|
|
6711
6867
|
}
|
|
6712
6868
|
async function api(pat, method, apiPath, body, orgId) {
|
|
@@ -6805,11 +6961,11 @@ async function ensureTestUsers(pat) {
|
|
|
6805
6961
|
}
|
|
6806
6962
|
}
|
|
6807
6963
|
function hubAuthPath() {
|
|
6808
|
-
return
|
|
6964
|
+
return path17.join(meshCacheDir("mesh-local"), "hub-auth.json");
|
|
6809
6965
|
}
|
|
6810
6966
|
function readHubAuth() {
|
|
6811
6967
|
try {
|
|
6812
|
-
const parsed = JSON.parse(
|
|
6968
|
+
const parsed = JSON.parse(fs17.readFileSync(hubAuthPath(), "utf-8"));
|
|
6813
6969
|
if (parsed?.clientId && parsed?.clientSecret && parsed?.cookieSecret) return parsed;
|
|
6814
6970
|
return null;
|
|
6815
6971
|
} catch {
|
|
@@ -6948,7 +7104,7 @@ async function seedHubAuth(pat) {
|
|
|
6948
7104
|
clientSecret: app.clientSecret ?? persisted?.clientSecret ?? "",
|
|
6949
7105
|
cookieSecret: persistedCookie ?? (await import("crypto")).randomBytes(16).toString("hex")
|
|
6950
7106
|
};
|
|
6951
|
-
|
|
7107
|
+
fs17.writeFileSync(hubAuthPath(), JSON.stringify(config, null, 2), { mode: 384 });
|
|
6952
7108
|
return config;
|
|
6953
7109
|
}
|
|
6954
7110
|
async function publishHubAuthzPointer(projectId, orgId, awsConfig) {
|
|
@@ -7104,7 +7260,79 @@ async function seedZitadel(awsConfig) {
|
|
|
7104
7260
|
logSuccess(`Login context '${LOGIN_CONTEXT}' configured \u2192 try: mesh login ${LOGIN_CONTEXT}`);
|
|
7105
7261
|
return { projectId, cliClientId, hubAuth };
|
|
7106
7262
|
}
|
|
7107
|
-
|
|
7263
|
+
async function fetchMockSamlMetadata() {
|
|
7264
|
+
const url = mockSamlMetadataUrl();
|
|
7265
|
+
let lastError = "no attempt made";
|
|
7266
|
+
for (let attempt = 0; attempt < 30; attempt++) {
|
|
7267
|
+
try {
|
|
7268
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(5e3) });
|
|
7269
|
+
const body = await res.text();
|
|
7270
|
+
if (res.ok && body.includes("EntityDescriptor")) {
|
|
7271
|
+
if (/<ds:X509Certificate\s*\/>|<ds:X509Certificate>\s*<\/ds:X509Certificate>/.test(body)) {
|
|
7272
|
+
throw new MeshCliError(
|
|
7273
|
+
"The mock SAML IdP served metadata with an empty signing certificate.",
|
|
7274
|
+
{
|
|
7275
|
+
remediation: {
|
|
7276
|
+
command: "rm -rf ~/.cache/mesh/mesh-local/mock-idp && mesh stop && mesh start --with-idps"
|
|
7277
|
+
}
|
|
7278
|
+
}
|
|
7279
|
+
);
|
|
7280
|
+
}
|
|
7281
|
+
return body;
|
|
7282
|
+
}
|
|
7283
|
+
lastError = `HTTP ${res.status}`;
|
|
7284
|
+
} catch (cause) {
|
|
7285
|
+
if (cause instanceof MeshCliError) throw cause;
|
|
7286
|
+
lastError = String(cause);
|
|
7287
|
+
}
|
|
7288
|
+
await new Promise((resolve20) => setTimeout(resolve20, 2e3));
|
|
7289
|
+
}
|
|
7290
|
+
throw new MeshCliError(`Could not read mock SAML metadata from ${url} (${lastError}).`, {
|
|
7291
|
+
remediation: { command: "mesh status # is mock-saml running?" }
|
|
7292
|
+
});
|
|
7293
|
+
}
|
|
7294
|
+
async function attachedLoginPolicyIdps(pat) {
|
|
7295
|
+
const res = await api(pat, "POST", "/admin/v1/policies/login/idps/_search", {});
|
|
7296
|
+
return (res?.result ?? []).map((idp) => String(idp.idpId ?? idp.id)).filter(Boolean);
|
|
7297
|
+
}
|
|
7298
|
+
async function findIdpByName(pat, name) {
|
|
7299
|
+
return pickIdpIdByName(await api(pat, "POST", IDP_SEARCH_PATH, {}), name);
|
|
7300
|
+
}
|
|
7301
|
+
async function seedMockIdps() {
|
|
7302
|
+
const pat = readSeederPat();
|
|
7303
|
+
const metadataXml = await fetchMockSamlMetadata();
|
|
7304
|
+
let samlIdpId = await findIdpByName(pat, MOCK_SAML_IDP_NAME);
|
|
7305
|
+
if (!samlIdpId) {
|
|
7306
|
+
const created = await api(pat, "POST", "/admin/v1/idps/saml", buildMockSamlIdpBody(metadataXml));
|
|
7307
|
+
samlIdpId = String(created.id);
|
|
7308
|
+
}
|
|
7309
|
+
logSuccess(`Mock SAML IdP ready (${MOCK_SAML_IDP_NAME}, id ${samlIdpId})`);
|
|
7310
|
+
let oidcIdpId = await findIdpByName(pat, MOCK_OIDC_IDP_NAME);
|
|
7311
|
+
if (!oidcIdpId) {
|
|
7312
|
+
const created = await api(pat, "POST", "/admin/v1/idps/oauth", buildMockOauthIdpBody());
|
|
7313
|
+
oidcIdpId = String(created.id);
|
|
7314
|
+
}
|
|
7315
|
+
logSuccess(`Mock OIDC IdP ready (${MOCK_OIDC_IDP_NAME}, id ${oidcIdpId})`);
|
|
7316
|
+
const policy = await api(pat, "GET", "/admin/v1/policies/login");
|
|
7317
|
+
if (policy?.policy?.allowExternalIdp !== true) {
|
|
7318
|
+
await api(pat, "PUT", "/admin/v1/policies/login", {
|
|
7319
|
+
...policy.policy,
|
|
7320
|
+
allowExternalIdp: true
|
|
7321
|
+
});
|
|
7322
|
+
logInfo("Instance login policy: allowExternalIdp turned on (federation buttons were hidden)");
|
|
7323
|
+
}
|
|
7324
|
+
const attached = await attachedLoginPolicyIdps(pat);
|
|
7325
|
+
const toAttach = missingLoginPolicyIdps(attached, [samlIdpId, oidcIdpId]);
|
|
7326
|
+
for (const idpId of toAttach) {
|
|
7327
|
+
await api(pat, "POST", "/admin/v1/policies/login/idps", { idpId, ownerType: "IDP_OWNER_TYPE_SYSTEM" });
|
|
7328
|
+
}
|
|
7329
|
+
const finalIdps = await attachedLoginPolicyIdps(pat);
|
|
7330
|
+
logSuccess(
|
|
7331
|
+
`Login policy carries ${finalIdps.length} federation(s) \u2014 both mocks attached, which is the state a login-policy change has to preserve`
|
|
7332
|
+
);
|
|
7333
|
+
return { samlIdpId, oidcIdpId };
|
|
7334
|
+
}
|
|
7335
|
+
var ZITADEL_ISSUER, LOGIN_CONTEXT, PLATFORM_ORG, CLI_PROJECT_NAME, CLI_APP_NAME, CLI_REDIRECT_URI, HUB_PROJECT_NAME, HUB_APP_NAME, hubRedirectUri, HUB_DEFAULT_REDIRECT_URI, HUB_ROLES, ZITADEL_SSM_PARAM, TEST_USERS_SSM_PREFIX, TEST_USERS, isAlreadyExists, ensureCliProject, ensureHubProject, OPS_HUB_SECRET_ID, LOCAL_SMTP, IDP_SEARCH_PATH, pickIdpIdByName;
|
|
7108
7336
|
var init_seed_zitadel = __esm({
|
|
7109
7337
|
"libs/mesh-cli/src/commands/local/seed-zitadel.ts"() {
|
|
7110
7338
|
"use strict";
|
|
@@ -7115,6 +7343,7 @@ var init_seed_zitadel = __esm({
|
|
|
7115
7343
|
init_stack();
|
|
7116
7344
|
init_seed();
|
|
7117
7345
|
init_cache_home();
|
|
7346
|
+
init_mock_idps();
|
|
7118
7347
|
ZITADEL_ISSUER = "http://localhost:8080";
|
|
7119
7348
|
LOGIN_CONTEXT = "local";
|
|
7120
7349
|
PLATFORM_ORG = "mesh";
|
|
@@ -7156,6 +7385,11 @@ var init_seed_zitadel = __esm({
|
|
|
7156
7385
|
from: "no-reply@local.mesh",
|
|
7157
7386
|
fromName: "Mesh (local)"
|
|
7158
7387
|
};
|
|
7388
|
+
IDP_SEARCH_PATH = "/admin/v1/idps/templates/_search";
|
|
7389
|
+
pickIdpIdByName = (searchResult, name) => {
|
|
7390
|
+
const hit = (searchResult?.result ?? []).find((idp) => idp?.name === name);
|
|
7391
|
+
return hit?.id ? String(hit.id) : void 0;
|
|
7392
|
+
};
|
|
7159
7393
|
}
|
|
7160
7394
|
});
|
|
7161
7395
|
|
|
@@ -7533,17 +7767,17 @@ var init_auth_provision = __esm({
|
|
|
7533
7767
|
});
|
|
7534
7768
|
|
|
7535
7769
|
// libs/mesh-cli/src/commands/local/dev-local.ts
|
|
7536
|
-
import * as
|
|
7537
|
-
import * as
|
|
7770
|
+
import * as fs18 from "fs";
|
|
7771
|
+
import * as path18 from "path";
|
|
7538
7772
|
function localAppNamespace(tenant, appName) {
|
|
7539
7773
|
return `${tenant}-${LOCAL_ENV}-${appName}`;
|
|
7540
7774
|
}
|
|
7541
7775
|
function logShipperPath() {
|
|
7542
|
-
return
|
|
7776
|
+
return path18.join(findPackageRoot(), "assets", "log-shipper.mjs");
|
|
7543
7777
|
}
|
|
7544
7778
|
function autoInstrumentationEnv(appRoot, src) {
|
|
7545
|
-
const pkgDir =
|
|
7546
|
-
const present =
|
|
7779
|
+
const pkgDir = path18.join("node_modules", "@opentelemetry", "auto-instrumentations-node");
|
|
7780
|
+
const present = fs18.existsSync(path18.join(appRoot, src, pkgDir)) || fs18.existsSync(path18.join(appRoot, pkgDir));
|
|
7547
7781
|
if (!present) return {};
|
|
7548
7782
|
return {
|
|
7549
7783
|
NODE_OPTIONS: { value: "--import @opentelemetry/auto-instrumentations-node/register" },
|
|
@@ -7599,26 +7833,26 @@ function localPlatformEnv(tenant, appName, serviceName) {
|
|
|
7599
7833
|
return env;
|
|
7600
7834
|
}
|
|
7601
7835
|
function isDagsterWorkspaceRoot(appRoot) {
|
|
7602
|
-
if (
|
|
7603
|
-
const pyproject =
|
|
7604
|
-
if (!
|
|
7836
|
+
if (fs18.existsSync(path18.join(appRoot, "dg.toml"))) return true;
|
|
7837
|
+
const pyproject = path18.join(appRoot, "pyproject.toml");
|
|
7838
|
+
if (!fs18.existsSync(pyproject)) return false;
|
|
7605
7839
|
try {
|
|
7606
|
-
return /^\s*\[tool\.dg[\].]/m.test(
|
|
7840
|
+
return /^\s*\[tool\.dg[\].]/m.test(fs18.readFileSync(pyproject, "utf-8"));
|
|
7607
7841
|
} catch {
|
|
7608
7842
|
return false;
|
|
7609
7843
|
}
|
|
7610
7844
|
}
|
|
7611
7845
|
function resolveDgBinary(appRoot) {
|
|
7612
7846
|
for (const candidate of ["deployments/local/.venv/bin/dg", ".venv/bin/dg"]) {
|
|
7613
|
-
if (
|
|
7847
|
+
if (fs18.existsSync(path18.join(appRoot, candidate))) return candidate;
|
|
7614
7848
|
}
|
|
7615
7849
|
return "dg";
|
|
7616
7850
|
}
|
|
7617
7851
|
function hasDevScript(dir) {
|
|
7618
|
-
const pkgPath =
|
|
7619
|
-
if (!
|
|
7852
|
+
const pkgPath = path18.join(dir, "package.json");
|
|
7853
|
+
if (!fs18.existsSync(pkgPath)) return false;
|
|
7620
7854
|
try {
|
|
7621
|
-
const pkg = JSON.parse(
|
|
7855
|
+
const pkg = JSON.parse(fs18.readFileSync(pkgPath, "utf-8"));
|
|
7622
7856
|
return typeof pkg?.scripts?.dev === "string";
|
|
7623
7857
|
} catch {
|
|
7624
7858
|
return false;
|
|
@@ -7626,14 +7860,14 @@ function hasDevScript(dir) {
|
|
|
7626
7860
|
}
|
|
7627
7861
|
function detectLocalServices(appRoot) {
|
|
7628
7862
|
const services = {};
|
|
7629
|
-
for (const entry of
|
|
7863
|
+
for (const entry of fs18.readdirSync(appRoot, { withFileTypes: true })) {
|
|
7630
7864
|
if (!entry.isDirectory() || entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
7631
|
-
if (hasDevScript(
|
|
7865
|
+
if (hasDevScript(path18.join(appRoot, entry.name))) {
|
|
7632
7866
|
services[entry.name] = { src: entry.name };
|
|
7633
7867
|
}
|
|
7634
7868
|
}
|
|
7635
7869
|
if (Object.keys(services).length === 0 && hasDevScript(appRoot)) {
|
|
7636
|
-
services[
|
|
7870
|
+
services[path18.basename(appRoot)] = { src: "." };
|
|
7637
7871
|
}
|
|
7638
7872
|
return services;
|
|
7639
7873
|
}
|
|
@@ -7647,15 +7881,15 @@ function buildLocalDevOutput(appRoot, tenant, opts = {}) {
|
|
|
7647
7881
|
{ remediation: { command: "mesh create-app" } }
|
|
7648
7882
|
);
|
|
7649
7883
|
}
|
|
7650
|
-
let appName =
|
|
7884
|
+
let appName = path18.basename(appRoot);
|
|
7651
7885
|
try {
|
|
7652
|
-
const pkg = JSON.parse(
|
|
7886
|
+
const pkg = JSON.parse(fs18.readFileSync(path18.join(appRoot, "package.json"), "utf-8"));
|
|
7653
7887
|
if (typeof pkg?.name === "string" && pkg.name) appName = pkg.name.replace(/^@[^/]+\//, "");
|
|
7654
7888
|
} catch {
|
|
7655
7889
|
}
|
|
7656
|
-
const pulumiYaml =
|
|
7657
|
-
if (
|
|
7658
|
-
const match =
|
|
7890
|
+
const pulumiYaml = path18.join(appRoot, "Pulumi.yaml");
|
|
7891
|
+
if (fs18.existsSync(pulumiYaml)) {
|
|
7892
|
+
const match = fs18.readFileSync(pulumiYaml, "utf-8").match(/^name:\s*(.+)$/m);
|
|
7659
7893
|
if (match?.[1]?.trim()) appName = match[1].trim();
|
|
7660
7894
|
}
|
|
7661
7895
|
const services = {};
|
|
@@ -7705,7 +7939,7 @@ function buildLocalDevOutput(appRoot, tenant, opts = {}) {
|
|
|
7705
7939
|
command: [resolveDgBinary(appRoot), "dev", "-h", "127.0.0.1", "-p", '"$PORT"'],
|
|
7706
7940
|
env: {
|
|
7707
7941
|
PORT: { value: String(port) },
|
|
7708
|
-
DAGSTER_HOME: { value:
|
|
7942
|
+
DAGSTER_HOME: { value: path18.join(appRoot, ".dagster") },
|
|
7709
7943
|
...localPlatformEnv(tenant, appName, "dagster")
|
|
7710
7944
|
}
|
|
7711
7945
|
};
|
|
@@ -7737,23 +7971,23 @@ function buildLocalDevOutput(appRoot, tenant, opts = {}) {
|
|
|
7737
7971
|
};
|
|
7738
7972
|
}
|
|
7739
7973
|
function hasStackBacking(appRoot) {
|
|
7740
|
-
const hasOwn =
|
|
7974
|
+
const hasOwn = fs18.existsSync(path18.join(appRoot, "Pulumi.yaml")) || fs18.readdirSync(appRoot).some((f) => /^Pulumi\..+\.yaml$/.test(f));
|
|
7741
7975
|
if (hasOwn) return true;
|
|
7742
|
-
let dir =
|
|
7976
|
+
let dir = path18.dirname(appRoot);
|
|
7743
7977
|
while (true) {
|
|
7744
|
-
if (
|
|
7745
|
-
if (
|
|
7746
|
-
return
|
|
7978
|
+
if (fs18.existsSync(path18.join(dir, "Pulumi.yaml"))) return true;
|
|
7979
|
+
if (fs18.existsSync(path18.join(dir, ".git")) || fs18.existsSync(path18.join(dir, "pnpm-workspace.yaml"))) {
|
|
7980
|
+
return fs18.existsSync(path18.join(dir, "Pulumi.yaml"));
|
|
7747
7981
|
}
|
|
7748
|
-
const parent =
|
|
7982
|
+
const parent = path18.dirname(dir);
|
|
7749
7983
|
if (parent === dir) return false;
|
|
7750
7984
|
dir = parent;
|
|
7751
7985
|
}
|
|
7752
7986
|
}
|
|
7753
7987
|
function detectLocalTenant(appRoot) {
|
|
7754
|
-
for (const file of
|
|
7988
|
+
for (const file of fs18.readdirSync(appRoot)) {
|
|
7755
7989
|
if (!/^Pulumi\..*\.yaml$/.test(file)) continue;
|
|
7756
|
-
const match =
|
|
7990
|
+
const match = fs18.readFileSync(path18.join(appRoot, file), "utf-8").match(/^\s*mesh:tenant:\s*["']?([A-Za-z0-9-]+)["']?\s*$/m);
|
|
7757
7991
|
if (match) return match[1];
|
|
7758
7992
|
}
|
|
7759
7993
|
const recorded = findMeshJson(appRoot);
|
|
@@ -7789,9 +8023,9 @@ var init_dev_local = __esm({
|
|
|
7789
8023
|
});
|
|
7790
8024
|
|
|
7791
8025
|
// libs/mesh-cli/src/commands/local/docker-runner.ts
|
|
7792
|
-
import { execFileSync as
|
|
7793
|
-
import * as
|
|
7794
|
-
import * as
|
|
8026
|
+
import { execFileSync as execFileSync14 } from "child_process";
|
|
8027
|
+
import * as fs19 from "fs";
|
|
8028
|
+
import * as path19 from "path";
|
|
7795
8029
|
function sessionDir(sessionName) {
|
|
7796
8030
|
return meshCacheDir("mesh-local", "dev", sessionName);
|
|
7797
8031
|
}
|
|
@@ -7813,8 +8047,8 @@ function writeDevCompose(sessionName, appRoot, services) {
|
|
|
7813
8047
|
];
|
|
7814
8048
|
for (const [name, service] of Object.entries(services)) {
|
|
7815
8049
|
const env = service.env ?? {};
|
|
7816
|
-
|
|
7817
|
-
const workdir =
|
|
8050
|
+
fs19.writeFileSync(path19.join(dir, `${name}.env`), renderDockerEnvFile(env), { mode: 384 });
|
|
8051
|
+
const workdir = path19.posix.join("/workspace", service.src === "." ? "" : service.src);
|
|
7818
8052
|
const ship = env.OTEL_RESOURCE_ATTRIBUTES ? ` 2>&1 | NODE_OPTIONS= node /mesh-assets/log-shipper.mjs` : "";
|
|
7819
8053
|
blocks.push(
|
|
7820
8054
|
` ${name}:`,
|
|
@@ -7823,7 +8057,7 @@ function writeDevCompose(sessionName, appRoot, services) {
|
|
|
7823
8057
|
` working_dir: ${workdir}`,
|
|
7824
8058
|
` volumes:`,
|
|
7825
8059
|
` - '${appRoot}:/workspace'`,
|
|
7826
|
-
` - '${
|
|
8060
|
+
` - '${path19.dirname(shipper)}:/mesh-assets:ro'`,
|
|
7827
8061
|
` environment:`,
|
|
7828
8062
|
// node_modules is the HOST's bind-mounted install — pnpm inside the
|
|
7829
8063
|
// container must never "verify" it and try a purge/reinstall (pnpm
|
|
@@ -7839,37 +8073,37 @@ function writeDevCompose(sessionName, appRoot, services) {
|
|
|
7839
8073
|
` restart: unless-stopped`
|
|
7840
8074
|
);
|
|
7841
8075
|
}
|
|
7842
|
-
const composePath =
|
|
7843
|
-
|
|
8076
|
+
const composePath = path19.join(dir, "compose.yml");
|
|
8077
|
+
fs19.writeFileSync(composePath, blocks.join("\n") + "\n");
|
|
7844
8078
|
return composePath;
|
|
7845
8079
|
}
|
|
7846
8080
|
function composeArgs(sessionName, args) {
|
|
7847
|
-
return ["compose", "-p", sessionName, "-f",
|
|
8081
|
+
return ["compose", "-p", sessionName, "-f", path19.join(sessionDir(sessionName), "compose.yml"), ...args];
|
|
7848
8082
|
}
|
|
7849
8083
|
function dockerDevUp(sessionName) {
|
|
7850
|
-
|
|
8084
|
+
execFileSync14("docker", composeArgs(sessionName, ["up", "-d"]), {
|
|
7851
8085
|
stdio: ["ignore", "inherit", "inherit"]
|
|
7852
8086
|
});
|
|
7853
8087
|
}
|
|
7854
8088
|
function dockerDevDown(sessionName) {
|
|
7855
|
-
|
|
8089
|
+
execFileSync14("docker", composeArgs(sessionName, ["down", "--remove-orphans"]), {
|
|
7856
8090
|
stdio: ["ignore", "inherit", "inherit"]
|
|
7857
8091
|
});
|
|
7858
8092
|
}
|
|
7859
8093
|
function dockerDevPs(sessionName) {
|
|
7860
|
-
return
|
|
8094
|
+
return execFileSync14("docker", composeArgs(sessionName, ["ps", "--format", "table {{.Service}} {{.State}} {{.Status}}"]), {
|
|
7861
8095
|
encoding: "utf-8",
|
|
7862
8096
|
stdio: ["ignore", "pipe", "pipe"]
|
|
7863
8097
|
});
|
|
7864
8098
|
}
|
|
7865
8099
|
function dockerDevLogs(sessionName, service, tail) {
|
|
7866
|
-
return
|
|
8100
|
+
return execFileSync14("docker", composeArgs(sessionName, ["logs", "--tail", String(tail), service]), {
|
|
7867
8101
|
encoding: "utf-8",
|
|
7868
8102
|
stdio: ["ignore", "pipe", "pipe"]
|
|
7869
8103
|
});
|
|
7870
8104
|
}
|
|
7871
8105
|
function dockerDevRestart(sessionName, service) {
|
|
7872
|
-
|
|
8106
|
+
execFileSync14("docker", composeArgs(sessionName, ["restart", service]), {
|
|
7873
8107
|
stdio: ["ignore", "inherit", "inherit"]
|
|
7874
8108
|
});
|
|
7875
8109
|
}
|
|
@@ -7938,9 +8172,9 @@ var init_peer_addressing = __esm({
|
|
|
7938
8172
|
});
|
|
7939
8173
|
|
|
7940
8174
|
// libs/mesh-cli/src/utils/worktree-identity.ts
|
|
7941
|
-
import { execFileSync as
|
|
8175
|
+
import { execFileSync as execFileSync15 } from "node:child_process";
|
|
7942
8176
|
import * as crypto3 from "node:crypto";
|
|
7943
|
-
import * as
|
|
8177
|
+
import * as path20 from "node:path";
|
|
7944
8178
|
function sanitizeSlug(name) {
|
|
7945
8179
|
const s = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
7946
8180
|
return s || "wt";
|
|
@@ -7958,7 +8192,7 @@ function blockBasePort(block) {
|
|
|
7958
8192
|
}
|
|
7959
8193
|
function withAppScopedPortBlock(wt, appRoot) {
|
|
7960
8194
|
if (wt.isPrimary) return wt;
|
|
7961
|
-
const appHash = worktreeHash(`${wt.worktreeRoot}#${
|
|
8195
|
+
const appHash = worktreeHash(`${wt.worktreeRoot}#${path20.resolve(appRoot)}`);
|
|
7962
8196
|
return { ...wt, portBlock: portBlockFor(appHash, false) };
|
|
7963
8197
|
}
|
|
7964
8198
|
function worktreeStackName(baseName, wt) {
|
|
@@ -7973,22 +8207,22 @@ function resolveWorktreeIdentity(cwd = process.cwd(), gitRunner = defaultGitRunn
|
|
|
7973
8207
|
let worktreeRoot;
|
|
7974
8208
|
let isPrimary = true;
|
|
7975
8209
|
try {
|
|
7976
|
-
worktreeRoot =
|
|
8210
|
+
worktreeRoot = path20.resolve(gitRunner(["rev-parse", "--show-toplevel"], cwd));
|
|
7977
8211
|
const commonDir = gitRunner(["rev-parse", "--git-common-dir"], cwd);
|
|
7978
|
-
const primaryRoot =
|
|
8212
|
+
const primaryRoot = path20.resolve(path20.dirname(path20.resolve(cwd, commonDir)));
|
|
7979
8213
|
isPrimary = worktreeRoot === primaryRoot;
|
|
7980
8214
|
} catch {
|
|
7981
8215
|
return {
|
|
7982
|
-
worktreeRoot:
|
|
8216
|
+
worktreeRoot: path20.resolve(cwd),
|
|
7983
8217
|
isPrimary: true,
|
|
7984
|
-
slug: sanitizeSlug(
|
|
7985
|
-
hash: worktreeHash(
|
|
8218
|
+
slug: sanitizeSlug(path20.basename(path20.resolve(cwd))),
|
|
8219
|
+
hash: worktreeHash(path20.resolve(cwd)),
|
|
7986
8220
|
token: "",
|
|
7987
8221
|
portBlock: 0,
|
|
7988
8222
|
taskQueueSuffix: ""
|
|
7989
8223
|
};
|
|
7990
8224
|
}
|
|
7991
|
-
const slug = sanitizeSlug(
|
|
8225
|
+
const slug = sanitizeSlug(path20.basename(worktreeRoot));
|
|
7992
8226
|
const hash = worktreeHash(worktreeRoot);
|
|
7993
8227
|
const token = isPrimary ? "" : `${slug}-${hash}`;
|
|
7994
8228
|
return {
|
|
@@ -8010,7 +8244,7 @@ var init_worktree_identity = __esm({
|
|
|
8010
8244
|
PORT_BLOCK_SIZE = 40;
|
|
8011
8245
|
PORT_BLOCK_SERVICE_SUBRANGE = 24;
|
|
8012
8246
|
STACK_SLUG_MAX = 16;
|
|
8013
|
-
defaultGitRunner = (args, cwd) =>
|
|
8247
|
+
defaultGitRunner = (args, cwd) => execFileSync15("git", args, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
8014
8248
|
}
|
|
8015
8249
|
});
|
|
8016
8250
|
|
|
@@ -8072,11 +8306,11 @@ var init_dev_token_server = __esm({
|
|
|
8072
8306
|
});
|
|
8073
8307
|
|
|
8074
8308
|
// libs/mesh-cli/src/commands/dev.ts
|
|
8075
|
-
import { execFileSync as
|
|
8076
|
-
import * as
|
|
8309
|
+
import { execFileSync as execFileSync16, spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
|
|
8310
|
+
import * as fs20 from "fs";
|
|
8077
8311
|
import * as net8 from "net";
|
|
8078
8312
|
import * as os6 from "os";
|
|
8079
|
-
import * as
|
|
8313
|
+
import * as path21 from "path";
|
|
8080
8314
|
import { Option } from "commander";
|
|
8081
8315
|
import { SecretsManagerClient as SecretsManagerClient2, GetSecretValueCommand as GetSecretValueCommand2 } from "@aws-sdk/client-secrets-manager";
|
|
8082
8316
|
function registerServiceProbes(devOutput, tenant, probeFiles) {
|
|
@@ -8124,9 +8358,9 @@ mesh dev plan \u2014 ${kind}
|
|
|
8124
8358
|
console.log(` (none \u2014 all services are deployed/K8s)`);
|
|
8125
8359
|
} else {
|
|
8126
8360
|
const monorepoRoot = findMonorepoRoot();
|
|
8127
|
-
const wtWithSep = wt.worktreeRoot.endsWith(
|
|
8361
|
+
const wtWithSep = wt.worktreeRoot.endsWith(path21.sep) ? wt.worktreeRoot : wt.worktreeRoot + path21.sep;
|
|
8128
8362
|
for (const [name, s] of locals) {
|
|
8129
|
-
const dir =
|
|
8363
|
+
const dir = path21.resolve(appRoot, rebaseServiceSrc(s.src, monorepoRoot));
|
|
8130
8364
|
const outside = dir !== wt.worktreeRoot && !dir.startsWith(wtWithSep);
|
|
8131
8365
|
const port = s.port > 0 ? `:${s.port}` : "(no port)";
|
|
8132
8366
|
console.log(` ${name.padEnd(18)} ${port.padEnd(7)} ${dir}${outside ? " \u26A0 OUTSIDE worktree" : ""}`);
|
|
@@ -8135,18 +8369,18 @@ mesh dev plan \u2014 ${kind}
|
|
|
8135
8369
|
console.log("");
|
|
8136
8370
|
}
|
|
8137
8371
|
function getSessionStatePath(sessionName) {
|
|
8138
|
-
const dir =
|
|
8139
|
-
if (!
|
|
8140
|
-
return
|
|
8372
|
+
const dir = path21.join(os6.tmpdir(), "mesh-dev-sessions");
|
|
8373
|
+
if (!fs20.existsSync(dir)) fs20.mkdirSync(dir, { recursive: true });
|
|
8374
|
+
return path21.join(dir, `${sessionName}.json`);
|
|
8141
8375
|
}
|
|
8142
8376
|
function saveSessionState(sessionName, state) {
|
|
8143
|
-
|
|
8377
|
+
fs20.writeFileSync(getSessionStatePath(sessionName), JSON.stringify(state, null, 2));
|
|
8144
8378
|
}
|
|
8145
8379
|
function loadSessionState(sessionName) {
|
|
8146
8380
|
const filePath = getSessionStatePath(sessionName);
|
|
8147
|
-
if (!
|
|
8381
|
+
if (!fs20.existsSync(filePath)) return null;
|
|
8148
8382
|
try {
|
|
8149
|
-
return JSON.parse(
|
|
8383
|
+
return JSON.parse(fs20.readFileSync(filePath, "utf-8"));
|
|
8150
8384
|
} catch {
|
|
8151
8385
|
return null;
|
|
8152
8386
|
}
|
|
@@ -8170,18 +8404,18 @@ function workflowChangeWouldStrand(priorState, appRoot, force) {
|
|
|
8170
8404
|
return true;
|
|
8171
8405
|
}
|
|
8172
8406
|
function getSessionEnvDir(sessionName) {
|
|
8173
|
-
return
|
|
8407
|
+
return path21.join(os6.tmpdir(), "mesh-dev-sessions", sessionName);
|
|
8174
8408
|
}
|
|
8175
8409
|
function getServiceEnvFilePath(sessionName, serviceName) {
|
|
8176
|
-
return
|
|
8410
|
+
return path21.join(getSessionEnvDir(sessionName), envFileName(serviceName));
|
|
8177
8411
|
}
|
|
8178
8412
|
function removeSessionState(sessionName) {
|
|
8179
8413
|
try {
|
|
8180
|
-
|
|
8414
|
+
fs20.unlinkSync(getSessionStatePath(sessionName));
|
|
8181
8415
|
} catch {
|
|
8182
8416
|
}
|
|
8183
8417
|
try {
|
|
8184
|
-
|
|
8418
|
+
fs20.rmSync(getSessionEnvDir(sessionName), { recursive: true, force: true });
|
|
8185
8419
|
} catch {
|
|
8186
8420
|
}
|
|
8187
8421
|
}
|
|
@@ -8309,16 +8543,16 @@ function mergePinnedPorts(fresh, pinned) {
|
|
|
8309
8543
|
}
|
|
8310
8544
|
function findMonorepoRoot() {
|
|
8311
8545
|
let dir = process.cwd();
|
|
8312
|
-
const root =
|
|
8546
|
+
const root = path21.parse(dir).root;
|
|
8313
8547
|
while (dir !== root) {
|
|
8314
|
-
if (
|
|
8548
|
+
if (fs20.existsSync(path21.join(dir, "pnpm-workspace.yaml")) || fs20.existsSync(path21.join(dir, "turbo.json"))) {
|
|
8315
8549
|
return dir;
|
|
8316
8550
|
}
|
|
8317
|
-
const gitPath =
|
|
8318
|
-
if (
|
|
8551
|
+
const gitPath = path21.join(dir, ".git");
|
|
8552
|
+
if (fs20.existsSync(gitPath)) {
|
|
8319
8553
|
return dir;
|
|
8320
8554
|
}
|
|
8321
|
-
dir =
|
|
8555
|
+
dir = path21.dirname(dir);
|
|
8322
8556
|
}
|
|
8323
8557
|
return null;
|
|
8324
8558
|
}
|
|
@@ -8326,40 +8560,40 @@ function discoverApps(monorepoRoot) {
|
|
|
8326
8560
|
const apps = [];
|
|
8327
8561
|
function addApp(appDir, tenant) {
|
|
8328
8562
|
const projectName = getProjectName(appDir);
|
|
8329
|
-
const stacks =
|
|
8563
|
+
const stacks = fs20.readdirSync(appDir).filter((f) => f.startsWith("Pulumi.") && f.endsWith(".yaml") && f !== "Pulumi.yaml").map((f) => f.replace(/^Pulumi\./, "").replace(/\.yaml$/, ""));
|
|
8330
8564
|
apps.push({
|
|
8331
8565
|
name: projectName,
|
|
8332
8566
|
tenant,
|
|
8333
8567
|
appPath: appDir,
|
|
8334
|
-
relativePath:
|
|
8568
|
+
relativePath: path21.relative(monorepoRoot, appDir),
|
|
8335
8569
|
stacks
|
|
8336
8570
|
});
|
|
8337
8571
|
}
|
|
8338
8572
|
const searchDirs = ["tenants", "tests/tenants"];
|
|
8339
8573
|
for (const searchDir of searchDirs) {
|
|
8340
|
-
const base =
|
|
8341
|
-
if (!
|
|
8342
|
-
for (const tenant of
|
|
8343
|
-
const appsDir =
|
|
8344
|
-
if (!
|
|
8345
|
-
for (const app of
|
|
8346
|
-
const appDir =
|
|
8347
|
-
if (!
|
|
8574
|
+
const base = path21.join(monorepoRoot, searchDir);
|
|
8575
|
+
if (!fs20.existsSync(base)) continue;
|
|
8576
|
+
for (const tenant of fs20.readdirSync(base)) {
|
|
8577
|
+
const appsDir = path21.join(base, tenant, "apps");
|
|
8578
|
+
if (!fs20.existsSync(appsDir) || !fs20.statSync(appsDir).isDirectory()) continue;
|
|
8579
|
+
for (const app of fs20.readdirSync(appsDir)) {
|
|
8580
|
+
const appDir = path21.join(appsDir, app);
|
|
8581
|
+
if (!fs20.existsSync(path21.join(appDir, "Pulumi.yaml"))) continue;
|
|
8348
8582
|
addApp(appDir, tenant);
|
|
8349
8583
|
}
|
|
8350
8584
|
}
|
|
8351
8585
|
}
|
|
8352
|
-
const flatAppsDir =
|
|
8353
|
-
if (
|
|
8354
|
-
for (const app of
|
|
8355
|
-
const appDir =
|
|
8356
|
-
if (!
|
|
8357
|
-
if (!
|
|
8586
|
+
const flatAppsDir = path21.join(monorepoRoot, "apps");
|
|
8587
|
+
if (fs20.existsSync(flatAppsDir) && fs20.statSync(flatAppsDir).isDirectory()) {
|
|
8588
|
+
for (const app of fs20.readdirSync(flatAppsDir)) {
|
|
8589
|
+
const appDir = path21.join(flatAppsDir, app);
|
|
8590
|
+
if (!fs20.statSync(appDir).isDirectory()) continue;
|
|
8591
|
+
if (!fs20.existsSync(path21.join(appDir, "Pulumi.yaml"))) continue;
|
|
8358
8592
|
let tenant = "unknown";
|
|
8359
|
-
const stackConfigs =
|
|
8593
|
+
const stackConfigs = fs20.readdirSync(appDir).filter((f) => f.startsWith("Pulumi.") && f.endsWith(".yaml") && f !== "Pulumi.yaml");
|
|
8360
8594
|
if (stackConfigs.length > 0) {
|
|
8361
8595
|
try {
|
|
8362
|
-
const content =
|
|
8596
|
+
const content = fs20.readFileSync(path21.join(appDir, stackConfigs[0]), "utf-8");
|
|
8363
8597
|
const tenantMatch = content.match(/mesh:tenant:\s*(\S+)/);
|
|
8364
8598
|
if (tenantMatch) tenant = tenantMatch[1];
|
|
8365
8599
|
} catch {
|
|
@@ -8372,38 +8606,38 @@ function discoverApps(monorepoRoot) {
|
|
|
8372
8606
|
}
|
|
8373
8607
|
function findAppRoot2(appPath) {
|
|
8374
8608
|
if (appPath) {
|
|
8375
|
-
const resolved =
|
|
8376
|
-
if (
|
|
8609
|
+
const resolved = path21.resolve(appPath);
|
|
8610
|
+
if (fs20.existsSync(path21.join(resolved, "Pulumi.yaml"))) return resolved;
|
|
8377
8611
|
const mono = findMonorepoRoot();
|
|
8378
8612
|
if (mono) {
|
|
8379
|
-
const fromMono =
|
|
8380
|
-
if (
|
|
8613
|
+
const fromMono = path21.resolve(mono, appPath);
|
|
8614
|
+
if (fs20.existsSync(path21.join(fromMono, "Pulumi.yaml"))) return fromMono;
|
|
8381
8615
|
}
|
|
8382
8616
|
logError(`No Pulumi.yaml found at: ${appPath}`);
|
|
8383
8617
|
process.exit(1);
|
|
8384
8618
|
}
|
|
8385
8619
|
let dir = process.cwd();
|
|
8386
|
-
const root =
|
|
8620
|
+
const root = path21.parse(dir).root;
|
|
8387
8621
|
while (dir !== root) {
|
|
8388
|
-
if (
|
|
8622
|
+
if (fs20.existsSync(path21.join(dir, "Pulumi.yaml"))) {
|
|
8389
8623
|
return dir;
|
|
8390
8624
|
}
|
|
8391
|
-
dir =
|
|
8625
|
+
dir = path21.dirname(dir);
|
|
8392
8626
|
}
|
|
8393
8627
|
return process.cwd();
|
|
8394
8628
|
}
|
|
8395
8629
|
function getProjectName(appRoot) {
|
|
8396
|
-
const yamlPath =
|
|
8397
|
-
if (!
|
|
8398
|
-
const content =
|
|
8630
|
+
const yamlPath = path21.join(appRoot, "Pulumi.yaml");
|
|
8631
|
+
if (!fs20.existsSync(yamlPath)) return path21.basename(appRoot);
|
|
8632
|
+
const content = fs20.readFileSync(yamlPath, "utf-8");
|
|
8399
8633
|
const match = content.match(/^name:\s*(.+)$/m);
|
|
8400
|
-
return match?.[1]?.trim() ??
|
|
8634
|
+
return match?.[1]?.trim() ?? path21.basename(appRoot);
|
|
8401
8635
|
}
|
|
8402
8636
|
function detectStack(appRoot, stageArg) {
|
|
8403
8637
|
if (stageArg) return stageArg;
|
|
8404
8638
|
if (process.env.MESH_STAGE) return process.env.MESH_STAGE;
|
|
8405
8639
|
try {
|
|
8406
|
-
const result =
|
|
8640
|
+
const result = execFileSync16("pulumi", ["stack", "--show-name"], {
|
|
8407
8641
|
cwd: appRoot,
|
|
8408
8642
|
encoding: "utf-8",
|
|
8409
8643
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -8412,7 +8646,7 @@ function detectStack(appRoot, stageArg) {
|
|
|
8412
8646
|
} catch {
|
|
8413
8647
|
}
|
|
8414
8648
|
try {
|
|
8415
|
-
const files =
|
|
8649
|
+
const files = fs20.readdirSync(appRoot).filter((f) => f.startsWith("Pulumi.") && f.endsWith(".yaml") && f !== "Pulumi.yaml");
|
|
8416
8650
|
if (files.length === 1) {
|
|
8417
8651
|
const match = files[0].match(/^Pulumi\.(.+)\.yaml$/);
|
|
8418
8652
|
if (match?.[1]) {
|
|
@@ -8426,7 +8660,7 @@ function detectStack(appRoot, stageArg) {
|
|
|
8426
8660
|
}
|
|
8427
8661
|
function stackArgs(appRoot, stack) {
|
|
8428
8662
|
try {
|
|
8429
|
-
const selected =
|
|
8663
|
+
const selected = execFileSync16("pulumi", ["stack", "--show-name"], {
|
|
8430
8664
|
cwd: appRoot,
|
|
8431
8665
|
encoding: "utf-8",
|
|
8432
8666
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -8435,7 +8669,7 @@ function stackArgs(appRoot, stack) {
|
|
|
8435
8669
|
} catch {
|
|
8436
8670
|
}
|
|
8437
8671
|
try {
|
|
8438
|
-
|
|
8672
|
+
execFileSync16("pulumi", ["stack", "select", stack], {
|
|
8439
8673
|
cwd: appRoot,
|
|
8440
8674
|
encoding: "utf-8",
|
|
8441
8675
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -8464,7 +8698,7 @@ function getDevOutput(appRoot, stack, awsEnv) {
|
|
|
8464
8698
|
}
|
|
8465
8699
|
function hasTmux() {
|
|
8466
8700
|
try {
|
|
8467
|
-
|
|
8701
|
+
execFileSync16("which", ["tmux"], { stdio: "ignore" });
|
|
8468
8702
|
return true;
|
|
8469
8703
|
} catch {
|
|
8470
8704
|
return false;
|
|
@@ -8472,7 +8706,7 @@ function hasTmux() {
|
|
|
8472
8706
|
}
|
|
8473
8707
|
function sessionExists(name) {
|
|
8474
8708
|
try {
|
|
8475
|
-
|
|
8709
|
+
execFileSync16("tmux", ["has-session", "-t", name], { stdio: "ignore" });
|
|
8476
8710
|
return true;
|
|
8477
8711
|
} catch {
|
|
8478
8712
|
return false;
|
|
@@ -8480,7 +8714,7 @@ function sessionExists(name) {
|
|
|
8480
8714
|
}
|
|
8481
8715
|
function killSession(name) {
|
|
8482
8716
|
try {
|
|
8483
|
-
|
|
8717
|
+
execFileSync16("tmux", ["kill-session", "-t", name], { stdio: "ignore" });
|
|
8484
8718
|
return true;
|
|
8485
8719
|
} catch {
|
|
8486
8720
|
return false;
|
|
@@ -8519,9 +8753,9 @@ function buildChildAwsEnv(awsEnv, method, profile, opts) {
|
|
|
8519
8753
|
if (method === "zitadel" && opts) {
|
|
8520
8754
|
const sanitizedContext = opts.context.replace(/[^A-Za-z0-9_-]/g, "-");
|
|
8521
8755
|
const profileName = `mesh-dev-${sanitizedContext}`;
|
|
8522
|
-
const configPath =
|
|
8756
|
+
const configPath = path21.join(opts.sessionScratchDir, "aws-config");
|
|
8523
8757
|
const region = awsEnv.AWS_REGION ?? awsEnv.AWS_DEFAULT_REGION ?? "";
|
|
8524
|
-
|
|
8758
|
+
fs20.mkdirSync(opts.sessionScratchDir, { recursive: true });
|
|
8525
8759
|
const profileBlock = renderCredentialProcessProfile({
|
|
8526
8760
|
profileName,
|
|
8527
8761
|
context: opts.context,
|
|
@@ -8529,7 +8763,7 @@ function buildChildAwsEnv(awsEnv, method, profile, opts) {
|
|
|
8529
8763
|
region,
|
|
8530
8764
|
meshBin: opts.meshBin
|
|
8531
8765
|
});
|
|
8532
|
-
const existing =
|
|
8766
|
+
const existing = fs20.existsSync(configPath) ? fs20.readFileSync(configPath, "utf8") : "";
|
|
8533
8767
|
const next = upsertManagedAwsConfigSection(
|
|
8534
8768
|
stripBareProfile(existing, profileName),
|
|
8535
8769
|
`${opts.context} (mesh dev)`,
|
|
@@ -8555,15 +8789,15 @@ function rebaseServiceSrc(src, monorepoRoot) {
|
|
|
8555
8789
|
if (!monorepoRoot) return src;
|
|
8556
8790
|
const rel2 = monorepoRelativeSrc(src);
|
|
8557
8791
|
if (rel2 === null) return src;
|
|
8558
|
-
const rebased =
|
|
8559
|
-
return
|
|
8792
|
+
const rebased = path21.join(monorepoRoot, rel2);
|
|
8793
|
+
return fs20.existsSync(rebased) ? rebased : src;
|
|
8560
8794
|
}
|
|
8561
8795
|
function isLinkedDependencyDir(serviceDir, appRoot) {
|
|
8562
8796
|
let pkgRoot = null;
|
|
8563
8797
|
let name = "";
|
|
8564
|
-
for (let dir = serviceDir; ; dir =
|
|
8798
|
+
for (let dir = serviceDir; ; dir = path21.dirname(dir)) {
|
|
8565
8799
|
try {
|
|
8566
|
-
const manifest = JSON.parse(
|
|
8800
|
+
const manifest = JSON.parse(fs20.readFileSync(path21.join(dir, "package.json"), "utf8"));
|
|
8567
8801
|
if (typeof manifest?.name === "string" && manifest.name) {
|
|
8568
8802
|
pkgRoot = dir;
|
|
8569
8803
|
name = manifest.name;
|
|
@@ -8571,21 +8805,21 @@ function isLinkedDependencyDir(serviceDir, appRoot) {
|
|
|
8571
8805
|
}
|
|
8572
8806
|
} catch {
|
|
8573
8807
|
}
|
|
8574
|
-
const parent =
|
|
8808
|
+
const parent = path21.dirname(dir);
|
|
8575
8809
|
if (parent === dir) break;
|
|
8576
8810
|
}
|
|
8577
8811
|
if (!pkgRoot) return false;
|
|
8578
|
-
for (let dir = appRoot; ; dir =
|
|
8812
|
+
for (let dir = appRoot; ; dir = path21.dirname(dir)) {
|
|
8579
8813
|
try {
|
|
8580
|
-
if (
|
|
8814
|
+
if (fs20.realpathSync(path21.join(dir, "node_modules", name)) === pkgRoot) return true;
|
|
8581
8815
|
} catch {
|
|
8582
8816
|
}
|
|
8583
|
-
const parent =
|
|
8817
|
+
const parent = path21.dirname(dir);
|
|
8584
8818
|
if (parent === dir) return false;
|
|
8585
8819
|
}
|
|
8586
8820
|
}
|
|
8587
8821
|
function monorepoRelativeSrc(src) {
|
|
8588
|
-
if (!
|
|
8822
|
+
if (!path21.isAbsolute(src)) return src.replace(/^\.\//, "") || ".";
|
|
8589
8823
|
const m = src.match(/^.*\/mesh-platform(?:\/(.*))?$/);
|
|
8590
8824
|
if (!m) return null;
|
|
8591
8825
|
const rest = (m[1] ?? "").replace(/^\.worktrees\/[^/]+(?:\/|$)/, "");
|
|
@@ -8620,7 +8854,7 @@ function getServiceEnvVars(service, tunnels) {
|
|
|
8620
8854
|
}
|
|
8621
8855
|
function setTmuxEnv(sessionName, vars) {
|
|
8622
8856
|
for (const [key, value] of Object.entries(vars)) {
|
|
8623
|
-
|
|
8857
|
+
execFileSync16("tmux", ["set-environment", "-t", sessionName, key, value], { stdio: "ignore" });
|
|
8624
8858
|
}
|
|
8625
8859
|
}
|
|
8626
8860
|
function envPrefix(vars) {
|
|
@@ -8661,7 +8895,7 @@ function resolveTemporalEncodingKey(tenant, env, appName) {
|
|
|
8661
8895
|
const namespace = `${tenant}-${env}-${appName}`;
|
|
8662
8896
|
const secretName = `${namespace}-temporal-encoding-key`;
|
|
8663
8897
|
try {
|
|
8664
|
-
const b64 =
|
|
8898
|
+
const b64 = execFileSync16(
|
|
8665
8899
|
"kubectl",
|
|
8666
8900
|
[
|
|
8667
8901
|
"get",
|
|
@@ -8697,7 +8931,7 @@ async function resolveTemporalAuthVars(sessionName, devOutput) {
|
|
|
8697
8931
|
setTmuxEnv(sessionName, { KUBECONFIG: kubeconfigPath });
|
|
8698
8932
|
} else if (!process.env.KUBECONFIG) {
|
|
8699
8933
|
const existing = sessionKubeconfigPath(sessionName);
|
|
8700
|
-
if (
|
|
8934
|
+
if (fs20.existsSync(existing)) {
|
|
8701
8935
|
process.env.KUBECONFIG = existing;
|
|
8702
8936
|
}
|
|
8703
8937
|
}
|
|
@@ -8866,7 +9100,7 @@ async function allocateSsmLocalPort(remotePort, reservedPorts) {
|
|
|
8866
9100
|
}
|
|
8867
9101
|
function hasSessionManagerPlugin() {
|
|
8868
9102
|
try {
|
|
8869
|
-
|
|
9103
|
+
execFileSync16("which", ["session-manager-plugin"], { stdio: "ignore" });
|
|
8870
9104
|
return true;
|
|
8871
9105
|
} catch {
|
|
8872
9106
|
return false;
|
|
@@ -8965,13 +9199,13 @@ async function startSsmTunnels(sessionName, devOutput) {
|
|
|
8965
9199
|
localPortNumber: [String(localPort)]
|
|
8966
9200
|
})}'`
|
|
8967
9201
|
].join(" ");
|
|
8968
|
-
|
|
8969
|
-
|
|
9202
|
+
execFileSync16("tmux", ["new-window", "-t", sessionName, "-n", windowName]);
|
|
9203
|
+
execFileSync16(
|
|
8970
9204
|
"tmux",
|
|
8971
9205
|
["set-option", "-t", `${sessionName}:${windowName}`, "remain-on-exit", "on"],
|
|
8972
9206
|
{ stdio: "ignore" }
|
|
8973
9207
|
);
|
|
8974
|
-
|
|
9208
|
+
execFileSync16("tmux", ["send-keys", "-t", `${sessionName}:${windowName}`, ssmCmd, "Enter"]);
|
|
8975
9209
|
rewritten.tunnels[tunnelName] = {
|
|
8976
9210
|
host: "localhost",
|
|
8977
9211
|
port: localPort
|
|
@@ -8983,7 +9217,7 @@ async function startSsmTunnels(sessionName, devOutput) {
|
|
|
8983
9217
|
return rewritten;
|
|
8984
9218
|
}
|
|
8985
9219
|
async function updateDevboxProxy(devOutput, appRoot) {
|
|
8986
|
-
const appName = devOutput.app ??
|
|
9220
|
+
const appName = devOutput.app ?? path21.basename(appRoot);
|
|
8987
9221
|
const tenant = devOutput.platform?.tenant ?? "mesh";
|
|
8988
9222
|
const env = devOutput.platform?.env ?? "dev";
|
|
8989
9223
|
const stack = devOutput.stack ?? "dev";
|
|
@@ -9015,7 +9249,7 @@ async function updateDevboxProxy(devOutput, appRoot) {
|
|
|
9015
9249
|
lines.push("");
|
|
9016
9250
|
}
|
|
9017
9251
|
const caddyfile = lines.join("\n");
|
|
9018
|
-
|
|
9252
|
+
execFileSync16(
|
|
9019
9253
|
"docker",
|
|
9020
9254
|
[
|
|
9021
9255
|
"run",
|
|
@@ -9031,7 +9265,7 @@ CADDYEOF`
|
|
|
9031
9265
|
],
|
|
9032
9266
|
{ stdio: "pipe" }
|
|
9033
9267
|
);
|
|
9034
|
-
|
|
9268
|
+
execFileSync16(
|
|
9035
9269
|
"docker",
|
|
9036
9270
|
[
|
|
9037
9271
|
"run",
|
|
@@ -9061,7 +9295,7 @@ CADDYEOF`
|
|
|
9061
9295
|
async function setupSubdomainRouting(devOutput, appRoot) {
|
|
9062
9296
|
const tsInfo = await getTailscaleInfo();
|
|
9063
9297
|
if (!tsInfo) return null;
|
|
9064
|
-
const appName = devOutput.app ??
|
|
9298
|
+
const appName = devOutput.app ?? path21.basename(appRoot);
|
|
9065
9299
|
const stack = devOutput.stack ?? "dev";
|
|
9066
9300
|
const baseDomain = `${appName}.${stack}.${tsInfo.hostname}.vpn.internal`;
|
|
9067
9301
|
const platform = devOutput.platform ?? { tenant: "mesh", env: "dev" };
|
|
@@ -9080,8 +9314,8 @@ async function setupSubdomainRouting(devOutput, appRoot) {
|
|
|
9080
9314
|
} catch {
|
|
9081
9315
|
}
|
|
9082
9316
|
const caddyDir = "/tmp/mesh-dev-caddy";
|
|
9083
|
-
const caddyfile =
|
|
9084
|
-
if (!
|
|
9317
|
+
const caddyfile = path21.join(caddyDir, "Caddyfile");
|
|
9318
|
+
if (!fs20.existsSync(caddyDir)) fs20.mkdirSync(caddyDir, { recursive: true });
|
|
9085
9319
|
const caddyLines = [`# mesh-dev: ${appName}/${stack} (${tsInfo.hostname})`, ""];
|
|
9086
9320
|
for (const [name, service] of Object.entries(devOutput.services)) {
|
|
9087
9321
|
if (service.port) {
|
|
@@ -9099,16 +9333,16 @@ async function setupSubdomainRouting(devOutput, appRoot) {
|
|
|
9099
9333
|
caddyLines.push("}");
|
|
9100
9334
|
caddyLines.push("");
|
|
9101
9335
|
}
|
|
9102
|
-
|
|
9336
|
+
fs20.writeFileSync(caddyfile, caddyLines.join("\n"));
|
|
9103
9337
|
let caddyRunning = false;
|
|
9104
9338
|
try {
|
|
9105
|
-
|
|
9339
|
+
execFileSync16("pgrep", ["-f", "caddy run.*mesh-dev-caddy"], { stdio: "pipe" });
|
|
9106
9340
|
caddyRunning = true;
|
|
9107
9341
|
} catch {
|
|
9108
9342
|
}
|
|
9109
9343
|
if (caddyRunning) {
|
|
9110
9344
|
try {
|
|
9111
|
-
|
|
9345
|
+
execFileSync16("caddy", ["reload", "--config", caddyfile, "--adapter", "caddyfile"], {
|
|
9112
9346
|
stdio: "pipe"
|
|
9113
9347
|
});
|
|
9114
9348
|
} catch {
|
|
@@ -9117,7 +9351,7 @@ async function setupSubdomainRouting(devOutput, appRoot) {
|
|
|
9117
9351
|
}
|
|
9118
9352
|
} else {
|
|
9119
9353
|
try {
|
|
9120
|
-
|
|
9354
|
+
execFileSync16("which", ["caddy"], { stdio: "pipe" });
|
|
9121
9355
|
} catch {
|
|
9122
9356
|
logWarn(
|
|
9123
9357
|
"Caddy not found. Install for subdomain routing: curl -fsSL https://caddyserver.com/api/download?os=linux&arch=arm64 -o /usr/local/bin/caddy && chmod +x /usr/local/bin/caddy"
|
|
@@ -9159,7 +9393,7 @@ async function startServices(sessionName, appRoot, devOutput, headless, awsEnv,
|
|
|
9159
9393
|
return devOutput;
|
|
9160
9394
|
}
|
|
9161
9395
|
logInfo(`Creating tmux session: ${sessionName}`);
|
|
9162
|
-
|
|
9396
|
+
execFileSync16("tmux", ["new-session", "-d", "-s", sessionName, "-n", "status", "-c", appRoot]);
|
|
9163
9397
|
setTmuxEnv(sessionName, awsEnv);
|
|
9164
9398
|
const hasTunnels = Object.keys(devOutput.tunnels).length > 0;
|
|
9165
9399
|
let effectiveTransport = tunnelPlan.transport;
|
|
@@ -9270,13 +9504,13 @@ async function startServices(sessionName, appRoot, devOutput, headless, awsEnv,
|
|
|
9270
9504
|
const tokenPort = await findFreePort3();
|
|
9271
9505
|
const tokenUrl = `http://127.0.0.1:${tokenPort}`;
|
|
9272
9506
|
setTmuxEnv(sessionName, { DEV_USER_TOKEN_URL: tokenUrl });
|
|
9273
|
-
|
|
9274
|
-
|
|
9507
|
+
execFileSync16("tmux", ["new-window", "-t", sessionName, "-n", "token-server"]);
|
|
9508
|
+
execFileSync16(
|
|
9275
9509
|
"tmux",
|
|
9276
9510
|
["set-option", "-t", `${sessionName}:token-server`, "remain-on-exit", "on"],
|
|
9277
9511
|
{ stdio: "ignore" }
|
|
9278
9512
|
);
|
|
9279
|
-
|
|
9513
|
+
execFileSync16("tmux", [
|
|
9280
9514
|
"send-keys",
|
|
9281
9515
|
"-t",
|
|
9282
9516
|
`${sessionName}:token-server`,
|
|
@@ -9299,9 +9533,9 @@ async function startServices(sessionName, appRoot, devOutput, headless, awsEnv,
|
|
|
9299
9533
|
logInfo(`Skipped: ${name} (no dev command, deployed to K8s)`);
|
|
9300
9534
|
continue;
|
|
9301
9535
|
}
|
|
9302
|
-
const serviceDir =
|
|
9303
|
-
if (worktreeRoot &&
|
|
9304
|
-
const wtRootWithSep = worktreeRoot.endsWith(
|
|
9536
|
+
const serviceDir = path21.resolve(appRoot, rebaseServiceSrc(service.src, monorepoRoot));
|
|
9537
|
+
if (worktreeRoot && fs20.existsSync(serviceDir)) {
|
|
9538
|
+
const wtRootWithSep = worktreeRoot.endsWith(path21.sep) ? worktreeRoot : worktreeRoot + path21.sep;
|
|
9305
9539
|
const outside = serviceDir !== worktreeRoot && !serviceDir.startsWith(wtRootWithSep);
|
|
9306
9540
|
if (outside && isLinkedDependencyDir(serviceDir, appRoot)) {
|
|
9307
9541
|
logInfo(`${name}: source is a dev-linked package (${serviceDir})`);
|
|
@@ -9312,7 +9546,7 @@ async function startServices(sessionName, appRoot, devOutput, headless, awsEnv,
|
|
|
9312
9546
|
process.exit(1);
|
|
9313
9547
|
}
|
|
9314
9548
|
}
|
|
9315
|
-
if (!
|
|
9549
|
+
if (!fs20.existsSync(serviceDir)) {
|
|
9316
9550
|
logWarn(
|
|
9317
9551
|
`Skipped: ${name} (source directory not found: ${serviceDir}${serviceDir !== service.src ? ` \u2014 rebased from ${service.src}` : ""})`
|
|
9318
9552
|
);
|
|
@@ -9352,11 +9586,11 @@ async function startServices(sessionName, appRoot, devOutput, headless, awsEnv,
|
|
|
9352
9586
|
cmd,
|
|
9353
9587
|
service.env?.OTEL_RESOURCE_ATTRIBUTES ? logShipperPath() : void 0
|
|
9354
9588
|
);
|
|
9355
|
-
|
|
9356
|
-
|
|
9589
|
+
execFileSync16("tmux", ["new-window", "-t", sessionName, "-n", name, "-c", serviceDir]);
|
|
9590
|
+
execFileSync16("tmux", ["set-option", "-t", `${sessionName}:${name}`, "remain-on-exit", "on"], {
|
|
9357
9591
|
stdio: "ignore"
|
|
9358
9592
|
});
|
|
9359
|
-
|
|
9593
|
+
execFileSync16("tmux", ["send-keys", "-t", `${sessionName}:${name}`, launchCmd, "Enter"]);
|
|
9360
9594
|
logSuccess(`Started: ${name} (${serviceDir}, port ${service.port})`);
|
|
9361
9595
|
}
|
|
9362
9596
|
if (process.env.DEVCONTAINER === "1") {
|
|
@@ -9367,7 +9601,7 @@ async function startServices(sessionName, appRoot, devOutput, headless, awsEnv,
|
|
|
9367
9601
|
}
|
|
9368
9602
|
}
|
|
9369
9603
|
const statusCmd = `watch -n2 -t npx mesh dev --status --session '${sessionName}'`;
|
|
9370
|
-
|
|
9604
|
+
execFileSync16("tmux", ["send-keys", "-t", `${sessionName}:status`, statusCmd, "Enter"]);
|
|
9371
9605
|
console.log("");
|
|
9372
9606
|
logSuccess(`Dev session started: ${sessionName}`);
|
|
9373
9607
|
console.log("");
|
|
@@ -9424,7 +9658,7 @@ async function showStatus2(sessionName, devOutput, asJson) {
|
|
|
9424
9658
|
}
|
|
9425
9659
|
let windows = [];
|
|
9426
9660
|
try {
|
|
9427
|
-
const raw =
|
|
9661
|
+
const raw = execFileSync16(
|
|
9428
9662
|
"tmux",
|
|
9429
9663
|
["list-windows", "-t", sessionName, "-F", "#{window_name} #{pane_dead}"],
|
|
9430
9664
|
{ encoding: "utf-8" }
|
|
@@ -9546,7 +9780,7 @@ async function restartService(sessionName, serviceName, appRoot, devOutput, awsE
|
|
|
9546
9780
|
}
|
|
9547
9781
|
const target = `${sessionName}:${serviceName}`;
|
|
9548
9782
|
try {
|
|
9549
|
-
|
|
9783
|
+
execFileSync16("tmux", ["respawn-pane", "-k", "-t", target], { stdio: "ignore" });
|
|
9550
9784
|
} catch {
|
|
9551
9785
|
logError(`Window '${serviceName}' not found in session.`);
|
|
9552
9786
|
process.exit(1);
|
|
@@ -9555,8 +9789,8 @@ async function restartService(sessionName, serviceName, appRoot, devOutput, awsE
|
|
|
9555
9789
|
const cmd = service.command.join(" ");
|
|
9556
9790
|
const envFilePath = getServiceEnvFilePath(sessionName, serviceName);
|
|
9557
9791
|
let restartCmd;
|
|
9558
|
-
if (
|
|
9559
|
-
const serviceDir =
|
|
9792
|
+
if (fs20.existsSync(envFilePath)) {
|
|
9793
|
+
const serviceDir = path21.resolve(appRoot, rebaseServiceSrc(service.src, findMonorepoRoot()));
|
|
9560
9794
|
restartCmd = buildLaunchCommand(
|
|
9561
9795
|
envFilePath,
|
|
9562
9796
|
serviceDir,
|
|
@@ -9571,7 +9805,7 @@ async function restartService(sessionName, serviceName, appRoot, devOutput, awsE
|
|
|
9571
9805
|
const serviceVars = getServiceEnvVars(service, devOutput.tunnels);
|
|
9572
9806
|
restartCmd = `${envPrefix(serviceVars)}${cmd}`;
|
|
9573
9807
|
}
|
|
9574
|
-
|
|
9808
|
+
execFileSync16("tmux", ["send-keys", "-t", target, restartCmd, "Enter"]);
|
|
9575
9809
|
logSuccess(`Restarted: ${serviceName}`);
|
|
9576
9810
|
}
|
|
9577
9811
|
function showLogs(sessionName, serviceName, tail) {
|
|
@@ -9581,7 +9815,7 @@ function showLogs(sessionName, serviceName, tail) {
|
|
|
9581
9815
|
}
|
|
9582
9816
|
const target = `${sessionName}:${serviceName}`;
|
|
9583
9817
|
try {
|
|
9584
|
-
const result =
|
|
9818
|
+
const result = execFileSync16("tmux", ["capture-pane", "-t", target, "-p", "-S", `-${tail}`], {
|
|
9585
9819
|
encoding: "utf-8"
|
|
9586
9820
|
});
|
|
9587
9821
|
process.stdout.write(result);
|
|
@@ -9809,7 +10043,7 @@ function registerDevCommand(program2) {
|
|
|
9809
10043
|
signInServices = [];
|
|
9810
10044
|
try {
|
|
9811
10045
|
const appPkg = JSON.parse(
|
|
9812
|
-
|
|
10046
|
+
fs20.readFileSync(path21.join(appRoot, "package.json"), "utf-8")
|
|
9813
10047
|
);
|
|
9814
10048
|
if (Array.isArray(appPkg?.mesh?.auth?.roles)) {
|
|
9815
10049
|
authRoles = appPkg.mesh.auth.roles.filter((r) => typeof r === "string");
|
|
@@ -9986,9 +10220,9 @@ function registerDevCommand(program2) {
|
|
|
9986
10220
|
logInfo(`Project: ${projectName}, Stack: ${stack}`);
|
|
9987
10221
|
const monorepoRoot = findMonorepoRoot();
|
|
9988
10222
|
const looksLikeStandaloneApp = ["api", "worker", "web"].some(
|
|
9989
|
-
(dir) =>
|
|
10223
|
+
(dir) => fs20.existsSync(path21.join(appRoot, dir, "package.json"))
|
|
9990
10224
|
);
|
|
9991
|
-
if (monorepoRoot &&
|
|
10225
|
+
if (monorepoRoot && path21.resolve(appRoot) === path21.resolve(monorepoRoot) && !looksLikeStandaloneApp) {
|
|
9992
10226
|
logError(`mesh dev should be run from an app directory, not the monorepo root.
|
|
9993
10227
|
`);
|
|
9994
10228
|
logInfo("Try:");
|
|
@@ -10464,10 +10698,10 @@ var init_dev = __esm({
|
|
|
10464
10698
|
});
|
|
10465
10699
|
|
|
10466
10700
|
// libs/mesh-cli/src/commands/dev-doctor.ts
|
|
10467
|
-
import { execFileSync as
|
|
10468
|
-
import * as
|
|
10701
|
+
import { execFileSync as execFileSync17 } from "node:child_process";
|
|
10702
|
+
import * as fs21 from "node:fs";
|
|
10469
10703
|
import * as net9 from "node:net";
|
|
10470
|
-
import * as
|
|
10704
|
+
import * as path22 from "node:path";
|
|
10471
10705
|
function aggregateStatus(results) {
|
|
10472
10706
|
if (results.some((r) => r.status === "error")) return "error";
|
|
10473
10707
|
if (results.some((r) => r.status === "warn")) return "warn";
|
|
@@ -10570,9 +10804,9 @@ function parsePortSquatter(lsofOut, psOut) {
|
|
|
10570
10804
|
return { pid, command };
|
|
10571
10805
|
}
|
|
10572
10806
|
function sharesWorktreeRoot(serviceSrc, repoRoot2) {
|
|
10573
|
-
const src =
|
|
10574
|
-
const root =
|
|
10575
|
-
return src === root || src.startsWith(root +
|
|
10807
|
+
const src = path22.resolve(serviceSrc);
|
|
10808
|
+
const root = path22.resolve(repoRoot2);
|
|
10809
|
+
return src === root || src.startsWith(root + path22.sep);
|
|
10576
10810
|
}
|
|
10577
10811
|
function classifyPortListener(listenerPid, sessionPids) {
|
|
10578
10812
|
if (listenerPid === null) return "dead";
|
|
@@ -10601,7 +10835,7 @@ function collectSessionPids(panePids, psOut) {
|
|
|
10601
10835
|
}
|
|
10602
10836
|
function whoHasPort(port) {
|
|
10603
10837
|
try {
|
|
10604
|
-
const lsof =
|
|
10838
|
+
const lsof = execFileSync17("lsof", ["-ti", `:${port}`], {
|
|
10605
10839
|
encoding: "utf8",
|
|
10606
10840
|
stdio: ["ignore", "pipe", "ignore"]
|
|
10607
10841
|
});
|
|
@@ -10609,7 +10843,7 @@ function whoHasPort(port) {
|
|
|
10609
10843
|
if (!pid) return null;
|
|
10610
10844
|
let ps = "";
|
|
10611
10845
|
try {
|
|
10612
|
-
ps =
|
|
10846
|
+
ps = execFileSync17("ps", ["-o", "comm=", "-p", pid], {
|
|
10613
10847
|
encoding: "utf8",
|
|
10614
10848
|
stdio: ["ignore", "pipe", "ignore"]
|
|
10615
10849
|
});
|
|
@@ -10623,7 +10857,7 @@ function whoHasPort(port) {
|
|
|
10623
10857
|
function sessionProcessTree(sessionName) {
|
|
10624
10858
|
let panePids;
|
|
10625
10859
|
try {
|
|
10626
|
-
const out =
|
|
10860
|
+
const out = execFileSync17(
|
|
10627
10861
|
"tmux",
|
|
10628
10862
|
["list-panes", "-s", "-t", sessionName, "-F", "#{pane_pid}"],
|
|
10629
10863
|
{ encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }
|
|
@@ -10635,7 +10869,7 @@ function sessionProcessTree(sessionName) {
|
|
|
10635
10869
|
if (panePids.length === 0) return /* @__PURE__ */ new Set();
|
|
10636
10870
|
let psOut = "";
|
|
10637
10871
|
try {
|
|
10638
|
-
psOut =
|
|
10872
|
+
psOut = execFileSync17("ps", ["-eo", "pid=,ppid="], {
|
|
10639
10873
|
encoding: "utf8",
|
|
10640
10874
|
stdio: ["ignore", "pipe", "ignore"]
|
|
10641
10875
|
});
|
|
@@ -10757,7 +10991,7 @@ var init_dev_doctor = __esm({
|
|
|
10757
10991
|
phases: ["preflight", "ondemand"],
|
|
10758
10992
|
async run() {
|
|
10759
10993
|
try {
|
|
10760
|
-
|
|
10994
|
+
execFileSync17("which", ["tmux"], { stdio: "ignore" });
|
|
10761
10995
|
return { status: "ok", summary: "installed" };
|
|
10762
10996
|
} catch {
|
|
10763
10997
|
return {
|
|
@@ -10832,14 +11066,14 @@ var init_dev_doctor = __esm({
|
|
|
10832
11066
|
if (!state) {
|
|
10833
11067
|
return { status: "ok", summary: "no session \u2014 config read fresh at launch" };
|
|
10834
11068
|
}
|
|
10835
|
-
const configPath =
|
|
10836
|
-
if (!
|
|
11069
|
+
const configPath = path22.join(ctx.appRoot, `Pulumi.${ctx.stack}.yaml`);
|
|
11070
|
+
if (!fs21.existsSync(configPath)) {
|
|
10837
11071
|
return {
|
|
10838
11072
|
status: "ok",
|
|
10839
11073
|
summary: `no Pulumi.${ctx.stack}.yaml to compare`
|
|
10840
11074
|
};
|
|
10841
11075
|
}
|
|
10842
|
-
const mtimeMs =
|
|
11076
|
+
const mtimeMs = fs21.statSync(configPath).mtimeMs;
|
|
10843
11077
|
if (isConfigStale(mtimeMs, state.startedAt)) {
|
|
10844
11078
|
return {
|
|
10845
11079
|
status: "warn",
|
|
@@ -10862,7 +11096,7 @@ var init_dev_doctor = __esm({
|
|
|
10862
11096
|
}
|
|
10863
11097
|
let repoRoot2;
|
|
10864
11098
|
try {
|
|
10865
|
-
repoRoot2 =
|
|
11099
|
+
repoRoot2 = execFileSync17("git", ["rev-parse", "--show-toplevel"], {
|
|
10866
11100
|
cwd: ctx.appRoot,
|
|
10867
11101
|
encoding: "utf8",
|
|
10868
11102
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -10998,21 +11232,21 @@ var init_dev_doctor = __esm({
|
|
|
10998
11232
|
});
|
|
10999
11233
|
|
|
11000
11234
|
// libs/mesh-cli/src/commands/app-check.ts
|
|
11001
|
-
import * as
|
|
11002
|
-
import * as
|
|
11235
|
+
import * as fs22 from "node:fs";
|
|
11236
|
+
import * as path23 from "node:path";
|
|
11003
11237
|
function rel(root, abs) {
|
|
11004
|
-
return
|
|
11238
|
+
return path23.relative(root, abs).split(path23.sep).join("/");
|
|
11005
11239
|
}
|
|
11006
11240
|
function isDir(p) {
|
|
11007
11241
|
try {
|
|
11008
|
-
return
|
|
11242
|
+
return fs22.statSync(p).isDirectory();
|
|
11009
11243
|
} catch {
|
|
11010
11244
|
return false;
|
|
11011
11245
|
}
|
|
11012
11246
|
}
|
|
11013
11247
|
function readText(p) {
|
|
11014
11248
|
try {
|
|
11015
|
-
return
|
|
11249
|
+
return fs22.readFileSync(p, "utf8");
|
|
11016
11250
|
} catch {
|
|
11017
11251
|
return "";
|
|
11018
11252
|
}
|
|
@@ -11022,19 +11256,19 @@ function srcFiles(dir) {
|
|
|
11022
11256
|
const walk2 = (d) => {
|
|
11023
11257
|
let entries;
|
|
11024
11258
|
try {
|
|
11025
|
-
entries =
|
|
11259
|
+
entries = fs22.readdirSync(d, { withFileTypes: true });
|
|
11026
11260
|
} catch {
|
|
11027
11261
|
return;
|
|
11028
11262
|
}
|
|
11029
11263
|
for (const e of entries) {
|
|
11030
|
-
const p =
|
|
11264
|
+
const p = path23.join(d, e.name);
|
|
11031
11265
|
if (e.isDirectory()) {
|
|
11032
11266
|
if (SKIP_DIRS.has(e.name) || e.name.startsWith("scenario")) continue;
|
|
11033
11267
|
walk2(p);
|
|
11034
11268
|
continue;
|
|
11035
11269
|
}
|
|
11036
11270
|
if (!e.isFile()) continue;
|
|
11037
|
-
if (!SRC_EXT.has(
|
|
11271
|
+
if (!SRC_EXT.has(path23.extname(e.name))) continue;
|
|
11038
11272
|
if (/\.(test|spec)\./.test(e.name) || /\.config\./.test(e.name) || e.name === "build.mjs") continue;
|
|
11039
11273
|
out.push(p);
|
|
11040
11274
|
}
|
|
@@ -11051,23 +11285,23 @@ function isUiDir(name) {
|
|
|
11051
11285
|
function serviceDirs(app) {
|
|
11052
11286
|
let entries;
|
|
11053
11287
|
try {
|
|
11054
|
-
entries =
|
|
11288
|
+
entries = fs22.readdirSync(app, { withFileTypes: true });
|
|
11055
11289
|
} catch {
|
|
11056
11290
|
return [];
|
|
11057
11291
|
}
|
|
11058
|
-
return entries.filter((e) => e.isDirectory() && !NON_SERVICE_DIRS.has(e.name) && !e.name.startsWith(".") && !isTestHarness(e.name)).map((e) =>
|
|
11292
|
+
return entries.filter((e) => e.isDirectory() && !NON_SERVICE_DIRS.has(e.name) && !e.name.startsWith(".") && !isTestHarness(e.name)).map((e) => path23.join(app, e.name)).sort();
|
|
11059
11293
|
}
|
|
11060
11294
|
function authzSurface(app) {
|
|
11061
11295
|
const hits = [];
|
|
11062
11296
|
const walk2 = (d) => {
|
|
11063
11297
|
let entries;
|
|
11064
11298
|
try {
|
|
11065
|
-
entries =
|
|
11299
|
+
entries = fs22.readdirSync(d, { withFileTypes: true });
|
|
11066
11300
|
} catch {
|
|
11067
11301
|
return;
|
|
11068
11302
|
}
|
|
11069
11303
|
for (const e of entries) {
|
|
11070
|
-
const p =
|
|
11304
|
+
const p = path23.join(d, e.name);
|
|
11071
11305
|
if (e.isDirectory()) {
|
|
11072
11306
|
if (["node_modules", "dist", "build"].includes(e.name)) continue;
|
|
11073
11307
|
walk2(p);
|
|
@@ -11366,32 +11600,32 @@ function docsAudienceUngrantable(text, decl, args, docs, httpText) {
|
|
|
11366
11600
|
}
|
|
11367
11601
|
function listApps(root) {
|
|
11368
11602
|
const apps = [];
|
|
11369
|
-
const appsDir =
|
|
11603
|
+
const appsDir = path23.join(root, "apps");
|
|
11370
11604
|
if (isDir(appsDir)) {
|
|
11371
|
-
for (const e of
|
|
11605
|
+
for (const e of fs22.readdirSync(appsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
11372
11606
|
if (!e.isDirectory()) continue;
|
|
11373
|
-
const d =
|
|
11374
|
-
if (
|
|
11607
|
+
const d = path23.join(appsDir, e.name);
|
|
11608
|
+
if (fs22.existsSync(path23.join(d, "index.ts")) || fs22.existsSync(path23.join(d, "Pulumi.yaml"))) apps.push(rel(root, d));
|
|
11375
11609
|
}
|
|
11376
11610
|
}
|
|
11377
|
-
if (
|
|
11611
|
+
if (fs22.existsSync(path23.join(root, "index.ts")) && fs22.existsSync(path23.join(root, "Pulumi.yaml"))) apps.push(".");
|
|
11378
11612
|
return apps;
|
|
11379
11613
|
}
|
|
11380
11614
|
function scanApp(root, appRel) {
|
|
11381
|
-
const app =
|
|
11382
|
-
const index =
|
|
11615
|
+
const app = path23.resolve(root, appRel);
|
|
11616
|
+
const index = path23.join(app, "index.ts");
|
|
11383
11617
|
const findings = [];
|
|
11384
11618
|
const hit = (code, p, why) => {
|
|
11385
11619
|
findings.push({ code, path: p, why });
|
|
11386
11620
|
};
|
|
11387
|
-
const hasProgram =
|
|
11621
|
+
const hasProgram = fs22.existsSync(index) || fs22.existsSync(path23.join(app, "Pulumi.yaml"));
|
|
11388
11622
|
if (!hasProgram) return findings;
|
|
11389
|
-
if (
|
|
11623
|
+
if (fs22.existsSync(index)) {
|
|
11390
11624
|
const indexRel = rel(root, index);
|
|
11391
11625
|
let servesHtml = false;
|
|
11392
11626
|
let hasUiService = false;
|
|
11393
11627
|
for (const svc of serviceDirs(app)) {
|
|
11394
|
-
const svcName =
|
|
11628
|
+
const svcName = path23.basename(svc);
|
|
11395
11629
|
if (isUiDir(svcName)) {
|
|
11396
11630
|
hasUiService = true;
|
|
11397
11631
|
continue;
|
|
@@ -11435,7 +11669,7 @@ function scanApp(root, appRel) {
|
|
|
11435
11669
|
const exposure = first(RE_EXPOSURE);
|
|
11436
11670
|
const pointer = first(RE_POINTER);
|
|
11437
11671
|
const metadata = first(RE_METADATA);
|
|
11438
|
-
const appLabel = appRel === "." ? "(root)" :
|
|
11672
|
+
const appLabel = appRel === "." ? "(root)" : path23.basename(appRel);
|
|
11439
11673
|
if (exposure && !pointer) {
|
|
11440
11674
|
const at = surface.find((h) => RE_EXPOSURE.test(h.text) && /(^|\/)index\.ts$/.test(h.file)) ?? exposure;
|
|
11441
11675
|
hit(
|
|
@@ -11471,7 +11705,7 @@ function scanApp(root, appRel) {
|
|
|
11471
11705
|
}
|
|
11472
11706
|
function isPlatformPackage(dir) {
|
|
11473
11707
|
try {
|
|
11474
|
-
const pkg = JSON.parse(readText(
|
|
11708
|
+
const pkg = JSON.parse(readText(path23.join(dir, "package.json")));
|
|
11475
11709
|
return typeof pkg.name === "string" && pkg.name.startsWith("@mesh-tech/");
|
|
11476
11710
|
} catch {
|
|
11477
11711
|
return false;
|
|
@@ -11480,11 +11714,11 @@ function isPlatformPackage(dir) {
|
|
|
11480
11714
|
function scanRepo(root) {
|
|
11481
11715
|
const findings = [];
|
|
11482
11716
|
for (const parent of ["libs", "packages"]) {
|
|
11483
|
-
const dir =
|
|
11717
|
+
const dir = path23.join(root, parent);
|
|
11484
11718
|
if (!isDir(dir)) continue;
|
|
11485
|
-
for (const e of
|
|
11719
|
+
for (const e of fs22.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
11486
11720
|
if (!e.isDirectory() || !e.name.includes("auth")) continue;
|
|
11487
|
-
const lib =
|
|
11721
|
+
const lib = path23.join(dir, e.name);
|
|
11488
11722
|
if (isPlatformPackage(lib)) continue;
|
|
11489
11723
|
const verifies = srcFiles(lib).filter((f) => f.endsWith(".ts")).some((f) => /introspect|jwtVerify|createRemoteJWKSet|from ["']jose["']/.test(readText(f)));
|
|
11490
11724
|
if (verifies) {
|
|
@@ -11521,7 +11755,7 @@ async function runAppCheck(root, apps) {
|
|
|
11521
11755
|
if (!isDir(root)) throw new MeshCliError(`no such checkout: ${root}`);
|
|
11522
11756
|
const targets = apps && apps.length > 0 ? apps.map((a) => a.replace(/\/+$/, "")) : listApps(root);
|
|
11523
11757
|
for (const a of targets) {
|
|
11524
|
-
if (!isDir(
|
|
11758
|
+
if (!isDir(path23.resolve(root, a))) throw new MeshCliError(`no such app dir: ${a}`);
|
|
11525
11759
|
}
|
|
11526
11760
|
const scopes = [];
|
|
11527
11761
|
for (const app of targets) {
|
|
@@ -11555,7 +11789,7 @@ function registerAppCommands(program2) {
|
|
|
11555
11789
|
app.command("check").description(
|
|
11556
11790
|
"Check tenant apps against the Mesh app contract (@mesh-tech/app-kit skills/apps/references/app-contract.md): a UI is its own service, the app registers with the Hub, sign-in goes through the platform proxy, logs go through @mesh-tech/logger, and people/roles/keys are surfaced through the Hub. Exit 1 on any blocking finding \u2014 the same gate mesh create-app, tenant CI and the platform reviewer run."
|
|
11557
11791
|
).argument("[apps...]", "repo-relative app dirs to check (default: every apps/* with a Pulumi program)").option("--root <dir>", "checkout to scan (default: the enclosing git root)").option("--json", "machine-readable output (one report per app plus the repo-scoped checks)", false).option("--verbose", "also print the gates that passed", false).action(async (apps, opts) => {
|
|
11558
|
-
const root =
|
|
11792
|
+
const root = path23.resolve(opts.root ?? resolveTargetRoot());
|
|
11559
11793
|
const report = await runAppCheck(root, apps);
|
|
11560
11794
|
if (opts.json) {
|
|
11561
11795
|
emitJsonPayload({ ok: report.status !== "error", ...report });
|
|
@@ -11795,14 +12029,14 @@ var init_resolve = __esm({
|
|
|
11795
12029
|
});
|
|
11796
12030
|
|
|
11797
12031
|
// packages/agent-targets/src/load.ts
|
|
11798
|
-
import { readFileSync as
|
|
12032
|
+
import { readFileSync as readFileSync19 } from "node:fs";
|
|
11799
12033
|
import { homedir as homedir3 } from "node:os";
|
|
11800
|
-
import
|
|
12034
|
+
import path24 from "node:path";
|
|
11801
12035
|
function loadTargetsFile(env = process.env) {
|
|
11802
12036
|
const file = env.MESH_AGENT_TARGETS || DEFAULT_REGISTRY_PATH;
|
|
11803
12037
|
let raw;
|
|
11804
12038
|
try {
|
|
11805
|
-
raw =
|
|
12039
|
+
raw = readFileSync19(file, "utf8");
|
|
11806
12040
|
} catch {
|
|
11807
12041
|
return { status: "absent", path: file };
|
|
11808
12042
|
}
|
|
@@ -11821,7 +12055,7 @@ var init_load = __esm({
|
|
|
11821
12055
|
"use strict";
|
|
11822
12056
|
init_schema();
|
|
11823
12057
|
init_resolve();
|
|
11824
|
-
DEFAULT_REGISTRY_PATH =
|
|
12058
|
+
DEFAULT_REGISTRY_PATH = path24.join(homedir3(), ".config", "mesh", "agent-targets.json");
|
|
11825
12059
|
}
|
|
11826
12060
|
});
|
|
11827
12061
|
|
|
@@ -12053,9 +12287,9 @@ var init_pull = __esm({
|
|
|
12053
12287
|
|
|
12054
12288
|
// packages/agent-targets/src/pull/write.ts
|
|
12055
12289
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
12056
|
-
import { join as
|
|
12290
|
+
import { join as join21, dirname as dirname19 } from "node:path";
|
|
12057
12291
|
async function put(dir, rel2, contents, written) {
|
|
12058
|
-
const abs =
|
|
12292
|
+
const abs = join21(dir, rel2);
|
|
12059
12293
|
await mkdir(dirname19(abs), { recursive: true });
|
|
12060
12294
|
await writeFile(abs, contents);
|
|
12061
12295
|
written.push(rel2);
|
|
@@ -12182,7 +12416,7 @@ import { execFile as execFile2 } from "node:child_process";
|
|
|
12182
12416
|
import { promisify } from "node:util";
|
|
12183
12417
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
12184
12418
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
12185
|
-
import { join as
|
|
12419
|
+
import { join as join22 } from "node:path";
|
|
12186
12420
|
function deriveVcsBaseUrl(apiBaseUrl) {
|
|
12187
12421
|
try {
|
|
12188
12422
|
const u = new URL(apiBaseUrl);
|
|
@@ -12241,7 +12475,7 @@ function createVcsFolderReader(opts) {
|
|
|
12241
12475
|
let p = clones.get(repo);
|
|
12242
12476
|
if (!p) {
|
|
12243
12477
|
p = (async () => {
|
|
12244
|
-
const dir = await mkdtemp(
|
|
12478
|
+
const dir = await mkdtemp(join22(tmpdir4(), "mesh-vcs-"));
|
|
12245
12479
|
await execFileAsync("git", [
|
|
12246
12480
|
"clone",
|
|
12247
12481
|
"--filter=blob:none",
|
|
@@ -12258,11 +12492,11 @@ function createVcsFolderReader(opts) {
|
|
|
12258
12492
|
}
|
|
12259
12493
|
return p;
|
|
12260
12494
|
};
|
|
12261
|
-
const readPath = async (repo,
|
|
12495
|
+
const readPath = async (repo, path48) => {
|
|
12262
12496
|
const dir = await cloneRepo(repo);
|
|
12263
|
-
const ref = await resolveFolderRef(dir,
|
|
12264
|
-
if (!ref) throw new Error(`path "${
|
|
12265
|
-
const files = await readFolderAtRef(dir, ref,
|
|
12497
|
+
const ref = await resolveFolderRef(dir, path48);
|
|
12498
|
+
if (!ref) throw new Error(`path "${path48}" not found on any ref of ${repo}`);
|
|
12499
|
+
const files = await readFolderAtRef(dir, ref, path48);
|
|
12266
12500
|
return { ref, files };
|
|
12267
12501
|
};
|
|
12268
12502
|
const cleanup = async () => {
|
|
@@ -12453,8 +12687,8 @@ var init_agent_api_client = __esm({
|
|
|
12453
12687
|
});
|
|
12454
12688
|
|
|
12455
12689
|
// libs/mesh-cli/src/commands/artifacts.ts
|
|
12456
|
-
import * as
|
|
12457
|
-
import * as
|
|
12690
|
+
import * as fs23 from "fs";
|
|
12691
|
+
import * as path25 from "path";
|
|
12458
12692
|
function parseRef(ref) {
|
|
12459
12693
|
const colonIdx = ref.indexOf(":");
|
|
12460
12694
|
if (colonIdx === -1) {
|
|
@@ -12477,28 +12711,28 @@ async function getArtifact(ref, options, target) {
|
|
|
12477
12711
|
const { conversationId, artifactId } = parseRef(ref);
|
|
12478
12712
|
logInfo(`Fetching ${conversationId}:${artifactId} from ${target.apiBaseUrl}\u2026`);
|
|
12479
12713
|
const bundle = await fetchExportBundle(target, conversationId, artifactId);
|
|
12480
|
-
const outputDir = options.output ??
|
|
12481
|
-
|
|
12714
|
+
const outputDir = options.output ?? path25.join("workflows", bundle.primaryWorkflow);
|
|
12715
|
+
fs23.mkdirSync(outputDir, { recursive: true });
|
|
12482
12716
|
let filesWritten = 0;
|
|
12483
12717
|
for (const file of bundle.files) {
|
|
12484
|
-
const filePath =
|
|
12485
|
-
|
|
12718
|
+
const filePath = path25.join(outputDir, file.filename);
|
|
12719
|
+
fs23.writeFileSync(filePath, file.code, "utf-8");
|
|
12486
12720
|
logSuccess(` ${file.filename}`);
|
|
12487
12721
|
filesWritten++;
|
|
12488
12722
|
}
|
|
12489
12723
|
if (bundle.overview) {
|
|
12490
|
-
const readmePath =
|
|
12491
|
-
|
|
12724
|
+
const readmePath = path25.join(outputDir, "README.md");
|
|
12725
|
+
fs23.writeFileSync(readmePath, bundle.overview, "utf-8");
|
|
12492
12726
|
logSuccess(` README.md`);
|
|
12493
12727
|
filesWritten++;
|
|
12494
12728
|
}
|
|
12495
12729
|
if (bundle.ir) {
|
|
12496
|
-
const irPath =
|
|
12497
|
-
|
|
12730
|
+
const irPath = path25.join(outputDir, "workflow-ir.json");
|
|
12731
|
+
fs23.writeFileSync(irPath, JSON.stringify(bundle.ir, null, 2), "utf-8");
|
|
12498
12732
|
logSuccess(` workflow-ir.json`);
|
|
12499
12733
|
filesWritten++;
|
|
12500
12734
|
}
|
|
12501
|
-
const metaPath =
|
|
12735
|
+
const metaPath = path25.join(outputDir, ".workflow-meta.json");
|
|
12502
12736
|
const meta = {
|
|
12503
12737
|
conversationId: bundle.conversationId,
|
|
12504
12738
|
artifactId,
|
|
@@ -12506,7 +12740,7 @@ async function getArtifact(ref, options, target) {
|
|
|
12506
12740
|
exportedAt: bundle.exportedAt,
|
|
12507
12741
|
files: bundle.files.map((f) => f.filename)
|
|
12508
12742
|
};
|
|
12509
|
-
|
|
12743
|
+
fs23.writeFileSync(metaPath, JSON.stringify(meta, null, 2), "utf-8");
|
|
12510
12744
|
console.log();
|
|
12511
12745
|
logSuccess(
|
|
12512
12746
|
`Exported ${filesWritten} files to ${outputDir}/`
|
|
@@ -12930,7 +13164,7 @@ var init_conversations = __esm({
|
|
|
12930
13164
|
});
|
|
12931
13165
|
|
|
12932
13166
|
// libs/mesh-cli/src/utils/scaffold-versions.ts
|
|
12933
|
-
import { execFileSync as
|
|
13167
|
+
import { execFileSync as execFileSync18 } from "child_process";
|
|
12934
13168
|
function isPrerelease(range) {
|
|
12935
13169
|
return /[-+]/.test(range.replace(/^\^/, ""));
|
|
12936
13170
|
}
|
|
@@ -12940,7 +13174,7 @@ function toCaretRange(version) {
|
|
|
12940
13174
|
}
|
|
12941
13175
|
function resolvePublishedRange(pkg, cwd) {
|
|
12942
13176
|
try {
|
|
12943
|
-
const out =
|
|
13177
|
+
const out = execFileSync18("npm", ["view", pkg, "version"], {
|
|
12944
13178
|
cwd,
|
|
12945
13179
|
encoding: "utf-8",
|
|
12946
13180
|
timeout: 15e3,
|
|
@@ -12986,23 +13220,23 @@ __export(create_app_exports, {
|
|
|
12986
13220
|
shouldBootstrapAppsRepo: () => shouldBootstrapAppsRepo,
|
|
12987
13221
|
workspaceGlobForApp: () => workspaceGlobForApp
|
|
12988
13222
|
});
|
|
12989
|
-
import * as
|
|
13223
|
+
import * as fs24 from "fs";
|
|
12990
13224
|
import * as os7 from "os";
|
|
12991
|
-
import * as
|
|
13225
|
+
import * as path26 from "path";
|
|
12992
13226
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
12993
13227
|
import Handlebars from "handlebars";
|
|
12994
13228
|
import { parse as parseYaml2 } from "yaml";
|
|
12995
13229
|
function isInsidePlatformMonorepo(dir) {
|
|
12996
|
-
let cur =
|
|
12997
|
-
while (cur !==
|
|
12998
|
-
if (
|
|
13230
|
+
let cur = path26.resolve(dir);
|
|
13231
|
+
while (cur !== path26.dirname(cur)) {
|
|
13232
|
+
if (fs24.existsSync(path26.join(cur, "pnpm-workspace.yaml"))) {
|
|
12999
13233
|
try {
|
|
13000
|
-
const pkg = JSON.parse(
|
|
13234
|
+
const pkg = JSON.parse(fs24.readFileSync(path26.join(cur, "package.json"), "utf-8"));
|
|
13001
13235
|
if (pkg?.name === PLATFORM_MONOREPO_NAME) return true;
|
|
13002
13236
|
} catch {
|
|
13003
13237
|
}
|
|
13004
13238
|
}
|
|
13005
|
-
cur =
|
|
13239
|
+
cur = path26.dirname(cur);
|
|
13006
13240
|
}
|
|
13007
13241
|
return false;
|
|
13008
13242
|
}
|
|
@@ -13011,46 +13245,46 @@ function resolveDeployerRoleArn(tenant, platformName, env) {
|
|
|
13011
13245
|
return `arn:aws:iam::${account}:role/${tenant}-${env}-apps-deployer`;
|
|
13012
13246
|
}
|
|
13013
13247
|
function shouldBootstrapAppsRepo(cwd) {
|
|
13014
|
-
return
|
|
13248
|
+
return fs24.existsSync(path26.join(cwd, ".git")) && !isInsidePlatformMonorepo(cwd) && !fs24.existsSync(path26.join(cwd, "package.json")) && !fs24.existsSync(path26.join(cwd, "tenants")) && !fs24.existsSync(path26.join(cwd, "apps"));
|
|
13015
13249
|
}
|
|
13016
13250
|
function bootstrapAppsRepo(cwd, tenant) {
|
|
13017
|
-
const templateDir =
|
|
13251
|
+
const templateDir = path26.join(packageRoot, "templates", "apps-repo");
|
|
13018
13252
|
const registryAccount = HUB_ACCOUNTS.mesh;
|
|
13019
13253
|
const context = {
|
|
13020
|
-
repoName:
|
|
13254
|
+
repoName: path26.basename(cwd),
|
|
13021
13255
|
tenant,
|
|
13022
13256
|
tenantTitle: tenant.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" "),
|
|
13023
13257
|
registryUrl: `https://mesh-platform-${registryAccount}.d.codeartifact.us-east-2.amazonaws.com/npm/mesh-packages/`,
|
|
13024
13258
|
intentRange: INTENT_RANGE
|
|
13025
13259
|
};
|
|
13026
|
-
const staging =
|
|
13260
|
+
const staging = fs24.mkdtempSync(path26.join(os7.tmpdir(), "mesh-apps-repo-"));
|
|
13027
13261
|
try {
|
|
13028
13262
|
copyTemplate(templateDir, staging, context);
|
|
13029
13263
|
for (const [from, to] of [
|
|
13030
13264
|
["gitignore", ".gitignore"],
|
|
13031
13265
|
["npmrc", ".npmrc"]
|
|
13032
13266
|
]) {
|
|
13033
|
-
const p =
|
|
13034
|
-
if (
|
|
13267
|
+
const p = path26.join(staging, from);
|
|
13268
|
+
if (fs24.existsSync(p)) fs24.renameSync(p, path26.join(staging, to));
|
|
13035
13269
|
}
|
|
13036
13270
|
const created = [];
|
|
13037
|
-
for (const entry of
|
|
13038
|
-
const dest =
|
|
13039
|
-
if (
|
|
13040
|
-
|
|
13271
|
+
for (const entry of fs24.readdirSync(staging)) {
|
|
13272
|
+
const dest = path26.join(cwd, entry);
|
|
13273
|
+
if (fs24.existsSync(dest)) continue;
|
|
13274
|
+
fs24.cpSync(path26.join(staging, entry), dest, { recursive: true });
|
|
13041
13275
|
created.push(entry);
|
|
13042
13276
|
}
|
|
13043
|
-
|
|
13277
|
+
fs24.mkdirSync(path26.join(cwd, "apps"), { recursive: true });
|
|
13044
13278
|
created.push("apps/");
|
|
13045
13279
|
return created;
|
|
13046
13280
|
} finally {
|
|
13047
|
-
|
|
13281
|
+
fs24.rmSync(staging, { recursive: true, force: true });
|
|
13048
13282
|
}
|
|
13049
13283
|
}
|
|
13050
13284
|
function ensureWorkspaceGlobs(root, required) {
|
|
13051
|
-
const file =
|
|
13052
|
-
if (!
|
|
13053
|
-
const text =
|
|
13285
|
+
const file = path26.join(root, "pnpm-workspace.yaml");
|
|
13286
|
+
if (!fs24.existsSync(file)) return [];
|
|
13287
|
+
const text = fs24.readFileSync(file, "utf-8");
|
|
13054
13288
|
let declared;
|
|
13055
13289
|
try {
|
|
13056
13290
|
declared = parseYaml2(text)?.packages ?? [];
|
|
@@ -13074,13 +13308,13 @@ function ensureWorkspaceGlobs(root, required) {
|
|
|
13074
13308
|
}
|
|
13075
13309
|
const indent = (lines[end] ?? "").match(/^(\s*)-/)?.[1] ?? " ";
|
|
13076
13310
|
lines.splice(end + 1, 0, ...missing.map((glob) => `${indent}- ${glob}`));
|
|
13077
|
-
|
|
13311
|
+
fs24.writeFileSync(file, lines.join("\n"));
|
|
13078
13312
|
return missing;
|
|
13079
13313
|
}
|
|
13080
13314
|
function workspaceGlobForApp(root, appDir) {
|
|
13081
|
-
const rel2 =
|
|
13315
|
+
const rel2 = path26.relative(root, appDir).split(path26.sep).join("/");
|
|
13082
13316
|
if (rel2 === "" || rel2.split("/")[0] === "..") return null;
|
|
13083
|
-
return `${
|
|
13317
|
+
return `${path26.posix.dirname(rel2)}/*/*`;
|
|
13084
13318
|
}
|
|
13085
13319
|
function maybeBootstrapAppsRepo(cwd, tenant, test) {
|
|
13086
13320
|
if (test || !shouldBootstrapAppsRepo(cwd)) return;
|
|
@@ -13130,9 +13364,9 @@ async function promptForOptions(options) {
|
|
|
13130
13364
|
return { tenant, name, primitives };
|
|
13131
13365
|
}
|
|
13132
13366
|
function copyTemplate(srcDir, destDir, context) {
|
|
13133
|
-
const entries =
|
|
13367
|
+
const entries = fs24.readdirSync(srcDir, { withFileTypes: true });
|
|
13134
13368
|
for (const entry of entries) {
|
|
13135
|
-
const srcPath =
|
|
13369
|
+
const srcPath = path26.join(srcDir, entry.name);
|
|
13136
13370
|
let destName = entry.name;
|
|
13137
13371
|
if (destName.endsWith(".hbs")) {
|
|
13138
13372
|
destName = destName.slice(0, -4);
|
|
@@ -13140,17 +13374,17 @@ function copyTemplate(srcDir, destDir, context) {
|
|
|
13140
13374
|
if (destName.includes("{{")) {
|
|
13141
13375
|
destName = Handlebars.compile(destName)(context);
|
|
13142
13376
|
}
|
|
13143
|
-
const destPath =
|
|
13377
|
+
const destPath = path26.join(destDir, destName);
|
|
13144
13378
|
if (entry.isDirectory()) {
|
|
13145
|
-
|
|
13379
|
+
fs24.mkdirSync(destPath, { recursive: true });
|
|
13146
13380
|
copyTemplate(srcPath, destPath, context);
|
|
13147
13381
|
} else if (entry.name.endsWith(".hbs")) {
|
|
13148
|
-
const templateContent =
|
|
13382
|
+
const templateContent = fs24.readFileSync(srcPath, "utf-8");
|
|
13149
13383
|
const template = Handlebars.compile(templateContent);
|
|
13150
13384
|
const output = template(context);
|
|
13151
|
-
|
|
13385
|
+
fs24.writeFileSync(destPath, output);
|
|
13152
13386
|
} else {
|
|
13153
|
-
|
|
13387
|
+
fs24.copyFileSync(srcPath, destPath);
|
|
13154
13388
|
}
|
|
13155
13389
|
}
|
|
13156
13390
|
}
|
|
@@ -13174,72 +13408,72 @@ function describeNoAppsHome(cwd, tenant, baseDir, test) {
|
|
|
13174
13408
|
};
|
|
13175
13409
|
}
|
|
13176
13410
|
return {
|
|
13177
|
-
message: `This directory is not a Mesh apps repo \u2014 no apps/ here${
|
|
13411
|
+
message: `This directory is not a Mesh apps repo \u2014 no apps/ here${fs24.existsSync(path26.join(cwd, ".git")) ? "" : " and it is not a git repo"}.`,
|
|
13178
13412
|
hint: `Run: mesh init (turns this folder into your ${tenant}-mesh-apps repo), or cd into that repo and re-run mesh create-app.`
|
|
13179
13413
|
};
|
|
13180
13414
|
}
|
|
13181
13415
|
function resolveAppDir(cwd, tenant, name, test) {
|
|
13182
13416
|
const baseDir = test ? "tests/tenants" : "tenants";
|
|
13183
|
-
const possiblePaths = test ? [
|
|
13184
|
-
|
|
13185
|
-
|
|
13186
|
-
|
|
13417
|
+
const possiblePaths = test ? [path26.join(cwd, baseDir, tenant, "apps")] : [
|
|
13418
|
+
path26.join(cwd, baseDir, tenant, "apps"),
|
|
13419
|
+
path26.join(cwd, "..", tenant, "apps"),
|
|
13420
|
+
path26.join(cwd, "apps")
|
|
13187
13421
|
];
|
|
13188
|
-
let appsDir = possiblePaths.find((p) =>
|
|
13422
|
+
let appsDir = possiblePaths.find((p) => fs24.existsSync(p));
|
|
13189
13423
|
if (!appsDir) {
|
|
13190
|
-
appsDir =
|
|
13191
|
-
if (!
|
|
13424
|
+
appsDir = path26.join(cwd, baseDir, tenant, "apps");
|
|
13425
|
+
if (!fs24.existsSync(path26.join(cwd, baseDir, tenant))) {
|
|
13192
13426
|
const { message, hint } = describeNoAppsHome(cwd, tenant, baseDir, test);
|
|
13193
13427
|
logError(message);
|
|
13194
13428
|
logInfo(hint);
|
|
13195
13429
|
process.exit(1);
|
|
13196
13430
|
}
|
|
13197
|
-
if (!
|
|
13431
|
+
if (!fs24.existsSync(appsDir)) {
|
|
13198
13432
|
logInfo(`Creating apps directory: ${appsDir}`);
|
|
13199
|
-
|
|
13433
|
+
fs24.mkdirSync(appsDir, { recursive: true });
|
|
13200
13434
|
}
|
|
13201
13435
|
}
|
|
13202
|
-
return
|
|
13436
|
+
return path26.join(appsDir, name);
|
|
13203
13437
|
}
|
|
13204
13438
|
function generateComposableApp(appDir, context) {
|
|
13205
|
-
const fragmentsDir =
|
|
13206
|
-
const baseDir =
|
|
13207
|
-
if (!
|
|
13439
|
+
const fragmentsDir = path26.join(packageRoot, "fragments");
|
|
13440
|
+
const baseDir = path26.join(fragmentsDir, "base");
|
|
13441
|
+
if (!fs24.existsSync(baseDir)) {
|
|
13208
13442
|
logError(`Fragments directory not found: ${baseDir}`);
|
|
13209
13443
|
logInfo("Make sure the mesh-cli package is installed correctly.");
|
|
13210
13444
|
process.exit(1);
|
|
13211
13445
|
}
|
|
13212
13446
|
copyTemplate(baseDir, appDir, context);
|
|
13213
13447
|
if (context.service) {
|
|
13214
|
-
const serviceDir =
|
|
13215
|
-
if (!
|
|
13448
|
+
const serviceDir = path26.join(fragmentsDir, "service");
|
|
13449
|
+
if (!fs24.existsSync(serviceDir)) {
|
|
13216
13450
|
throw new Error(`Fragment directory not found: ${serviceDir}`);
|
|
13217
13451
|
}
|
|
13218
13452
|
copyTemplate(serviceDir, appDir, context);
|
|
13219
13453
|
}
|
|
13220
13454
|
if (context.database) {
|
|
13221
|
-
const dbDir =
|
|
13222
|
-
if (!
|
|
13455
|
+
const dbDir = path26.join(fragmentsDir, "database");
|
|
13456
|
+
if (!fs24.existsSync(dbDir)) {
|
|
13223
13457
|
throw new Error(`Fragment directory not found: ${dbDir}`);
|
|
13224
13458
|
}
|
|
13225
13459
|
copyTemplate(dbDir, appDir, context);
|
|
13226
13460
|
}
|
|
13227
13461
|
if (context.temporal) {
|
|
13228
|
-
const temporalDir =
|
|
13229
|
-
if (!
|
|
13462
|
+
const temporalDir = path26.join(fragmentsDir, "temporal");
|
|
13463
|
+
if (!fs24.existsSync(temporalDir)) {
|
|
13230
13464
|
throw new Error(`Fragment directory not found: ${temporalDir}`);
|
|
13231
13465
|
}
|
|
13232
13466
|
copyTemplate(temporalDir, appDir, context);
|
|
13233
13467
|
}
|
|
13234
13468
|
if (context.bucket) {
|
|
13235
|
-
const bucketDir =
|
|
13236
|
-
if (!
|
|
13469
|
+
const bucketDir = path26.join(fragmentsDir, "bucket");
|
|
13470
|
+
if (!fs24.existsSync(bucketDir)) {
|
|
13237
13471
|
throw new Error(`Fragment directory not found: ${bucketDir}`);
|
|
13238
13472
|
}
|
|
13239
13473
|
copyTemplate(bucketDir, appDir, context);
|
|
13240
13474
|
}
|
|
13241
|
-
const agentsDir =
|
|
13242
|
-
if (
|
|
13475
|
+
const agentsDir = path26.join(fragmentsDir, "agents");
|
|
13476
|
+
if (fs24.existsSync(agentsDir)) {
|
|
13243
13477
|
copyTemplate(agentsDir, appDir, context);
|
|
13244
13478
|
}
|
|
13245
13479
|
}
|
|
@@ -13340,22 +13574,22 @@ async function runLegacyTemplate(tenant, name, template, test) {
|
|
|
13340
13574
|
}
|
|
13341
13575
|
maybeBootstrapAppsRepo(process.cwd(), tenant, test);
|
|
13342
13576
|
const appDir = resolveAppDir(process.cwd(), tenant, name, test);
|
|
13343
|
-
if (
|
|
13577
|
+
if (fs24.existsSync(appDir)) {
|
|
13344
13578
|
logError(`App directory already exists: ${appDir}`);
|
|
13345
13579
|
process.exit(1);
|
|
13346
13580
|
}
|
|
13347
|
-
const templateDir =
|
|
13348
|
-
if (!
|
|
13581
|
+
const templateDir = path26.join(packageRoot, "templates", template);
|
|
13582
|
+
if (!fs24.existsSync(templateDir)) {
|
|
13349
13583
|
logError(`Template not found: ${templateDir}`);
|
|
13350
13584
|
process.exit(1);
|
|
13351
13585
|
}
|
|
13352
|
-
|
|
13586
|
+
fs24.mkdirSync(appDir, { recursive: true });
|
|
13353
13587
|
try {
|
|
13354
13588
|
copyTemplate(templateDir, appDir, { name, tenant });
|
|
13355
13589
|
logSuccess(`Created app at ${appDir}`);
|
|
13356
13590
|
} catch (error) {
|
|
13357
13591
|
logError(`Failed to create app: ${error}`);
|
|
13358
|
-
|
|
13592
|
+
fs24.rmSync(appDir, { recursive: true, force: true });
|
|
13359
13593
|
process.exit(1);
|
|
13360
13594
|
}
|
|
13361
13595
|
autoSyncSkills(appDir, name);
|
|
@@ -13370,7 +13604,7 @@ function autoSyncSkills(appDir, appName) {
|
|
|
13370
13604
|
logWarn(`Agent-skill sync skipped: ${err instanceof Error ? err.message : err} \u2014 run: mesh skills sync`);
|
|
13371
13605
|
}
|
|
13372
13606
|
try {
|
|
13373
|
-
const seeded = seedAppSkill(root, appName,
|
|
13607
|
+
const seeded = seedAppSkill(root, appName, path26.relative(root, appDir));
|
|
13374
13608
|
if (seeded) logSuccess(`seeded: ${seeded} (yours to grow \u2014 not managed by mesh skills sync)`);
|
|
13375
13609
|
} catch (err) {
|
|
13376
13610
|
logWarn(`App skill stub skipped: ${err instanceof Error ? err.message : err}`);
|
|
@@ -13378,7 +13612,7 @@ function autoSyncSkills(appDir, appName) {
|
|
|
13378
13612
|
}
|
|
13379
13613
|
async function checkScaffoldContract(appDir) {
|
|
13380
13614
|
const root = resolveTargetRoot(appDir);
|
|
13381
|
-
const report = await runAppCheck(root, [
|
|
13615
|
+
const report = await runAppCheck(root, [path26.relative(root, appDir) || "."]);
|
|
13382
13616
|
if (report.status === "ok") {
|
|
13383
13617
|
logSuccess("app contract: met (mesh app check)");
|
|
13384
13618
|
return;
|
|
@@ -13401,7 +13635,7 @@ async function runComposable(tenant, name, primitives, test) {
|
|
|
13401
13635
|
}
|
|
13402
13636
|
maybeBootstrapAppsRepo(process.cwd(), tenant, test);
|
|
13403
13637
|
const appDir = resolveAppDir(process.cwd(), tenant, name, test);
|
|
13404
|
-
if (
|
|
13638
|
+
if (fs24.existsSync(appDir)) {
|
|
13405
13639
|
logError(`App directory already exists: ${appDir}`);
|
|
13406
13640
|
process.exit(1);
|
|
13407
13641
|
}
|
|
@@ -13433,16 +13667,16 @@ async function runComposable(tenant, name, primitives, test) {
|
|
|
13433
13667
|
typescriptRange: SCAFFOLD_TOOLCHAIN.typescript,
|
|
13434
13668
|
deployerRoleArn: resolveDeployerRoleArn(tenant, platformName, platformEnv)
|
|
13435
13669
|
};
|
|
13436
|
-
|
|
13670
|
+
fs24.mkdirSync(appDir, { recursive: true });
|
|
13437
13671
|
try {
|
|
13438
13672
|
generateComposableApp(appDir, context);
|
|
13439
13673
|
logSuccess(`Created app at ${appDir}`);
|
|
13440
13674
|
} catch (error) {
|
|
13441
13675
|
logError(`Failed to create app: ${error}`);
|
|
13442
|
-
|
|
13676
|
+
fs24.rmSync(appDir, { recursive: true, force: true });
|
|
13443
13677
|
process.exit(1);
|
|
13444
13678
|
}
|
|
13445
|
-
const nested =
|
|
13679
|
+
const nested = fs24.readdirSync(appDir, { withFileTypes: true }).some((entry) => entry.isDirectory() && fs24.existsSync(path26.join(appDir, entry.name, "package.json")));
|
|
13446
13680
|
const glob = workspaceGlobForApp(repoRoot2, appDir);
|
|
13447
13681
|
if (nested && glob) {
|
|
13448
13682
|
const added = ensureWorkspaceGlobs(repoRoot2, [glob]);
|
|
@@ -13526,7 +13760,7 @@ var init_create_app = __esm({
|
|
|
13526
13760
|
init_errors();
|
|
13527
13761
|
init_mesh_json();
|
|
13528
13762
|
__filename = fileURLToPath2(import.meta.url);
|
|
13529
|
-
__dirname =
|
|
13763
|
+
__dirname = path26.dirname(__filename);
|
|
13530
13764
|
packageRoot = findPackageRoot(__dirname);
|
|
13531
13765
|
TEMPLATES = {
|
|
13532
13766
|
workflow: "Hono API + Temporal worker + hello workflow (Pulumi/app-kit)",
|
|
@@ -13850,20 +14084,20 @@ var init_psql = __esm({
|
|
|
13850
14084
|
// libs/mesh-cli/src/commands/db/exec.ts
|
|
13851
14085
|
import { spawn as spawn6 } from "child_process";
|
|
13852
14086
|
import * as net11 from "net";
|
|
13853
|
-
import * as
|
|
13854
|
-
import * as
|
|
14087
|
+
import * as fs25 from "fs";
|
|
14088
|
+
import * as path27 from "path";
|
|
13855
14089
|
import {
|
|
13856
14090
|
SecretsManagerClient as SecretsManagerClient3,
|
|
13857
14091
|
GetSecretValueCommand as GetSecretValueCommand3
|
|
13858
14092
|
} from "@aws-sdk/client-secrets-manager";
|
|
13859
14093
|
function findSstOutputs() {
|
|
13860
14094
|
let dir = process.cwd();
|
|
13861
|
-
const root =
|
|
14095
|
+
const root = path27.parse(dir).root;
|
|
13862
14096
|
while (dir !== root) {
|
|
13863
|
-
const outputsPath =
|
|
13864
|
-
if (
|
|
14097
|
+
const outputsPath = path27.join(dir, ".sst", "outputs.json");
|
|
14098
|
+
if (fs25.existsSync(outputsPath)) {
|
|
13865
14099
|
try {
|
|
13866
|
-
const content =
|
|
14100
|
+
const content = fs25.readFileSync(outputsPath, "utf-8");
|
|
13867
14101
|
const outputs = JSON.parse(content);
|
|
13868
14102
|
if (outputs.databaseUrl) {
|
|
13869
14103
|
const secretArnMatch = outputs.databaseUrl.match(/secretArn=([^&]+)/);
|
|
@@ -13878,7 +14112,7 @@ function findSstOutputs() {
|
|
|
13878
14112
|
} catch {
|
|
13879
14113
|
}
|
|
13880
14114
|
}
|
|
13881
|
-
dir =
|
|
14115
|
+
dir = path27.dirname(dir);
|
|
13882
14116
|
}
|
|
13883
14117
|
return null;
|
|
13884
14118
|
}
|
|
@@ -14137,8 +14371,8 @@ var init_db = __esm({
|
|
|
14137
14371
|
});
|
|
14138
14372
|
|
|
14139
14373
|
// libs/mesh-cli/src/utils/deploy-preflight.ts
|
|
14140
|
-
import { existsSync as
|
|
14141
|
-
import { dirname as dirname22, join as
|
|
14374
|
+
import { existsSync as existsSync21, readFileSync as readFileSync22 } from "node:fs";
|
|
14375
|
+
import { dirname as dirname22, join as join26, relative as relative7 } from "node:path";
|
|
14142
14376
|
import { parse as parseYaml3 } from "yaml";
|
|
14143
14377
|
function isGated(name) {
|
|
14144
14378
|
return GATED_PREFIXES.some((p) => name.startsWith(p));
|
|
@@ -14176,8 +14410,8 @@ function diffLockVsInstalled(expected, installed) {
|
|
|
14176
14410
|
function findPnpmLock(startDir) {
|
|
14177
14411
|
let dir = startDir;
|
|
14178
14412
|
for (; ; ) {
|
|
14179
|
-
const candidate =
|
|
14180
|
-
if (
|
|
14413
|
+
const candidate = join26(dir, "pnpm-lock.yaml");
|
|
14414
|
+
if (existsSync21(candidate)) return candidate;
|
|
14181
14415
|
const parent = dirname22(dir);
|
|
14182
14416
|
if (parent === dir) return null;
|
|
14183
14417
|
dir = parent;
|
|
@@ -14185,8 +14419,8 @@ function findPnpmLock(startDir) {
|
|
|
14185
14419
|
}
|
|
14186
14420
|
function readInstalledVersion(fromDir, name) {
|
|
14187
14421
|
try {
|
|
14188
|
-
const pkgPath =
|
|
14189
|
-
const version = JSON.parse(
|
|
14422
|
+
const pkgPath = join26(fromDir, "node_modules", name, "package.json");
|
|
14423
|
+
const version = JSON.parse(readFileSync22(pkgPath, "utf8")).version;
|
|
14190
14424
|
return typeof version === "string" ? version : null;
|
|
14191
14425
|
} catch {
|
|
14192
14426
|
return null;
|
|
@@ -14197,7 +14431,7 @@ function checkDeployDepsFresh(appRoot) {
|
|
|
14197
14431
|
if (!lockPath) return null;
|
|
14198
14432
|
let lockDoc;
|
|
14199
14433
|
try {
|
|
14200
|
-
lockDoc = parseYaml3(
|
|
14434
|
+
lockDoc = parseYaml3(readFileSync22(lockPath, "utf8"));
|
|
14201
14435
|
} catch {
|
|
14202
14436
|
logWarn(
|
|
14203
14437
|
`deploy preflight: could not parse ${lockPath} \u2014 skipping the stale-node_modules check.`
|
|
@@ -14253,7 +14487,7 @@ var init_deploy_preflight = __esm({
|
|
|
14253
14487
|
});
|
|
14254
14488
|
|
|
14255
14489
|
// libs/mesh-cli/src/commands/deploy.ts
|
|
14256
|
-
import { execFileSync as
|
|
14490
|
+
import { execFileSync as execFileSync19 } from "child_process";
|
|
14257
14491
|
function buildPulumiArgs(pulumiArgs, stack) {
|
|
14258
14492
|
const base = pulumiArgs.length === 0 || pulumiArgs[0]?.startsWith("-") ? ["up", ...pulumiArgs] : [...pulumiArgs];
|
|
14259
14493
|
const op = base[0];
|
|
@@ -14316,7 +14550,7 @@ function registerDeployCommand(program2) {
|
|
|
14316
14550
|
delete env.AWS_PROFILE;
|
|
14317
14551
|
const finalArgs = buildPulumiArgs(pulumiArgs, stack);
|
|
14318
14552
|
try {
|
|
14319
|
-
|
|
14553
|
+
execFileSync19("pulumi", finalArgs, {
|
|
14320
14554
|
cwd: appRoot,
|
|
14321
14555
|
env,
|
|
14322
14556
|
stdio: "inherit"
|
|
@@ -14421,8 +14655,8 @@ var init_schema2 = __esm({
|
|
|
14421
14655
|
});
|
|
14422
14656
|
|
|
14423
14657
|
// libs/mesh-cli/src/docs/discover.ts
|
|
14424
|
-
import { existsSync as
|
|
14425
|
-
import
|
|
14658
|
+
import { existsSync as existsSync22, readdirSync as readdirSync9, readFileSync as readFileSync23, statSync as statSync5 } from "node:fs";
|
|
14659
|
+
import path28 from "node:path";
|
|
14426
14660
|
function routePathFor(relPath) {
|
|
14427
14661
|
const withoutExt = relPath.replace(/\.md$/i, "");
|
|
14428
14662
|
const parts = withoutExt.split("/").map(slugify2);
|
|
@@ -14442,7 +14676,7 @@ function walkMarkdown(absDir, relDir, errors, rootDir) {
|
|
|
14442
14676
|
if (hasReservedSegment(entry.name)) {
|
|
14443
14677
|
continue;
|
|
14444
14678
|
}
|
|
14445
|
-
const abs =
|
|
14679
|
+
const abs = path28.join(absDir, entry.name);
|
|
14446
14680
|
if (entry.isDirectory()) {
|
|
14447
14681
|
if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
|
|
14448
14682
|
out.push(...walkMarkdown(abs, rel2, errors, rootDir));
|
|
@@ -14488,7 +14722,7 @@ function discoverDocRoots(repoRoot2) {
|
|
|
14488
14722
|
if (entry.name.startsWith(".")) continue;
|
|
14489
14723
|
const rel2 = relDir ? `${relDir}/${entry.name}` : entry.name;
|
|
14490
14724
|
findRoots(
|
|
14491
|
-
|
|
14725
|
+
path28.join(absDir, entry.name),
|
|
14492
14726
|
rel2,
|
|
14493
14727
|
insideReserved || hasReservedSegment(entry.name)
|
|
14494
14728
|
);
|
|
@@ -14497,7 +14731,7 @@ function discoverDocRoots(repoRoot2) {
|
|
|
14497
14731
|
findRoots(repoRoot2, "", false);
|
|
14498
14732
|
const pages = [];
|
|
14499
14733
|
for (const root of roots) {
|
|
14500
|
-
const absRoot =
|
|
14734
|
+
const absRoot = path28.join(repoRoot2, root.dir);
|
|
14501
14735
|
const relFiles = walkMarkdown(absRoot, "", errors, root.dir);
|
|
14502
14736
|
for (const relPath of relFiles.sort()) {
|
|
14503
14737
|
pages.push({
|
|
@@ -14521,14 +14755,14 @@ function discoverDocRoots(repoRoot2) {
|
|
|
14521
14755
|
);
|
|
14522
14756
|
continue;
|
|
14523
14757
|
}
|
|
14524
|
-
if (!
|
|
14758
|
+
if (!existsSync22(path28.join(repoRoot2, normalized))) {
|
|
14525
14759
|
errors.push(
|
|
14526
14760
|
`${root.dir}/docs.json includes ${normalized}, which does not exist`
|
|
14527
14761
|
);
|
|
14528
14762
|
continue;
|
|
14529
14763
|
}
|
|
14530
14764
|
if (pages.some((p) => p.source === normalized)) continue;
|
|
14531
|
-
const stem =
|
|
14765
|
+
const stem = path28.posix.basename(normalized).replace(/\.md$/i, "");
|
|
14532
14766
|
pages.push({
|
|
14533
14767
|
source: normalized,
|
|
14534
14768
|
root,
|
|
@@ -14556,10 +14790,10 @@ function discoverDocRoots(repoRoot2) {
|
|
|
14556
14790
|
return { roots, pages, errors };
|
|
14557
14791
|
}
|
|
14558
14792
|
function loadRoot(absDir, relDir, errors) {
|
|
14559
|
-
const configPath =
|
|
14793
|
+
const configPath = path28.join(absDir, "docs.json");
|
|
14560
14794
|
let raw;
|
|
14561
14795
|
try {
|
|
14562
|
-
raw = JSON.parse(
|
|
14796
|
+
raw = JSON.parse(readFileSync23(configPath, "utf-8"));
|
|
14563
14797
|
} catch (error) {
|
|
14564
14798
|
errors.push(
|
|
14565
14799
|
`${relDir}/docs.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -14609,9 +14843,9 @@ var init_discover = __esm({
|
|
|
14609
14843
|
});
|
|
14610
14844
|
|
|
14611
14845
|
// libs/mesh-cli/src/docs/assemble.ts
|
|
14612
|
-
import { execFileSync as
|
|
14613
|
-
import { mkdirSync as
|
|
14614
|
-
import
|
|
14846
|
+
import { execFileSync as execFileSync20 } from "node:child_process";
|
|
14847
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync24, rmSync as rmSync5, writeFileSync as writeFileSync15 } from "node:fs";
|
|
14848
|
+
import path29 from "node:path";
|
|
14615
14849
|
import { parse as parseYaml4 } from "yaml";
|
|
14616
14850
|
function splitFrontMatter(markdown) {
|
|
14617
14851
|
const normalized = markdown.replace(/^\uFEFF/, "");
|
|
@@ -14671,7 +14905,7 @@ function deriveTitle(frontMatter, body, source) {
|
|
|
14671
14905
|
if (typeof fmTitle === "string" && fmTitle.trim()) return fmTitle.trim();
|
|
14672
14906
|
const heading = firstHeading(body);
|
|
14673
14907
|
if (heading) return heading;
|
|
14674
|
-
const stem =
|
|
14908
|
+
const stem = path29.posix.basename(source).replace(/\.md$/i, "");
|
|
14675
14909
|
return titleizeStem(stem);
|
|
14676
14910
|
}
|
|
14677
14911
|
function scanLinks(markdown) {
|
|
@@ -14803,7 +15037,7 @@ function isAbsoluteHref(href) {
|
|
|
14803
15037
|
return /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(href);
|
|
14804
15038
|
}
|
|
14805
15039
|
function normalizeRepoPath(value) {
|
|
14806
|
-
return
|
|
15040
|
+
return path29.posix.normalize(value.replace(/\\/g, "/")).replace(/^\.\//, "").replace(/\/+$/, "");
|
|
14807
15041
|
}
|
|
14808
15042
|
function splitHash(href) {
|
|
14809
15043
|
const index = href.indexOf("#");
|
|
@@ -14821,7 +15055,7 @@ function resolveLink(args) {
|
|
|
14821
15055
|
const route = rawTarget.replace(/\/$/, "") || "/";
|
|
14822
15056
|
return routes.has(route) ? { href: `${route}${hash}` } : { href, issue: { kind: "broken", page: pageRoute2, href } };
|
|
14823
15057
|
}
|
|
14824
|
-
const repoPath = normalizeRepoPath(
|
|
15058
|
+
const repoPath = normalizeRepoPath(path29.posix.join(sourceDir, rawTarget));
|
|
14825
15059
|
const page = sourceIndex.get(repoPath);
|
|
14826
15060
|
if (page) return { href: `${page.route}${hash}` };
|
|
14827
15061
|
for (const candidate of [`${repoPath}/index.md`]) {
|
|
@@ -14842,7 +15076,7 @@ function rewriteLinks(args) {
|
|
|
14842
15076
|
const issues = [];
|
|
14843
15077
|
const hits = scanLinks(args.body);
|
|
14844
15078
|
if (hits.length === 0) return { body: args.body, issues };
|
|
14845
|
-
const sourceDir =
|
|
15079
|
+
const sourceDir = path29.posix.dirname(args.page.source);
|
|
14846
15080
|
let out = "";
|
|
14847
15081
|
let cursor = 0;
|
|
14848
15082
|
for (const hit of hits) {
|
|
@@ -14893,9 +15127,9 @@ function assemblePortal(options) {
|
|
|
14893
15127
|
const brokenLinks = [];
|
|
14894
15128
|
const externalLinks = [];
|
|
14895
15129
|
rmSync5(outDir, { recursive: true, force: true });
|
|
14896
|
-
|
|
15130
|
+
mkdirSync12(outDir, { recursive: true });
|
|
14897
15131
|
for (const page of pages) {
|
|
14898
|
-
const raw =
|
|
15132
|
+
const raw = readFileSync24(path29.join(repoRoot2, page.source), "utf-8");
|
|
14899
15133
|
const frontMatter = splitFrontMatter(raw);
|
|
14900
15134
|
const title = deriveTitle(frontMatter.data, frontMatter.body, page.source);
|
|
14901
15135
|
page.title = title;
|
|
@@ -14907,7 +15141,7 @@ function assemblePortal(options) {
|
|
|
14907
15141
|
sourceIndex,
|
|
14908
15142
|
routes,
|
|
14909
15143
|
ignoreLinkPrefixes,
|
|
14910
|
-
pathKind: (rel2) => pathKind(
|
|
15144
|
+
pathKind: (rel2) => pathKind(path29.join(repoRoot2, rel2)),
|
|
14911
15145
|
repoUrl
|
|
14912
15146
|
});
|
|
14913
15147
|
for (const issue of rewritten.issues) {
|
|
@@ -14921,8 +15155,8 @@ function assemblePortal(options) {
|
|
|
14921
15155
|
|
|
14922
15156
|
<sub>Source: [\`${page.source}\`](${blobBase}/blob/main/${page.source}) \u2014 edit that file, not this page.</sub>
|
|
14923
15157
|
`;
|
|
14924
|
-
const outFile =
|
|
14925
|
-
|
|
15158
|
+
const outFile = path29.join(outDir, page.filePath);
|
|
15159
|
+
mkdirSync12(path29.dirname(outFile), { recursive: true });
|
|
14926
15160
|
writeFileSync15(
|
|
14927
15161
|
outFile,
|
|
14928
15162
|
joinFrontMatter(outData, rewritten.body.trimEnd() + sourceNote)
|
|
@@ -15100,7 +15334,7 @@ function renderVersionJson(args) {
|
|
|
15100
15334
|
}
|
|
15101
15335
|
function currentCommit(repoRoot2) {
|
|
15102
15336
|
try {
|
|
15103
|
-
return
|
|
15337
|
+
return execFileSync20("git", ["rev-parse", "--short", "HEAD"], {
|
|
15104
15338
|
cwd: repoRoot2,
|
|
15105
15339
|
encoding: "utf-8"
|
|
15106
15340
|
}).trim();
|
|
@@ -15111,7 +15345,7 @@ function currentCommit(repoRoot2) {
|
|
|
15111
15345
|
function currentBaseline(repoRoot2) {
|
|
15112
15346
|
try {
|
|
15113
15347
|
const pkg = JSON.parse(
|
|
15114
|
-
|
|
15348
|
+
readFileSync24(path29.join(repoRoot2, "libs/app-kit/package.json"), "utf-8")
|
|
15115
15349
|
);
|
|
15116
15350
|
return pkg.version;
|
|
15117
15351
|
} catch {
|
|
@@ -15119,7 +15353,7 @@ function currentBaseline(repoRoot2) {
|
|
|
15119
15353
|
}
|
|
15120
15354
|
}
|
|
15121
15355
|
function publishSetAtRef(repoRoot2, ref) {
|
|
15122
|
-
const git = (gitArgs) =>
|
|
15356
|
+
const git = (gitArgs) => execFileSync20("git", gitArgs, {
|
|
15123
15357
|
cwd: repoRoot2,
|
|
15124
15358
|
encoding: "utf-8",
|
|
15125
15359
|
maxBuffer: 64 * 1024 * 1024
|
|
@@ -15144,7 +15378,7 @@ function publishSetAtRef(repoRoot2, ref) {
|
|
|
15144
15378
|
continue;
|
|
15145
15379
|
const rel2 = file.slice(prefix2.length);
|
|
15146
15380
|
if (hasReservedSegment(rel2)) continue;
|
|
15147
|
-
if (
|
|
15381
|
+
if (path29.posix.basename(file).toLowerCase() === "readme.md") continue;
|
|
15148
15382
|
published.add(file);
|
|
15149
15383
|
}
|
|
15150
15384
|
for (const include of config.include ?? []) {
|
|
@@ -15230,8 +15464,8 @@ function formatDefault(value, paths = currentMachinePaths()) {
|
|
|
15230
15464
|
if (typeof value === "boolean" || typeof value === "number") return String(value);
|
|
15231
15465
|
return normalizeMachinePaths(JSON.stringify(value), paths);
|
|
15232
15466
|
}
|
|
15233
|
-
function slugifyCommandPath(
|
|
15234
|
-
return
|
|
15467
|
+
function slugifyCommandPath(path48) {
|
|
15468
|
+
return path48.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
15235
15469
|
}
|
|
15236
15470
|
function extractOptions(command) {
|
|
15237
15471
|
const options = command.options ?? [];
|
|
@@ -15265,17 +15499,17 @@ function isUndocumented(command) {
|
|
|
15265
15499
|
function extractCommand(command, parentPath, depth) {
|
|
15266
15500
|
const internals = command;
|
|
15267
15501
|
const name = internals._name ?? "";
|
|
15268
|
-
const
|
|
15502
|
+
const path48 = parentPath ? `${parentPath} ${name}` : name;
|
|
15269
15503
|
return {
|
|
15270
|
-
path:
|
|
15504
|
+
path: path48,
|
|
15271
15505
|
name,
|
|
15272
15506
|
aliases: [...internals._aliases ?? []],
|
|
15273
15507
|
description: internals._description ?? "",
|
|
15274
15508
|
args: extractArgs(command),
|
|
15275
15509
|
options: extractOptions(command),
|
|
15276
|
-
slug: slugifyCommandPath(
|
|
15510
|
+
slug: slugifyCommandPath(path48),
|
|
15277
15511
|
depth,
|
|
15278
|
-
subcommands: (internals.commands ?? []).filter((child) => !isUndocumented(child)).map((child) => extractCommand(child,
|
|
15512
|
+
subcommands: (internals.commands ?? []).filter((child) => !isUndocumented(child)).map((child) => extractCommand(child, path48, depth + 1))
|
|
15279
15513
|
};
|
|
15280
15514
|
}
|
|
15281
15515
|
function extractCliReference(program2) {
|
|
@@ -15367,14 +15601,14 @@ var init_cli_reference = __esm({
|
|
|
15367
15601
|
import { spawn as spawn7 } from "node:child_process";
|
|
15368
15602
|
import {
|
|
15369
15603
|
appendFileSync,
|
|
15370
|
-
existsSync as
|
|
15371
|
-
mkdirSync as
|
|
15604
|
+
existsSync as existsSync23,
|
|
15605
|
+
mkdirSync as mkdirSync13,
|
|
15372
15606
|
mkdtempSync as mkdtempSync3,
|
|
15373
|
-
readFileSync as
|
|
15607
|
+
readFileSync as readFileSync25,
|
|
15374
15608
|
writeFileSync as writeFileSync16
|
|
15375
15609
|
} from "node:fs";
|
|
15376
15610
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
15377
|
-
import
|
|
15611
|
+
import path30 from "node:path";
|
|
15378
15612
|
function runAssemble(args) {
|
|
15379
15613
|
const discovery = discoverDocRoots(args.repoRoot);
|
|
15380
15614
|
const assembled = assemblePortal({
|
|
@@ -15386,7 +15620,7 @@ function runAssemble(args) {
|
|
|
15386
15620
|
});
|
|
15387
15621
|
const errors = [...discovery.errors];
|
|
15388
15622
|
if (args.writeFiles !== false) {
|
|
15389
|
-
const manifestPath = args.outDir.includes(tmpdir6()) ?
|
|
15623
|
+
const manifestPath = args.outDir.includes(tmpdir6()) ? path30.join(args.outDir, PUBLISH_MANIFEST) : path30.join(args.outDir, "..", PUBLISH_MANIFEST);
|
|
15390
15624
|
writeFileSync16(
|
|
15391
15625
|
manifestPath,
|
|
15392
15626
|
`${JSON.stringify(assembled.publishManifest, null, 2)}
|
|
@@ -15403,13 +15637,13 @@ function runAssemble(args) {
|
|
|
15403
15637
|
commit: currentCommit(args.repoRoot)
|
|
15404
15638
|
})
|
|
15405
15639
|
);
|
|
15406
|
-
const versionDir =
|
|
15407
|
-
|
|
15640
|
+
const versionDir = path30.join(
|
|
15641
|
+
path30.dirname(args.configOut),
|
|
15408
15642
|
VERSION_JSON_DIR
|
|
15409
15643
|
);
|
|
15410
|
-
|
|
15644
|
+
mkdirSync13(versionDir, { recursive: true });
|
|
15411
15645
|
writeFileSync16(
|
|
15412
|
-
|
|
15646
|
+
path30.join(versionDir, VERSION_JSON),
|
|
15413
15647
|
renderVersionJson({
|
|
15414
15648
|
baseline: currentBaseline(args.repoRoot),
|
|
15415
15649
|
commit: currentCommit(args.repoRoot),
|
|
@@ -15441,7 +15675,7 @@ function reportAssembly(result) {
|
|
|
15441
15675
|
}
|
|
15442
15676
|
}
|
|
15443
15677
|
async function checkPortal(args) {
|
|
15444
|
-
const scratch = mkdtempSync3(
|
|
15678
|
+
const scratch = mkdtempSync3(path30.join(tmpdir6(), "mesh-docs-check-"));
|
|
15445
15679
|
const result = runAssemble({ repoRoot: args.repoRoot, outDir: scratch });
|
|
15446
15680
|
const failures = [...result.errors];
|
|
15447
15681
|
for (const violation of result.assembled.reservedViolations) {
|
|
@@ -15462,7 +15696,7 @@ async function checkPortal(args) {
|
|
|
15462
15696
|
);
|
|
15463
15697
|
}
|
|
15464
15698
|
if (args.manifestOut) {
|
|
15465
|
-
|
|
15699
|
+
mkdirSync13(path30.dirname(args.manifestOut), { recursive: true });
|
|
15466
15700
|
writeFileSync16(
|
|
15467
15701
|
args.manifestOut,
|
|
15468
15702
|
`${JSON.stringify(result.assembled.publishManifest, null, 2)}
|
|
@@ -15532,12 +15766,12 @@ async function runPortalCommand(opts, deps) {
|
|
|
15532
15766
|
logSuccess("Docs portal check passed");
|
|
15533
15767
|
return;
|
|
15534
15768
|
}
|
|
15535
|
-
const appDir =
|
|
15536
|
-
const outDir = opts.out ?
|
|
15769
|
+
const appDir = path30.join(repoRoot2, DOCS_APP_DIR);
|
|
15770
|
+
const outDir = opts.out ? path30.resolve(repoRoot2, opts.out) : path30.join(appDir, CONTENT_DIR);
|
|
15537
15771
|
const result = runAssemble({
|
|
15538
15772
|
repoRoot: repoRoot2,
|
|
15539
15773
|
outDir,
|
|
15540
|
-
configOut:
|
|
15774
|
+
configOut: path30.join(appDir, GENERATED_CONFIG)
|
|
15541
15775
|
});
|
|
15542
15776
|
reportAssembly(result);
|
|
15543
15777
|
if (result.errors.length > 0) {
|
|
@@ -15548,7 +15782,7 @@ async function runPortalCommand(opts, deps) {
|
|
|
15548
15782
|
}
|
|
15549
15783
|
if (opts.assembleOnly || opts.out) {
|
|
15550
15784
|
logInfo(
|
|
15551
|
-
`Assembled content at ${
|
|
15785
|
+
`Assembled content at ${path30.relative(repoRoot2, outDir)} \u2014 build with: pnpm --filter @mesh-tech/docs build`
|
|
15552
15786
|
);
|
|
15553
15787
|
return;
|
|
15554
15788
|
}
|
|
@@ -15568,7 +15802,7 @@ async function runPortalCommand(opts, deps) {
|
|
|
15568
15802
|
if (code !== 0) throw new Error(`zudoku ${mode} exited with code ${code}`);
|
|
15569
15803
|
if (mode === "build") {
|
|
15570
15804
|
logSuccess(
|
|
15571
|
-
`Portal built \u2192 ${
|
|
15805
|
+
`Portal built \u2192 ${path30.join(path30.relative(repoRoot2, appDir), "dist")}`
|
|
15572
15806
|
);
|
|
15573
15807
|
}
|
|
15574
15808
|
}
|
|
@@ -15580,11 +15814,11 @@ async function cliReferenceStaleness(repoRoot2) {
|
|
|
15580
15814
|
Promise.resolve().then(() => (init_program(), program_exports)),
|
|
15581
15815
|
Promise.resolve().then(() => (init_cli_reference(), cli_reference_exports))
|
|
15582
15816
|
]);
|
|
15583
|
-
const outPath =
|
|
15817
|
+
const outPath = path30.join(repoRoot2, "docs/portal/generated/cli-reference.md");
|
|
15584
15818
|
const markdown = renderCliReferenceMarkdown2(
|
|
15585
15819
|
extractCliReference2(createProgram2())
|
|
15586
15820
|
);
|
|
15587
|
-
const existing =
|
|
15821
|
+
const existing = existsSync23(outPath) ? readFileSync25(outPath, "utf-8") : null;
|
|
15588
15822
|
if (existing === markdown) return null;
|
|
15589
15823
|
return `${existing === null ? "CLI reference is missing" : "CLI reference is stale"}: docs/portal/generated/cli-reference.md \u2014 the commander tree changed; regenerate and commit with \`pnpm exec mesh docs cli-reference\``;
|
|
15590
15824
|
}
|
|
@@ -15607,9 +15841,9 @@ var init_portal = __esm({
|
|
|
15607
15841
|
});
|
|
15608
15842
|
|
|
15609
15843
|
// libs/mesh-cli/src/utils/build-info.ts
|
|
15610
|
-
import { execFileSync as
|
|
15611
|
-
import * as
|
|
15612
|
-
import * as
|
|
15844
|
+
import { execFileSync as execFileSync21 } from "child_process";
|
|
15845
|
+
import * as fs26 from "fs";
|
|
15846
|
+
import * as path31 from "path";
|
|
15613
15847
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
15614
15848
|
function detectRuntimeMode(modulePath) {
|
|
15615
15849
|
return modulePath.split(/[\\/]/).includes("dist") ? "dist" : "source";
|
|
@@ -15628,11 +15862,11 @@ function findCliPackageRoot(startDir) {
|
|
|
15628
15862
|
let dir = startDir;
|
|
15629
15863
|
for (let i = 0; i < 8; i++) {
|
|
15630
15864
|
try {
|
|
15631
|
-
const pkg = JSON.parse(
|
|
15865
|
+
const pkg = JSON.parse(fs26.readFileSync(path31.join(dir, "package.json"), "utf-8"));
|
|
15632
15866
|
if (pkg.name === "@mesh-tech/mesh-cli") return dir;
|
|
15633
15867
|
} catch {
|
|
15634
15868
|
}
|
|
15635
|
-
const parent =
|
|
15869
|
+
const parent = path31.dirname(dir);
|
|
15636
15870
|
if (parent === dir) break;
|
|
15637
15871
|
dir = parent;
|
|
15638
15872
|
}
|
|
@@ -15640,13 +15874,13 @@ function findCliPackageRoot(startDir) {
|
|
|
15640
15874
|
}
|
|
15641
15875
|
function resolveCliRuntime(opts) {
|
|
15642
15876
|
const vcs = opts?.vcs ?? true;
|
|
15643
|
-
const here =
|
|
15877
|
+
const here = path31.dirname(fileURLToPath3(import.meta.url));
|
|
15644
15878
|
const mode = detectRuntimeMode(here);
|
|
15645
15879
|
const root = findCliPackageRoot(here);
|
|
15646
15880
|
let version = "0.0.0";
|
|
15647
15881
|
if (root) {
|
|
15648
15882
|
try {
|
|
15649
|
-
version = JSON.parse(
|
|
15883
|
+
version = JSON.parse(fs26.readFileSync(path31.join(root, "package.json"), "utf-8")).version ?? version;
|
|
15650
15884
|
} catch {
|
|
15651
15885
|
}
|
|
15652
15886
|
}
|
|
@@ -15655,7 +15889,7 @@ function resolveCliRuntime(opts) {
|
|
|
15655
15889
|
if (mode === "dist") {
|
|
15656
15890
|
try {
|
|
15657
15891
|
const meta = JSON.parse(
|
|
15658
|
-
|
|
15892
|
+
fs26.readFileSync(path31.join(root, "dist", "build-info.json"), "utf-8")
|
|
15659
15893
|
);
|
|
15660
15894
|
info.commit = meta.commit;
|
|
15661
15895
|
info.builtAt = meta.builtAt;
|
|
@@ -15665,7 +15899,7 @@ function resolveCliRuntime(opts) {
|
|
|
15665
15899
|
}
|
|
15666
15900
|
if (!vcs) return info;
|
|
15667
15901
|
try {
|
|
15668
|
-
const git = (args) =>
|
|
15902
|
+
const git = (args) => execFileSync21("git", args, {
|
|
15669
15903
|
cwd: root,
|
|
15670
15904
|
encoding: "utf-8",
|
|
15671
15905
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -15685,7 +15919,7 @@ var init_build_info = __esm({
|
|
|
15685
15919
|
// libs/mesh-cli/src/docs/serve.ts
|
|
15686
15920
|
import { createServer as createServer8 } from "node:http";
|
|
15687
15921
|
import { readFile } from "node:fs/promises";
|
|
15688
|
-
import { extname as extname2, join as
|
|
15922
|
+
import { extname as extname2, join as join28, normalize, sep as sep5 } from "node:path";
|
|
15689
15923
|
async function serveDocsSite(args) {
|
|
15690
15924
|
const root = normalize(args.root);
|
|
15691
15925
|
const rootPrefix = root.endsWith(sep5) ? root : root + sep5;
|
|
@@ -15704,7 +15938,7 @@ async function serveDocsSite(args) {
|
|
|
15704
15938
|
];
|
|
15705
15939
|
if (pathname !== "/") candidates.push("/index.html");
|
|
15706
15940
|
for (const candidate of candidates) {
|
|
15707
|
-
const filePath = normalize(
|
|
15941
|
+
const filePath = normalize(join28(root, candidate));
|
|
15708
15942
|
if (filePath !== root && !filePath.startsWith(rootPrefix)) continue;
|
|
15709
15943
|
try {
|
|
15710
15944
|
const body = await readFile(filePath);
|
|
@@ -15762,13 +15996,13 @@ var init_serve = __esm({
|
|
|
15762
15996
|
});
|
|
15763
15997
|
|
|
15764
15998
|
// libs/mesh-cli/src/docs/registry-docs.ts
|
|
15765
|
-
import { execFileSync as
|
|
15766
|
-
import { existsSync as
|
|
15999
|
+
import { execFileSync as execFileSync22 } from "node:child_process";
|
|
16000
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as readFileSync27, renameSync as renameSync3, rmSync as rmSync6, writeFileSync as writeFileSync17 } from "node:fs";
|
|
15767
16001
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
15768
|
-
import
|
|
16002
|
+
import path32 from "node:path";
|
|
15769
16003
|
function readDocsRegistryAuth(npmrcPath2 = homeNpmrcPath()) {
|
|
15770
|
-
if (!
|
|
15771
|
-
return parseNpmrcRegistryAuth(
|
|
16004
|
+
if (!existsSync24(npmrcPath2)) return null;
|
|
16005
|
+
return parseNpmrcRegistryAuth(readFileSync27(npmrcPath2, "utf-8"));
|
|
15772
16006
|
}
|
|
15773
16007
|
function packumentUrl(endpoint, pkg) {
|
|
15774
16008
|
return `${endpoint.replace(/\/+$/, "")}/${pkg.replace(/\//g, "%2f")}`;
|
|
@@ -15818,15 +16052,15 @@ async function listDocsVersions(auth, fetchImpl = fetch) {
|
|
|
15818
16052
|
return { versions, latest: packument["dist-tags"]?.latest };
|
|
15819
16053
|
}
|
|
15820
16054
|
function docsCacheRoot() {
|
|
15821
|
-
const base = process.env.XDG_CACHE_HOME ??
|
|
15822
|
-
return
|
|
16055
|
+
const base = process.env.XDG_CACHE_HOME ?? path32.join(homeDir(), ".cache");
|
|
16056
|
+
return path32.join(base, "mesh", "docs");
|
|
15823
16057
|
}
|
|
15824
16058
|
function homeDir() {
|
|
15825
16059
|
return process.env.HOME ?? tmpdir7();
|
|
15826
16060
|
}
|
|
15827
16061
|
async function fetchDocsArtifact(auth, version, cacheRoot = docsCacheRoot(), fetchImpl = fetch) {
|
|
15828
|
-
const targetDir =
|
|
15829
|
-
if (
|
|
16062
|
+
const targetDir = path32.join(cacheRoot, version);
|
|
16063
|
+
if (existsSync24(path32.join(targetDir, "dist", "index.html"))) return targetDir;
|
|
15830
16064
|
const listResponse = await registryFetch(auth, packumentUrl(auth.endpoint, DOCS_PACKAGE), fetchImpl);
|
|
15831
16065
|
if (!listResponse.ok) {
|
|
15832
16066
|
throw new Error(`registry returned ${listResponse.status} for ${DOCS_PACKAGE}`);
|
|
@@ -15847,20 +16081,20 @@ async function fetchDocsArtifact(auth, version, cacheRoot = docsCacheRoot(), fet
|
|
|
15847
16081
|
if (!tgzResponse.ok) {
|
|
15848
16082
|
throw new Error(`downloading ${DOCS_PACKAGE}@${version} failed: ${tgzResponse.status}`);
|
|
15849
16083
|
}
|
|
15850
|
-
|
|
15851
|
-
const tgzPath =
|
|
16084
|
+
mkdirSync14(cacheRoot, { recursive: true });
|
|
16085
|
+
const tgzPath = path32.join(cacheRoot, `.${version}.tgz`);
|
|
15852
16086
|
writeFileSync17(tgzPath, Buffer.from(await tgzResponse.arrayBuffer()));
|
|
15853
|
-
const staging =
|
|
16087
|
+
const staging = path32.join(cacheRoot, `.staging-${version}`);
|
|
15854
16088
|
rmSync6(staging, { recursive: true, force: true });
|
|
15855
|
-
|
|
16089
|
+
mkdirSync14(staging, { recursive: true });
|
|
15856
16090
|
try {
|
|
15857
|
-
|
|
16091
|
+
execFileSync22("tar", ["-xzf", tgzPath, "-C", staging, "--strip-components", "1"], {
|
|
15858
16092
|
stdio: ["pipe", "pipe", "pipe"]
|
|
15859
16093
|
});
|
|
15860
16094
|
} finally {
|
|
15861
16095
|
rmSync6(tgzPath, { force: true });
|
|
15862
16096
|
}
|
|
15863
|
-
if (!
|
|
16097
|
+
if (!existsSync24(path32.join(staging, "dist", "index.html"))) {
|
|
15864
16098
|
rmSync6(staging, { recursive: true, force: true });
|
|
15865
16099
|
throw new Error(`${DOCS_PACKAGE}@${version} unpacked without a dist/index.html \u2014 the artifact is malformed`);
|
|
15866
16100
|
}
|
|
@@ -15892,9 +16126,9 @@ __export(start_exports, {
|
|
|
15892
16126
|
tmuxInstallHint: () => tmuxInstallHint,
|
|
15893
16127
|
tmuxServeArgs: () => tmuxServeArgs
|
|
15894
16128
|
});
|
|
15895
|
-
import { execFileSync as
|
|
15896
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
15897
|
-
import
|
|
16129
|
+
import { execFileSync as execFileSync23 } from "node:child_process";
|
|
16130
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync25, writeFileSync as writeFileSync18 } from "node:fs";
|
|
16131
|
+
import path33 from "node:path";
|
|
15898
16132
|
function registryAuthOrThrow() {
|
|
15899
16133
|
const auth = readDocsRegistryAuth();
|
|
15900
16134
|
if (!auth) {
|
|
@@ -15925,7 +16159,7 @@ function tmuxInstallHint(platform = process.platform) {
|
|
|
15925
16159
|
}
|
|
15926
16160
|
function tmuxAvailable() {
|
|
15927
16161
|
try {
|
|
15928
|
-
|
|
16162
|
+
execFileSync23("tmux", ["-V"], { stdio: ["pipe", "pipe", "pipe"] });
|
|
15929
16163
|
return true;
|
|
15930
16164
|
} catch {
|
|
15931
16165
|
return false;
|
|
@@ -15936,7 +16170,7 @@ function shouldDetach(args) {
|
|
|
15936
16170
|
}
|
|
15937
16171
|
function docsSessionExists() {
|
|
15938
16172
|
try {
|
|
15939
|
-
|
|
16173
|
+
execFileSync23("tmux", ["has-session", "-t", DOCS_TMUX_SESSION], { stdio: ["pipe", "pipe", "pipe"] });
|
|
15940
16174
|
return true;
|
|
15941
16175
|
} catch {
|
|
15942
16176
|
return false;
|
|
@@ -15960,12 +16194,12 @@ Or run in the foreground instead: mesh docs start --foreground`
|
|
|
15960
16194
|
if (docsSessionExists()) {
|
|
15961
16195
|
logInfo(`Replacing the docs server already running in tmux session "${DOCS_TMUX_SESSION}".`);
|
|
15962
16196
|
try {
|
|
15963
|
-
|
|
16197
|
+
execFileSync23("tmux", ["kill-session", "-t", DOCS_TMUX_SESSION], { stdio: ["pipe", "pipe", "pipe"] });
|
|
15964
16198
|
} catch {
|
|
15965
16199
|
}
|
|
15966
16200
|
}
|
|
15967
16201
|
const { command, cwd } = tmuxServeArgs(args);
|
|
15968
|
-
|
|
16202
|
+
execFileSync23(
|
|
15969
16203
|
"tmux",
|
|
15970
16204
|
["new-session", "-d", "-s", DOCS_TMUX_SESSION, "-c", cwd, "--", ...command],
|
|
15971
16205
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -16003,7 +16237,7 @@ function printReady(url, label) {
|
|
|
16003
16237
|
}
|
|
16004
16238
|
function runDocsStop() {
|
|
16005
16239
|
try {
|
|
16006
|
-
|
|
16240
|
+
execFileSync23("tmux", ["kill-session", "-t", DOCS_TMUX_SESSION], { stdio: ["pipe", "pipe", "pipe"] });
|
|
16007
16241
|
logSuccess(`Stopped the docs server (tmux session "${DOCS_TMUX_SESSION}").`);
|
|
16008
16242
|
} catch {
|
|
16009
16243
|
logInfo(`No docs server is running (no tmux session named "${DOCS_TMUX_SESSION}").`);
|
|
@@ -16014,7 +16248,7 @@ async function runDocsServeStatic(args) {
|
|
|
16014
16248
|
if (!Number.isInteger(requestedPort) || requestedPort < 0 || requestedPort > 65535) {
|
|
16015
16249
|
throw new Error(`Invalid --port: ${args.port}`);
|
|
16016
16250
|
}
|
|
16017
|
-
if (!args.root || !
|
|
16251
|
+
if (!args.root || !existsSync25(path33.join(args.root, "index.html"))) {
|
|
16018
16252
|
throw new Error(
|
|
16019
16253
|
`--root ${args.root || "(empty)"} does not hold a built site (no index.html). This command exists so the detached tmux session can re-enter; you probably want \`mesh docs start\`.`
|
|
16020
16254
|
);
|
|
@@ -16055,19 +16289,19 @@ async function runDocsStart(args) {
|
|
|
16055
16289
|
}
|
|
16056
16290
|
logInfo(`Fetching ${DOCS_PACKAGE}@${version} from the registry\u2026`);
|
|
16057
16291
|
const artifactDir = await fetchDocsArtifact(auth, version);
|
|
16058
|
-
serveRoot =
|
|
16292
|
+
serveRoot = path33.join(artifactDir, "dist");
|
|
16059
16293
|
label = `@mesh-tech/* ${version} (published artifact)`;
|
|
16060
16294
|
} else {
|
|
16061
16295
|
if (localRoots.errors.length > 0) {
|
|
16062
16296
|
for (const error of localRoots.errors) logError(error);
|
|
16063
16297
|
throw new Error(`docs discovery failed with ${localRoots.errors.length} problem(s)`);
|
|
16064
16298
|
}
|
|
16065
|
-
const appDir =
|
|
16299
|
+
const appDir = path33.join(args.repoRoot, DOCS_APP_DIR);
|
|
16066
16300
|
if (args.dev) {
|
|
16067
16301
|
const result2 = runAssemble({
|
|
16068
16302
|
repoRoot: args.repoRoot,
|
|
16069
|
-
outDir:
|
|
16070
|
-
configOut:
|
|
16303
|
+
outDir: path33.join(appDir, "content"),
|
|
16304
|
+
configOut: path33.join(appDir, "zudoku.config.ts")
|
|
16071
16305
|
});
|
|
16072
16306
|
reportAssembly(result2);
|
|
16073
16307
|
const { spawn: spawn11 } = await import("node:child_process");
|
|
@@ -16083,12 +16317,12 @@ async function runDocsStart(args) {
|
|
|
16083
16317
|
});
|
|
16084
16318
|
return;
|
|
16085
16319
|
}
|
|
16086
|
-
const buildLog =
|
|
16087
|
-
logInfo(`Preparing the docs from this checkout (assemble + build \u2014 log: ${
|
|
16320
|
+
const buildLog = path33.join(args.repoRoot, DOCS_APP_DIR, "build.log");
|
|
16321
|
+
logInfo(`Preparing the docs from this checkout (assemble + build \u2014 log: ${path33.relative(args.repoRoot, buildLog)})\u2026`);
|
|
16088
16322
|
const result = runAssemble({
|
|
16089
16323
|
repoRoot: args.repoRoot,
|
|
16090
|
-
outDir:
|
|
16091
|
-
configOut:
|
|
16324
|
+
outDir: path33.join(appDir, "content"),
|
|
16325
|
+
configOut: path33.join(appDir, "zudoku.config.ts")
|
|
16092
16326
|
});
|
|
16093
16327
|
reportAssembly(result);
|
|
16094
16328
|
const { spawn: spawn10 } = await import("node:child_process");
|
|
@@ -16105,7 +16339,7 @@ async function runDocsStart(args) {
|
|
|
16105
16339
|
child.on("close", (exitCode) => resolve20(exitCode ?? 1));
|
|
16106
16340
|
});
|
|
16107
16341
|
if (code !== 0) throw new Error(`zudoku build exited with code ${code} \u2014 see ${buildLog}`);
|
|
16108
|
-
serveRoot =
|
|
16342
|
+
serveRoot = path33.join(appDir, "dist");
|
|
16109
16343
|
label = "this checkout";
|
|
16110
16344
|
}
|
|
16111
16345
|
if (detached) {
|
|
@@ -16145,30 +16379,30 @@ var init_start = __esm({
|
|
|
16145
16379
|
});
|
|
16146
16380
|
|
|
16147
16381
|
// libs/mesh-cli/src/commands/docs.ts
|
|
16148
|
-
import * as
|
|
16149
|
-
import * as
|
|
16382
|
+
import * as fs27 from "fs";
|
|
16383
|
+
import * as path34 from "path";
|
|
16150
16384
|
import { createRequire } from "module";
|
|
16151
16385
|
import { pathToFileURL } from "url";
|
|
16152
16386
|
function findProjectRoot(start = process.cwd()) {
|
|
16153
16387
|
let dir = start;
|
|
16154
16388
|
while (true) {
|
|
16155
|
-
if (
|
|
16156
|
-
const parent =
|
|
16389
|
+
if (fs27.existsSync(path34.join(dir, "package.json"))) return dir;
|
|
16390
|
+
const parent = path34.dirname(dir);
|
|
16157
16391
|
if (parent === dir) return start;
|
|
16158
16392
|
dir = parent;
|
|
16159
16393
|
}
|
|
16160
16394
|
}
|
|
16161
16395
|
function resolvePath(projectRoot, candidate) {
|
|
16162
|
-
return
|
|
16396
|
+
return path34.isAbsolute(candidate) ? candidate : path34.join(projectRoot, candidate);
|
|
16163
16397
|
}
|
|
16164
16398
|
function ensureParentDir(filePath) {
|
|
16165
|
-
|
|
16399
|
+
fs27.mkdirSync(path34.dirname(filePath), { recursive: true });
|
|
16166
16400
|
}
|
|
16167
16401
|
function readConfig2(configPath) {
|
|
16168
|
-
if (!
|
|
16402
|
+
if (!fs27.existsSync(configPath)) {
|
|
16169
16403
|
throw new Error(`Docs config not found: ${configPath}`);
|
|
16170
16404
|
}
|
|
16171
|
-
const raw =
|
|
16405
|
+
const raw = fs27.readFileSync(configPath, "utf-8");
|
|
16172
16406
|
const parsed = JSON.parse(raw);
|
|
16173
16407
|
if (parsed.openapi && !Array.isArray(parsed.openapi)) {
|
|
16174
16408
|
throw new Error(`Invalid docs config: 'openapi' must be an array`);
|
|
@@ -16176,7 +16410,7 @@ function readConfig2(configPath) {
|
|
|
16176
16410
|
return parsed;
|
|
16177
16411
|
}
|
|
16178
16412
|
function validateOpenApiSpec(specPath) {
|
|
16179
|
-
const content =
|
|
16413
|
+
const content = fs27.readFileSync(specPath, "utf-8");
|
|
16180
16414
|
const parsed = JSON.parse(content);
|
|
16181
16415
|
if (typeof parsed.openapi !== "string") {
|
|
16182
16416
|
throw new Error(`Invalid OpenAPI spec (${specPath}): missing 'openapi'`);
|
|
@@ -16189,7 +16423,7 @@ function validateOpenApiSpec(specPath) {
|
|
|
16189
16423
|
}
|
|
16190
16424
|
}
|
|
16191
16425
|
async function loadSymxchangeGenerator(projectRoot) {
|
|
16192
|
-
const requireFromProject = createRequire(
|
|
16426
|
+
const requireFromProject = createRequire(path34.join(projectRoot, "package.json"));
|
|
16193
16427
|
const entryPath = requireFromProject.resolve("@mesh-tech/jh-symitar-api");
|
|
16194
16428
|
const mod = await import(pathToFileURL(entryPath).href);
|
|
16195
16429
|
const fn = mod.generateSymxchangeOpenApi;
|
|
@@ -16202,8 +16436,8 @@ async function loadSymxchangeGenerator(projectRoot) {
|
|
|
16202
16436
|
}
|
|
16203
16437
|
async function buildDocs(configPathArg) {
|
|
16204
16438
|
const cwd = process.cwd();
|
|
16205
|
-
const configPath =
|
|
16206
|
-
const projectRoot = findProjectRoot(
|
|
16439
|
+
const configPath = path34.isAbsolute(configPathArg ?? "") ? configPathArg : path34.resolve(cwd, configPathArg ?? "docs/docs.config.json");
|
|
16440
|
+
const projectRoot = findProjectRoot(path34.dirname(configPath));
|
|
16207
16441
|
const config = readConfig2(configPath);
|
|
16208
16442
|
logInfo(`Using docs config: ${configPath}`);
|
|
16209
16443
|
const generatedSpecs = /* @__PURE__ */ new Set();
|
|
@@ -16211,15 +16445,15 @@ async function buildDocs(configPathArg) {
|
|
|
16211
16445
|
if (task.kind === "file") {
|
|
16212
16446
|
const inputPath = resolvePath(projectRoot, task.input);
|
|
16213
16447
|
const outputPath = resolvePath(projectRoot, task.output ?? task.input);
|
|
16214
|
-
if (!
|
|
16448
|
+
if (!fs27.existsSync(inputPath)) {
|
|
16215
16449
|
throw new Error(`OpenAPI source file not found: ${inputPath}`);
|
|
16216
16450
|
}
|
|
16217
16451
|
if (inputPath !== outputPath) {
|
|
16218
16452
|
ensureParentDir(outputPath);
|
|
16219
|
-
|
|
16220
|
-
logSuccess(`Copied OpenAPI spec \u2192 ${
|
|
16453
|
+
fs27.copyFileSync(inputPath, outputPath);
|
|
16454
|
+
logSuccess(`Copied OpenAPI spec \u2192 ${path34.relative(projectRoot, outputPath)}`);
|
|
16221
16455
|
} else {
|
|
16222
|
-
logInfo(`Using OpenAPI spec: ${
|
|
16456
|
+
logInfo(`Using OpenAPI spec: ${path34.relative(projectRoot, inputPath)}`);
|
|
16223
16457
|
}
|
|
16224
16458
|
validateOpenApiSpec(outputPath);
|
|
16225
16459
|
generatedSpecs.add(outputPath);
|
|
@@ -16237,10 +16471,10 @@ async function buildDocs(configPathArg) {
|
|
|
16237
16471
|
servers: task.servers
|
|
16238
16472
|
});
|
|
16239
16473
|
ensureParentDir(outputPath);
|
|
16240
|
-
|
|
16474
|
+
fs27.writeFileSync(outputPath, JSON.stringify(spec, null, 2));
|
|
16241
16475
|
validateOpenApiSpec(outputPath);
|
|
16242
16476
|
generatedSpecs.add(outputPath);
|
|
16243
|
-
logSuccess(`Generated SymXchange OpenAPI \u2192 ${
|
|
16477
|
+
logSuccess(`Generated SymXchange OpenAPI \u2192 ${path34.relative(projectRoot, outputPath)}`);
|
|
16244
16478
|
continue;
|
|
16245
16479
|
}
|
|
16246
16480
|
const exhaustive = task;
|
|
@@ -16248,12 +16482,12 @@ async function buildDocs(configPathArg) {
|
|
|
16248
16482
|
}
|
|
16249
16483
|
for (const relPath of config.validate ?? []) {
|
|
16250
16484
|
const abs = resolvePath(projectRoot, relPath);
|
|
16251
|
-
if (!
|
|
16485
|
+
if (!fs27.existsSync(abs)) {
|
|
16252
16486
|
throw new Error(`OpenAPI spec to validate not found: ${abs}`);
|
|
16253
16487
|
}
|
|
16254
16488
|
validateOpenApiSpec(abs);
|
|
16255
16489
|
generatedSpecs.add(abs);
|
|
16256
|
-
logSuccess(`Validated OpenAPI spec: ${
|
|
16490
|
+
logSuccess(`Validated OpenAPI spec: ${path34.relative(projectRoot, abs)}`);
|
|
16257
16491
|
}
|
|
16258
16492
|
if (generatedSpecs.size === 0) {
|
|
16259
16493
|
logInfo("No docs tasks configured (nothing to do)");
|
|
@@ -16283,20 +16517,20 @@ async function runCliReference(opts) {
|
|
|
16283
16517
|
const outPath = resolvePath(repoRoot2, opts.out);
|
|
16284
16518
|
const markdown = await renderCliReference();
|
|
16285
16519
|
if (opts.check) {
|
|
16286
|
-
const existing =
|
|
16520
|
+
const existing = fs27.existsSync(outPath) ? fs27.readFileSync(outPath, "utf-8") : null;
|
|
16287
16521
|
if (existing === markdown) {
|
|
16288
|
-
logSuccess(`CLI reference is up to date (${
|
|
16522
|
+
logSuccess(`CLI reference is up to date (${path34.relative(repoRoot2, outPath)})`);
|
|
16289
16523
|
return;
|
|
16290
16524
|
}
|
|
16291
16525
|
throw new Error(
|
|
16292
|
-
`${existing === null ? "CLI reference is missing" : "CLI reference is stale"}: ${
|
|
16526
|
+
`${existing === null ? "CLI reference is missing" : "CLI reference is stale"}: ${path34.relative(repoRoot2, outPath)}
|
|
16293
16527
|
The commander tree changed. Regenerate and commit:
|
|
16294
16528
|
pnpm exec mesh docs cli-reference`
|
|
16295
16529
|
);
|
|
16296
16530
|
}
|
|
16297
16531
|
ensureParentDir(outPath);
|
|
16298
|
-
|
|
16299
|
-
logSuccess(`CLI reference \u2192 ${
|
|
16532
|
+
fs27.writeFileSync(outPath, markdown);
|
|
16533
|
+
logSuccess(`CLI reference \u2192 ${path34.relative(repoRoot2, outPath)}`);
|
|
16300
16534
|
}
|
|
16301
16535
|
async function runPortal(opts) {
|
|
16302
16536
|
const repoRoot2 = findRepoRoot2(process.cwd());
|
|
@@ -16376,23 +16610,23 @@ var init_docs = __esm({
|
|
|
16376
16610
|
});
|
|
16377
16611
|
|
|
16378
16612
|
// libs/mesh-cli/src/commands/hub/index.ts
|
|
16379
|
-
import { execFileSync as
|
|
16380
|
-
import * as
|
|
16613
|
+
import { execFileSync as execFileSync24 } from "node:child_process";
|
|
16614
|
+
import * as fs28 from "node:fs";
|
|
16381
16615
|
import * as net12 from "node:net";
|
|
16382
16616
|
import * as os9 from "node:os";
|
|
16383
|
-
import * as
|
|
16617
|
+
import * as path35 from "node:path";
|
|
16384
16618
|
import chalk3 from "chalk";
|
|
16385
16619
|
function devSessionsDir() {
|
|
16386
|
-
return
|
|
16620
|
+
return path35.join(os9.tmpdir(), "mesh-dev-sessions");
|
|
16387
16621
|
}
|
|
16388
16622
|
function listDevSessions(dir = devSessionsDir()) {
|
|
16389
|
-
if (!
|
|
16623
|
+
if (!fs28.existsSync(dir)) return [];
|
|
16390
16624
|
const sessions = [];
|
|
16391
|
-
for (const entry of
|
|
16625
|
+
for (const entry of fs28.readdirSync(dir)) {
|
|
16392
16626
|
if (!entry.endsWith(".json")) continue;
|
|
16393
16627
|
try {
|
|
16394
16628
|
const state = JSON.parse(
|
|
16395
|
-
|
|
16629
|
+
fs28.readFileSync(path35.join(dir, entry), "utf-8")
|
|
16396
16630
|
);
|
|
16397
16631
|
if (state && typeof state === "object" && state.devOutput) {
|
|
16398
16632
|
sessions.push({ name: entry.slice(0, -".json".length), state });
|
|
@@ -16420,8 +16654,8 @@ function pickDevSession(sessions, opts) {
|
|
|
16420
16654
|
);
|
|
16421
16655
|
}
|
|
16422
16656
|
if (opts.cwdAppRoot) {
|
|
16423
|
-
const root =
|
|
16424
|
-
const match = sessions.find((s) =>
|
|
16657
|
+
const root = path35.resolve(opts.cwdAppRoot);
|
|
16658
|
+
const match = sessions.find((s) => path35.resolve(s.state.appRoot) === root);
|
|
16425
16659
|
if (match) return match;
|
|
16426
16660
|
}
|
|
16427
16661
|
if (sessions.length === 1) return sessions[0];
|
|
@@ -16442,7 +16676,7 @@ function parseTmuxEnv(output) {
|
|
|
16442
16676
|
}
|
|
16443
16677
|
function readTmuxSessionEnv(sessionName) {
|
|
16444
16678
|
try {
|
|
16445
|
-
const out =
|
|
16679
|
+
const out = execFileSync24("tmux", ["show-environment", "-t", sessionName], {
|
|
16446
16680
|
encoding: "utf-8",
|
|
16447
16681
|
stdio: ["ignore", "pipe", "ignore"]
|
|
16448
16682
|
});
|
|
@@ -16453,7 +16687,7 @@ function readTmuxSessionEnv(sessionName) {
|
|
|
16453
16687
|
}
|
|
16454
16688
|
function tmuxSessionExists(sessionName) {
|
|
16455
16689
|
try {
|
|
16456
|
-
|
|
16690
|
+
execFileSync24("tmux", ["has-session", "-t", sessionName], { stdio: "ignore" });
|
|
16457
16691
|
return true;
|
|
16458
16692
|
} catch {
|
|
16459
16693
|
return false;
|
|
@@ -16539,11 +16773,11 @@ function assembleHubEnv(session, sessionEnv, opts) {
|
|
|
16539
16773
|
return { apiEnv, uiEnv, scope: { hubTenant, scopeEnv, scopeTenants }, temporalAddress, warnings, notes };
|
|
16540
16774
|
}
|
|
16541
16775
|
function isPlatformRoot(dir) {
|
|
16542
|
-
return
|
|
16776
|
+
return fs28.existsSync(path35.join(dir, "apps", "hub", "api", "package.json")) && fs28.existsSync(path35.join(dir, "apps", "hub", "ui", "package.json"));
|
|
16543
16777
|
}
|
|
16544
16778
|
function resolvePlatformDir(explicit, cwd, env = process.env) {
|
|
16545
16779
|
if (explicit) {
|
|
16546
|
-
const resolved =
|
|
16780
|
+
const resolved = path35.resolve(explicit);
|
|
16547
16781
|
if (isPlatformRoot(resolved)) return resolved;
|
|
16548
16782
|
throw new MeshCliError(
|
|
16549
16783
|
`'${resolved}' is not a mesh-platform checkout (apps/hub/{api,ui} not found).`,
|
|
@@ -16551,16 +16785,16 @@ function resolvePlatformDir(explicit, cwd, env = process.env) {
|
|
|
16551
16785
|
);
|
|
16552
16786
|
}
|
|
16553
16787
|
if (env.MESH_PLATFORM_DIR) {
|
|
16554
|
-
const resolved =
|
|
16788
|
+
const resolved = path35.resolve(env.MESH_PLATFORM_DIR);
|
|
16555
16789
|
if (isPlatformRoot(resolved)) return resolved;
|
|
16556
16790
|
logWarn(
|
|
16557
16791
|
`MESH_PLATFORM_DIR='${resolved}' is not a mesh-platform checkout (apps/hub/{api,ui} not found) \u2014 ignoring it.`
|
|
16558
16792
|
);
|
|
16559
16793
|
}
|
|
16560
|
-
let dir =
|
|
16794
|
+
let dir = path35.resolve(cwd);
|
|
16561
16795
|
for (; ; ) {
|
|
16562
16796
|
if (isPlatformRoot(dir)) return dir;
|
|
16563
|
-
const parent =
|
|
16797
|
+
const parent = path35.dirname(dir);
|
|
16564
16798
|
if (parent === dir) break;
|
|
16565
16799
|
dir = parent;
|
|
16566
16800
|
}
|
|
@@ -16599,7 +16833,7 @@ function isPortListening2(port) {
|
|
|
16599
16833
|
});
|
|
16600
16834
|
}
|
|
16601
16835
|
function hubEnvDir() {
|
|
16602
|
-
return
|
|
16836
|
+
return path35.join(os9.tmpdir(), "mesh-dev-sessions", HUB_SESSION);
|
|
16603
16837
|
}
|
|
16604
16838
|
function parsePort(raw, fallback, source) {
|
|
16605
16839
|
if (raw === void 0) return fallback;
|
|
@@ -16622,8 +16856,8 @@ function redactEnv(env) {
|
|
|
16622
16856
|
async function hubDevAction(opts) {
|
|
16623
16857
|
if (opts.kill) {
|
|
16624
16858
|
if (tmuxSessionExists(HUB_SESSION)) {
|
|
16625
|
-
|
|
16626
|
-
|
|
16859
|
+
execFileSync24("tmux", ["kill-session", "-t", HUB_SESSION], { stdio: "ignore" });
|
|
16860
|
+
fs28.rmSync(hubEnvDir(), { recursive: true, force: true });
|
|
16627
16861
|
logSuccess(`Killed Hub session '${HUB_SESSION}'.`);
|
|
16628
16862
|
} else {
|
|
16629
16863
|
logInfo(`No '${HUB_SESSION}' tmux session running.`);
|
|
@@ -16674,19 +16908,19 @@ async function hubDevAction(opts) {
|
|
|
16674
16908
|
logInfo(`Temporal : ${assembled.temporalAddress}`);
|
|
16675
16909
|
for (const note of assembled.notes) logInfo(note);
|
|
16676
16910
|
for (const warning of assembled.warnings) logWarn(warning);
|
|
16677
|
-
const apiDir =
|
|
16678
|
-
const uiDir =
|
|
16679
|
-
|
|
16911
|
+
const apiDir = path35.join(platformDir, "apps", "hub", "api");
|
|
16912
|
+
const uiDir = path35.join(platformDir, "apps", "hub", "ui");
|
|
16913
|
+
execFileSync24("tmux", ["new-session", "-d", "-s", HUB_SESSION, "-n", "api", "-c", apiDir]);
|
|
16680
16914
|
if (!assembled.apiEnv.DEV_USER_TOKEN_URL && assembled.apiEnv.DEV_USER_ID_TOKEN) {
|
|
16681
16915
|
const platform = session.state.devOutput.platform;
|
|
16682
16916
|
const credContext = `mesh.${platform.env}`;
|
|
16683
16917
|
const tokenPort = await findFreePort4();
|
|
16684
16918
|
const tokenUrl = `http://127.0.0.1:${tokenPort}`;
|
|
16685
|
-
|
|
16686
|
-
|
|
16919
|
+
execFileSync24("tmux", ["new-window", "-t", HUB_SESSION, "-n", "token-server", "-c", platformDir]);
|
|
16920
|
+
execFileSync24("tmux", ["set-option", "-t", `${HUB_SESSION}:token-server`, "remain-on-exit", "on"], {
|
|
16687
16921
|
stdio: "ignore"
|
|
16688
16922
|
});
|
|
16689
|
-
|
|
16923
|
+
execFileSync24("tmux", [
|
|
16690
16924
|
"send-keys",
|
|
16691
16925
|
"-t",
|
|
16692
16926
|
`${HUB_SESSION}:token-server`,
|
|
@@ -16701,15 +16935,15 @@ async function hubDevAction(opts) {
|
|
|
16701
16935
|
logSuccess(`Dev-user token-server: ${tokenUrl} (context ${credContext})`);
|
|
16702
16936
|
}
|
|
16703
16937
|
const launch = (window, dir, env, cmd, createWindow) => {
|
|
16704
|
-
const envFile =
|
|
16938
|
+
const envFile = path35.join(hubEnvDir(), `${window}.env.sh`);
|
|
16705
16939
|
writeEnvFile(envFile, env);
|
|
16706
16940
|
if (createWindow) {
|
|
16707
|
-
|
|
16941
|
+
execFileSync24("tmux", ["new-window", "-t", HUB_SESSION, "-n", window, "-c", dir]);
|
|
16708
16942
|
}
|
|
16709
|
-
|
|
16943
|
+
execFileSync24("tmux", ["set-option", "-t", `${HUB_SESSION}:${window}`, "remain-on-exit", "on"], {
|
|
16710
16944
|
stdio: "ignore"
|
|
16711
16945
|
});
|
|
16712
|
-
|
|
16946
|
+
execFileSync24("tmux", ["send-keys", "-t", `${HUB_SESSION}:${window}`, buildLaunchCommand(envFile, dir, cmd), "Enter"]);
|
|
16713
16947
|
};
|
|
16714
16948
|
launch("api", apiDir, assembled.apiEnv, "pnpm dev", false);
|
|
16715
16949
|
launch("ui", uiDir, assembled.uiEnv, `pnpm dev --port ${uiPort} --strictPort`, true);
|
|
@@ -16807,9 +17041,9 @@ __export(platform_setup_exports, {
|
|
|
16807
17041
|
validateRegion: () => validateRegion,
|
|
16808
17042
|
validateStateBucket: () => validateStateBucket
|
|
16809
17043
|
});
|
|
16810
|
-
import * as
|
|
16811
|
-
import * as
|
|
16812
|
-
import { execFileSync as
|
|
17044
|
+
import * as fs29 from "fs";
|
|
17045
|
+
import * as path36 from "path";
|
|
17046
|
+
import { execFileSync as execFileSync25 } from "child_process";
|
|
16813
17047
|
function defaultStateBucket(tenant) {
|
|
16814
17048
|
return `${tenant}-mesh-platform-pulumi-state`;
|
|
16815
17049
|
}
|
|
@@ -16838,8 +17072,8 @@ function validateStateBucket(value) {
|
|
|
16838
17072
|
return /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test(bucket) && !bucket.includes("..") ? true : "3\u201363 characters: lowercase letters, digits, dots and dashes, starting and ending alphanumeric";
|
|
16839
17073
|
}
|
|
16840
17074
|
function resolveTargetDir(tenant, flags, cwd) {
|
|
16841
|
-
const dir =
|
|
16842
|
-
if (
|
|
17075
|
+
const dir = path36.resolve(cwd, flags.dir ?? defaultPlatformDir(tenant));
|
|
17076
|
+
if (fs29.existsSync(dir) && fs29.readdirSync(dir).length > 0) {
|
|
16843
17077
|
throw new MeshCliError(`Target directory is not empty: ${dir}`, {
|
|
16844
17078
|
remediation: { command: `mesh init platform ${tenant} --dir <empty-dir>` }
|
|
16845
17079
|
});
|
|
@@ -16893,7 +17127,7 @@ function stateBucketCreateCommand(setup) {
|
|
|
16893
17127
|
return `aws s3api create-bucket --bucket ${setup.stateBucket} --region ${setup.region}${location} --profile ${setup.profile}`;
|
|
16894
17128
|
}
|
|
16895
17129
|
function awsJson(args, profile) {
|
|
16896
|
-
return
|
|
17130
|
+
return execFileSync25("aws", [...args, "--profile", profile], {
|
|
16897
17131
|
encoding: "utf8",
|
|
16898
17132
|
stdio: ["ignore", "pipe", "pipe"]
|
|
16899
17133
|
});
|
|
@@ -16953,7 +17187,7 @@ function renderPlatformNextSteps(setup, opts = {}) {
|
|
|
16953
17187
|
return steps;
|
|
16954
17188
|
}
|
|
16955
17189
|
async function scaffoldPlatformRepo(setup) {
|
|
16956
|
-
if (
|
|
17190
|
+
if (fs29.existsSync(setup.dir) && fs29.readdirSync(setup.dir).length > 0) {
|
|
16957
17191
|
throw new MeshCliError(`Target directory is not empty: ${setup.dir}`, {
|
|
16958
17192
|
remediation: { command: `mesh init platform ${setup.tenant} --dir <empty-dir>` }
|
|
16959
17193
|
});
|
|
@@ -16961,8 +17195,8 @@ async function scaffoldPlatformRepo(setup) {
|
|
|
16961
17195
|
const { copyTemplate: copyTemplate2 } = await Promise.resolve().then(() => (init_create_app(), create_app_exports));
|
|
16962
17196
|
const { findPackageRoot: findPackageRoot2 } = await Promise.resolve().then(() => (init_stack(), stack_exports));
|
|
16963
17197
|
const { syncSkills: syncSkills2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
|
|
16964
|
-
const templateDir =
|
|
16965
|
-
|
|
17198
|
+
const templateDir = path36.join(findPackageRoot2(), "templates", "platform-repo");
|
|
17199
|
+
fs29.mkdirSync(setup.dir, { recursive: true });
|
|
16966
17200
|
copyTemplate2(templateDir, setup.dir, {
|
|
16967
17201
|
tenant: setup.tenant,
|
|
16968
17202
|
env: setup.env,
|
|
@@ -17009,9 +17243,9 @@ var init_platform_setup = __esm({
|
|
|
17009
17243
|
});
|
|
17010
17244
|
|
|
17011
17245
|
// libs/mesh-cli/src/commands/registry-publish.ts
|
|
17012
|
-
import { execFileSync as
|
|
17013
|
-
import * as
|
|
17014
|
-
import * as
|
|
17246
|
+
import { execFileSync as execFileSync26, execSync } from "child_process";
|
|
17247
|
+
import * as fs30 from "fs";
|
|
17248
|
+
import * as path37 from "path";
|
|
17015
17249
|
function repoRoot() {
|
|
17016
17250
|
return execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
17017
17251
|
}
|
|
@@ -17021,9 +17255,9 @@ function computeSnapshotVersion(root) {
|
|
|
17021
17255
|
return `0.0.0-dev.${stamp}.${sha}`;
|
|
17022
17256
|
}
|
|
17023
17257
|
function setPackageVersion(file, version) {
|
|
17024
|
-
const content =
|
|
17258
|
+
const content = fs30.readFileSync(file, "utf-8");
|
|
17025
17259
|
const next = content.replace(/"version"(\s*:\s*)"[^"]*"/, `"version"$1"${version}"`);
|
|
17026
|
-
|
|
17260
|
+
fs30.writeFileSync(file, next);
|
|
17027
17261
|
}
|
|
17028
17262
|
function dirtyPackageJsons(root) {
|
|
17029
17263
|
const out = execSync("git diff --name-only", { cwd: root, encoding: "utf-8" });
|
|
@@ -17056,8 +17290,8 @@ function registerRegistryPublish(registry) {
|
|
|
17056
17290
|
logError("CodeArtifact login failed. Run: mesh registry login <context>");
|
|
17057
17291
|
process.exit(1);
|
|
17058
17292
|
}
|
|
17059
|
-
const listPath =
|
|
17060
|
-
const all = JSON.parse(
|
|
17293
|
+
const listPath = path37.join(root, "scripts/lib/publishable-packages.json");
|
|
17294
|
+
const all = JSON.parse(fs30.readFileSync(listPath, "utf-8"));
|
|
17061
17295
|
const patterns = (opts.only ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
17062
17296
|
const selected = patterns.length ? all.filter((p) => patterns.some((pat) => p.dir.includes(pat) || p.name.includes(pat))) : all;
|
|
17063
17297
|
if (selected.length === 0) {
|
|
@@ -17069,16 +17303,16 @@ function registerRegistryPublish(registry) {
|
|
|
17069
17303
|
const preDirty = dirtyPackageJsons(root);
|
|
17070
17304
|
const backups = [];
|
|
17071
17305
|
const stamp = (dir) => {
|
|
17072
|
-
const file =
|
|
17073
|
-
if (!
|
|
17074
|
-
backups.push({ file, content:
|
|
17306
|
+
const file = path37.join(root, dir, "package.json");
|
|
17307
|
+
if (!fs30.existsSync(file)) return;
|
|
17308
|
+
backups.push({ file, content: fs30.readFileSync(file, "utf-8") });
|
|
17075
17309
|
setPackageVersion(file, version);
|
|
17076
17310
|
};
|
|
17077
17311
|
try {
|
|
17078
17312
|
for (const p of selected) {
|
|
17079
17313
|
stamp(p.dir);
|
|
17080
17314
|
for (const sub of p.subPackages ?? []) {
|
|
17081
|
-
stamp(
|
|
17315
|
+
stamp(path37.join(p.dir, typeof sub === "string" ? sub : sub.dir));
|
|
17082
17316
|
}
|
|
17083
17317
|
}
|
|
17084
17318
|
const args = [
|
|
@@ -17093,14 +17327,14 @@ function registerRegistryPublish(registry) {
|
|
|
17093
17327
|
...opts.dryRun ? ["--dry-run"] : []
|
|
17094
17328
|
];
|
|
17095
17329
|
logInfo(`Publishing ${selected.length} package(s)...`);
|
|
17096
|
-
|
|
17330
|
+
execFileSync26("bash", args, { cwd: root, stdio: "inherit", env: env ?? process.env });
|
|
17097
17331
|
} finally {
|
|
17098
|
-
for (const b of backups)
|
|
17332
|
+
for (const b of backups) fs30.writeFileSync(b.file, b.content);
|
|
17099
17333
|
logInfo("Restored source package.json versions.");
|
|
17100
17334
|
const collateral = [...dirtyPackageJsons(root)].filter((f) => !preDirty.has(f));
|
|
17101
17335
|
if (collateral.length) {
|
|
17102
17336
|
try {
|
|
17103
|
-
|
|
17337
|
+
execFileSync26("git", ["checkout", "--", ...collateral], { cwd: root, stdio: "inherit" });
|
|
17104
17338
|
logInfo(`Reverted ${collateral.length} package.json file(s) re-vendored by build:publish.`);
|
|
17105
17339
|
} catch {
|
|
17106
17340
|
logError(
|
|
@@ -17152,12 +17386,12 @@ __export(registry_exports, {
|
|
|
17152
17386
|
shouldRemintAfter: () => shouldRemintAfter,
|
|
17153
17387
|
shouldRepairUserNpmrc: () => shouldRepairUserNpmrc
|
|
17154
17388
|
});
|
|
17155
|
-
import { execFileSync as
|
|
17156
|
-
import * as
|
|
17157
|
-
import * as
|
|
17389
|
+
import { execFileSync as execFileSync27 } from "child_process";
|
|
17390
|
+
import * as fs31 from "fs";
|
|
17391
|
+
import * as path38 from "path";
|
|
17158
17392
|
function getEndpoint(env) {
|
|
17159
17393
|
try {
|
|
17160
|
-
const result =
|
|
17394
|
+
const result = execFileSync27("aws", [
|
|
17161
17395
|
"codeartifact",
|
|
17162
17396
|
"get-repository-endpoint",
|
|
17163
17397
|
"--domain",
|
|
@@ -17184,7 +17418,7 @@ function getEndpoint(env) {
|
|
|
17184
17418
|
}
|
|
17185
17419
|
function codeartifactLogin(env) {
|
|
17186
17420
|
try {
|
|
17187
|
-
|
|
17421
|
+
execFileSync27("aws", [
|
|
17188
17422
|
"codeartifact",
|
|
17189
17423
|
"login",
|
|
17190
17424
|
"--tool",
|
|
@@ -17239,7 +17473,7 @@ function resolvePublisherRoleArn({
|
|
|
17239
17473
|
}
|
|
17240
17474
|
function assumeRole2(roleArn) {
|
|
17241
17475
|
try {
|
|
17242
|
-
const result =
|
|
17476
|
+
const result = execFileSync27("aws", [
|
|
17243
17477
|
"sts",
|
|
17244
17478
|
"assume-role",
|
|
17245
17479
|
"--role-arn",
|
|
@@ -17261,7 +17495,7 @@ function assumeRole2(roleArn) {
|
|
|
17261
17495
|
}
|
|
17262
17496
|
function assumeRoleWithWebIdentity2(roleArn, idToken, sessionName) {
|
|
17263
17497
|
try {
|
|
17264
|
-
const result =
|
|
17498
|
+
const result = execFileSync27("aws", [
|
|
17265
17499
|
"sts",
|
|
17266
17500
|
"assume-role-with-web-identity",
|
|
17267
17501
|
"--role-arn",
|
|
@@ -17325,50 +17559,50 @@ function resolveCredentials(context, roleArn) {
|
|
|
17325
17559
|
function findProjectRoot2() {
|
|
17326
17560
|
let dir = process.cwd();
|
|
17327
17561
|
while (true) {
|
|
17328
|
-
if (
|
|
17562
|
+
if (fs31.existsSync(path38.join(dir, "pnpm-workspace.yaml")) || fs31.existsSync(path38.join(dir, "pnpm-lock.yaml")) || fs31.existsSync(path38.join(dir, "Pulumi.yaml")) || fs31.existsSync(path38.join(dir, ".npmrc"))) {
|
|
17329
17563
|
return dir;
|
|
17330
17564
|
}
|
|
17331
|
-
const parent =
|
|
17565
|
+
const parent = path38.dirname(dir);
|
|
17332
17566
|
if (parent === dir) return null;
|
|
17333
17567
|
dir = parent;
|
|
17334
17568
|
}
|
|
17335
17569
|
}
|
|
17336
17570
|
function ensureProjectNpmrc(endpoint) {
|
|
17337
17571
|
const projectRoot = findProjectRoot2() ?? process.cwd();
|
|
17338
|
-
const npmrcPath2 =
|
|
17572
|
+
const npmrcPath2 = path38.join(projectRoot, ".npmrc");
|
|
17339
17573
|
const scopeLine = `${CA_NAMESPACE}:registry=${endpoint}`;
|
|
17340
|
-
if (!
|
|
17341
|
-
|
|
17574
|
+
if (!fs31.existsSync(npmrcPath2)) {
|
|
17575
|
+
fs31.writeFileSync(npmrcPath2, scopeLine + "\n", "utf-8");
|
|
17342
17576
|
return { created: true, updated: false, path: npmrcPath2 };
|
|
17343
17577
|
}
|
|
17344
|
-
const content =
|
|
17578
|
+
const content = fs31.readFileSync(npmrcPath2, "utf-8");
|
|
17345
17579
|
const scopeRegex = new RegExp(`^${CA_NAMESPACE.replace("/", "\\/")}:registry=.+$`, "m");
|
|
17346
17580
|
if (scopeRegex.test(content)) {
|
|
17347
17581
|
if (content.includes(scopeLine)) {
|
|
17348
17582
|
return { created: false, updated: false, path: npmrcPath2 };
|
|
17349
17583
|
}
|
|
17350
17584
|
const updated = content.replace(scopeRegex, scopeLine);
|
|
17351
|
-
|
|
17585
|
+
fs31.writeFileSync(npmrcPath2, updated, "utf-8");
|
|
17352
17586
|
return { created: false, updated: true, path: npmrcPath2 };
|
|
17353
17587
|
}
|
|
17354
17588
|
const separator = content.endsWith("\n") ? "" : "\n";
|
|
17355
|
-
|
|
17589
|
+
fs31.writeFileSync(npmrcPath2, content + separator + scopeLine + "\n", "utf-8");
|
|
17356
17590
|
return { created: false, updated: true, path: npmrcPath2 };
|
|
17357
17591
|
}
|
|
17358
17592
|
function applyGrantToUserNpmrc(grant, npmrcPath2 = homeNpmrcPath()) {
|
|
17359
17593
|
let existing = "";
|
|
17360
17594
|
try {
|
|
17361
|
-
existing =
|
|
17595
|
+
existing = fs31.readFileSync(npmrcPath2, "utf-8");
|
|
17362
17596
|
} catch {
|
|
17363
17597
|
}
|
|
17364
17598
|
const content = upsertNpmrcLines(existing, [
|
|
17365
17599
|
{ key: `${grant.scope}:registry`, value: grant.endpoint },
|
|
17366
17600
|
{ key: `${npmrcAuthKeyForEndpoint(grant.endpoint)}:_authToken`, value: grant.authorizationToken }
|
|
17367
17601
|
]);
|
|
17368
|
-
|
|
17369
|
-
|
|
17602
|
+
fs31.mkdirSync(path38.dirname(npmrcPath2), { recursive: true });
|
|
17603
|
+
fs31.writeFileSync(npmrcPath2, content, { mode: 384 });
|
|
17370
17604
|
try {
|
|
17371
|
-
|
|
17605
|
+
fs31.chmodSync(npmrcPath2, 384);
|
|
17372
17606
|
} catch {
|
|
17373
17607
|
}
|
|
17374
17608
|
return { path: npmrcPath2 };
|
|
@@ -17491,7 +17725,7 @@ function shouldRepairUserNpmrc(opts) {
|
|
|
17491
17725
|
function repairUnscopedRegistry(npmrcPath2 = homeNpmrcPath()) {
|
|
17492
17726
|
let original;
|
|
17493
17727
|
try {
|
|
17494
|
-
original =
|
|
17728
|
+
original = fs31.readFileSync(npmrcPath2, "utf-8");
|
|
17495
17729
|
} catch {
|
|
17496
17730
|
return { removed: null };
|
|
17497
17731
|
}
|
|
@@ -17499,8 +17733,8 @@ function repairUnscopedRegistry(npmrcPath2 = homeNpmrcPath()) {
|
|
|
17499
17733
|
if (!removed) return { removed: null };
|
|
17500
17734
|
const backupPath = `${npmrcPath2}.bak-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
17501
17735
|
try {
|
|
17502
|
-
|
|
17503
|
-
|
|
17736
|
+
fs31.writeFileSync(backupPath, original, "utf-8");
|
|
17737
|
+
fs31.writeFileSync(npmrcPath2, content, "utf-8");
|
|
17504
17738
|
} catch (err) {
|
|
17505
17739
|
return { removed: null, error: err instanceof Error ? err.message : String(err) };
|
|
17506
17740
|
}
|
|
@@ -17512,9 +17746,9 @@ function renderRegistrySessionLine(session, now = Date.now()) {
|
|
|
17512
17746
|
}
|
|
17513
17747
|
async function checkExistingToken() {
|
|
17514
17748
|
const npmrcPath2 = homeNpmrcPath();
|
|
17515
|
-
if (!
|
|
17749
|
+
if (!fs31.existsSync(npmrcPath2)) return { valid: false, state: "missing", reason: "no ~/.npmrc" };
|
|
17516
17750
|
const hijackLine = findUnscopedCodeArtifactRegistry(
|
|
17517
|
-
|
|
17751
|
+
fs31.readFileSync(npmrcPath2, "utf-8")
|
|
17518
17752
|
) ?? void 0;
|
|
17519
17753
|
const probe = await probeRegistryToken({ npmrcPath: npmrcPath2 });
|
|
17520
17754
|
if (probe.state === "missing") {
|
|
@@ -17567,9 +17801,9 @@ async function runRegistryStatus(opts) {
|
|
|
17567
17801
|
logInfo(renderRegistrySessionLine(opts?.session ?? readRegistrySession()));
|
|
17568
17802
|
const projectRoot = findProjectRoot2();
|
|
17569
17803
|
if (projectRoot) {
|
|
17570
|
-
const npmrcPath2 =
|
|
17571
|
-
if (
|
|
17572
|
-
const content =
|
|
17804
|
+
const npmrcPath2 = path38.join(projectRoot, ".npmrc");
|
|
17805
|
+
if (fs31.existsSync(npmrcPath2)) {
|
|
17806
|
+
const content = fs31.readFileSync(npmrcPath2, "utf-8");
|
|
17573
17807
|
if (content.includes(`${CA_NAMESPACE}:registry=`)) {
|
|
17574
17808
|
logSuccess(`Project .npmrc configured (${npmrcPath2})`);
|
|
17575
17809
|
} else {
|
|
@@ -17603,7 +17837,7 @@ region = us-east-2`,
|
|
|
17603
17837
|
{ remediation: { command: `aws configure sso --profile ${profile}` } }
|
|
17604
17838
|
);
|
|
17605
17839
|
}
|
|
17606
|
-
const probe = () =>
|
|
17840
|
+
const probe = () => execFileSync27("aws", ["sts", "get-caller-identity", "--profile", profile], {
|
|
17607
17841
|
stdio: ["ignore", "pipe", "pipe"],
|
|
17608
17842
|
timeout: 2e4
|
|
17609
17843
|
});
|
|
@@ -17614,7 +17848,7 @@ region = us-east-2`,
|
|
|
17614
17848
|
} catch {
|
|
17615
17849
|
logInfo(`AWS SSO session for profile '${profile}' is stale \u2014 opening browser login\u2026`);
|
|
17616
17850
|
}
|
|
17617
|
-
|
|
17851
|
+
execFileSync27("aws", ["sso", "login", "--profile", profile], { stdio: "inherit" });
|
|
17618
17852
|
try {
|
|
17619
17853
|
probe();
|
|
17620
17854
|
} catch (err) {
|
|
@@ -17850,9 +18084,9 @@ __export(wizard_exports, {
|
|
|
17850
18084
|
wizardExitCode: () => wizardExitCode,
|
|
17851
18085
|
wizardNextCommands: () => wizardNextCommands
|
|
17852
18086
|
});
|
|
17853
|
-
import * as
|
|
17854
|
-
import * as
|
|
17855
|
-
import { execFileSync as
|
|
18087
|
+
import * as fs32 from "fs";
|
|
18088
|
+
import * as path39 from "path";
|
|
18089
|
+
import { execFileSync as execFileSync28 } from "child_process";
|
|
17856
18090
|
import chalk4 from "chalk";
|
|
17857
18091
|
function isNewPlatform(mode) {
|
|
17858
18092
|
return typeof mode === "object" && "newPlatform" in mode;
|
|
@@ -17929,18 +18163,18 @@ function classifyRepo(cwd) {
|
|
|
17929
18163
|
if (isInsidePlatformMonorepo(cwd)) return { kind: "platform-monorepo", root: resolveTargetRoot(cwd) };
|
|
17930
18164
|
if (shouldBootstrapAppsRepo(cwd)) return { kind: "empty-apps-repo", root: cwd };
|
|
17931
18165
|
const root = resolveTargetRoot(cwd);
|
|
17932
|
-
const inRepo =
|
|
18166
|
+
const inRepo = fs32.existsSync(path39.join(root, ".git"));
|
|
17933
18167
|
if (!inRepo) {
|
|
17934
|
-
const hasContent =
|
|
18168
|
+
const hasContent = fs32.readdirSync(cwd).some((entry) => !entry.startsWith("."));
|
|
17935
18169
|
return { kind: hasContent ? "no-repo" : "empty-dir", root: cwd };
|
|
17936
18170
|
}
|
|
17937
|
-
const hasWorkspace =
|
|
17938
|
-
const hasApps =
|
|
18171
|
+
const hasWorkspace = fs32.existsSync(path39.join(root, "pnpm-workspace.yaml")) || fs32.existsSync(path39.join(root, "pnpm-lock.yaml"));
|
|
18172
|
+
const hasApps = fs32.existsSync(path39.join(root, "apps")) || fs32.existsSync(path39.join(root, "tenants"));
|
|
17939
18173
|
if (hasWorkspace || hasApps) return { kind: "apps-repo", root };
|
|
17940
18174
|
return { kind: "other-repo", root };
|
|
17941
18175
|
}
|
|
17942
18176
|
function gitInit(dir) {
|
|
17943
|
-
|
|
18177
|
+
execFileSync28("git", ["init", "-q"], { cwd: dir, stdio: ["ignore", "ignore", "pipe"] });
|
|
17944
18178
|
}
|
|
17945
18179
|
async function runWizardSteps(ctx, steps) {
|
|
17946
18180
|
const results = [];
|
|
@@ -18161,7 +18395,7 @@ var init_wizard = __esm({
|
|
|
18161
18395
|
return { name, status: "fail", detail: `platform repo not scaffolded: ${err.message.split("\n")[0]}`, fix: `mesh init platform ${ctx.tenant} --dir <empty-dir>` };
|
|
18162
18396
|
}
|
|
18163
18397
|
const bucket = await ensureStateBucket(setup, ctx.seams?.stateBucket);
|
|
18164
|
-
const next = renderPlatformNextSteps(setup, { bucket, relativeDir:
|
|
18398
|
+
const next = renderPlatformNextSteps(setup, { bucket, relativeDir: path39.relative(ctx.cwd, setup.dir) || "." });
|
|
18165
18399
|
return {
|
|
18166
18400
|
name,
|
|
18167
18401
|
status: setup.createStateBucket && !bucket.present ? "warn" : "pass",
|
|
@@ -18259,8 +18493,8 @@ var init_wizard = __esm({
|
|
|
18259
18493
|
}
|
|
18260
18494
|
case "apps-repo": {
|
|
18261
18495
|
const missing = [];
|
|
18262
|
-
if (!
|
|
18263
|
-
if (!
|
|
18496
|
+
if (!fs32.existsSync(path39.join(root, "package.json"))) missing.push("package.json");
|
|
18497
|
+
if (!fs32.existsSync(path39.join(root, "pnpm-workspace.yaml")) && !fs32.existsSync(path39.join(root, "pnpm-lock.yaml"))) {
|
|
18264
18498
|
missing.push("pnpm-workspace.yaml");
|
|
18265
18499
|
}
|
|
18266
18500
|
if (missing.length) {
|
|
@@ -18297,8 +18531,8 @@ var init_wizard = __esm({
|
|
|
18297
18531
|
|
|
18298
18532
|
// libs/mesh-cli/src/commands/init.ts
|
|
18299
18533
|
import chalk5 from "chalk";
|
|
18300
|
-
import * as
|
|
18301
|
-
import * as
|
|
18534
|
+
import * as fs33 from "fs";
|
|
18535
|
+
import * as path40 from "path";
|
|
18302
18536
|
async function setupPrompts() {
|
|
18303
18537
|
const [{ default: input2 }, { default: confirm }] = await Promise.all([
|
|
18304
18538
|
import("@inquirer/input"),
|
|
@@ -18324,7 +18558,7 @@ async function probeHubTenants(hubUrl, accessToken) {
|
|
|
18324
18558
|
}
|
|
18325
18559
|
function readHomeNpmrc() {
|
|
18326
18560
|
try {
|
|
18327
|
-
return
|
|
18561
|
+
return fs33.readFileSync(homeNpmrcPath(), "utf-8");
|
|
18328
18562
|
} catch {
|
|
18329
18563
|
return "";
|
|
18330
18564
|
}
|
|
@@ -18448,9 +18682,9 @@ async function runChecks2(args) {
|
|
|
18448
18682
|
if (local) {
|
|
18449
18683
|
checks.push({ name: "Deployer role", status: "pass", detail: "local context \u2014 no deployer role required" });
|
|
18450
18684
|
} else {
|
|
18451
|
-
const stackFiles =
|
|
18685
|
+
const stackFiles = fs33.existsSync(root) ? fs33.readdirSync(root).filter((f) => /^Pulumi\..*\.yaml$/.test(f)) : [];
|
|
18452
18686
|
const hasRole = stackFiles.some(
|
|
18453
|
-
(f) => /mesh:deployerRole/.test(
|
|
18687
|
+
(f) => /mesh:deployerRole/.test(fs33.readFileSync(path40.join(root, f), "utf-8"))
|
|
18454
18688
|
);
|
|
18455
18689
|
checks.push(
|
|
18456
18690
|
hasRole ? { name: "Deployer role", status: "pass", detail: "mesh:deployerRole configured in stack config" } : {
|
|
@@ -18462,8 +18696,8 @@ async function runChecks2(args) {
|
|
|
18462
18696
|
);
|
|
18463
18697
|
}
|
|
18464
18698
|
const shapeProblems = [];
|
|
18465
|
-
if (!
|
|
18466
|
-
const hasWorkspace =
|
|
18699
|
+
if (!fs33.existsSync(path40.join(root, "package.json"))) shapeProblems.push("package.json");
|
|
18700
|
+
const hasWorkspace = fs33.existsSync(path40.join(root, "pnpm-workspace.yaml")) || fs33.existsSync(path40.join(root, "pnpm-lock.yaml"));
|
|
18467
18701
|
if (!hasWorkspace) shapeProblems.push("pnpm-workspace.yaml");
|
|
18468
18702
|
checks.push(
|
|
18469
18703
|
shapeProblems.length === 0 ? { name: "Repo shape", status: "pass", detail: "pnpm workspace layout present" } : {
|
|
@@ -18519,7 +18753,7 @@ function registerInitCommands(program2) {
|
|
|
18519
18753
|
if (bucket.detail !== "not requested") logInfo(`Pulumi state bucket: ${bucket.detail}`);
|
|
18520
18754
|
console.log("");
|
|
18521
18755
|
console.log("Next steps:");
|
|
18522
|
-
for (const line of renderPlatformNextSteps2(setup, { bucket, relativeDir:
|
|
18756
|
+
for (const line of renderPlatformNextSteps2(setup, { bucket, relativeDir: path40.relative(process.cwd(), setup.dir) || "." })) {
|
|
18523
18757
|
console.log(line ? ` ${line}` : "");
|
|
18524
18758
|
}
|
|
18525
18759
|
console.log("");
|
|
@@ -18587,10 +18821,10 @@ var init_init = __esm({
|
|
|
18587
18821
|
});
|
|
18588
18822
|
|
|
18589
18823
|
// libs/mesh-cli/src/commands/install-shim.ts
|
|
18590
|
-
import { execFileSync as
|
|
18591
|
-
import * as
|
|
18824
|
+
import { execFileSync as execFileSync29 } from "child_process";
|
|
18825
|
+
import * as fs34 from "fs";
|
|
18592
18826
|
import * as os10 from "os";
|
|
18593
|
-
import * as
|
|
18827
|
+
import * as path41 from "path";
|
|
18594
18828
|
function shimScript() {
|
|
18595
18829
|
return `#!/bin/sh
|
|
18596
18830
|
# mesh \u2014 canonical launcher shim (installed by \`mesh install-shim\`).
|
|
@@ -18663,25 +18897,25 @@ exit 1
|
|
|
18663
18897
|
`;
|
|
18664
18898
|
}
|
|
18665
18899
|
function defaultShimDir() {
|
|
18666
|
-
return
|
|
18900
|
+
return path41.join(os10.homedir(), ".local", "bin");
|
|
18667
18901
|
}
|
|
18668
18902
|
function dirOnPath(dir, pathEnv) {
|
|
18669
18903
|
if (!pathEnv) return false;
|
|
18670
|
-
return pathEnv.split(
|
|
18904
|
+
return pathEnv.split(path41.delimiter).some((p) => p === dir);
|
|
18671
18905
|
}
|
|
18672
18906
|
function registerInstallShimCommand(program2) {
|
|
18673
18907
|
program2.command("install-shim").description("Install a build-free `mesh` shim on your PATH so bare `mesh` runs the local source").option("--dir <dir>", "Directory to install into (must be on your PATH)", defaultShimDir()).option("-f, --force", "Overwrite an existing file at the target path", false).action((opts) => {
|
|
18674
|
-
const dir =
|
|
18675
|
-
const target =
|
|
18676
|
-
if (
|
|
18908
|
+
const dir = path41.resolve(opts.dir);
|
|
18909
|
+
const target = path41.join(dir, "mesh");
|
|
18910
|
+
if (fs34.existsSync(target) && !opts.force) {
|
|
18677
18911
|
logWarn(`A file already exists at ${target}.`);
|
|
18678
18912
|
logInfo("Re-run with --force to overwrite it, or pass --dir <other-path-on-PATH>.");
|
|
18679
18913
|
return;
|
|
18680
18914
|
}
|
|
18681
18915
|
try {
|
|
18682
|
-
|
|
18683
|
-
|
|
18684
|
-
|
|
18916
|
+
fs34.mkdirSync(dir, { recursive: true });
|
|
18917
|
+
fs34.writeFileSync(target, shimScript(), { mode: 493 });
|
|
18918
|
+
fs34.chmodSync(target, 493);
|
|
18685
18919
|
} catch (err) {
|
|
18686
18920
|
logError(`Could not write the shim to ${target}: ${err.message}`);
|
|
18687
18921
|
process.exitCode = 1;
|
|
@@ -18694,13 +18928,13 @@ function registerInstallShimCommand(program2) {
|
|
|
18694
18928
|
} else {
|
|
18695
18929
|
logInfo("Bare `mesh <cmd>` now runs the local source of whatever workspace you're in.");
|
|
18696
18930
|
}
|
|
18697
|
-
const diagPath =
|
|
18931
|
+
const diagPath = path41.join(os10.tmpdir(), "mesh-shim-selftest.log");
|
|
18698
18932
|
let stdout = "";
|
|
18699
18933
|
let stderr = "";
|
|
18700
18934
|
let status = 0;
|
|
18701
18935
|
let ok = true;
|
|
18702
18936
|
try {
|
|
18703
|
-
stdout =
|
|
18937
|
+
stdout = execFileSync29(target, ["--help"], {
|
|
18704
18938
|
cwd: process.cwd(),
|
|
18705
18939
|
encoding: "utf8",
|
|
18706
18940
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -18727,7 +18961,7 @@ function registerInstallShimCommand(program2) {
|
|
|
18727
18961
|
""
|
|
18728
18962
|
].join("\n");
|
|
18729
18963
|
try {
|
|
18730
|
-
|
|
18964
|
+
fs34.writeFileSync(diagPath, diag);
|
|
18731
18965
|
} catch {
|
|
18732
18966
|
}
|
|
18733
18967
|
if (ok && /Commands:|Usage:/.test(stdout)) {
|
|
@@ -18747,17 +18981,17 @@ var init_install_shim = __esm({
|
|
|
18747
18981
|
});
|
|
18748
18982
|
|
|
18749
18983
|
// libs/mesh-cli/src/commands/local/hub-local.ts
|
|
18750
|
-
import { execFile as execFile3, execFileSync as
|
|
18751
|
-
import * as
|
|
18984
|
+
import { execFile as execFile3, execFileSync as execFileSync30 } from "child_process";
|
|
18985
|
+
import * as fs35 from "fs";
|
|
18752
18986
|
import * as os11 from "os";
|
|
18753
|
-
import * as
|
|
18987
|
+
import * as path42 from "path";
|
|
18754
18988
|
import { promisify as promisify2 } from "util";
|
|
18755
18989
|
function cacheDir() {
|
|
18756
18990
|
return meshCacheDir("hub-local");
|
|
18757
18991
|
}
|
|
18758
18992
|
function npmrcPath() {
|
|
18759
|
-
const p =
|
|
18760
|
-
if (!
|
|
18993
|
+
const p = path42.join(os11.homedir(), ".npmrc");
|
|
18994
|
+
if (!fs35.existsSync(p) || !fs35.readFileSync(p, "utf-8").includes("codeartifact")) {
|
|
18761
18995
|
throw new MeshCliError(
|
|
18762
18996
|
"The local Hub builds from the published @mesh-tech/hub tarball, which needs registry auth.",
|
|
18763
18997
|
{ remediation: { command: REGISTRY_LOGIN_FIX } }
|
|
@@ -18767,7 +19001,7 @@ function npmrcPath() {
|
|
|
18767
19001
|
}
|
|
18768
19002
|
function imageExists(tag) {
|
|
18769
19003
|
try {
|
|
18770
|
-
|
|
19004
|
+
execFileSync30("docker", ["image", "inspect", tag], { stdio: ["ignore", "pipe", "pipe"] });
|
|
18771
19005
|
return true;
|
|
18772
19006
|
} catch {
|
|
18773
19007
|
return false;
|
|
@@ -18776,22 +19010,22 @@ function imageExists(tag) {
|
|
|
18776
19010
|
function ensureHubAuthImage() {
|
|
18777
19011
|
if (imageExists(HUB_AUTH_IMAGE)) return;
|
|
18778
19012
|
logInfo(`Building ${HUB_AUTH_IMAGE} (Hub auth proxy)\u2026`);
|
|
18779
|
-
const hubStackDir =
|
|
18780
|
-
|
|
19013
|
+
const hubStackDir = path42.join(findPackageRoot(), "stack", "hub");
|
|
19014
|
+
execFileSync30(
|
|
18781
19015
|
"docker",
|
|
18782
|
-
["build", "-f",
|
|
19016
|
+
["build", "-f", path42.join(hubStackDir, "Dockerfile.auth"), "-t", HUB_AUTH_IMAGE, hubStackDir],
|
|
18783
19017
|
{ stdio: ["ignore", "inherit", "inherit"], env: { ...process.env, DOCKER_BUILDKIT: "1" } }
|
|
18784
19018
|
);
|
|
18785
19019
|
logSuccess(`Built ${HUB_AUTH_IMAGE}`);
|
|
18786
19020
|
}
|
|
18787
19021
|
function hasRegistryAuth() {
|
|
18788
|
-
const p =
|
|
18789
|
-
return
|
|
19022
|
+
const p = path42.join(os11.homedir(), ".npmrc");
|
|
19023
|
+
return fs35.existsSync(p) && fs35.readFileSync(p, "utf-8").includes("codeartifact");
|
|
18790
19024
|
}
|
|
18791
19025
|
function localHubVersion() {
|
|
18792
19026
|
const versions = HUB_IMAGES.map((name) => {
|
|
18793
19027
|
try {
|
|
18794
|
-
const out =
|
|
19028
|
+
const out = execFileSync30("docker", ["images", name, "--format", "{{.Tag}}"], {
|
|
18795
19029
|
encoding: "utf-8",
|
|
18796
19030
|
stdio: ["ignore", "pipe", "pipe"]
|
|
18797
19031
|
});
|
|
@@ -18817,10 +19051,10 @@ async function fetchTarball() {
|
|
|
18817
19051
|
{ encoding: "utf-8" }
|
|
18818
19052
|
);
|
|
18819
19053
|
const info = JSON.parse(stdout)[0];
|
|
18820
|
-
return { tarball:
|
|
19054
|
+
return { tarball: path42.join(dir, info.filename), version: info.version };
|
|
18821
19055
|
} catch (err) {
|
|
18822
19056
|
const authFailure = isNpmAuthError(err);
|
|
18823
|
-
const cached =
|
|
19057
|
+
const cached = fs35.readdirSync(dir).filter((f) => f.startsWith("mesh-tech-hub-") && f.endsWith(".tgz")).sort((a, b) => a.localeCompare(b, void 0, { numeric: true })).at(-1);
|
|
18824
19058
|
if (!cached) {
|
|
18825
19059
|
if (authFailure) {
|
|
18826
19060
|
throw new MeshCliError(
|
|
@@ -18838,7 +19072,7 @@ async function fetchTarball() {
|
|
|
18838
19072
|
} else {
|
|
18839
19073
|
logInfo(`Registry unavailable \u2014 using the cached hub tarball v${version}`);
|
|
18840
19074
|
}
|
|
18841
|
-
return { tarball:
|
|
19075
|
+
return { tarball: path42.join(dir, cached), version };
|
|
18842
19076
|
} finally {
|
|
18843
19077
|
heartbeat.stop();
|
|
18844
19078
|
}
|
|
@@ -18867,13 +19101,13 @@ async function ensureHubImages() {
|
|
|
18867
19101
|
logInfo(`Local Hub images ready (v${version})`);
|
|
18868
19102
|
return version;
|
|
18869
19103
|
}
|
|
18870
|
-
const context =
|
|
18871
|
-
|
|
18872
|
-
|
|
18873
|
-
|
|
19104
|
+
const context = path42.join(cacheDir(), `context-${version}`);
|
|
19105
|
+
fs35.rmSync(context, { recursive: true, force: true });
|
|
19106
|
+
fs35.mkdirSync(context, { recursive: true });
|
|
19107
|
+
execFileSync30("tar", ["-xzf", tarball, "-C", context, "--strip-components", "1"], {
|
|
18874
19108
|
stdio: ["ignore", "pipe", "pipe"]
|
|
18875
19109
|
});
|
|
18876
|
-
const hubStackDir =
|
|
19110
|
+
const hubStackDir = path42.join(findPackageRoot(), "stack", "hub");
|
|
18877
19111
|
for (const [name, dockerfile] of [
|
|
18878
19112
|
["mesh-local-hub-api", "Dockerfile.api"],
|
|
18879
19113
|
["mesh-local-hub-ui", "Dockerfile.ui"]
|
|
@@ -18881,12 +19115,12 @@ async function ensureHubImages() {
|
|
|
18881
19115
|
const tag = `${name}:${version}`;
|
|
18882
19116
|
if (imageExists(tag)) continue;
|
|
18883
19117
|
logInfo(`Building ${tag} from the published tarball\u2026`);
|
|
18884
|
-
|
|
19118
|
+
execFileSync30(
|
|
18885
19119
|
"docker",
|
|
18886
19120
|
[
|
|
18887
19121
|
"build",
|
|
18888
19122
|
"-f",
|
|
18889
|
-
|
|
19123
|
+
path42.join(hubStackDir, dockerfile),
|
|
18890
19124
|
"-t",
|
|
18891
19125
|
tag,
|
|
18892
19126
|
"--secret",
|
|
@@ -18904,29 +19138,29 @@ function tarballNameForImageVersion(version) {
|
|
|
18904
19138
|
return `mesh-tech-hub-${version.replace(/-r\d+$/, "")}.tgz`;
|
|
18905
19139
|
}
|
|
18906
19140
|
function readHubCompiledAuthz(version) {
|
|
18907
|
-
const context =
|
|
18908
|
-
const file =
|
|
18909
|
-
if (!
|
|
19141
|
+
const context = path42.join(cacheDir(), `context-${version}`);
|
|
19142
|
+
const file = path42.join(context, HUB_COMPILED_AUTHZ_REL);
|
|
19143
|
+
if (!fs35.existsSync(file)) {
|
|
18910
19144
|
const tarball = tarballNameForImageVersion(version);
|
|
18911
|
-
if (!tarball || !
|
|
18912
|
-
|
|
19145
|
+
if (!tarball || !fs35.existsSync(path42.join(cacheDir(), tarball))) return null;
|
|
19146
|
+
fs35.mkdirSync(context, { recursive: true });
|
|
18913
19147
|
try {
|
|
18914
|
-
|
|
19148
|
+
execFileSync30(
|
|
18915
19149
|
"tar",
|
|
18916
|
-
["-xzf",
|
|
19150
|
+
["-xzf", path42.join(cacheDir(), tarball), "-C", context, "--strip-components", "1", `package/${HUB_COMPILED_AUTHZ_REL}`],
|
|
18917
19151
|
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
18918
19152
|
);
|
|
18919
19153
|
} catch {
|
|
18920
19154
|
return null;
|
|
18921
19155
|
}
|
|
18922
|
-
if (!
|
|
19156
|
+
if (!fs35.existsSync(file)) return null;
|
|
18923
19157
|
}
|
|
18924
|
-
const parsed = JSON.parse(
|
|
19158
|
+
const parsed = JSON.parse(fs35.readFileSync(file, "utf-8"));
|
|
18925
19159
|
if (typeof parsed.zed !== "string" || !parsed.metadata || typeof parsed.metadata !== "object") return null;
|
|
18926
19160
|
return { zed: parsed.zed, metadata: parsed.metadata };
|
|
18927
19161
|
}
|
|
18928
19162
|
function readWorkspaceCatalog(repoRoot2) {
|
|
18929
|
-
const text =
|
|
19163
|
+
const text = fs35.readFileSync(path42.join(repoRoot2, "pnpm-workspace.yaml"), "utf-8");
|
|
18930
19164
|
const marker = "\ncatalog:\n";
|
|
18931
19165
|
const at = text.indexOf(marker);
|
|
18932
19166
|
if (at === -1) return {};
|
|
@@ -18941,11 +19175,11 @@ function readWorkspaceCatalog(repoRoot2) {
|
|
|
18941
19175
|
function normalizeHubManifests(contextDir, catalog) {
|
|
18942
19176
|
const DEP_FIELDS = ["dependencies", "optionalDependencies", "peerDependencies"];
|
|
18943
19177
|
const touched = [];
|
|
18944
|
-
for (const entry of
|
|
19178
|
+
for (const entry of fs35.readdirSync(contextDir, { withFileTypes: true })) {
|
|
18945
19179
|
if (!entry.isDirectory()) continue;
|
|
18946
|
-
const manifest =
|
|
18947
|
-
if (!
|
|
18948
|
-
const pkg = JSON.parse(
|
|
19180
|
+
const manifest = path42.join(contextDir, entry.name, "package.json");
|
|
19181
|
+
if (!fs35.existsSync(manifest)) continue;
|
|
19182
|
+
const pkg = JSON.parse(fs35.readFileSync(manifest, "utf-8"));
|
|
18949
19183
|
let changed = false;
|
|
18950
19184
|
if (pkg.devDependencies) {
|
|
18951
19185
|
delete pkg.devDependencies;
|
|
@@ -18974,7 +19208,7 @@ function normalizeHubManifests(contextDir, catalog) {
|
|
|
18974
19208
|
}
|
|
18975
19209
|
}
|
|
18976
19210
|
if (changed) {
|
|
18977
|
-
|
|
19211
|
+
fs35.writeFileSync(manifest, `${JSON.stringify(pkg, null, 2)}
|
|
18978
19212
|
`);
|
|
18979
19213
|
touched.push(`${entry.name}/package.json`);
|
|
18980
19214
|
}
|
|
@@ -18982,15 +19216,15 @@ function normalizeHubManifests(contextDir, catalog) {
|
|
|
18982
19216
|
return touched;
|
|
18983
19217
|
}
|
|
18984
19218
|
async function buildHubImagesFromSource(repoRoot2) {
|
|
18985
|
-
const hubDir =
|
|
18986
|
-
if (!
|
|
19219
|
+
const hubDir = path42.join(repoRoot2, "apps", "hub");
|
|
19220
|
+
if (!fs35.existsSync(path42.join(hubDir, "package.json"))) {
|
|
18987
19221
|
throw new MeshCliError(
|
|
18988
19222
|
`--hub-from-source needs a mesh-platform checkout; no apps/hub under ${repoRoot2}.`,
|
|
18989
19223
|
{ remediation: { command: "Run mesh start from a mesh-platform checkout, or drop --hub-from-source" } }
|
|
18990
19224
|
);
|
|
18991
19225
|
}
|
|
18992
19226
|
const npmrc = npmrcPath();
|
|
18993
|
-
const version = `${JSON.parse(
|
|
19227
|
+
const version = `${JSON.parse(fs35.readFileSync(path42.join(hubDir, "package.json"), "utf-8")).version}-src`;
|
|
18994
19228
|
const build = startHeartbeat("building apps/hub (api + ui) from source");
|
|
18995
19229
|
try {
|
|
18996
19230
|
for (const pkg of ["@mesh-tech/hub-api", "@mesh-tech/hub-ui"]) {
|
|
@@ -18999,27 +19233,27 @@ async function buildHubImagesFromSource(repoRoot2) {
|
|
|
18999
19233
|
} finally {
|
|
19000
19234
|
build.stop();
|
|
19001
19235
|
}
|
|
19002
|
-
const context =
|
|
19003
|
-
|
|
19004
|
-
|
|
19236
|
+
const context = path42.join(cacheDir(), `context-${version}`);
|
|
19237
|
+
fs35.rmSync(context, { recursive: true, force: true });
|
|
19238
|
+
fs35.mkdirSync(context, { recursive: true });
|
|
19005
19239
|
await execFileAsync2("pnpm", ["pack", "--pack-destination", context], { cwd: hubDir, maxBuffer: 64 * 1024 * 1024 });
|
|
19006
|
-
const tarball =
|
|
19240
|
+
const tarball = fs35.readdirSync(context).find((f) => f.endsWith(".tgz"));
|
|
19007
19241
|
if (!tarball) throw new MeshCliError("pnpm pack produced no tarball for apps/hub");
|
|
19008
|
-
|
|
19242
|
+
execFileSync30("tar", ["-xzf", path42.join(context, tarball), "-C", context, "--strip-components", "1"], {
|
|
19009
19243
|
stdio: ["ignore", "pipe", "pipe"]
|
|
19010
19244
|
});
|
|
19011
19245
|
const rewritten = normalizeHubManifests(context, readWorkspaceCatalog(repoRoot2));
|
|
19012
19246
|
if (rewritten.length > 0) logInfo(`Normalized ${rewritten.length} manifest(s) for npm: ${rewritten.join(", ")}`);
|
|
19013
|
-
const hubStackDir =
|
|
19247
|
+
const hubStackDir = path42.join(findPackageRoot(), "stack", "hub");
|
|
19014
19248
|
for (const [name, dockerfile] of [
|
|
19015
19249
|
["mesh-local-hub-api", "Dockerfile.api"],
|
|
19016
19250
|
["mesh-local-hub-ui", "Dockerfile.ui"]
|
|
19017
19251
|
]) {
|
|
19018
19252
|
const tag = `${name}:${version}`;
|
|
19019
19253
|
logInfo(`Building ${tag} from source\u2026`);
|
|
19020
|
-
|
|
19254
|
+
execFileSync30(
|
|
19021
19255
|
"docker",
|
|
19022
|
-
["build", "-f",
|
|
19256
|
+
["build", "-f", path42.join(hubStackDir, dockerfile), "-t", tag, "--secret", `id=npmrc,src=${npmrc}`, context],
|
|
19023
19257
|
{ stdio: ["ignore", "inherit", "inherit"], env: { ...process.env, DOCKER_BUILDKIT: "1" } }
|
|
19024
19258
|
);
|
|
19025
19259
|
logSuccess(`Built ${tag}`);
|
|
@@ -19104,8 +19338,8 @@ var init_seed_hub_catalog = __esm({
|
|
|
19104
19338
|
});
|
|
19105
19339
|
|
|
19106
19340
|
// libs/mesh-cli/src/commands/local/index.ts
|
|
19107
|
-
import * as
|
|
19108
|
-
import * as
|
|
19341
|
+
import * as fs36 from "fs";
|
|
19342
|
+
import * as path43 from "path";
|
|
19109
19343
|
import chalk6 from "chalk";
|
|
19110
19344
|
function crashError(crashed) {
|
|
19111
19345
|
return new MeshCliError(
|
|
@@ -19117,10 +19351,13 @@ function crashError(crashed) {
|
|
|
19117
19351
|
}
|
|
19118
19352
|
);
|
|
19119
19353
|
}
|
|
19120
|
-
async function waitForStack(io = {
|
|
19354
|
+
async function waitForStack(opts, io = {
|
|
19121
19355
|
probe: probeEndpoint,
|
|
19122
19356
|
services: stackServices,
|
|
19123
|
-
|
|
19357
|
+
overlays: () => [
|
|
19358
|
+
{ services: hubOverlayServices(), started: false },
|
|
19359
|
+
{ services: idpsOverlayServices(), started: opts.idpsStarted }
|
|
19360
|
+
]
|
|
19124
19361
|
}) {
|
|
19125
19362
|
const deadline = Date.now() + WAIT_TIMEOUT_MS;
|
|
19126
19363
|
let pending = STACK_ENDPOINTS.filter((e) => e.probe.kind !== "none");
|
|
@@ -19135,10 +19372,7 @@ async function waitForStack(io = {
|
|
|
19135
19372
|
}
|
|
19136
19373
|
}
|
|
19137
19374
|
pending = stillDown;
|
|
19138
|
-
const crashed = crashedServices(io.services(), {
|
|
19139
|
-
overlayServices: io.overlayServices(),
|
|
19140
|
-
overlayStarted: false
|
|
19141
|
-
});
|
|
19375
|
+
const crashed = crashedServices(io.services(), { overlays: io.overlays() });
|
|
19142
19376
|
if (crashed.length > 0) throw crashError(crashed);
|
|
19143
19377
|
if (pending.length === 0) break;
|
|
19144
19378
|
if (Date.now() > deadline) {
|
|
@@ -19222,17 +19456,22 @@ function portMoveHints() {
|
|
|
19222
19456
|
[
|
|
19223
19457
|
Number(hubPort()),
|
|
19224
19458
|
"MESH_HUB_PORT=<free port> mesh start (or mesh start --no-hub, which starts everything else)"
|
|
19459
|
+
],
|
|
19460
|
+
[MOCK_SAML_PORT, "mesh start (without --with-idps \u2014 the mock identity providers are opt-in)"],
|
|
19461
|
+
[
|
|
19462
|
+
MOCK_OIDC_PORT,
|
|
19463
|
+
"mesh start (without --with-idps; 5556 is Dex's own default port, so a Dex of your own is the usual holder)"
|
|
19225
19464
|
]
|
|
19226
19465
|
]);
|
|
19227
19466
|
}
|
|
19228
19467
|
function repoRootForHubSource() {
|
|
19229
19468
|
for (let dir = process.cwd(); ; ) {
|
|
19230
|
-
if (
|
|
19231
|
-
const parent =
|
|
19469
|
+
if (fs36.existsSync(path43.join(dir, "apps", "hub", "package.json"))) return dir;
|
|
19470
|
+
const parent = path43.dirname(dir);
|
|
19232
19471
|
if (parent === dir) break;
|
|
19233
19472
|
dir = parent;
|
|
19234
19473
|
}
|
|
19235
|
-
return
|
|
19474
|
+
return path43.resolve(findPackageRoot(), "..", "..");
|
|
19236
19475
|
}
|
|
19237
19476
|
function registerLocalCommands(program2) {
|
|
19238
19477
|
program2.command("start").description("Start the full-local Mesh platform (Docker only \u2014 no AWS, no VPN)").option("--no-seed", "skip first-boot seeding (tenant registry, artifacts bucket)").option("--no-hub", "start without the Hub (API + UI)").option(
|
|
@@ -19241,6 +19480,10 @@ function registerLocalCommands(program2) {
|
|
|
19241
19480
|
).option(
|
|
19242
19481
|
"--hub-from-source",
|
|
19243
19482
|
"build the Hub images from THIS checkout's apps/hub instead of the published tarball (the only way to exercise a Hub change locally)"
|
|
19483
|
+
).option(
|
|
19484
|
+
"--with-idps",
|
|
19485
|
+
"also run mock SAML and OIDC identity providers, and federate the local Zitadel with both (for testing enterprise SSO without a cloud tenant or an IdP admin)",
|
|
19486
|
+
false
|
|
19244
19487
|
).option(
|
|
19245
19488
|
"--takeover",
|
|
19246
19489
|
"re-own a stack that another checkout started (may recreate shared containers with THIS checkout's config)",
|
|
@@ -19268,7 +19511,11 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19268
19511
|
logWarn(`Taking over the running stack (previously driven from ${foreign}).`);
|
|
19269
19512
|
}
|
|
19270
19513
|
if (!opts.skipPortCheck && !stackServices().some((s) => s.state === "running")) {
|
|
19271
|
-
const ports = hostPortsOf([
|
|
19514
|
+
const ports = hostPortsOf([
|
|
19515
|
+
...STACK_ENDPOINTS,
|
|
19516
|
+
...opts.hub ? hubEndpoints() : [],
|
|
19517
|
+
...opts.withIdps ? idpEndpoints() : []
|
|
19518
|
+
]);
|
|
19272
19519
|
const conflicts = await findPortConflicts(ports, `${COMPOSE_PROJECT}-`);
|
|
19273
19520
|
if (conflicts.length > 0) {
|
|
19274
19521
|
throw new MeshCliError(describePortConflicts(conflicts, portMoveHints()), {
|
|
@@ -19313,9 +19560,10 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19313
19560
|
}
|
|
19314
19561
|
}
|
|
19315
19562
|
logInfo("Starting the local Mesh platform (docker compose project: mesh-local)\u2026");
|
|
19316
|
-
|
|
19563
|
+
const idpEnv = opts.withIdps ? mockIdpComposeEnv() : void 0;
|
|
19564
|
+
await composeStreamed(["up", "-d"], { idps: opts.withIdps, env: idpEnv });
|
|
19317
19565
|
compose(["restart", "prometheus", "blackbox-exporter"], { inherit: true });
|
|
19318
|
-
await waitForStack();
|
|
19566
|
+
await waitForStack({ idpsStarted: opts.withIdps });
|
|
19319
19567
|
let hubAuth = readHubAuth();
|
|
19320
19568
|
if (opts.seed) {
|
|
19321
19569
|
logInfo("Seeding local platform (tenant registry, artifacts bucket)\u2026");
|
|
@@ -19323,6 +19571,16 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19323
19571
|
logInfo("Seeding Zitadel (Platform project, Mesh CLI app, Hub auth, test users)\u2026");
|
|
19324
19572
|
const zitadel = await seedZitadel(LOCAL_AWS_CONFIG);
|
|
19325
19573
|
hubAuth = zitadel.hubAuth;
|
|
19574
|
+
if (opts.withIdps) {
|
|
19575
|
+
logInfo("Federating local Zitadel with the mock SAML and OIDC identity providers\u2026");
|
|
19576
|
+
await seedMockIdps();
|
|
19577
|
+
logInfo(
|
|
19578
|
+
`Mock SAML IdP: http://localhost:${MOCK_SAML_PORT} \xB7 mock OIDC IdP: http://localhost:${MOCK_OIDC_PORT}/dex \xB7 sign in at http://localhost:8080 and both federation buttons are offered`
|
|
19579
|
+
);
|
|
19580
|
+
logInfo(
|
|
19581
|
+
"Both are listed in the Zitadel console under Settings \u2192 Identity Providers (owner: Instance): http://localhost:8080/ui/console/org-settings?id=idp"
|
|
19582
|
+
);
|
|
19583
|
+
}
|
|
19326
19584
|
if (hubVersion) {
|
|
19327
19585
|
const compiled = readHubCompiledAuthz(hubVersion);
|
|
19328
19586
|
if (compiled) {
|
|
@@ -19365,19 +19623,23 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19365
19623
|
hubEnv.MESH_HUB_OAUTH2_CLIENT_SECRET = hubAuth.clientSecret;
|
|
19366
19624
|
hubEnv.MESH_HUB_OAUTH2_COOKIE_SECRET = hubAuth.cookieSecret;
|
|
19367
19625
|
}
|
|
19368
|
-
await composeStreamed(["up", "-d"], {
|
|
19626
|
+
await composeStreamed(["up", "-d"], {
|
|
19627
|
+
hub: true,
|
|
19628
|
+
idps: opts.withIdps,
|
|
19629
|
+
env: { ...idpEnv, ...hubEnv }
|
|
19630
|
+
});
|
|
19369
19631
|
if (opts.seed) {
|
|
19370
19632
|
compose(["restart", "hub-api"], { hub: true, env: hubEnv });
|
|
19371
19633
|
}
|
|
19372
|
-
const
|
|
19634
|
+
const overlays = [
|
|
19635
|
+
{ services: hubOverlayServices(), started: true },
|
|
19636
|
+
{ services: idpsOverlayServices(), started: opts.withIdps }
|
|
19637
|
+
];
|
|
19373
19638
|
for (const endpoint of hubEndpoints()) {
|
|
19374
19639
|
logInfo(`Waiting for ${endpoint.label}\u2026`);
|
|
19375
19640
|
let up = await probeEndpoint(endpoint);
|
|
19376
19641
|
for (let i = 0; i < 60 && !up; i++) {
|
|
19377
|
-
const crashed = crashedServices(stackServices(), {
|
|
19378
|
-
overlayServices,
|
|
19379
|
-
overlayStarted: true
|
|
19380
|
-
});
|
|
19642
|
+
const crashed = crashedServices(stackServices(), { overlays });
|
|
19381
19643
|
if (crashed.length > 0) throw crashError(crashed);
|
|
19382
19644
|
await new Promise((resolve20) => setTimeout(resolve20, 2e3));
|
|
19383
19645
|
up = await probeEndpoint(endpoint);
|
|
@@ -19421,11 +19683,20 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19421
19683
|
remediation: { command: "mesh start" }
|
|
19422
19684
|
});
|
|
19423
19685
|
}
|
|
19424
|
-
const
|
|
19425
|
-
const
|
|
19426
|
-
const
|
|
19686
|
+
const hubOverlay = hubOverlayServices();
|
|
19687
|
+
const idpsOverlay = idpsOverlayServices();
|
|
19688
|
+
const idpsStarted = overlayRunning(services, idpsOverlay);
|
|
19689
|
+
const overlays = [
|
|
19690
|
+
{ services: hubOverlay, started: overlayRunning(services, hubOverlay) },
|
|
19691
|
+
{ services: idpsOverlay, started: idpsStarted }
|
|
19692
|
+
];
|
|
19693
|
+
const notStarted = (s) => s.state === "exited" && overlays.some((o) => !o.started && o.services.has(s.name));
|
|
19427
19694
|
const hasHub = hubApiRunning(services);
|
|
19428
|
-
const endpoints =
|
|
19695
|
+
const endpoints = [
|
|
19696
|
+
...STACK_ENDPOINTS,
|
|
19697
|
+
...hasHub ? hubEndpoints() : [],
|
|
19698
|
+
...idpsStarted ? idpEndpoints() : []
|
|
19699
|
+
];
|
|
19429
19700
|
const probes = await Promise.all(
|
|
19430
19701
|
endpoints.map(async (endpoint) => ({
|
|
19431
19702
|
service: endpoint.service,
|
|
@@ -19450,6 +19721,7 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19450
19721
|
services,
|
|
19451
19722
|
endpoints: probes,
|
|
19452
19723
|
fabric,
|
|
19724
|
+
mockIdps: idpsStarted,
|
|
19453
19725
|
awsEnv: localAwsEnv()
|
|
19454
19726
|
})
|
|
19455
19727
|
);
|
|
@@ -19464,7 +19736,7 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19464
19736
|
const idle = notStarted(service);
|
|
19465
19737
|
const icon = ok || oneShotDone ? chalk6.green("\u25CF") : idle ? chalk6.dim("\u25CB") : chalk6.red("\u25CF");
|
|
19466
19738
|
const health = service.health ? ` (${service.health})` : "";
|
|
19467
|
-
const note = idle ? chalk6.dim(" (
|
|
19739
|
+
const note = idle ? chalk6.dim(" (not started this run)") : "";
|
|
19468
19740
|
console.log(` ${icon} ${service.name.padEnd(22)} ${service.state}${health}${note}`);
|
|
19469
19741
|
}
|
|
19470
19742
|
console.log("");
|
|
@@ -19478,8 +19750,13 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19478
19750
|
const detail = fabric.ok ? "8 KB Advanced-tier round-trip OK" : fabric.error;
|
|
19479
19751
|
console.log(` ${icon} ${"AWS fabric check".padEnd(34)} ${chalk6.dim(detail ?? "")}`);
|
|
19480
19752
|
}
|
|
19753
|
+
if (!idpsStarted) {
|
|
19754
|
+
console.log(
|
|
19755
|
+
` ${chalk6.dim("\u25CB")} ${"Mock IdPs (SAML + OIDC)".padEnd(34)} ${chalk6.dim("not started \u2014 mesh start --with-idps")}`
|
|
19756
|
+
);
|
|
19757
|
+
}
|
|
19481
19758
|
const down = probes.filter((p) => !p.up);
|
|
19482
|
-
const crashed = crashedServices(services, {
|
|
19759
|
+
const crashed = crashedServices(services, { overlays });
|
|
19483
19760
|
if (fabric && !fabric.ok) process.exitCode = 1;
|
|
19484
19761
|
if (down.length > 0 || crashed.length > 0) {
|
|
19485
19762
|
console.log("");
|
|
@@ -19502,6 +19779,7 @@ var init_local = __esm({
|
|
|
19502
19779
|
init_auth_provision();
|
|
19503
19780
|
init_seed();
|
|
19504
19781
|
init_seed_zitadel();
|
|
19782
|
+
init_mock_idps();
|
|
19505
19783
|
init_seed_hub_catalog();
|
|
19506
19784
|
init_helpers();
|
|
19507
19785
|
WAIT_TIMEOUT_MS = 18e4;
|
|
@@ -20492,7 +20770,7 @@ var init_secrets = __esm({
|
|
|
20492
20770
|
import { createHash as createHash4 } from "node:crypto";
|
|
20493
20771
|
import { createReadStream } from "node:fs";
|
|
20494
20772
|
import { readdir, readFile as readFile2, stat } from "node:fs/promises";
|
|
20495
|
-
import { join as
|
|
20773
|
+
import { join as join39, relative as relative11, resolve as resolve17, sep as sep6 } from "node:path";
|
|
20496
20774
|
async function describeSiteHttpError(res, target, site) {
|
|
20497
20775
|
if (res.status === 403) {
|
|
20498
20776
|
return `not allowed to publish "${site}" \u2014 you are authenticated but lack the grant. Need one of: sites:${site}:publish, sites:*:publish, or studio-admin.`;
|
|
@@ -20514,7 +20792,7 @@ async function walk(root) {
|
|
|
20514
20792
|
async function visit(dir) {
|
|
20515
20793
|
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
20516
20794
|
if (SKIP_ENTRIES.has(entry.name)) continue;
|
|
20517
|
-
const absolute =
|
|
20795
|
+
const absolute = join39(dir, entry.name);
|
|
20518
20796
|
if (entry.isSymbolicLink()) {
|
|
20519
20797
|
logWarn(`skipping symlink ${relative11(root, absolute)}`);
|
|
20520
20798
|
continue;
|
|
@@ -20709,23 +20987,23 @@ var init_site = __esm({
|
|
|
20709
20987
|
});
|
|
20710
20988
|
|
|
20711
20989
|
// libs/mesh-cli/src/commands/stack.ts
|
|
20712
|
-
import { execFileSync as
|
|
20713
|
-
import * as
|
|
20714
|
-
import * as
|
|
20990
|
+
import { execFileSync as execFileSync31 } from "child_process";
|
|
20991
|
+
import * as path44 from "path";
|
|
20992
|
+
import * as fs37 from "fs";
|
|
20715
20993
|
import { parse as parseYaml5 } from "yaml";
|
|
20716
20994
|
function readTopLevelYamlKey(appRoot, stack, key) {
|
|
20717
|
-
const configFile =
|
|
20718
|
-
if (!
|
|
20719
|
-
const content =
|
|
20995
|
+
const configFile = path44.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
20996
|
+
if (!fs37.existsSync(configFile)) return null;
|
|
20997
|
+
const content = fs37.readFileSync(configFile, "utf-8");
|
|
20720
20998
|
const pattern = new RegExp(`^${key}:\\s*(.+)$`, "m");
|
|
20721
20999
|
const match = content.match(pattern);
|
|
20722
21000
|
if (!match) return null;
|
|
20723
21001
|
return match[1].trim().replace(/^["']|["']$/g, "");
|
|
20724
21002
|
}
|
|
20725
21003
|
function readConfigBlockKey(appRoot, stack, key) {
|
|
20726
|
-
const configFile =
|
|
20727
|
-
if (!
|
|
20728
|
-
const content =
|
|
21004
|
+
const configFile = path44.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
21005
|
+
if (!fs37.existsSync(configFile)) return null;
|
|
21006
|
+
const content = fs37.readFileSync(configFile, "utf-8");
|
|
20729
21007
|
const pattern = new RegExp(`^\\s{2}${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}:\\s*(.+)$`, "m");
|
|
20730
21008
|
const match = content.match(pattern);
|
|
20731
21009
|
if (!match) return null;
|
|
@@ -20785,11 +21063,11 @@ ${records}
|
|
|
20785
21063
|
}
|
|
20786
21064
|
}
|
|
20787
21065
|
function readBaseConfigFromYaml(appRoot, stack) {
|
|
20788
|
-
const file =
|
|
20789
|
-
if (!
|
|
21066
|
+
const file = path44.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
21067
|
+
if (!fs37.existsSync(file)) return {};
|
|
20790
21068
|
let doc;
|
|
20791
21069
|
try {
|
|
20792
|
-
doc = parseYaml5(
|
|
21070
|
+
doc = parseYaml5(fs37.readFileSync(file, "utf-8"));
|
|
20793
21071
|
} catch {
|
|
20794
21072
|
return {};
|
|
20795
21073
|
}
|
|
@@ -20802,7 +21080,7 @@ function readBaseConfigFromYaml(appRoot, stack) {
|
|
|
20802
21080
|
}
|
|
20803
21081
|
function getGitHubUsername() {
|
|
20804
21082
|
try {
|
|
20805
|
-
const result =
|
|
21083
|
+
const result = execFileSync31("gh", ["api", "user", "--jq", ".login"], {
|
|
20806
21084
|
encoding: "utf-8",
|
|
20807
21085
|
stdio: ["pipe", "pipe", "pipe"]
|
|
20808
21086
|
});
|
|
@@ -20811,7 +21089,7 @@ function getGitHubUsername() {
|
|
|
20811
21089
|
} catch {
|
|
20812
21090
|
}
|
|
20813
21091
|
try {
|
|
20814
|
-
const result =
|
|
21092
|
+
const result = execFileSync31("git", ["config", "user.email"], {
|
|
20815
21093
|
encoding: "utf-8",
|
|
20816
21094
|
stdio: ["pipe", "pipe", "pipe"]
|
|
20817
21095
|
});
|
|
@@ -20866,7 +21144,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20866
21144
|
}
|
|
20867
21145
|
}
|
|
20868
21146
|
const baseConfigPath = `${appRoot}/Pulumi.${baseStack}.yaml`;
|
|
20869
|
-
if (!
|
|
21147
|
+
if (!fs37.existsSync(baseConfigPath)) {
|
|
20870
21148
|
logError(`Stack config not found: Pulumi.${baseStack}.yaml`);
|
|
20871
21149
|
process.exit(1);
|
|
20872
21150
|
}
|
|
@@ -20888,8 +21166,8 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20888
21166
|
);
|
|
20889
21167
|
}
|
|
20890
21168
|
}
|
|
20891
|
-
const newConfigPath =
|
|
20892
|
-
const configExists =
|
|
21169
|
+
const newConfigPath = path44.join(appRoot, `Pulumi.${newStack}.yaml`);
|
|
21170
|
+
const configExists = fs37.existsSync(newConfigPath);
|
|
20893
21171
|
const secretsProvider = readTopLevelYamlKey(appRoot, baseStack, "secretsprovider");
|
|
20894
21172
|
const credEnv = await resolvePulumiEnv({ appRoot, stack: baseStack });
|
|
20895
21173
|
const pulumiEnv = { ...process.env, ...credEnv };
|
|
@@ -20897,7 +21175,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20897
21175
|
if (!opts.adopt) {
|
|
20898
21176
|
let existing = [];
|
|
20899
21177
|
try {
|
|
20900
|
-
const raw =
|
|
21178
|
+
const raw = execFileSync31("pulumi", ["stack", "ls", "--json"], {
|
|
20901
21179
|
cwd: appRoot,
|
|
20902
21180
|
encoding: "utf-8",
|
|
20903
21181
|
env: pulumiEnv,
|
|
@@ -20921,7 +21199,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20921
21199
|
logInfo(`Using KMS secrets provider: ${secretsProvider}`);
|
|
20922
21200
|
}
|
|
20923
21201
|
try {
|
|
20924
|
-
|
|
21202
|
+
execFileSync31("pulumi", initArgs, {
|
|
20925
21203
|
cwd: appRoot,
|
|
20926
21204
|
env: pulumiEnv,
|
|
20927
21205
|
stdio: "inherit"
|
|
@@ -20938,7 +21216,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20938
21216
|
}
|
|
20939
21217
|
}
|
|
20940
21218
|
try {
|
|
20941
|
-
|
|
21219
|
+
execFileSync31("pulumi", ["stack", "select", newStack], {
|
|
20942
21220
|
cwd: appRoot,
|
|
20943
21221
|
env: pulumiEnv,
|
|
20944
21222
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -20948,7 +21226,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20948
21226
|
if (!configExists) {
|
|
20949
21227
|
let baseConfig = {};
|
|
20950
21228
|
try {
|
|
20951
|
-
const raw =
|
|
21229
|
+
const raw = execFileSync31(
|
|
20952
21230
|
"pulumi",
|
|
20953
21231
|
["config", "--json", "--stack", baseStack],
|
|
20954
21232
|
{ cwd: appRoot, env: pulumiEnv, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -20966,19 +21244,19 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20966
21244
|
if (key === "mesh:deploy") continue;
|
|
20967
21245
|
try {
|
|
20968
21246
|
if (entry.objectValue !== void 0) {
|
|
20969
|
-
|
|
21247
|
+
execFileSync31(
|
|
20970
21248
|
"pulumi",
|
|
20971
21249
|
["config", "set", key, JSON.stringify(entry.objectValue)],
|
|
20972
21250
|
{ cwd: appRoot, env: pulumiEnv, stdio: ["pipe", "pipe", "pipe"] }
|
|
20973
21251
|
);
|
|
20974
21252
|
} else if (entry.value === "true" || entry.value === "false") {
|
|
20975
|
-
|
|
21253
|
+
execFileSync31(
|
|
20976
21254
|
"pulumi",
|
|
20977
21255
|
["config", "set", "--type", "bool", key, entry.value],
|
|
20978
21256
|
{ cwd: appRoot, env: pulumiEnv, stdio: ["pipe", "pipe", "pipe"] }
|
|
20979
21257
|
);
|
|
20980
21258
|
} else {
|
|
20981
|
-
|
|
21259
|
+
execFileSync31(
|
|
20982
21260
|
"pulumi",
|
|
20983
21261
|
["config", "set", key, entry.value],
|
|
20984
21262
|
{ cwd: appRoot, env: pulumiEnv, stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -20991,7 +21269,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20991
21269
|
const baseEnv = readConfigBlockKey(appRoot, baseStack, "mesh:coreEnv") ?? (baseTenant && baseStack.startsWith(`${baseTenant}-`) ? baseStack.slice(baseTenant.length + 1) : baseStack);
|
|
20992
21270
|
const setCfg = (args) => {
|
|
20993
21271
|
try {
|
|
20994
|
-
|
|
21272
|
+
execFileSync31("pulumi", ["config", "set", ...args], {
|
|
20995
21273
|
cwd: appRoot,
|
|
20996
21274
|
env: pulumiEnv,
|
|
20997
21275
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -21040,7 +21318,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21040
21318
|
`Configured Pulumi.${newStack}.yaml (personal platform env on core '${baseEnv}'${opts.parentZone ? `, DNS zone ${newStack.startsWith(`${baseTenant}-`) ? newStack.slice(baseTenant.length + 1) : newStack}.${opts.parentZone}` : ""})`
|
|
21041
21319
|
);
|
|
21042
21320
|
} else {
|
|
21043
|
-
|
|
21321
|
+
execFileSync31("pulumi", ["config", "set", "--type", "bool", "mesh:deploy", "false"], {
|
|
21044
21322
|
cwd: appRoot,
|
|
21045
21323
|
env: pulumiEnv,
|
|
21046
21324
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -21070,7 +21348,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21070
21348
|
const args = ["stack", "rm", name];
|
|
21071
21349
|
if (opts.yes) args.push("--yes");
|
|
21072
21350
|
try {
|
|
21073
|
-
|
|
21351
|
+
execFileSync31("pulumi", args, { cwd: appRoot, env: pulumiEnv, stdio: "inherit" });
|
|
21074
21352
|
logSuccess(`Removed stack ${name}`);
|
|
21075
21353
|
} catch (err) {
|
|
21076
21354
|
process.exit(err.status ?? 1);
|
|
@@ -21282,12 +21560,12 @@ var init_recover_conversation = __esm({
|
|
|
21282
21560
|
});
|
|
21283
21561
|
|
|
21284
21562
|
// libs/mesh-cli/src/utils/temporal-codec.ts
|
|
21285
|
-
import { execFileSync as
|
|
21563
|
+
import { execFileSync as execFileSync32 } from "child_process";
|
|
21286
21564
|
import { webcrypto as crypto4 } from "node:crypto";
|
|
21287
21565
|
function resolveTemporalEncodingKeyFromK8s(namespace) {
|
|
21288
21566
|
const secretName = `${namespace}-temporal-encoding-key`;
|
|
21289
21567
|
try {
|
|
21290
|
-
const b64 =
|
|
21568
|
+
const b64 = execFileSync32(
|
|
21291
21569
|
"kubectl",
|
|
21292
21570
|
[
|
|
21293
21571
|
"get",
|
|
@@ -21536,9 +21814,9 @@ var init_capture_history = __esm({
|
|
|
21536
21814
|
|
|
21537
21815
|
// libs/mesh-cli/src/commands/temporal.ts
|
|
21538
21816
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
21539
|
-
import { writeFileSync as writeFileSync24, mkdirSync as
|
|
21817
|
+
import { writeFileSync as writeFileSync24, mkdirSync as mkdirSync20 } from "node:fs";
|
|
21540
21818
|
import { homedir as homedir6 } from "node:os";
|
|
21541
|
-
import { dirname as dirname28, join as
|
|
21819
|
+
import { dirname as dirname28, join as join41, resolve as resolve18 } from "node:path";
|
|
21542
21820
|
async function resolveConnection(options) {
|
|
21543
21821
|
if (options.address && options.namespace) {
|
|
21544
21822
|
return { address: options.address, namespace: options.namespace };
|
|
@@ -21966,8 +22244,8 @@ async function captureHistory(workflowId, runId, options) {
|
|
|
21966
22244
|
}
|
|
21967
22245
|
const { serializeHistoryToFixture: serializeHistoryToFixture2 } = await Promise.resolve().then(() => (init_capture_history(), capture_history_exports));
|
|
21968
22246
|
const { fixture, eventCount, decryptedPayloads } = await serializeHistoryToFixture2(events, decrypter);
|
|
21969
|
-
const outPath = options.out ??
|
|
21970
|
-
|
|
22247
|
+
const outPath = options.out ?? join41(homedir6(), ".mesh", "replay-histories", `${sanitizeFileId(workflowId)}.json`);
|
|
22248
|
+
mkdirSync20(dirname28(outPath), { recursive: true });
|
|
21971
22249
|
if (options.out) warnIfNotGitIgnored(options.out);
|
|
21972
22250
|
writeFileSync24(outPath, JSON.stringify(fixture, null, 2) + "\n");
|
|
21973
22251
|
logSuccess(
|
|
@@ -22158,8 +22436,8 @@ var init_temporal = __esm({
|
|
|
22158
22436
|
|
|
22159
22437
|
// libs/mesh-cli/src/commands/tenant.ts
|
|
22160
22438
|
import chalk7 from "chalk";
|
|
22161
|
-
import * as
|
|
22162
|
-
import * as
|
|
22439
|
+
import * as fs38 from "fs";
|
|
22440
|
+
import * as path45 from "path";
|
|
22163
22441
|
import { parseDocument, YAMLMap, isMap } from "yaml";
|
|
22164
22442
|
function validateTenantName(name) {
|
|
22165
22443
|
return /^[a-z][a-z0-9-]*$/.test(name) && !name.endsWith("-");
|
|
@@ -22227,16 +22505,16 @@ function resolveStackConfig(explicitStack) {
|
|
|
22227
22505
|
{ remediation: { command: "mesh tenant add <name> --stack <stack>" } }
|
|
22228
22506
|
);
|
|
22229
22507
|
}
|
|
22230
|
-
const file =
|
|
22231
|
-
if (!
|
|
22508
|
+
const file = path45.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
22509
|
+
if (!fs38.existsSync(file)) {
|
|
22232
22510
|
throw new MeshCliError(`Stack config not found: ${file}`, {
|
|
22233
22511
|
remediation: { command: "mesh tenant add <name> --stack <stack>" }
|
|
22234
22512
|
});
|
|
22235
22513
|
}
|
|
22236
|
-
return { appRoot, stack, file, content:
|
|
22514
|
+
return { appRoot, stack, file, content: fs38.readFileSync(file, "utf-8") };
|
|
22237
22515
|
}
|
|
22238
22516
|
function readProjectName(appRoot) {
|
|
22239
|
-
const projectDoc = parseDocument(
|
|
22517
|
+
const projectDoc = parseDocument(fs38.readFileSync(path45.join(appRoot, "Pulumi.yaml"), "utf-8"));
|
|
22240
22518
|
return String(projectDoc.get("name") ?? "");
|
|
22241
22519
|
}
|
|
22242
22520
|
function looksLikePlatformLayer(projectName) {
|
|
@@ -22279,12 +22557,12 @@ function registerTenantCommands(program2) {
|
|
|
22279
22557
|
if (!result.ok) {
|
|
22280
22558
|
if (result.reason === "exists") {
|
|
22281
22559
|
throw new MeshCliError(
|
|
22282
|
-
`${result.detail} (${
|
|
22560
|
+
`${result.detail} (${path45.basename(resolved.file)}). Edit the existing entry instead of re-adding it.`
|
|
22283
22561
|
);
|
|
22284
22562
|
}
|
|
22285
22563
|
throw new MeshCliError(`${resolved.file}: ${result.detail}`);
|
|
22286
22564
|
}
|
|
22287
|
-
atomicWriteFileSync(resolved.file, result.yaml,
|
|
22565
|
+
atomicWriteFileSync(resolved.file, result.yaml, fs38.statSync(resolved.file).mode & 511);
|
|
22288
22566
|
if (opts.json) {
|
|
22289
22567
|
emitJsonPayload({
|
|
22290
22568
|
ok: true,
|
|
@@ -22297,7 +22575,7 @@ function registerTenantCommands(program2) {
|
|
|
22297
22575
|
return;
|
|
22298
22576
|
}
|
|
22299
22577
|
logInfo(
|
|
22300
|
-
`Tenant '${name}' registered in ${
|
|
22578
|
+
`Tenant '${name}' registered in ${path45.basename(resolved.file)} (mesh:tenants, subdomain '${subdomain}')${result.createdTenantsBlock ? " \u2014 created the mesh:tenants block" : ""}`
|
|
22301
22579
|
);
|
|
22302
22580
|
console.log("");
|
|
22303
22581
|
console.log("Next steps:");
|
|
@@ -22323,7 +22601,7 @@ function registerTenantCommands(program2) {
|
|
|
22323
22601
|
`Project '${projectName}' does not look like a platform layer \u2014 tenants are declared on the tenant platform repo's PLATFORM stack (e.g. mesh-sandbox/platform).`
|
|
22324
22602
|
);
|
|
22325
22603
|
}
|
|
22326
|
-
logInfo(`No tenants declared in ${
|
|
22604
|
+
logInfo(`No tenants declared in ${path45.basename(resolved.file)}.`);
|
|
22327
22605
|
return;
|
|
22328
22606
|
}
|
|
22329
22607
|
logInfo(`Tenants on stack '${resolved.stack}':`);
|
|
@@ -22345,9 +22623,9 @@ var init_tenant = __esm({
|
|
|
22345
22623
|
|
|
22346
22624
|
// libs/mesh-cli/src/commands/tunnel/index.ts
|
|
22347
22625
|
import { spawn as spawn9 } from "child_process";
|
|
22348
|
-
import * as
|
|
22626
|
+
import * as fs39 from "fs";
|
|
22349
22627
|
import * as os12 from "os";
|
|
22350
|
-
import * as
|
|
22628
|
+
import * as path46 from "path";
|
|
22351
22629
|
import {
|
|
22352
22630
|
SecretsManagerClient as SecretsManagerClient9,
|
|
22353
22631
|
GetSecretValueCommand as GetSecretValueCommand9
|
|
@@ -22367,9 +22645,9 @@ function readPulumiAwsRegion(stage) {
|
|
|
22367
22645
|
const preferred = stage ? `Pulumi.${stage}.yaml` : void 0;
|
|
22368
22646
|
const rank = (f) => f === preferred ? 0 : f === "Pulumi.yaml" ? 2 : 1;
|
|
22369
22647
|
try {
|
|
22370
|
-
const files =
|
|
22648
|
+
const files = fs39.readdirSync(".").filter((f) => f.startsWith("Pulumi.") && f.endsWith(".yaml")).sort((a, b) => rank(a) - rank(b));
|
|
22371
22649
|
for (const f of files) {
|
|
22372
|
-
const m =
|
|
22650
|
+
const m = fs39.readFileSync(f, "utf-8").match(/^\s*aws:region:\s*["']?([^"'\n]+)["']?/m);
|
|
22373
22651
|
if (m?.[1]) return m[1].trim();
|
|
22374
22652
|
}
|
|
22375
22653
|
} catch {
|
|
@@ -22378,14 +22656,14 @@ function readPulumiAwsRegion(stage) {
|
|
|
22378
22656
|
}
|
|
22379
22657
|
function awsProfileSections(name) {
|
|
22380
22658
|
return [
|
|
22381
|
-
[
|
|
22382
|
-
[
|
|
22659
|
+
[path46.join(os12.homedir(), ".aws", "config"), `[profile ${name}]`],
|
|
22660
|
+
[path46.join(os12.homedir(), ".aws", "credentials"), `[${name}]`]
|
|
22383
22661
|
];
|
|
22384
22662
|
}
|
|
22385
22663
|
function awsProfileExists(name) {
|
|
22386
22664
|
for (const [file, header] of awsProfileSections(name)) {
|
|
22387
22665
|
try {
|
|
22388
|
-
const lines =
|
|
22666
|
+
const lines = fs39.readFileSync(file, "utf-8").split("\n");
|
|
22389
22667
|
if (lines.some((l) => l.trim() === header)) return true;
|
|
22390
22668
|
} catch {
|
|
22391
22669
|
}
|
|
@@ -22411,7 +22689,7 @@ function awsProfileRegion(profile) {
|
|
|
22411
22689
|
if (!profile) return void 0;
|
|
22412
22690
|
for (const [file, header] of awsProfileSections(profile)) {
|
|
22413
22691
|
try {
|
|
22414
|
-
const region = parseProfileRegion(
|
|
22692
|
+
const region = parseProfileRegion(fs39.readFileSync(file, "utf-8"), header);
|
|
22415
22693
|
if (region) return region;
|
|
22416
22694
|
} catch {
|
|
22417
22695
|
}
|
|
@@ -22420,14 +22698,14 @@ function awsProfileRegion(profile) {
|
|
|
22420
22698
|
}
|
|
22421
22699
|
function awsDefaultProfileSections() {
|
|
22422
22700
|
return [
|
|
22423
|
-
[
|
|
22424
|
-
[
|
|
22701
|
+
[path46.join(os12.homedir(), ".aws", "config"), "[default]"],
|
|
22702
|
+
[path46.join(os12.homedir(), ".aws", "credentials"), "[default]"]
|
|
22425
22703
|
];
|
|
22426
22704
|
}
|
|
22427
22705
|
function awsDefaultProfileRegion() {
|
|
22428
22706
|
for (const [file, header] of awsDefaultProfileSections()) {
|
|
22429
22707
|
try {
|
|
22430
|
-
const region = parseProfileRegion(
|
|
22708
|
+
const region = parseProfileRegion(fs39.readFileSync(file, "utf-8"), header);
|
|
22431
22709
|
if (region) return region;
|
|
22432
22710
|
} catch {
|
|
22433
22711
|
}
|
|
@@ -22814,8 +23092,8 @@ async function resolveToken(opts) {
|
|
|
22814
23092
|
"no token: pass --token, set VCS_TOKEN, or pass --context <platform-context> (after mesh login)"
|
|
22815
23093
|
);
|
|
22816
23094
|
}
|
|
22817
|
-
async function vcsApi(baseUrl, token,
|
|
22818
|
-
const res = await fetch(`${baseUrl}${
|
|
23095
|
+
async function vcsApi(baseUrl, token, path48, method = "GET", body) {
|
|
23096
|
+
const res = await fetch(`${baseUrl}${path48}`, {
|
|
22819
23097
|
method,
|
|
22820
23098
|
headers: {
|
|
22821
23099
|
authorization: `Bearer ${token}`,
|
|
@@ -22826,7 +23104,7 @@ async function vcsApi(baseUrl, token, path47, method = "GET", body) {
|
|
|
22826
23104
|
const data = await res.json().catch(() => ({}));
|
|
22827
23105
|
if (!res.ok) {
|
|
22828
23106
|
throw new Error(
|
|
22829
|
-
`${method} ${
|
|
23107
|
+
`${method} ${path48} failed (${res.status}): ${String(data.error ?? "unknown error")}`
|
|
22830
23108
|
);
|
|
22831
23109
|
}
|
|
22832
23110
|
return data;
|
|
@@ -22872,8 +23150,8 @@ var init_clone = __esm({
|
|
|
22872
23150
|
|
|
22873
23151
|
// libs/mesh-cli/src/commands/vcs/get.ts
|
|
22874
23152
|
import { writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
|
|
22875
|
-
import { join as
|
|
22876
|
-
async function getCommand(repo,
|
|
23153
|
+
import { join as join44, dirname as dirname29 } from "node:path";
|
|
23154
|
+
async function getCommand(repo, path48, opts) {
|
|
22877
23155
|
let vcsBaseUrl;
|
|
22878
23156
|
let token;
|
|
22879
23157
|
if (opts.target) {
|
|
@@ -22888,18 +23166,18 @@ async function getCommand(repo, path47, opts) {
|
|
|
22888
23166
|
if (!token) throw new Error("no token: pass --target (after mesh login), or --token / --context");
|
|
22889
23167
|
const reader = createVcsFolderReader({ vcsBaseUrl, token });
|
|
22890
23168
|
try {
|
|
22891
|
-
const { ref, files } = await reader.readPath(repo,
|
|
23169
|
+
const { ref, files } = await reader.readPath(repo, path48);
|
|
22892
23170
|
if (files.length === 0) {
|
|
22893
|
-
logInfo(`no files at ${repo}:${
|
|
23171
|
+
logInfo(`no files at ${repo}:${path48}`);
|
|
22894
23172
|
return;
|
|
22895
23173
|
}
|
|
22896
23174
|
if (opts.output) {
|
|
22897
23175
|
for (const f of files) {
|
|
22898
|
-
const abs =
|
|
23176
|
+
const abs = join44(opts.output, f.path);
|
|
22899
23177
|
await mkdir2(dirname29(abs), { recursive: true });
|
|
22900
23178
|
await writeFile2(abs, f.contents);
|
|
22901
23179
|
}
|
|
22902
|
-
logInfo(`wrote ${files.length} file(s) from ${repo}:${
|
|
23180
|
+
logInfo(`wrote ${files.length} file(s) from ${repo}:${path48} (${ref}) \u2192 ${opts.output}`);
|
|
22903
23181
|
} else {
|
|
22904
23182
|
for (const f of files) {
|
|
22905
23183
|
if (files.length > 1) process.stdout.write(`
|
|
@@ -22924,10 +23202,10 @@ var init_get = __esm({
|
|
|
22924
23202
|
});
|
|
22925
23203
|
|
|
22926
23204
|
// libs/mesh-cli/src/commands/vcs/drafts.ts
|
|
22927
|
-
async function call(opts, repo,
|
|
23205
|
+
async function call(opts, repo, path48, method = "GET", body) {
|
|
22928
23206
|
const target = await resolveTarget2({ ...opts, repo });
|
|
22929
23207
|
const token = await resolveToken(opts);
|
|
22930
|
-
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${
|
|
23208
|
+
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${path48}`, method, body);
|
|
22931
23209
|
}
|
|
22932
23210
|
async function draftsListCommand(repo, opts) {
|
|
22933
23211
|
const data = await call(opts, repo, `/drafts${opts.all ? "?all=true" : ""}`);
|
|
@@ -22982,7 +23260,7 @@ var init_drafts = __esm({
|
|
|
22982
23260
|
|
|
22983
23261
|
// libs/mesh-cli/src/commands/vcs/propose.ts
|
|
22984
23262
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
22985
|
-
import { join as
|
|
23263
|
+
import { join as join45 } from "node:path";
|
|
22986
23264
|
function parseStatus(out) {
|
|
22987
23265
|
const tokens = out.split("\0");
|
|
22988
23266
|
const changes = [];
|
|
@@ -23015,13 +23293,13 @@ function parseStatus(out) {
|
|
|
23015
23293
|
}
|
|
23016
23294
|
return changes;
|
|
23017
23295
|
}
|
|
23018
|
-
async function writeOp(cwd,
|
|
23019
|
-
const buf = await readFile3(
|
|
23296
|
+
async function writeOp(cwd, path48) {
|
|
23297
|
+
const buf = await readFile3(join45(cwd, path48));
|
|
23020
23298
|
const asUtf8 = buf.toString("utf8");
|
|
23021
23299
|
if (Buffer.from(asUtf8, "utf8").equals(buf)) {
|
|
23022
|
-
return { op: "write", path:
|
|
23300
|
+
return { op: "write", path: path48, content: asUtf8 };
|
|
23023
23301
|
}
|
|
23024
|
-
return { op: "write", path:
|
|
23302
|
+
return { op: "write", path: path48, content: buf.toString("base64"), encoding: "base64" };
|
|
23025
23303
|
}
|
|
23026
23304
|
async function proposeCommand(opts) {
|
|
23027
23305
|
const cwd = process.cwd();
|
|
@@ -23065,8 +23343,8 @@ async function proposeCommand(opts) {
|
|
|
23065
23343
|
operations,
|
|
23066
23344
|
...opts.mergeParent ? { mergeParent: opts.mergeParent } : {}
|
|
23067
23345
|
};
|
|
23068
|
-
const
|
|
23069
|
-
const data = await vcsApi(target.baseUrl, token,
|
|
23346
|
+
const path48 = opts.revise ? `/v1/repos/${target.repo}/proposals/${opts.revise}/revisions` : `/v1/repos/${target.repo}/proposals`;
|
|
23347
|
+
const data = await vcsApi(target.baseUrl, token, path48, "POST", body);
|
|
23070
23348
|
console.log(
|
|
23071
23349
|
`proposal ${data.proposalId} @ ${data.sha.slice(0, 8)} \u2014 review: mesh vcs show ${target.repo} ${data.proposalId} --url ${target.baseUrl}`
|
|
23072
23350
|
);
|
|
@@ -23081,28 +23359,28 @@ var init_propose = __esm({
|
|
|
23081
23359
|
// libs/mesh-cli/src/commands/vcs/rm.ts
|
|
23082
23360
|
import { mkdtemp as mkdtemp2, rm as rmrf } from "node:fs/promises";
|
|
23083
23361
|
import { tmpdir as tmpdir10 } from "node:os";
|
|
23084
|
-
import { join as
|
|
23362
|
+
import { join as join46 } from "node:path";
|
|
23085
23363
|
function normalize2(p) {
|
|
23086
23364
|
return p.trim().replace(/^\.\//, "").replace(/\/+$/, "");
|
|
23087
23365
|
}
|
|
23088
23366
|
function expandPathsToDeletions(repoFiles, requested) {
|
|
23089
23367
|
const out = /* @__PURE__ */ new Set();
|
|
23090
23368
|
for (const raw of requested) {
|
|
23091
|
-
const
|
|
23092
|
-
if (
|
|
23369
|
+
const path48 = normalize2(raw);
|
|
23370
|
+
if (path48.startsWith("/") || path48.split("/").includes("..")) {
|
|
23093
23371
|
throw new Error(
|
|
23094
23372
|
`"${raw}" is not a repo-relative path \u2014 vcs paths never start with "/" or traverse with "..".`
|
|
23095
23373
|
);
|
|
23096
23374
|
}
|
|
23097
|
-
const exact = repoFiles.filter((f) => f ===
|
|
23375
|
+
const exact = repoFiles.filter((f) => f === path48);
|
|
23098
23376
|
if (exact.length > 0) {
|
|
23099
23377
|
for (const f of exact) out.add(f);
|
|
23100
23378
|
continue;
|
|
23101
23379
|
}
|
|
23102
|
-
const under = repoFiles.filter((f) => f.startsWith(`${
|
|
23380
|
+
const under = repoFiles.filter((f) => f.startsWith(`${path48}/`));
|
|
23103
23381
|
if (under.length === 0) {
|
|
23104
23382
|
throw new Error(
|
|
23105
|
-
`"${raw}" matched no files in the repo \u2014 nothing was proposed. Check the path with: mesh vcs get <repo> ${
|
|
23383
|
+
`"${raw}" matched no files in the repo \u2014 nothing was proposed. Check the path with: mesh vcs get <repo> ${path48}`
|
|
23106
23384
|
);
|
|
23107
23385
|
}
|
|
23108
23386
|
for (const f of under) out.add(f);
|
|
@@ -23113,7 +23391,7 @@ async function rmCommand(repo, paths, opts) {
|
|
|
23113
23391
|
const baseUrl = (opts.url ?? process.env.VCS_URL)?.replace(/\/$/, "");
|
|
23114
23392
|
if (!baseUrl) throw new Error("rm requires --url or VCS_URL");
|
|
23115
23393
|
const token = await resolveToken(opts);
|
|
23116
|
-
const dir = await mkdtemp2(
|
|
23394
|
+
const dir = await mkdtemp2(join46(tmpdir10(), "mesh-vcs-rm-"));
|
|
23117
23395
|
try {
|
|
23118
23396
|
const git = (args, cwd) => gitWithAuth(args, token, cwd);
|
|
23119
23397
|
await git([
|
|
@@ -23138,7 +23416,7 @@ async function rmCommand(repo, paths, opts) {
|
|
|
23138
23416
|
const body = {
|
|
23139
23417
|
baseCommit: head.trim(),
|
|
23140
23418
|
message: opts.message ?? `Delete ${doomed.length} file(s)`,
|
|
23141
|
-
operations: doomed.map((
|
|
23419
|
+
operations: doomed.map((path48) => ({ op: "delete", path: path48 }))
|
|
23142
23420
|
};
|
|
23143
23421
|
const data = await vcsApi(
|
|
23144
23422
|
baseUrl,
|
|
@@ -23164,10 +23442,10 @@ var init_rm = __esm({
|
|
|
23164
23442
|
});
|
|
23165
23443
|
|
|
23166
23444
|
// libs/mesh-cli/src/commands/vcs/review.ts
|
|
23167
|
-
async function call2(opts, repo,
|
|
23445
|
+
async function call2(opts, repo, path48, method = "GET", body) {
|
|
23168
23446
|
const target = await resolveTarget2({ ...opts, repo });
|
|
23169
23447
|
const token = await resolveToken(opts);
|
|
23170
|
-
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${
|
|
23448
|
+
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${path48}`, method, body);
|
|
23171
23449
|
}
|
|
23172
23450
|
async function proposalsCommand(repo, opts) {
|
|
23173
23451
|
console.log(JSON.stringify(await call2(opts, repo, "/proposals"), null, 2));
|
|
@@ -23314,8 +23592,8 @@ function computeHappyPath(nodes, edges) {
|
|
|
23314
23592
|
];
|
|
23315
23593
|
const visited = /* @__PURE__ */ new Set([startNode.id]);
|
|
23316
23594
|
while (queue.length > 0) {
|
|
23317
|
-
const { id, path:
|
|
23318
|
-
if (targetIds.has(id)) return
|
|
23595
|
+
const { id, path: path48 } = queue.shift();
|
|
23596
|
+
if (targetIds.has(id)) return path48;
|
|
23319
23597
|
const neighbors = adjacency.get(id) ?? [];
|
|
23320
23598
|
const hasMainEdge = neighbors.some((e) => e.isMainPath);
|
|
23321
23599
|
const candidates = hasMainEdge ? neighbors.filter((e) => e.isMainPath) : neighbors;
|
|
@@ -23335,7 +23613,7 @@ function computeHappyPath(nodes, edges) {
|
|
|
23335
23613
|
if (!allowExceptional && (neighbor.isExceptional || neighbor.isTimeout || failureEndIds.has(neighbor.to)))
|
|
23336
23614
|
continue;
|
|
23337
23615
|
visited.add(neighbor.to);
|
|
23338
|
-
queue.push({ id: neighbor.to, path: [...
|
|
23616
|
+
queue.push({ id: neighbor.to, path: [...path48, neighbor.to] });
|
|
23339
23617
|
}
|
|
23340
23618
|
}
|
|
23341
23619
|
return null;
|
|
@@ -23620,11 +23898,11 @@ function wrapIntoGroup(workflow, nodeIds, groupId, label, groupType) {
|
|
|
23620
23898
|
}
|
|
23621
23899
|
}
|
|
23622
23900
|
if (found) {
|
|
23623
|
-
const
|
|
23624
|
-
for (let c = found; c !== void 0; c = prev.get(c))
|
|
23625
|
-
for (let i = 0; i <
|
|
23901
|
+
const path48 = [];
|
|
23902
|
+
for (let c = found; c !== void 0; c = prev.get(c)) path48.unshift(c);
|
|
23903
|
+
for (let i = 0; i < path48.length - 1; i++) mainEdgeKeys.add(edgeKey(path48[i], path48[i + 1]));
|
|
23626
23904
|
mainEdgeKeys.add(edgeKey(found, successExit.id));
|
|
23627
|
-
mainBody =
|
|
23905
|
+
mainBody = path48;
|
|
23628
23906
|
mainTail = [successExit.id];
|
|
23629
23907
|
}
|
|
23630
23908
|
}
|
|
@@ -24160,11 +24438,11 @@ function buildProcessManifest(artifact, outcomeNodeIds) {
|
|
|
24160
24438
|
...pointOfNoReturnStage ? { pointOfNoReturnStageId: pointOfNoReturnStage.id } : {}
|
|
24161
24439
|
};
|
|
24162
24440
|
}
|
|
24163
|
-
function formatPath(
|
|
24164
|
-
return
|
|
24441
|
+
function formatPath(path48) {
|
|
24442
|
+
return path48.length > 0 ? z4.core.toDotPath(path48) : "(root)";
|
|
24165
24443
|
}
|
|
24166
24444
|
function issueToDiagnostic(issue) {
|
|
24167
|
-
const
|
|
24445
|
+
const path48 = formatPath(issue.path);
|
|
24168
24446
|
let code = "SCHEMA_INVALID";
|
|
24169
24447
|
if (issue.code === "custom") {
|
|
24170
24448
|
const paramCode = issue.params?.code;
|
|
@@ -24175,8 +24453,8 @@ function issueToDiagnostic(issue) {
|
|
|
24175
24453
|
return {
|
|
24176
24454
|
severity: "error",
|
|
24177
24455
|
code,
|
|
24178
|
-
message: `${
|
|
24179
|
-
path:
|
|
24456
|
+
message: `${path48}: ${issue.message}`,
|
|
24457
|
+
path: path48
|
|
24180
24458
|
};
|
|
24181
24459
|
}
|
|
24182
24460
|
function upgradeV1(artifact) {
|
|
@@ -24343,24 +24621,24 @@ var init_process_artifact = __esm({
|
|
|
24343
24621
|
});
|
|
24344
24622
|
}
|
|
24345
24623
|
const declaredSelectors = new Set(Object.keys(process2.selectors ?? {}));
|
|
24346
|
-
const checkActor = (actorId,
|
|
24624
|
+
const checkActor = (actorId, path48) => {
|
|
24347
24625
|
if (actorId === void 0) return;
|
|
24348
24626
|
if (!Object.prototype.hasOwnProperty.call(process2.actors, actorId)) {
|
|
24349
24627
|
ctx.addIssue({
|
|
24350
24628
|
code: "custom",
|
|
24351
|
-
path:
|
|
24352
|
-
message: `Actor "${actorId}" is referenced at ${z4.core.toDotPath(
|
|
24629
|
+
path: path48,
|
|
24630
|
+
message: `Actor "${actorId}" is referenced at ${z4.core.toDotPath(path48)} but not declared in process.actors. Declare the actor (label, and optionally category/selector) or fix the reference.`,
|
|
24353
24631
|
params: { code: "UNDECLARED_ACTOR" }
|
|
24354
24632
|
});
|
|
24355
24633
|
}
|
|
24356
24634
|
};
|
|
24357
|
-
const checkSelector = (selector,
|
|
24635
|
+
const checkSelector = (selector, path48) => {
|
|
24358
24636
|
if (selector === void 0) return;
|
|
24359
24637
|
if (!declaredSelectors.has(selector)) {
|
|
24360
24638
|
ctx.addIssue({
|
|
24361
24639
|
code: "custom",
|
|
24362
|
-
path:
|
|
24363
|
-
message: `Selector "${selector}" is referenced at ${z4.core.toDotPath(
|
|
24640
|
+
path: path48,
|
|
24641
|
+
message: `Selector "${selector}" is referenced at ${z4.core.toDotPath(path48)} but not declared in process.selectors. Declare the selector or fix the reference.`,
|
|
24364
24642
|
params: { code: "UNDECLARED_SELECTOR" }
|
|
24365
24643
|
});
|
|
24366
24644
|
}
|
|
@@ -24374,20 +24652,20 @@ var init_process_artifact = __esm({
|
|
|
24374
24652
|
outcome: "DUPLICATE_OUTCOME_ID"
|
|
24375
24653
|
};
|
|
24376
24654
|
const idFirstSeenAt = /* @__PURE__ */ new Map();
|
|
24377
|
-
const checkId = (id, kind,
|
|
24655
|
+
const checkId = (id, kind, path48) => {
|
|
24378
24656
|
const first = idFirstSeenAt.get(id);
|
|
24379
24657
|
if (first) {
|
|
24380
24658
|
const kindLabel = kind === first.kind ? kind : "process";
|
|
24381
24659
|
ctx.addIssue({
|
|
24382
24660
|
code: "custom",
|
|
24383
|
-
path:
|
|
24384
|
-
message: `Duplicate ${kindLabel} id "${id}": ${kind} at ${z4.core.toDotPath(
|
|
24661
|
+
path: path48,
|
|
24662
|
+
message: `Duplicate ${kindLabel} id "${id}": ${kind} at ${z4.core.toDotPath(path48)} collides with ${first.kind} at ${z4.core.toDotPath(first.path)}.`,
|
|
24385
24663
|
params: {
|
|
24386
24664
|
code: kind === first.kind ? SAME_KIND_CODE[kind] : "DUPLICATE_PROCESS_ID"
|
|
24387
24665
|
}
|
|
24388
24666
|
});
|
|
24389
24667
|
} else {
|
|
24390
|
-
idFirstSeenAt.set(id, { kind, path:
|
|
24668
|
+
idFirstSeenAt.set(id, { kind, path: path48 });
|
|
24391
24669
|
}
|
|
24392
24670
|
};
|
|
24393
24671
|
process2.stages.forEach((stage, stageIndex) => {
|
|
@@ -24434,13 +24712,13 @@ function lintProcess(artifact, inventory, predicateNames, options = {}) {
|
|
|
24434
24712
|
const internalCommands = process2.internalCommands ?? [];
|
|
24435
24713
|
const internalSet = new Set(internalCommands);
|
|
24436
24714
|
const boundCommandPaths = /* @__PURE__ */ new Map();
|
|
24437
|
-
const checkPredicate = (predicate,
|
|
24715
|
+
const checkPredicate = (predicate, path48) => {
|
|
24438
24716
|
if (!predicateSet.has(predicate)) {
|
|
24439
24717
|
diagnostics.push({
|
|
24440
24718
|
severity: "error",
|
|
24441
24719
|
code: "UNKNOWN_PREDICATE",
|
|
24442
|
-
message: `Predicate "${predicate}" referenced at ${
|
|
24443
|
-
path:
|
|
24720
|
+
message: `Predicate "${predicate}" referenced at ${path48} is not in the predicate registry.`,
|
|
24721
|
+
path: path48
|
|
24444
24722
|
});
|
|
24445
24723
|
}
|
|
24446
24724
|
};
|
|
@@ -24500,19 +24778,19 @@ function lintProcess(artifact, inventory, predicateNames, options = {}) {
|
|
|
24500
24778
|
process2.outcomes.forEach((outcome, outcomeIndex) => {
|
|
24501
24779
|
const whenPath = `process.outcomes[${outcomeIndex}].when`;
|
|
24502
24780
|
outcomeTriggers(outcome).forEach((trigger, triggerIndex) => {
|
|
24503
|
-
const
|
|
24781
|
+
const path48 = Array.isArray(outcome.when) ? `${whenPath}[${triggerIndex}]` : whenPath;
|
|
24504
24782
|
if (trigger.kind === "predicate") {
|
|
24505
|
-
checkPredicate(trigger.name, `${
|
|
24783
|
+
checkPredicate(trigger.name, `${path48}.predicate`);
|
|
24506
24784
|
} else if (trigger.kind === "command") {
|
|
24507
24785
|
if (!boundCommandPaths.has(trigger.name)) {
|
|
24508
|
-
boundCommandPaths.set(trigger.name, `${
|
|
24786
|
+
boundCommandPaths.set(trigger.name, `${path48}.command`);
|
|
24509
24787
|
}
|
|
24510
24788
|
if (!commandNames.has(trigger.name)) {
|
|
24511
24789
|
diagnostics.push({
|
|
24512
24790
|
severity: "error",
|
|
24513
24791
|
code: "BOUND_COMMAND_NOT_IN_INVENTORY",
|
|
24514
|
-
message: `Command "${trigger.name}" triggering outcome "${outcome.id}" (${
|
|
24515
|
-
path: `${
|
|
24792
|
+
message: `Command "${trigger.name}" triggering outcome "${outcome.id}" (${path48}.command) does not exist in the inventory.`,
|
|
24793
|
+
path: `${path48}.command`
|
|
24516
24794
|
});
|
|
24517
24795
|
}
|
|
24518
24796
|
}
|
|
@@ -24624,10 +24902,10 @@ var init_src4 = __esm({
|
|
|
24624
24902
|
});
|
|
24625
24903
|
|
|
24626
24904
|
// libs/mesh-cli/src/commands/workflow.ts
|
|
24627
|
-
import * as
|
|
24628
|
-
import * as
|
|
24905
|
+
import * as fs40 from "fs";
|
|
24906
|
+
import * as path47 from "path";
|
|
24629
24907
|
import { createRequire as createRequire2 } from "module";
|
|
24630
|
-
import { execFileSync as
|
|
24908
|
+
import { execFileSync as execFileSync33 } from "child_process";
|
|
24631
24909
|
function resolveExtractorPath() {
|
|
24632
24910
|
try {
|
|
24633
24911
|
const require2 = createRequire2(import.meta.url);
|
|
@@ -24641,7 +24919,7 @@ function runExtraction(targetPath, extractorPath, explicitProcessPath) {
|
|
|
24641
24919
|
let explicitProcessArtifact;
|
|
24642
24920
|
if (explicitProcessPath) {
|
|
24643
24921
|
try {
|
|
24644
|
-
explicitProcessArtifact = JSON.parse(
|
|
24922
|
+
explicitProcessArtifact = JSON.parse(fs40.readFileSync(explicitProcessPath, "utf-8"));
|
|
24645
24923
|
} catch (err) {
|
|
24646
24924
|
logError(
|
|
24647
24925
|
`Could not read/parse --process ${explicitProcessPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -24682,7 +24960,7 @@ for (const file of files) {
|
|
|
24682
24960
|
process.stdout.write(JSON.stringify(results));
|
|
24683
24961
|
`;
|
|
24684
24962
|
try {
|
|
24685
|
-
const result =
|
|
24963
|
+
const result = execFileSync33("npx", ["tsx", "--eval", script], {
|
|
24686
24964
|
encoding: "utf-8",
|
|
24687
24965
|
stdio: ["pipe", "pipe", "inherit"],
|
|
24688
24966
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -24724,7 +25002,7 @@ for (const file of files) {
|
|
|
24724
25002
|
process.stdout.write(JSON.stringify(results));
|
|
24725
25003
|
`;
|
|
24726
25004
|
try {
|
|
24727
|
-
const result =
|
|
25005
|
+
const result = execFileSync33("npx", ["tsx", "--eval", script], {
|
|
24728
25006
|
encoding: "utf-8",
|
|
24729
25007
|
stdio: ["pipe", "pipe", "inherit"],
|
|
24730
25008
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -24741,7 +25019,7 @@ function runLintExtraction(targetPath, extractorPath, explicitProcessPath) {
|
|
|
24741
25019
|
let explicitProcessArtifact;
|
|
24742
25020
|
if (explicitProcessPath) {
|
|
24743
25021
|
try {
|
|
24744
|
-
explicitProcessArtifact = JSON.parse(
|
|
25022
|
+
explicitProcessArtifact = JSON.parse(fs40.readFileSync(explicitProcessPath, "utf-8"));
|
|
24745
25023
|
} catch (err) {
|
|
24746
25024
|
logError(
|
|
24747
25025
|
`Could not read/parse --process ${explicitProcessPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -24779,7 +25057,7 @@ for (const file of files) {
|
|
|
24779
25057
|
process.stdout.write(JSON.stringify(results));
|
|
24780
25058
|
`;
|
|
24781
25059
|
try {
|
|
24782
|
-
const result =
|
|
25060
|
+
const result = execFileSync33("npx", ["tsx", "--eval", script], {
|
|
24783
25061
|
encoding: "utf-8",
|
|
24784
25062
|
stdio: ["pipe", "pipe", "inherit"],
|
|
24785
25063
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -24849,16 +25127,16 @@ function registerWorkflowCommands(program2) {
|
|
|
24849
25127
|
).action(
|
|
24850
25128
|
async (targetPath, opts) => {
|
|
24851
25129
|
try {
|
|
24852
|
-
const resolvedPath =
|
|
24853
|
-
if (!
|
|
25130
|
+
const resolvedPath = path47.resolve(targetPath);
|
|
25131
|
+
if (!fs40.existsSync(resolvedPath)) {
|
|
24854
25132
|
logError(`Path does not exist: ${resolvedPath}`);
|
|
24855
25133
|
process.exitCode = 1;
|
|
24856
25134
|
return;
|
|
24857
25135
|
}
|
|
24858
25136
|
let resolvedProcessPath;
|
|
24859
25137
|
if (opts.process) {
|
|
24860
|
-
resolvedProcessPath =
|
|
24861
|
-
if (!
|
|
25138
|
+
resolvedProcessPath = path47.resolve(opts.process);
|
|
25139
|
+
if (!fs40.existsSync(resolvedProcessPath)) {
|
|
24862
25140
|
logError(`--process path does not exist: ${resolvedProcessPath}`);
|
|
24863
25141
|
process.exitCode = 1;
|
|
24864
25142
|
return;
|
|
@@ -24907,8 +25185,8 @@ function registerWorkflowCommands(program2) {
|
|
|
24907
25185
|
"Extract the as-built command/query/activity inventory from Temporal workflow source\n\nThe inventory ({ workflowType, commands, queries, activities }) is the process-\nconformance lint's code-side input \u2014 it is never hand-edited. Supports single\nfiles or directories."
|
|
24908
25186
|
).action(async (targetPath) => {
|
|
24909
25187
|
try {
|
|
24910
|
-
const resolvedPath =
|
|
24911
|
-
if (!
|
|
25188
|
+
const resolvedPath = path47.resolve(targetPath);
|
|
25189
|
+
if (!fs40.existsSync(resolvedPath)) {
|
|
24912
25190
|
logError(`Path does not exist: ${resolvedPath}`);
|
|
24913
25191
|
process.exitCode = 1;
|
|
24914
25192
|
return;
|
|
@@ -24954,16 +25232,16 @@ function registerWorkflowCommands(program2) {
|
|
|
24954
25232
|
"Comma-separated named-selector registry (enables UNKNOWN_SELECTOR checks)"
|
|
24955
25233
|
).action(async (targetPath, opts) => {
|
|
24956
25234
|
try {
|
|
24957
|
-
const resolvedPath =
|
|
24958
|
-
if (!
|
|
25235
|
+
const resolvedPath = path47.resolve(targetPath);
|
|
25236
|
+
if (!fs40.existsSync(resolvedPath)) {
|
|
24959
25237
|
logError(`Path does not exist: ${resolvedPath}`);
|
|
24960
25238
|
process.exitCode = 1;
|
|
24961
25239
|
return;
|
|
24962
25240
|
}
|
|
24963
25241
|
let resolvedProcessPath;
|
|
24964
25242
|
if (opts.process) {
|
|
24965
|
-
resolvedProcessPath =
|
|
24966
|
-
if (!
|
|
25243
|
+
resolvedProcessPath = path47.resolve(opts.process);
|
|
25244
|
+
if (!fs40.existsSync(resolvedProcessPath)) {
|
|
24967
25245
|
logError(`--process path does not exist: ${resolvedProcessPath}`);
|
|
24968
25246
|
process.exitCode = 1;
|
|
24969
25247
|
return;
|