@mesh-tech/mesh-cli 0.26.0 → 0.28.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 +1083 -782
- package/dist/bin/mesh.js.map +3 -3
- package/dist/build-info.json +2 -2
- package/dist/src/commands/app-check.js +2 -1
- package/dist/src/commands/hub/index.d.ts +2 -0
- package/dist/src/commands/hub/index.js +16 -1
- 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/fragments/base/index.ts.hbs +13 -1
- 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/templates/api-auth/index.ts.hbs +5 -1
- package/templates/api-role-gating/index.ts.hbs +5 -1
- package/templates/external-service/index.ts.hbs +5 -1
- package/templates/platform-repo/AGENTS.md.hbs +20 -4
- package/templates/workflow/index.ts.hbs +5 -1
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 });
|
|
@@ -11596,7 +11830,11 @@ var init_app_check = __esm({
|
|
|
11596
11830
|
gate: "0.2",
|
|
11597
11831
|
title: "App registers with the Hub",
|
|
11598
11832
|
severity: "block",
|
|
11599
|
-
|
|
11833
|
+
// The registration's prose is read by the CLIENT's operators, so the
|
|
11834
|
+
// remediation names the split rather than one field: `description` is one
|
|
11835
|
+
// sentence for them, `operatorNote` is where the engineering material goes
|
|
11836
|
+
// (a tenant-audience Hub drops that key from the response entirely).
|
|
11837
|
+
remediation: "end index.ts with `export const app = env.register({ displayName, description })` \u2014 one sentence a non-technical operator can act on; put the caveats in `operatorNote`",
|
|
11600
11838
|
scope: "app"
|
|
11601
11839
|
},
|
|
11602
11840
|
CUSTOM_SESSION_AUTH: {
|
|
@@ -11795,14 +12033,14 @@ var init_resolve = __esm({
|
|
|
11795
12033
|
});
|
|
11796
12034
|
|
|
11797
12035
|
// packages/agent-targets/src/load.ts
|
|
11798
|
-
import { readFileSync as
|
|
12036
|
+
import { readFileSync as readFileSync19 } from "node:fs";
|
|
11799
12037
|
import { homedir as homedir3 } from "node:os";
|
|
11800
|
-
import
|
|
12038
|
+
import path24 from "node:path";
|
|
11801
12039
|
function loadTargetsFile(env = process.env) {
|
|
11802
12040
|
const file = env.MESH_AGENT_TARGETS || DEFAULT_REGISTRY_PATH;
|
|
11803
12041
|
let raw;
|
|
11804
12042
|
try {
|
|
11805
|
-
raw =
|
|
12043
|
+
raw = readFileSync19(file, "utf8");
|
|
11806
12044
|
} catch {
|
|
11807
12045
|
return { status: "absent", path: file };
|
|
11808
12046
|
}
|
|
@@ -11821,7 +12059,7 @@ var init_load = __esm({
|
|
|
11821
12059
|
"use strict";
|
|
11822
12060
|
init_schema();
|
|
11823
12061
|
init_resolve();
|
|
11824
|
-
DEFAULT_REGISTRY_PATH =
|
|
12062
|
+
DEFAULT_REGISTRY_PATH = path24.join(homedir3(), ".config", "mesh", "agent-targets.json");
|
|
11825
12063
|
}
|
|
11826
12064
|
});
|
|
11827
12065
|
|
|
@@ -12053,9 +12291,9 @@ var init_pull = __esm({
|
|
|
12053
12291
|
|
|
12054
12292
|
// packages/agent-targets/src/pull/write.ts
|
|
12055
12293
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
12056
|
-
import { join as
|
|
12294
|
+
import { join as join21, dirname as dirname19 } from "node:path";
|
|
12057
12295
|
async function put(dir, rel2, contents, written) {
|
|
12058
|
-
const abs =
|
|
12296
|
+
const abs = join21(dir, rel2);
|
|
12059
12297
|
await mkdir(dirname19(abs), { recursive: true });
|
|
12060
12298
|
await writeFile(abs, contents);
|
|
12061
12299
|
written.push(rel2);
|
|
@@ -12182,7 +12420,7 @@ import { execFile as execFile2 } from "node:child_process";
|
|
|
12182
12420
|
import { promisify } from "node:util";
|
|
12183
12421
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
12184
12422
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
12185
|
-
import { join as
|
|
12423
|
+
import { join as join22 } from "node:path";
|
|
12186
12424
|
function deriveVcsBaseUrl(apiBaseUrl) {
|
|
12187
12425
|
try {
|
|
12188
12426
|
const u = new URL(apiBaseUrl);
|
|
@@ -12241,7 +12479,7 @@ function createVcsFolderReader(opts) {
|
|
|
12241
12479
|
let p = clones.get(repo);
|
|
12242
12480
|
if (!p) {
|
|
12243
12481
|
p = (async () => {
|
|
12244
|
-
const dir = await mkdtemp(
|
|
12482
|
+
const dir = await mkdtemp(join22(tmpdir4(), "mesh-vcs-"));
|
|
12245
12483
|
await execFileAsync("git", [
|
|
12246
12484
|
"clone",
|
|
12247
12485
|
"--filter=blob:none",
|
|
@@ -12258,11 +12496,11 @@ function createVcsFolderReader(opts) {
|
|
|
12258
12496
|
}
|
|
12259
12497
|
return p;
|
|
12260
12498
|
};
|
|
12261
|
-
const readPath = async (repo,
|
|
12499
|
+
const readPath = async (repo, path48) => {
|
|
12262
12500
|
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,
|
|
12501
|
+
const ref = await resolveFolderRef(dir, path48);
|
|
12502
|
+
if (!ref) throw new Error(`path "${path48}" not found on any ref of ${repo}`);
|
|
12503
|
+
const files = await readFolderAtRef(dir, ref, path48);
|
|
12266
12504
|
return { ref, files };
|
|
12267
12505
|
};
|
|
12268
12506
|
const cleanup = async () => {
|
|
@@ -12453,8 +12691,8 @@ var init_agent_api_client = __esm({
|
|
|
12453
12691
|
});
|
|
12454
12692
|
|
|
12455
12693
|
// libs/mesh-cli/src/commands/artifacts.ts
|
|
12456
|
-
import * as
|
|
12457
|
-
import * as
|
|
12694
|
+
import * as fs23 from "fs";
|
|
12695
|
+
import * as path25 from "path";
|
|
12458
12696
|
function parseRef(ref) {
|
|
12459
12697
|
const colonIdx = ref.indexOf(":");
|
|
12460
12698
|
if (colonIdx === -1) {
|
|
@@ -12477,28 +12715,28 @@ async function getArtifact(ref, options, target) {
|
|
|
12477
12715
|
const { conversationId, artifactId } = parseRef(ref);
|
|
12478
12716
|
logInfo(`Fetching ${conversationId}:${artifactId} from ${target.apiBaseUrl}\u2026`);
|
|
12479
12717
|
const bundle = await fetchExportBundle(target, conversationId, artifactId);
|
|
12480
|
-
const outputDir = options.output ??
|
|
12481
|
-
|
|
12718
|
+
const outputDir = options.output ?? path25.join("workflows", bundle.primaryWorkflow);
|
|
12719
|
+
fs23.mkdirSync(outputDir, { recursive: true });
|
|
12482
12720
|
let filesWritten = 0;
|
|
12483
12721
|
for (const file of bundle.files) {
|
|
12484
|
-
const filePath =
|
|
12485
|
-
|
|
12722
|
+
const filePath = path25.join(outputDir, file.filename);
|
|
12723
|
+
fs23.writeFileSync(filePath, file.code, "utf-8");
|
|
12486
12724
|
logSuccess(` ${file.filename}`);
|
|
12487
12725
|
filesWritten++;
|
|
12488
12726
|
}
|
|
12489
12727
|
if (bundle.overview) {
|
|
12490
|
-
const readmePath =
|
|
12491
|
-
|
|
12728
|
+
const readmePath = path25.join(outputDir, "README.md");
|
|
12729
|
+
fs23.writeFileSync(readmePath, bundle.overview, "utf-8");
|
|
12492
12730
|
logSuccess(` README.md`);
|
|
12493
12731
|
filesWritten++;
|
|
12494
12732
|
}
|
|
12495
12733
|
if (bundle.ir) {
|
|
12496
|
-
const irPath =
|
|
12497
|
-
|
|
12734
|
+
const irPath = path25.join(outputDir, "workflow-ir.json");
|
|
12735
|
+
fs23.writeFileSync(irPath, JSON.stringify(bundle.ir, null, 2), "utf-8");
|
|
12498
12736
|
logSuccess(` workflow-ir.json`);
|
|
12499
12737
|
filesWritten++;
|
|
12500
12738
|
}
|
|
12501
|
-
const metaPath =
|
|
12739
|
+
const metaPath = path25.join(outputDir, ".workflow-meta.json");
|
|
12502
12740
|
const meta = {
|
|
12503
12741
|
conversationId: bundle.conversationId,
|
|
12504
12742
|
artifactId,
|
|
@@ -12506,7 +12744,7 @@ async function getArtifact(ref, options, target) {
|
|
|
12506
12744
|
exportedAt: bundle.exportedAt,
|
|
12507
12745
|
files: bundle.files.map((f) => f.filename)
|
|
12508
12746
|
};
|
|
12509
|
-
|
|
12747
|
+
fs23.writeFileSync(metaPath, JSON.stringify(meta, null, 2), "utf-8");
|
|
12510
12748
|
console.log();
|
|
12511
12749
|
logSuccess(
|
|
12512
12750
|
`Exported ${filesWritten} files to ${outputDir}/`
|
|
@@ -12930,7 +13168,7 @@ var init_conversations = __esm({
|
|
|
12930
13168
|
});
|
|
12931
13169
|
|
|
12932
13170
|
// libs/mesh-cli/src/utils/scaffold-versions.ts
|
|
12933
|
-
import { execFileSync as
|
|
13171
|
+
import { execFileSync as execFileSync18 } from "child_process";
|
|
12934
13172
|
function isPrerelease(range) {
|
|
12935
13173
|
return /[-+]/.test(range.replace(/^\^/, ""));
|
|
12936
13174
|
}
|
|
@@ -12940,7 +13178,7 @@ function toCaretRange(version) {
|
|
|
12940
13178
|
}
|
|
12941
13179
|
function resolvePublishedRange(pkg, cwd) {
|
|
12942
13180
|
try {
|
|
12943
|
-
const out =
|
|
13181
|
+
const out = execFileSync18("npm", ["view", pkg, "version"], {
|
|
12944
13182
|
cwd,
|
|
12945
13183
|
encoding: "utf-8",
|
|
12946
13184
|
timeout: 15e3,
|
|
@@ -12986,23 +13224,23 @@ __export(create_app_exports, {
|
|
|
12986
13224
|
shouldBootstrapAppsRepo: () => shouldBootstrapAppsRepo,
|
|
12987
13225
|
workspaceGlobForApp: () => workspaceGlobForApp
|
|
12988
13226
|
});
|
|
12989
|
-
import * as
|
|
13227
|
+
import * as fs24 from "fs";
|
|
12990
13228
|
import * as os7 from "os";
|
|
12991
|
-
import * as
|
|
13229
|
+
import * as path26 from "path";
|
|
12992
13230
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
12993
13231
|
import Handlebars from "handlebars";
|
|
12994
13232
|
import { parse as parseYaml2 } from "yaml";
|
|
12995
13233
|
function isInsidePlatformMonorepo(dir) {
|
|
12996
|
-
let cur =
|
|
12997
|
-
while (cur !==
|
|
12998
|
-
if (
|
|
13234
|
+
let cur = path26.resolve(dir);
|
|
13235
|
+
while (cur !== path26.dirname(cur)) {
|
|
13236
|
+
if (fs24.existsSync(path26.join(cur, "pnpm-workspace.yaml"))) {
|
|
12999
13237
|
try {
|
|
13000
|
-
const pkg = JSON.parse(
|
|
13238
|
+
const pkg = JSON.parse(fs24.readFileSync(path26.join(cur, "package.json"), "utf-8"));
|
|
13001
13239
|
if (pkg?.name === PLATFORM_MONOREPO_NAME) return true;
|
|
13002
13240
|
} catch {
|
|
13003
13241
|
}
|
|
13004
13242
|
}
|
|
13005
|
-
cur =
|
|
13243
|
+
cur = path26.dirname(cur);
|
|
13006
13244
|
}
|
|
13007
13245
|
return false;
|
|
13008
13246
|
}
|
|
@@ -13011,46 +13249,46 @@ function resolveDeployerRoleArn(tenant, platformName, env) {
|
|
|
13011
13249
|
return `arn:aws:iam::${account}:role/${tenant}-${env}-apps-deployer`;
|
|
13012
13250
|
}
|
|
13013
13251
|
function shouldBootstrapAppsRepo(cwd) {
|
|
13014
|
-
return
|
|
13252
|
+
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
13253
|
}
|
|
13016
13254
|
function bootstrapAppsRepo(cwd, tenant) {
|
|
13017
|
-
const templateDir =
|
|
13255
|
+
const templateDir = path26.join(packageRoot, "templates", "apps-repo");
|
|
13018
13256
|
const registryAccount = HUB_ACCOUNTS.mesh;
|
|
13019
13257
|
const context = {
|
|
13020
|
-
repoName:
|
|
13258
|
+
repoName: path26.basename(cwd),
|
|
13021
13259
|
tenant,
|
|
13022
13260
|
tenantTitle: tenant.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" "),
|
|
13023
13261
|
registryUrl: `https://mesh-platform-${registryAccount}.d.codeartifact.us-east-2.amazonaws.com/npm/mesh-packages/`,
|
|
13024
13262
|
intentRange: INTENT_RANGE
|
|
13025
13263
|
};
|
|
13026
|
-
const staging =
|
|
13264
|
+
const staging = fs24.mkdtempSync(path26.join(os7.tmpdir(), "mesh-apps-repo-"));
|
|
13027
13265
|
try {
|
|
13028
13266
|
copyTemplate(templateDir, staging, context);
|
|
13029
13267
|
for (const [from, to] of [
|
|
13030
13268
|
["gitignore", ".gitignore"],
|
|
13031
13269
|
["npmrc", ".npmrc"]
|
|
13032
13270
|
]) {
|
|
13033
|
-
const p =
|
|
13034
|
-
if (
|
|
13271
|
+
const p = path26.join(staging, from);
|
|
13272
|
+
if (fs24.existsSync(p)) fs24.renameSync(p, path26.join(staging, to));
|
|
13035
13273
|
}
|
|
13036
13274
|
const created = [];
|
|
13037
|
-
for (const entry of
|
|
13038
|
-
const dest =
|
|
13039
|
-
if (
|
|
13040
|
-
|
|
13275
|
+
for (const entry of fs24.readdirSync(staging)) {
|
|
13276
|
+
const dest = path26.join(cwd, entry);
|
|
13277
|
+
if (fs24.existsSync(dest)) continue;
|
|
13278
|
+
fs24.cpSync(path26.join(staging, entry), dest, { recursive: true });
|
|
13041
13279
|
created.push(entry);
|
|
13042
13280
|
}
|
|
13043
|
-
|
|
13281
|
+
fs24.mkdirSync(path26.join(cwd, "apps"), { recursive: true });
|
|
13044
13282
|
created.push("apps/");
|
|
13045
13283
|
return created;
|
|
13046
13284
|
} finally {
|
|
13047
|
-
|
|
13285
|
+
fs24.rmSync(staging, { recursive: true, force: true });
|
|
13048
13286
|
}
|
|
13049
13287
|
}
|
|
13050
13288
|
function ensureWorkspaceGlobs(root, required) {
|
|
13051
|
-
const file =
|
|
13052
|
-
if (!
|
|
13053
|
-
const text =
|
|
13289
|
+
const file = path26.join(root, "pnpm-workspace.yaml");
|
|
13290
|
+
if (!fs24.existsSync(file)) return [];
|
|
13291
|
+
const text = fs24.readFileSync(file, "utf-8");
|
|
13054
13292
|
let declared;
|
|
13055
13293
|
try {
|
|
13056
13294
|
declared = parseYaml2(text)?.packages ?? [];
|
|
@@ -13074,13 +13312,13 @@ function ensureWorkspaceGlobs(root, required) {
|
|
|
13074
13312
|
}
|
|
13075
13313
|
const indent = (lines[end] ?? "").match(/^(\s*)-/)?.[1] ?? " ";
|
|
13076
13314
|
lines.splice(end + 1, 0, ...missing.map((glob) => `${indent}- ${glob}`));
|
|
13077
|
-
|
|
13315
|
+
fs24.writeFileSync(file, lines.join("\n"));
|
|
13078
13316
|
return missing;
|
|
13079
13317
|
}
|
|
13080
13318
|
function workspaceGlobForApp(root, appDir) {
|
|
13081
|
-
const rel2 =
|
|
13319
|
+
const rel2 = path26.relative(root, appDir).split(path26.sep).join("/");
|
|
13082
13320
|
if (rel2 === "" || rel2.split("/")[0] === "..") return null;
|
|
13083
|
-
return `${
|
|
13321
|
+
return `${path26.posix.dirname(rel2)}/*/*`;
|
|
13084
13322
|
}
|
|
13085
13323
|
function maybeBootstrapAppsRepo(cwd, tenant, test) {
|
|
13086
13324
|
if (test || !shouldBootstrapAppsRepo(cwd)) return;
|
|
@@ -13130,9 +13368,9 @@ async function promptForOptions(options) {
|
|
|
13130
13368
|
return { tenant, name, primitives };
|
|
13131
13369
|
}
|
|
13132
13370
|
function copyTemplate(srcDir, destDir, context) {
|
|
13133
|
-
const entries =
|
|
13371
|
+
const entries = fs24.readdirSync(srcDir, { withFileTypes: true });
|
|
13134
13372
|
for (const entry of entries) {
|
|
13135
|
-
const srcPath =
|
|
13373
|
+
const srcPath = path26.join(srcDir, entry.name);
|
|
13136
13374
|
let destName = entry.name;
|
|
13137
13375
|
if (destName.endsWith(".hbs")) {
|
|
13138
13376
|
destName = destName.slice(0, -4);
|
|
@@ -13140,17 +13378,17 @@ function copyTemplate(srcDir, destDir, context) {
|
|
|
13140
13378
|
if (destName.includes("{{")) {
|
|
13141
13379
|
destName = Handlebars.compile(destName)(context);
|
|
13142
13380
|
}
|
|
13143
|
-
const destPath =
|
|
13381
|
+
const destPath = path26.join(destDir, destName);
|
|
13144
13382
|
if (entry.isDirectory()) {
|
|
13145
|
-
|
|
13383
|
+
fs24.mkdirSync(destPath, { recursive: true });
|
|
13146
13384
|
copyTemplate(srcPath, destPath, context);
|
|
13147
13385
|
} else if (entry.name.endsWith(".hbs")) {
|
|
13148
|
-
const templateContent =
|
|
13386
|
+
const templateContent = fs24.readFileSync(srcPath, "utf-8");
|
|
13149
13387
|
const template = Handlebars.compile(templateContent);
|
|
13150
13388
|
const output = template(context);
|
|
13151
|
-
|
|
13389
|
+
fs24.writeFileSync(destPath, output);
|
|
13152
13390
|
} else {
|
|
13153
|
-
|
|
13391
|
+
fs24.copyFileSync(srcPath, destPath);
|
|
13154
13392
|
}
|
|
13155
13393
|
}
|
|
13156
13394
|
}
|
|
@@ -13174,72 +13412,72 @@ function describeNoAppsHome(cwd, tenant, baseDir, test) {
|
|
|
13174
13412
|
};
|
|
13175
13413
|
}
|
|
13176
13414
|
return {
|
|
13177
|
-
message: `This directory is not a Mesh apps repo \u2014 no apps/ here${
|
|
13415
|
+
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
13416
|
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
13417
|
};
|
|
13180
13418
|
}
|
|
13181
13419
|
function resolveAppDir(cwd, tenant, name, test) {
|
|
13182
13420
|
const baseDir = test ? "tests/tenants" : "tenants";
|
|
13183
|
-
const possiblePaths = test ? [
|
|
13184
|
-
|
|
13185
|
-
|
|
13186
|
-
|
|
13421
|
+
const possiblePaths = test ? [path26.join(cwd, baseDir, tenant, "apps")] : [
|
|
13422
|
+
path26.join(cwd, baseDir, tenant, "apps"),
|
|
13423
|
+
path26.join(cwd, "..", tenant, "apps"),
|
|
13424
|
+
path26.join(cwd, "apps")
|
|
13187
13425
|
];
|
|
13188
|
-
let appsDir = possiblePaths.find((p) =>
|
|
13426
|
+
let appsDir = possiblePaths.find((p) => fs24.existsSync(p));
|
|
13189
13427
|
if (!appsDir) {
|
|
13190
|
-
appsDir =
|
|
13191
|
-
if (!
|
|
13428
|
+
appsDir = path26.join(cwd, baseDir, tenant, "apps");
|
|
13429
|
+
if (!fs24.existsSync(path26.join(cwd, baseDir, tenant))) {
|
|
13192
13430
|
const { message, hint } = describeNoAppsHome(cwd, tenant, baseDir, test);
|
|
13193
13431
|
logError(message);
|
|
13194
13432
|
logInfo(hint);
|
|
13195
13433
|
process.exit(1);
|
|
13196
13434
|
}
|
|
13197
|
-
if (!
|
|
13435
|
+
if (!fs24.existsSync(appsDir)) {
|
|
13198
13436
|
logInfo(`Creating apps directory: ${appsDir}`);
|
|
13199
|
-
|
|
13437
|
+
fs24.mkdirSync(appsDir, { recursive: true });
|
|
13200
13438
|
}
|
|
13201
13439
|
}
|
|
13202
|
-
return
|
|
13440
|
+
return path26.join(appsDir, name);
|
|
13203
13441
|
}
|
|
13204
13442
|
function generateComposableApp(appDir, context) {
|
|
13205
|
-
const fragmentsDir =
|
|
13206
|
-
const baseDir =
|
|
13207
|
-
if (!
|
|
13443
|
+
const fragmentsDir = path26.join(packageRoot, "fragments");
|
|
13444
|
+
const baseDir = path26.join(fragmentsDir, "base");
|
|
13445
|
+
if (!fs24.existsSync(baseDir)) {
|
|
13208
13446
|
logError(`Fragments directory not found: ${baseDir}`);
|
|
13209
13447
|
logInfo("Make sure the mesh-cli package is installed correctly.");
|
|
13210
13448
|
process.exit(1);
|
|
13211
13449
|
}
|
|
13212
13450
|
copyTemplate(baseDir, appDir, context);
|
|
13213
13451
|
if (context.service) {
|
|
13214
|
-
const serviceDir =
|
|
13215
|
-
if (!
|
|
13452
|
+
const serviceDir = path26.join(fragmentsDir, "service");
|
|
13453
|
+
if (!fs24.existsSync(serviceDir)) {
|
|
13216
13454
|
throw new Error(`Fragment directory not found: ${serviceDir}`);
|
|
13217
13455
|
}
|
|
13218
13456
|
copyTemplate(serviceDir, appDir, context);
|
|
13219
13457
|
}
|
|
13220
13458
|
if (context.database) {
|
|
13221
|
-
const dbDir =
|
|
13222
|
-
if (!
|
|
13459
|
+
const dbDir = path26.join(fragmentsDir, "database");
|
|
13460
|
+
if (!fs24.existsSync(dbDir)) {
|
|
13223
13461
|
throw new Error(`Fragment directory not found: ${dbDir}`);
|
|
13224
13462
|
}
|
|
13225
13463
|
copyTemplate(dbDir, appDir, context);
|
|
13226
13464
|
}
|
|
13227
13465
|
if (context.temporal) {
|
|
13228
|
-
const temporalDir =
|
|
13229
|
-
if (!
|
|
13466
|
+
const temporalDir = path26.join(fragmentsDir, "temporal");
|
|
13467
|
+
if (!fs24.existsSync(temporalDir)) {
|
|
13230
13468
|
throw new Error(`Fragment directory not found: ${temporalDir}`);
|
|
13231
13469
|
}
|
|
13232
13470
|
copyTemplate(temporalDir, appDir, context);
|
|
13233
13471
|
}
|
|
13234
13472
|
if (context.bucket) {
|
|
13235
|
-
const bucketDir =
|
|
13236
|
-
if (!
|
|
13473
|
+
const bucketDir = path26.join(fragmentsDir, "bucket");
|
|
13474
|
+
if (!fs24.existsSync(bucketDir)) {
|
|
13237
13475
|
throw new Error(`Fragment directory not found: ${bucketDir}`);
|
|
13238
13476
|
}
|
|
13239
13477
|
copyTemplate(bucketDir, appDir, context);
|
|
13240
13478
|
}
|
|
13241
|
-
const agentsDir =
|
|
13242
|
-
if (
|
|
13479
|
+
const agentsDir = path26.join(fragmentsDir, "agents");
|
|
13480
|
+
if (fs24.existsSync(agentsDir)) {
|
|
13243
13481
|
copyTemplate(agentsDir, appDir, context);
|
|
13244
13482
|
}
|
|
13245
13483
|
}
|
|
@@ -13340,22 +13578,22 @@ async function runLegacyTemplate(tenant, name, template, test) {
|
|
|
13340
13578
|
}
|
|
13341
13579
|
maybeBootstrapAppsRepo(process.cwd(), tenant, test);
|
|
13342
13580
|
const appDir = resolveAppDir(process.cwd(), tenant, name, test);
|
|
13343
|
-
if (
|
|
13581
|
+
if (fs24.existsSync(appDir)) {
|
|
13344
13582
|
logError(`App directory already exists: ${appDir}`);
|
|
13345
13583
|
process.exit(1);
|
|
13346
13584
|
}
|
|
13347
|
-
const templateDir =
|
|
13348
|
-
if (!
|
|
13585
|
+
const templateDir = path26.join(packageRoot, "templates", template);
|
|
13586
|
+
if (!fs24.existsSync(templateDir)) {
|
|
13349
13587
|
logError(`Template not found: ${templateDir}`);
|
|
13350
13588
|
process.exit(1);
|
|
13351
13589
|
}
|
|
13352
|
-
|
|
13590
|
+
fs24.mkdirSync(appDir, { recursive: true });
|
|
13353
13591
|
try {
|
|
13354
13592
|
copyTemplate(templateDir, appDir, { name, tenant });
|
|
13355
13593
|
logSuccess(`Created app at ${appDir}`);
|
|
13356
13594
|
} catch (error) {
|
|
13357
13595
|
logError(`Failed to create app: ${error}`);
|
|
13358
|
-
|
|
13596
|
+
fs24.rmSync(appDir, { recursive: true, force: true });
|
|
13359
13597
|
process.exit(1);
|
|
13360
13598
|
}
|
|
13361
13599
|
autoSyncSkills(appDir, name);
|
|
@@ -13370,7 +13608,7 @@ function autoSyncSkills(appDir, appName) {
|
|
|
13370
13608
|
logWarn(`Agent-skill sync skipped: ${err instanceof Error ? err.message : err} \u2014 run: mesh skills sync`);
|
|
13371
13609
|
}
|
|
13372
13610
|
try {
|
|
13373
|
-
const seeded = seedAppSkill(root, appName,
|
|
13611
|
+
const seeded = seedAppSkill(root, appName, path26.relative(root, appDir));
|
|
13374
13612
|
if (seeded) logSuccess(`seeded: ${seeded} (yours to grow \u2014 not managed by mesh skills sync)`);
|
|
13375
13613
|
} catch (err) {
|
|
13376
13614
|
logWarn(`App skill stub skipped: ${err instanceof Error ? err.message : err}`);
|
|
@@ -13378,7 +13616,7 @@ function autoSyncSkills(appDir, appName) {
|
|
|
13378
13616
|
}
|
|
13379
13617
|
async function checkScaffoldContract(appDir) {
|
|
13380
13618
|
const root = resolveTargetRoot(appDir);
|
|
13381
|
-
const report = await runAppCheck(root, [
|
|
13619
|
+
const report = await runAppCheck(root, [path26.relative(root, appDir) || "."]);
|
|
13382
13620
|
if (report.status === "ok") {
|
|
13383
13621
|
logSuccess("app contract: met (mesh app check)");
|
|
13384
13622
|
return;
|
|
@@ -13401,7 +13639,7 @@ async function runComposable(tenant, name, primitives, test) {
|
|
|
13401
13639
|
}
|
|
13402
13640
|
maybeBootstrapAppsRepo(process.cwd(), tenant, test);
|
|
13403
13641
|
const appDir = resolveAppDir(process.cwd(), tenant, name, test);
|
|
13404
|
-
if (
|
|
13642
|
+
if (fs24.existsSync(appDir)) {
|
|
13405
13643
|
logError(`App directory already exists: ${appDir}`);
|
|
13406
13644
|
process.exit(1);
|
|
13407
13645
|
}
|
|
@@ -13433,16 +13671,16 @@ async function runComposable(tenant, name, primitives, test) {
|
|
|
13433
13671
|
typescriptRange: SCAFFOLD_TOOLCHAIN.typescript,
|
|
13434
13672
|
deployerRoleArn: resolveDeployerRoleArn(tenant, platformName, platformEnv)
|
|
13435
13673
|
};
|
|
13436
|
-
|
|
13674
|
+
fs24.mkdirSync(appDir, { recursive: true });
|
|
13437
13675
|
try {
|
|
13438
13676
|
generateComposableApp(appDir, context);
|
|
13439
13677
|
logSuccess(`Created app at ${appDir}`);
|
|
13440
13678
|
} catch (error) {
|
|
13441
13679
|
logError(`Failed to create app: ${error}`);
|
|
13442
|
-
|
|
13680
|
+
fs24.rmSync(appDir, { recursive: true, force: true });
|
|
13443
13681
|
process.exit(1);
|
|
13444
13682
|
}
|
|
13445
|
-
const nested =
|
|
13683
|
+
const nested = fs24.readdirSync(appDir, { withFileTypes: true }).some((entry) => entry.isDirectory() && fs24.existsSync(path26.join(appDir, entry.name, "package.json")));
|
|
13446
13684
|
const glob = workspaceGlobForApp(repoRoot2, appDir);
|
|
13447
13685
|
if (nested && glob) {
|
|
13448
13686
|
const added = ensureWorkspaceGlobs(repoRoot2, [glob]);
|
|
@@ -13526,7 +13764,7 @@ var init_create_app = __esm({
|
|
|
13526
13764
|
init_errors();
|
|
13527
13765
|
init_mesh_json();
|
|
13528
13766
|
__filename = fileURLToPath2(import.meta.url);
|
|
13529
|
-
__dirname =
|
|
13767
|
+
__dirname = path26.dirname(__filename);
|
|
13530
13768
|
packageRoot = findPackageRoot(__dirname);
|
|
13531
13769
|
TEMPLATES = {
|
|
13532
13770
|
workflow: "Hono API + Temporal worker + hello workflow (Pulumi/app-kit)",
|
|
@@ -13850,20 +14088,20 @@ var init_psql = __esm({
|
|
|
13850
14088
|
// libs/mesh-cli/src/commands/db/exec.ts
|
|
13851
14089
|
import { spawn as spawn6 } from "child_process";
|
|
13852
14090
|
import * as net11 from "net";
|
|
13853
|
-
import * as
|
|
13854
|
-
import * as
|
|
14091
|
+
import * as fs25 from "fs";
|
|
14092
|
+
import * as path27 from "path";
|
|
13855
14093
|
import {
|
|
13856
14094
|
SecretsManagerClient as SecretsManagerClient3,
|
|
13857
14095
|
GetSecretValueCommand as GetSecretValueCommand3
|
|
13858
14096
|
} from "@aws-sdk/client-secrets-manager";
|
|
13859
14097
|
function findSstOutputs() {
|
|
13860
14098
|
let dir = process.cwd();
|
|
13861
|
-
const root =
|
|
14099
|
+
const root = path27.parse(dir).root;
|
|
13862
14100
|
while (dir !== root) {
|
|
13863
|
-
const outputsPath =
|
|
13864
|
-
if (
|
|
14101
|
+
const outputsPath = path27.join(dir, ".sst", "outputs.json");
|
|
14102
|
+
if (fs25.existsSync(outputsPath)) {
|
|
13865
14103
|
try {
|
|
13866
|
-
const content =
|
|
14104
|
+
const content = fs25.readFileSync(outputsPath, "utf-8");
|
|
13867
14105
|
const outputs = JSON.parse(content);
|
|
13868
14106
|
if (outputs.databaseUrl) {
|
|
13869
14107
|
const secretArnMatch = outputs.databaseUrl.match(/secretArn=([^&]+)/);
|
|
@@ -13878,7 +14116,7 @@ function findSstOutputs() {
|
|
|
13878
14116
|
} catch {
|
|
13879
14117
|
}
|
|
13880
14118
|
}
|
|
13881
|
-
dir =
|
|
14119
|
+
dir = path27.dirname(dir);
|
|
13882
14120
|
}
|
|
13883
14121
|
return null;
|
|
13884
14122
|
}
|
|
@@ -14137,8 +14375,8 @@ var init_db = __esm({
|
|
|
14137
14375
|
});
|
|
14138
14376
|
|
|
14139
14377
|
// libs/mesh-cli/src/utils/deploy-preflight.ts
|
|
14140
|
-
import { existsSync as
|
|
14141
|
-
import { dirname as dirname22, join as
|
|
14378
|
+
import { existsSync as existsSync21, readFileSync as readFileSync22 } from "node:fs";
|
|
14379
|
+
import { dirname as dirname22, join as join26, relative as relative7 } from "node:path";
|
|
14142
14380
|
import { parse as parseYaml3 } from "yaml";
|
|
14143
14381
|
function isGated(name) {
|
|
14144
14382
|
return GATED_PREFIXES.some((p) => name.startsWith(p));
|
|
@@ -14176,8 +14414,8 @@ function diffLockVsInstalled(expected, installed) {
|
|
|
14176
14414
|
function findPnpmLock(startDir) {
|
|
14177
14415
|
let dir = startDir;
|
|
14178
14416
|
for (; ; ) {
|
|
14179
|
-
const candidate =
|
|
14180
|
-
if (
|
|
14417
|
+
const candidate = join26(dir, "pnpm-lock.yaml");
|
|
14418
|
+
if (existsSync21(candidate)) return candidate;
|
|
14181
14419
|
const parent = dirname22(dir);
|
|
14182
14420
|
if (parent === dir) return null;
|
|
14183
14421
|
dir = parent;
|
|
@@ -14185,8 +14423,8 @@ function findPnpmLock(startDir) {
|
|
|
14185
14423
|
}
|
|
14186
14424
|
function readInstalledVersion(fromDir, name) {
|
|
14187
14425
|
try {
|
|
14188
|
-
const pkgPath =
|
|
14189
|
-
const version = JSON.parse(
|
|
14426
|
+
const pkgPath = join26(fromDir, "node_modules", name, "package.json");
|
|
14427
|
+
const version = JSON.parse(readFileSync22(pkgPath, "utf8")).version;
|
|
14190
14428
|
return typeof version === "string" ? version : null;
|
|
14191
14429
|
} catch {
|
|
14192
14430
|
return null;
|
|
@@ -14197,7 +14435,7 @@ function checkDeployDepsFresh(appRoot) {
|
|
|
14197
14435
|
if (!lockPath) return null;
|
|
14198
14436
|
let lockDoc;
|
|
14199
14437
|
try {
|
|
14200
|
-
lockDoc = parseYaml3(
|
|
14438
|
+
lockDoc = parseYaml3(readFileSync22(lockPath, "utf8"));
|
|
14201
14439
|
} catch {
|
|
14202
14440
|
logWarn(
|
|
14203
14441
|
`deploy preflight: could not parse ${lockPath} \u2014 skipping the stale-node_modules check.`
|
|
@@ -14253,7 +14491,7 @@ var init_deploy_preflight = __esm({
|
|
|
14253
14491
|
});
|
|
14254
14492
|
|
|
14255
14493
|
// libs/mesh-cli/src/commands/deploy.ts
|
|
14256
|
-
import { execFileSync as
|
|
14494
|
+
import { execFileSync as execFileSync19 } from "child_process";
|
|
14257
14495
|
function buildPulumiArgs(pulumiArgs, stack) {
|
|
14258
14496
|
const base = pulumiArgs.length === 0 || pulumiArgs[0]?.startsWith("-") ? ["up", ...pulumiArgs] : [...pulumiArgs];
|
|
14259
14497
|
const op = base[0];
|
|
@@ -14316,7 +14554,7 @@ function registerDeployCommand(program2) {
|
|
|
14316
14554
|
delete env.AWS_PROFILE;
|
|
14317
14555
|
const finalArgs = buildPulumiArgs(pulumiArgs, stack);
|
|
14318
14556
|
try {
|
|
14319
|
-
|
|
14557
|
+
execFileSync19("pulumi", finalArgs, {
|
|
14320
14558
|
cwd: appRoot,
|
|
14321
14559
|
env,
|
|
14322
14560
|
stdio: "inherit"
|
|
@@ -14421,8 +14659,8 @@ var init_schema2 = __esm({
|
|
|
14421
14659
|
});
|
|
14422
14660
|
|
|
14423
14661
|
// libs/mesh-cli/src/docs/discover.ts
|
|
14424
|
-
import { existsSync as
|
|
14425
|
-
import
|
|
14662
|
+
import { existsSync as existsSync22, readdirSync as readdirSync9, readFileSync as readFileSync23, statSync as statSync5 } from "node:fs";
|
|
14663
|
+
import path28 from "node:path";
|
|
14426
14664
|
function routePathFor(relPath) {
|
|
14427
14665
|
const withoutExt = relPath.replace(/\.md$/i, "");
|
|
14428
14666
|
const parts = withoutExt.split("/").map(slugify2);
|
|
@@ -14442,7 +14680,7 @@ function walkMarkdown(absDir, relDir, errors, rootDir) {
|
|
|
14442
14680
|
if (hasReservedSegment(entry.name)) {
|
|
14443
14681
|
continue;
|
|
14444
14682
|
}
|
|
14445
|
-
const abs =
|
|
14683
|
+
const abs = path28.join(absDir, entry.name);
|
|
14446
14684
|
if (entry.isDirectory()) {
|
|
14447
14685
|
if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
|
|
14448
14686
|
out.push(...walkMarkdown(abs, rel2, errors, rootDir));
|
|
@@ -14488,7 +14726,7 @@ function discoverDocRoots(repoRoot2) {
|
|
|
14488
14726
|
if (entry.name.startsWith(".")) continue;
|
|
14489
14727
|
const rel2 = relDir ? `${relDir}/${entry.name}` : entry.name;
|
|
14490
14728
|
findRoots(
|
|
14491
|
-
|
|
14729
|
+
path28.join(absDir, entry.name),
|
|
14492
14730
|
rel2,
|
|
14493
14731
|
insideReserved || hasReservedSegment(entry.name)
|
|
14494
14732
|
);
|
|
@@ -14497,7 +14735,7 @@ function discoverDocRoots(repoRoot2) {
|
|
|
14497
14735
|
findRoots(repoRoot2, "", false);
|
|
14498
14736
|
const pages = [];
|
|
14499
14737
|
for (const root of roots) {
|
|
14500
|
-
const absRoot =
|
|
14738
|
+
const absRoot = path28.join(repoRoot2, root.dir);
|
|
14501
14739
|
const relFiles = walkMarkdown(absRoot, "", errors, root.dir);
|
|
14502
14740
|
for (const relPath of relFiles.sort()) {
|
|
14503
14741
|
pages.push({
|
|
@@ -14521,14 +14759,14 @@ function discoverDocRoots(repoRoot2) {
|
|
|
14521
14759
|
);
|
|
14522
14760
|
continue;
|
|
14523
14761
|
}
|
|
14524
|
-
if (!
|
|
14762
|
+
if (!existsSync22(path28.join(repoRoot2, normalized))) {
|
|
14525
14763
|
errors.push(
|
|
14526
14764
|
`${root.dir}/docs.json includes ${normalized}, which does not exist`
|
|
14527
14765
|
);
|
|
14528
14766
|
continue;
|
|
14529
14767
|
}
|
|
14530
14768
|
if (pages.some((p) => p.source === normalized)) continue;
|
|
14531
|
-
const stem =
|
|
14769
|
+
const stem = path28.posix.basename(normalized).replace(/\.md$/i, "");
|
|
14532
14770
|
pages.push({
|
|
14533
14771
|
source: normalized,
|
|
14534
14772
|
root,
|
|
@@ -14556,10 +14794,10 @@ function discoverDocRoots(repoRoot2) {
|
|
|
14556
14794
|
return { roots, pages, errors };
|
|
14557
14795
|
}
|
|
14558
14796
|
function loadRoot(absDir, relDir, errors) {
|
|
14559
|
-
const configPath =
|
|
14797
|
+
const configPath = path28.join(absDir, "docs.json");
|
|
14560
14798
|
let raw;
|
|
14561
14799
|
try {
|
|
14562
|
-
raw = JSON.parse(
|
|
14800
|
+
raw = JSON.parse(readFileSync23(configPath, "utf-8"));
|
|
14563
14801
|
} catch (error) {
|
|
14564
14802
|
errors.push(
|
|
14565
14803
|
`${relDir}/docs.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -14609,9 +14847,9 @@ var init_discover = __esm({
|
|
|
14609
14847
|
});
|
|
14610
14848
|
|
|
14611
14849
|
// libs/mesh-cli/src/docs/assemble.ts
|
|
14612
|
-
import { execFileSync as
|
|
14613
|
-
import { mkdirSync as
|
|
14614
|
-
import
|
|
14850
|
+
import { execFileSync as execFileSync20 } from "node:child_process";
|
|
14851
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync24, rmSync as rmSync5, writeFileSync as writeFileSync15 } from "node:fs";
|
|
14852
|
+
import path29 from "node:path";
|
|
14615
14853
|
import { parse as parseYaml4 } from "yaml";
|
|
14616
14854
|
function splitFrontMatter(markdown) {
|
|
14617
14855
|
const normalized = markdown.replace(/^\uFEFF/, "");
|
|
@@ -14671,7 +14909,7 @@ function deriveTitle(frontMatter, body, source) {
|
|
|
14671
14909
|
if (typeof fmTitle === "string" && fmTitle.trim()) return fmTitle.trim();
|
|
14672
14910
|
const heading = firstHeading(body);
|
|
14673
14911
|
if (heading) return heading;
|
|
14674
|
-
const stem =
|
|
14912
|
+
const stem = path29.posix.basename(source).replace(/\.md$/i, "");
|
|
14675
14913
|
return titleizeStem(stem);
|
|
14676
14914
|
}
|
|
14677
14915
|
function scanLinks(markdown) {
|
|
@@ -14803,7 +15041,7 @@ function isAbsoluteHref(href) {
|
|
|
14803
15041
|
return /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(href);
|
|
14804
15042
|
}
|
|
14805
15043
|
function normalizeRepoPath(value) {
|
|
14806
|
-
return
|
|
15044
|
+
return path29.posix.normalize(value.replace(/\\/g, "/")).replace(/^\.\//, "").replace(/\/+$/, "");
|
|
14807
15045
|
}
|
|
14808
15046
|
function splitHash(href) {
|
|
14809
15047
|
const index = href.indexOf("#");
|
|
@@ -14821,7 +15059,7 @@ function resolveLink(args) {
|
|
|
14821
15059
|
const route = rawTarget.replace(/\/$/, "") || "/";
|
|
14822
15060
|
return routes.has(route) ? { href: `${route}${hash}` } : { href, issue: { kind: "broken", page: pageRoute2, href } };
|
|
14823
15061
|
}
|
|
14824
|
-
const repoPath = normalizeRepoPath(
|
|
15062
|
+
const repoPath = normalizeRepoPath(path29.posix.join(sourceDir, rawTarget));
|
|
14825
15063
|
const page = sourceIndex.get(repoPath);
|
|
14826
15064
|
if (page) return { href: `${page.route}${hash}` };
|
|
14827
15065
|
for (const candidate of [`${repoPath}/index.md`]) {
|
|
@@ -14842,7 +15080,7 @@ function rewriteLinks(args) {
|
|
|
14842
15080
|
const issues = [];
|
|
14843
15081
|
const hits = scanLinks(args.body);
|
|
14844
15082
|
if (hits.length === 0) return { body: args.body, issues };
|
|
14845
|
-
const sourceDir =
|
|
15083
|
+
const sourceDir = path29.posix.dirname(args.page.source);
|
|
14846
15084
|
let out = "";
|
|
14847
15085
|
let cursor = 0;
|
|
14848
15086
|
for (const hit of hits) {
|
|
@@ -14893,9 +15131,9 @@ function assemblePortal(options) {
|
|
|
14893
15131
|
const brokenLinks = [];
|
|
14894
15132
|
const externalLinks = [];
|
|
14895
15133
|
rmSync5(outDir, { recursive: true, force: true });
|
|
14896
|
-
|
|
15134
|
+
mkdirSync12(outDir, { recursive: true });
|
|
14897
15135
|
for (const page of pages) {
|
|
14898
|
-
const raw =
|
|
15136
|
+
const raw = readFileSync24(path29.join(repoRoot2, page.source), "utf-8");
|
|
14899
15137
|
const frontMatter = splitFrontMatter(raw);
|
|
14900
15138
|
const title = deriveTitle(frontMatter.data, frontMatter.body, page.source);
|
|
14901
15139
|
page.title = title;
|
|
@@ -14907,7 +15145,7 @@ function assemblePortal(options) {
|
|
|
14907
15145
|
sourceIndex,
|
|
14908
15146
|
routes,
|
|
14909
15147
|
ignoreLinkPrefixes,
|
|
14910
|
-
pathKind: (rel2) => pathKind(
|
|
15148
|
+
pathKind: (rel2) => pathKind(path29.join(repoRoot2, rel2)),
|
|
14911
15149
|
repoUrl
|
|
14912
15150
|
});
|
|
14913
15151
|
for (const issue of rewritten.issues) {
|
|
@@ -14921,8 +15159,8 @@ function assemblePortal(options) {
|
|
|
14921
15159
|
|
|
14922
15160
|
<sub>Source: [\`${page.source}\`](${blobBase}/blob/main/${page.source}) \u2014 edit that file, not this page.</sub>
|
|
14923
15161
|
`;
|
|
14924
|
-
const outFile =
|
|
14925
|
-
|
|
15162
|
+
const outFile = path29.join(outDir, page.filePath);
|
|
15163
|
+
mkdirSync12(path29.dirname(outFile), { recursive: true });
|
|
14926
15164
|
writeFileSync15(
|
|
14927
15165
|
outFile,
|
|
14928
15166
|
joinFrontMatter(outData, rewritten.body.trimEnd() + sourceNote)
|
|
@@ -15100,7 +15338,7 @@ function renderVersionJson(args) {
|
|
|
15100
15338
|
}
|
|
15101
15339
|
function currentCommit(repoRoot2) {
|
|
15102
15340
|
try {
|
|
15103
|
-
return
|
|
15341
|
+
return execFileSync20("git", ["rev-parse", "--short", "HEAD"], {
|
|
15104
15342
|
cwd: repoRoot2,
|
|
15105
15343
|
encoding: "utf-8"
|
|
15106
15344
|
}).trim();
|
|
@@ -15111,7 +15349,7 @@ function currentCommit(repoRoot2) {
|
|
|
15111
15349
|
function currentBaseline(repoRoot2) {
|
|
15112
15350
|
try {
|
|
15113
15351
|
const pkg = JSON.parse(
|
|
15114
|
-
|
|
15352
|
+
readFileSync24(path29.join(repoRoot2, "libs/app-kit/package.json"), "utf-8")
|
|
15115
15353
|
);
|
|
15116
15354
|
return pkg.version;
|
|
15117
15355
|
} catch {
|
|
@@ -15119,7 +15357,7 @@ function currentBaseline(repoRoot2) {
|
|
|
15119
15357
|
}
|
|
15120
15358
|
}
|
|
15121
15359
|
function publishSetAtRef(repoRoot2, ref) {
|
|
15122
|
-
const git = (gitArgs) =>
|
|
15360
|
+
const git = (gitArgs) => execFileSync20("git", gitArgs, {
|
|
15123
15361
|
cwd: repoRoot2,
|
|
15124
15362
|
encoding: "utf-8",
|
|
15125
15363
|
maxBuffer: 64 * 1024 * 1024
|
|
@@ -15144,7 +15382,7 @@ function publishSetAtRef(repoRoot2, ref) {
|
|
|
15144
15382
|
continue;
|
|
15145
15383
|
const rel2 = file.slice(prefix2.length);
|
|
15146
15384
|
if (hasReservedSegment(rel2)) continue;
|
|
15147
|
-
if (
|
|
15385
|
+
if (path29.posix.basename(file).toLowerCase() === "readme.md") continue;
|
|
15148
15386
|
published.add(file);
|
|
15149
15387
|
}
|
|
15150
15388
|
for (const include of config.include ?? []) {
|
|
@@ -15230,8 +15468,8 @@ function formatDefault(value, paths = currentMachinePaths()) {
|
|
|
15230
15468
|
if (typeof value === "boolean" || typeof value === "number") return String(value);
|
|
15231
15469
|
return normalizeMachinePaths(JSON.stringify(value), paths);
|
|
15232
15470
|
}
|
|
15233
|
-
function slugifyCommandPath(
|
|
15234
|
-
return
|
|
15471
|
+
function slugifyCommandPath(path48) {
|
|
15472
|
+
return path48.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
15235
15473
|
}
|
|
15236
15474
|
function extractOptions(command) {
|
|
15237
15475
|
const options = command.options ?? [];
|
|
@@ -15265,17 +15503,17 @@ function isUndocumented(command) {
|
|
|
15265
15503
|
function extractCommand(command, parentPath, depth) {
|
|
15266
15504
|
const internals = command;
|
|
15267
15505
|
const name = internals._name ?? "";
|
|
15268
|
-
const
|
|
15506
|
+
const path48 = parentPath ? `${parentPath} ${name}` : name;
|
|
15269
15507
|
return {
|
|
15270
|
-
path:
|
|
15508
|
+
path: path48,
|
|
15271
15509
|
name,
|
|
15272
15510
|
aliases: [...internals._aliases ?? []],
|
|
15273
15511
|
description: internals._description ?? "",
|
|
15274
15512
|
args: extractArgs(command),
|
|
15275
15513
|
options: extractOptions(command),
|
|
15276
|
-
slug: slugifyCommandPath(
|
|
15514
|
+
slug: slugifyCommandPath(path48),
|
|
15277
15515
|
depth,
|
|
15278
|
-
subcommands: (internals.commands ?? []).filter((child) => !isUndocumented(child)).map((child) => extractCommand(child,
|
|
15516
|
+
subcommands: (internals.commands ?? []).filter((child) => !isUndocumented(child)).map((child) => extractCommand(child, path48, depth + 1))
|
|
15279
15517
|
};
|
|
15280
15518
|
}
|
|
15281
15519
|
function extractCliReference(program2) {
|
|
@@ -15367,14 +15605,14 @@ var init_cli_reference = __esm({
|
|
|
15367
15605
|
import { spawn as spawn7 } from "node:child_process";
|
|
15368
15606
|
import {
|
|
15369
15607
|
appendFileSync,
|
|
15370
|
-
existsSync as
|
|
15371
|
-
mkdirSync as
|
|
15608
|
+
existsSync as existsSync23,
|
|
15609
|
+
mkdirSync as mkdirSync13,
|
|
15372
15610
|
mkdtempSync as mkdtempSync3,
|
|
15373
|
-
readFileSync as
|
|
15611
|
+
readFileSync as readFileSync25,
|
|
15374
15612
|
writeFileSync as writeFileSync16
|
|
15375
15613
|
} from "node:fs";
|
|
15376
15614
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
15377
|
-
import
|
|
15615
|
+
import path30 from "node:path";
|
|
15378
15616
|
function runAssemble(args) {
|
|
15379
15617
|
const discovery = discoverDocRoots(args.repoRoot);
|
|
15380
15618
|
const assembled = assemblePortal({
|
|
@@ -15386,7 +15624,7 @@ function runAssemble(args) {
|
|
|
15386
15624
|
});
|
|
15387
15625
|
const errors = [...discovery.errors];
|
|
15388
15626
|
if (args.writeFiles !== false) {
|
|
15389
|
-
const manifestPath = args.outDir.includes(tmpdir6()) ?
|
|
15627
|
+
const manifestPath = args.outDir.includes(tmpdir6()) ? path30.join(args.outDir, PUBLISH_MANIFEST) : path30.join(args.outDir, "..", PUBLISH_MANIFEST);
|
|
15390
15628
|
writeFileSync16(
|
|
15391
15629
|
manifestPath,
|
|
15392
15630
|
`${JSON.stringify(assembled.publishManifest, null, 2)}
|
|
@@ -15403,13 +15641,13 @@ function runAssemble(args) {
|
|
|
15403
15641
|
commit: currentCommit(args.repoRoot)
|
|
15404
15642
|
})
|
|
15405
15643
|
);
|
|
15406
|
-
const versionDir =
|
|
15407
|
-
|
|
15644
|
+
const versionDir = path30.join(
|
|
15645
|
+
path30.dirname(args.configOut),
|
|
15408
15646
|
VERSION_JSON_DIR
|
|
15409
15647
|
);
|
|
15410
|
-
|
|
15648
|
+
mkdirSync13(versionDir, { recursive: true });
|
|
15411
15649
|
writeFileSync16(
|
|
15412
|
-
|
|
15650
|
+
path30.join(versionDir, VERSION_JSON),
|
|
15413
15651
|
renderVersionJson({
|
|
15414
15652
|
baseline: currentBaseline(args.repoRoot),
|
|
15415
15653
|
commit: currentCommit(args.repoRoot),
|
|
@@ -15441,7 +15679,7 @@ function reportAssembly(result) {
|
|
|
15441
15679
|
}
|
|
15442
15680
|
}
|
|
15443
15681
|
async function checkPortal(args) {
|
|
15444
|
-
const scratch = mkdtempSync3(
|
|
15682
|
+
const scratch = mkdtempSync3(path30.join(tmpdir6(), "mesh-docs-check-"));
|
|
15445
15683
|
const result = runAssemble({ repoRoot: args.repoRoot, outDir: scratch });
|
|
15446
15684
|
const failures = [...result.errors];
|
|
15447
15685
|
for (const violation of result.assembled.reservedViolations) {
|
|
@@ -15462,7 +15700,7 @@ async function checkPortal(args) {
|
|
|
15462
15700
|
);
|
|
15463
15701
|
}
|
|
15464
15702
|
if (args.manifestOut) {
|
|
15465
|
-
|
|
15703
|
+
mkdirSync13(path30.dirname(args.manifestOut), { recursive: true });
|
|
15466
15704
|
writeFileSync16(
|
|
15467
15705
|
args.manifestOut,
|
|
15468
15706
|
`${JSON.stringify(result.assembled.publishManifest, null, 2)}
|
|
@@ -15532,12 +15770,12 @@ async function runPortalCommand(opts, deps) {
|
|
|
15532
15770
|
logSuccess("Docs portal check passed");
|
|
15533
15771
|
return;
|
|
15534
15772
|
}
|
|
15535
|
-
const appDir =
|
|
15536
|
-
const outDir = opts.out ?
|
|
15773
|
+
const appDir = path30.join(repoRoot2, DOCS_APP_DIR);
|
|
15774
|
+
const outDir = opts.out ? path30.resolve(repoRoot2, opts.out) : path30.join(appDir, CONTENT_DIR);
|
|
15537
15775
|
const result = runAssemble({
|
|
15538
15776
|
repoRoot: repoRoot2,
|
|
15539
15777
|
outDir,
|
|
15540
|
-
configOut:
|
|
15778
|
+
configOut: path30.join(appDir, GENERATED_CONFIG)
|
|
15541
15779
|
});
|
|
15542
15780
|
reportAssembly(result);
|
|
15543
15781
|
if (result.errors.length > 0) {
|
|
@@ -15548,7 +15786,7 @@ async function runPortalCommand(opts, deps) {
|
|
|
15548
15786
|
}
|
|
15549
15787
|
if (opts.assembleOnly || opts.out) {
|
|
15550
15788
|
logInfo(
|
|
15551
|
-
`Assembled content at ${
|
|
15789
|
+
`Assembled content at ${path30.relative(repoRoot2, outDir)} \u2014 build with: pnpm --filter @mesh-tech/docs build`
|
|
15552
15790
|
);
|
|
15553
15791
|
return;
|
|
15554
15792
|
}
|
|
@@ -15568,7 +15806,7 @@ async function runPortalCommand(opts, deps) {
|
|
|
15568
15806
|
if (code !== 0) throw new Error(`zudoku ${mode} exited with code ${code}`);
|
|
15569
15807
|
if (mode === "build") {
|
|
15570
15808
|
logSuccess(
|
|
15571
|
-
`Portal built \u2192 ${
|
|
15809
|
+
`Portal built \u2192 ${path30.join(path30.relative(repoRoot2, appDir), "dist")}`
|
|
15572
15810
|
);
|
|
15573
15811
|
}
|
|
15574
15812
|
}
|
|
@@ -15580,11 +15818,11 @@ async function cliReferenceStaleness(repoRoot2) {
|
|
|
15580
15818
|
Promise.resolve().then(() => (init_program(), program_exports)),
|
|
15581
15819
|
Promise.resolve().then(() => (init_cli_reference(), cli_reference_exports))
|
|
15582
15820
|
]);
|
|
15583
|
-
const outPath =
|
|
15821
|
+
const outPath = path30.join(repoRoot2, "docs/portal/generated/cli-reference.md");
|
|
15584
15822
|
const markdown = renderCliReferenceMarkdown2(
|
|
15585
15823
|
extractCliReference2(createProgram2())
|
|
15586
15824
|
);
|
|
15587
|
-
const existing =
|
|
15825
|
+
const existing = existsSync23(outPath) ? readFileSync25(outPath, "utf-8") : null;
|
|
15588
15826
|
if (existing === markdown) return null;
|
|
15589
15827
|
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
15828
|
}
|
|
@@ -15607,9 +15845,9 @@ var init_portal = __esm({
|
|
|
15607
15845
|
});
|
|
15608
15846
|
|
|
15609
15847
|
// libs/mesh-cli/src/utils/build-info.ts
|
|
15610
|
-
import { execFileSync as
|
|
15611
|
-
import * as
|
|
15612
|
-
import * as
|
|
15848
|
+
import { execFileSync as execFileSync21 } from "child_process";
|
|
15849
|
+
import * as fs26 from "fs";
|
|
15850
|
+
import * as path31 from "path";
|
|
15613
15851
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
15614
15852
|
function detectRuntimeMode(modulePath) {
|
|
15615
15853
|
return modulePath.split(/[\\/]/).includes("dist") ? "dist" : "source";
|
|
@@ -15628,11 +15866,11 @@ function findCliPackageRoot(startDir) {
|
|
|
15628
15866
|
let dir = startDir;
|
|
15629
15867
|
for (let i = 0; i < 8; i++) {
|
|
15630
15868
|
try {
|
|
15631
|
-
const pkg = JSON.parse(
|
|
15869
|
+
const pkg = JSON.parse(fs26.readFileSync(path31.join(dir, "package.json"), "utf-8"));
|
|
15632
15870
|
if (pkg.name === "@mesh-tech/mesh-cli") return dir;
|
|
15633
15871
|
} catch {
|
|
15634
15872
|
}
|
|
15635
|
-
const parent =
|
|
15873
|
+
const parent = path31.dirname(dir);
|
|
15636
15874
|
if (parent === dir) break;
|
|
15637
15875
|
dir = parent;
|
|
15638
15876
|
}
|
|
@@ -15640,13 +15878,13 @@ function findCliPackageRoot(startDir) {
|
|
|
15640
15878
|
}
|
|
15641
15879
|
function resolveCliRuntime(opts) {
|
|
15642
15880
|
const vcs = opts?.vcs ?? true;
|
|
15643
|
-
const here =
|
|
15881
|
+
const here = path31.dirname(fileURLToPath3(import.meta.url));
|
|
15644
15882
|
const mode = detectRuntimeMode(here);
|
|
15645
15883
|
const root = findCliPackageRoot(here);
|
|
15646
15884
|
let version = "0.0.0";
|
|
15647
15885
|
if (root) {
|
|
15648
15886
|
try {
|
|
15649
|
-
version = JSON.parse(
|
|
15887
|
+
version = JSON.parse(fs26.readFileSync(path31.join(root, "package.json"), "utf-8")).version ?? version;
|
|
15650
15888
|
} catch {
|
|
15651
15889
|
}
|
|
15652
15890
|
}
|
|
@@ -15655,7 +15893,7 @@ function resolveCliRuntime(opts) {
|
|
|
15655
15893
|
if (mode === "dist") {
|
|
15656
15894
|
try {
|
|
15657
15895
|
const meta = JSON.parse(
|
|
15658
|
-
|
|
15896
|
+
fs26.readFileSync(path31.join(root, "dist", "build-info.json"), "utf-8")
|
|
15659
15897
|
);
|
|
15660
15898
|
info.commit = meta.commit;
|
|
15661
15899
|
info.builtAt = meta.builtAt;
|
|
@@ -15665,7 +15903,7 @@ function resolveCliRuntime(opts) {
|
|
|
15665
15903
|
}
|
|
15666
15904
|
if (!vcs) return info;
|
|
15667
15905
|
try {
|
|
15668
|
-
const git = (args) =>
|
|
15906
|
+
const git = (args) => execFileSync21("git", args, {
|
|
15669
15907
|
cwd: root,
|
|
15670
15908
|
encoding: "utf-8",
|
|
15671
15909
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -15685,7 +15923,7 @@ var init_build_info = __esm({
|
|
|
15685
15923
|
// libs/mesh-cli/src/docs/serve.ts
|
|
15686
15924
|
import { createServer as createServer8 } from "node:http";
|
|
15687
15925
|
import { readFile } from "node:fs/promises";
|
|
15688
|
-
import { extname as extname2, join as
|
|
15926
|
+
import { extname as extname2, join as join28, normalize, sep as sep5 } from "node:path";
|
|
15689
15927
|
async function serveDocsSite(args) {
|
|
15690
15928
|
const root = normalize(args.root);
|
|
15691
15929
|
const rootPrefix = root.endsWith(sep5) ? root : root + sep5;
|
|
@@ -15704,7 +15942,7 @@ async function serveDocsSite(args) {
|
|
|
15704
15942
|
];
|
|
15705
15943
|
if (pathname !== "/") candidates.push("/index.html");
|
|
15706
15944
|
for (const candidate of candidates) {
|
|
15707
|
-
const filePath = normalize(
|
|
15945
|
+
const filePath = normalize(join28(root, candidate));
|
|
15708
15946
|
if (filePath !== root && !filePath.startsWith(rootPrefix)) continue;
|
|
15709
15947
|
try {
|
|
15710
15948
|
const body = await readFile(filePath);
|
|
@@ -15762,13 +16000,13 @@ var init_serve = __esm({
|
|
|
15762
16000
|
});
|
|
15763
16001
|
|
|
15764
16002
|
// libs/mesh-cli/src/docs/registry-docs.ts
|
|
15765
|
-
import { execFileSync as
|
|
15766
|
-
import { existsSync as
|
|
16003
|
+
import { execFileSync as execFileSync22 } from "node:child_process";
|
|
16004
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as readFileSync27, renameSync as renameSync3, rmSync as rmSync6, writeFileSync as writeFileSync17 } from "node:fs";
|
|
15767
16005
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
15768
|
-
import
|
|
16006
|
+
import path32 from "node:path";
|
|
15769
16007
|
function readDocsRegistryAuth(npmrcPath2 = homeNpmrcPath()) {
|
|
15770
|
-
if (!
|
|
15771
|
-
return parseNpmrcRegistryAuth(
|
|
16008
|
+
if (!existsSync24(npmrcPath2)) return null;
|
|
16009
|
+
return parseNpmrcRegistryAuth(readFileSync27(npmrcPath2, "utf-8"));
|
|
15772
16010
|
}
|
|
15773
16011
|
function packumentUrl(endpoint, pkg) {
|
|
15774
16012
|
return `${endpoint.replace(/\/+$/, "")}/${pkg.replace(/\//g, "%2f")}`;
|
|
@@ -15818,15 +16056,15 @@ async function listDocsVersions(auth, fetchImpl = fetch) {
|
|
|
15818
16056
|
return { versions, latest: packument["dist-tags"]?.latest };
|
|
15819
16057
|
}
|
|
15820
16058
|
function docsCacheRoot() {
|
|
15821
|
-
const base = process.env.XDG_CACHE_HOME ??
|
|
15822
|
-
return
|
|
16059
|
+
const base = process.env.XDG_CACHE_HOME ?? path32.join(homeDir(), ".cache");
|
|
16060
|
+
return path32.join(base, "mesh", "docs");
|
|
15823
16061
|
}
|
|
15824
16062
|
function homeDir() {
|
|
15825
16063
|
return process.env.HOME ?? tmpdir7();
|
|
15826
16064
|
}
|
|
15827
16065
|
async function fetchDocsArtifact(auth, version, cacheRoot = docsCacheRoot(), fetchImpl = fetch) {
|
|
15828
|
-
const targetDir =
|
|
15829
|
-
if (
|
|
16066
|
+
const targetDir = path32.join(cacheRoot, version);
|
|
16067
|
+
if (existsSync24(path32.join(targetDir, "dist", "index.html"))) return targetDir;
|
|
15830
16068
|
const listResponse = await registryFetch(auth, packumentUrl(auth.endpoint, DOCS_PACKAGE), fetchImpl);
|
|
15831
16069
|
if (!listResponse.ok) {
|
|
15832
16070
|
throw new Error(`registry returned ${listResponse.status} for ${DOCS_PACKAGE}`);
|
|
@@ -15847,20 +16085,20 @@ async function fetchDocsArtifact(auth, version, cacheRoot = docsCacheRoot(), fet
|
|
|
15847
16085
|
if (!tgzResponse.ok) {
|
|
15848
16086
|
throw new Error(`downloading ${DOCS_PACKAGE}@${version} failed: ${tgzResponse.status}`);
|
|
15849
16087
|
}
|
|
15850
|
-
|
|
15851
|
-
const tgzPath =
|
|
16088
|
+
mkdirSync14(cacheRoot, { recursive: true });
|
|
16089
|
+
const tgzPath = path32.join(cacheRoot, `.${version}.tgz`);
|
|
15852
16090
|
writeFileSync17(tgzPath, Buffer.from(await tgzResponse.arrayBuffer()));
|
|
15853
|
-
const staging =
|
|
16091
|
+
const staging = path32.join(cacheRoot, `.staging-${version}`);
|
|
15854
16092
|
rmSync6(staging, { recursive: true, force: true });
|
|
15855
|
-
|
|
16093
|
+
mkdirSync14(staging, { recursive: true });
|
|
15856
16094
|
try {
|
|
15857
|
-
|
|
16095
|
+
execFileSync22("tar", ["-xzf", tgzPath, "-C", staging, "--strip-components", "1"], {
|
|
15858
16096
|
stdio: ["pipe", "pipe", "pipe"]
|
|
15859
16097
|
});
|
|
15860
16098
|
} finally {
|
|
15861
16099
|
rmSync6(tgzPath, { force: true });
|
|
15862
16100
|
}
|
|
15863
|
-
if (!
|
|
16101
|
+
if (!existsSync24(path32.join(staging, "dist", "index.html"))) {
|
|
15864
16102
|
rmSync6(staging, { recursive: true, force: true });
|
|
15865
16103
|
throw new Error(`${DOCS_PACKAGE}@${version} unpacked without a dist/index.html \u2014 the artifact is malformed`);
|
|
15866
16104
|
}
|
|
@@ -15892,9 +16130,9 @@ __export(start_exports, {
|
|
|
15892
16130
|
tmuxInstallHint: () => tmuxInstallHint,
|
|
15893
16131
|
tmuxServeArgs: () => tmuxServeArgs
|
|
15894
16132
|
});
|
|
15895
|
-
import { execFileSync as
|
|
15896
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
15897
|
-
import
|
|
16133
|
+
import { execFileSync as execFileSync23 } from "node:child_process";
|
|
16134
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync25, writeFileSync as writeFileSync18 } from "node:fs";
|
|
16135
|
+
import path33 from "node:path";
|
|
15898
16136
|
function registryAuthOrThrow() {
|
|
15899
16137
|
const auth = readDocsRegistryAuth();
|
|
15900
16138
|
if (!auth) {
|
|
@@ -15925,7 +16163,7 @@ function tmuxInstallHint(platform = process.platform) {
|
|
|
15925
16163
|
}
|
|
15926
16164
|
function tmuxAvailable() {
|
|
15927
16165
|
try {
|
|
15928
|
-
|
|
16166
|
+
execFileSync23("tmux", ["-V"], { stdio: ["pipe", "pipe", "pipe"] });
|
|
15929
16167
|
return true;
|
|
15930
16168
|
} catch {
|
|
15931
16169
|
return false;
|
|
@@ -15936,7 +16174,7 @@ function shouldDetach(args) {
|
|
|
15936
16174
|
}
|
|
15937
16175
|
function docsSessionExists() {
|
|
15938
16176
|
try {
|
|
15939
|
-
|
|
16177
|
+
execFileSync23("tmux", ["has-session", "-t", DOCS_TMUX_SESSION], { stdio: ["pipe", "pipe", "pipe"] });
|
|
15940
16178
|
return true;
|
|
15941
16179
|
} catch {
|
|
15942
16180
|
return false;
|
|
@@ -15960,12 +16198,12 @@ Or run in the foreground instead: mesh docs start --foreground`
|
|
|
15960
16198
|
if (docsSessionExists()) {
|
|
15961
16199
|
logInfo(`Replacing the docs server already running in tmux session "${DOCS_TMUX_SESSION}".`);
|
|
15962
16200
|
try {
|
|
15963
|
-
|
|
16201
|
+
execFileSync23("tmux", ["kill-session", "-t", DOCS_TMUX_SESSION], { stdio: ["pipe", "pipe", "pipe"] });
|
|
15964
16202
|
} catch {
|
|
15965
16203
|
}
|
|
15966
16204
|
}
|
|
15967
16205
|
const { command, cwd } = tmuxServeArgs(args);
|
|
15968
|
-
|
|
16206
|
+
execFileSync23(
|
|
15969
16207
|
"tmux",
|
|
15970
16208
|
["new-session", "-d", "-s", DOCS_TMUX_SESSION, "-c", cwd, "--", ...command],
|
|
15971
16209
|
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -16003,7 +16241,7 @@ function printReady(url, label) {
|
|
|
16003
16241
|
}
|
|
16004
16242
|
function runDocsStop() {
|
|
16005
16243
|
try {
|
|
16006
|
-
|
|
16244
|
+
execFileSync23("tmux", ["kill-session", "-t", DOCS_TMUX_SESSION], { stdio: ["pipe", "pipe", "pipe"] });
|
|
16007
16245
|
logSuccess(`Stopped the docs server (tmux session "${DOCS_TMUX_SESSION}").`);
|
|
16008
16246
|
} catch {
|
|
16009
16247
|
logInfo(`No docs server is running (no tmux session named "${DOCS_TMUX_SESSION}").`);
|
|
@@ -16014,7 +16252,7 @@ async function runDocsServeStatic(args) {
|
|
|
16014
16252
|
if (!Number.isInteger(requestedPort) || requestedPort < 0 || requestedPort > 65535) {
|
|
16015
16253
|
throw new Error(`Invalid --port: ${args.port}`);
|
|
16016
16254
|
}
|
|
16017
|
-
if (!args.root || !
|
|
16255
|
+
if (!args.root || !existsSync25(path33.join(args.root, "index.html"))) {
|
|
16018
16256
|
throw new Error(
|
|
16019
16257
|
`--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
16258
|
);
|
|
@@ -16055,19 +16293,19 @@ async function runDocsStart(args) {
|
|
|
16055
16293
|
}
|
|
16056
16294
|
logInfo(`Fetching ${DOCS_PACKAGE}@${version} from the registry\u2026`);
|
|
16057
16295
|
const artifactDir = await fetchDocsArtifact(auth, version);
|
|
16058
|
-
serveRoot =
|
|
16296
|
+
serveRoot = path33.join(artifactDir, "dist");
|
|
16059
16297
|
label = `@mesh-tech/* ${version} (published artifact)`;
|
|
16060
16298
|
} else {
|
|
16061
16299
|
if (localRoots.errors.length > 0) {
|
|
16062
16300
|
for (const error of localRoots.errors) logError(error);
|
|
16063
16301
|
throw new Error(`docs discovery failed with ${localRoots.errors.length} problem(s)`);
|
|
16064
16302
|
}
|
|
16065
|
-
const appDir =
|
|
16303
|
+
const appDir = path33.join(args.repoRoot, DOCS_APP_DIR);
|
|
16066
16304
|
if (args.dev) {
|
|
16067
16305
|
const result2 = runAssemble({
|
|
16068
16306
|
repoRoot: args.repoRoot,
|
|
16069
|
-
outDir:
|
|
16070
|
-
configOut:
|
|
16307
|
+
outDir: path33.join(appDir, "content"),
|
|
16308
|
+
configOut: path33.join(appDir, "zudoku.config.ts")
|
|
16071
16309
|
});
|
|
16072
16310
|
reportAssembly(result2);
|
|
16073
16311
|
const { spawn: spawn11 } = await import("node:child_process");
|
|
@@ -16083,12 +16321,12 @@ async function runDocsStart(args) {
|
|
|
16083
16321
|
});
|
|
16084
16322
|
return;
|
|
16085
16323
|
}
|
|
16086
|
-
const buildLog =
|
|
16087
|
-
logInfo(`Preparing the docs from this checkout (assemble + build \u2014 log: ${
|
|
16324
|
+
const buildLog = path33.join(args.repoRoot, DOCS_APP_DIR, "build.log");
|
|
16325
|
+
logInfo(`Preparing the docs from this checkout (assemble + build \u2014 log: ${path33.relative(args.repoRoot, buildLog)})\u2026`);
|
|
16088
16326
|
const result = runAssemble({
|
|
16089
16327
|
repoRoot: args.repoRoot,
|
|
16090
|
-
outDir:
|
|
16091
|
-
configOut:
|
|
16328
|
+
outDir: path33.join(appDir, "content"),
|
|
16329
|
+
configOut: path33.join(appDir, "zudoku.config.ts")
|
|
16092
16330
|
});
|
|
16093
16331
|
reportAssembly(result);
|
|
16094
16332
|
const { spawn: spawn10 } = await import("node:child_process");
|
|
@@ -16105,7 +16343,7 @@ async function runDocsStart(args) {
|
|
|
16105
16343
|
child.on("close", (exitCode) => resolve20(exitCode ?? 1));
|
|
16106
16344
|
});
|
|
16107
16345
|
if (code !== 0) throw new Error(`zudoku build exited with code ${code} \u2014 see ${buildLog}`);
|
|
16108
|
-
serveRoot =
|
|
16346
|
+
serveRoot = path33.join(appDir, "dist");
|
|
16109
16347
|
label = "this checkout";
|
|
16110
16348
|
}
|
|
16111
16349
|
if (detached) {
|
|
@@ -16145,30 +16383,30 @@ var init_start = __esm({
|
|
|
16145
16383
|
});
|
|
16146
16384
|
|
|
16147
16385
|
// libs/mesh-cli/src/commands/docs.ts
|
|
16148
|
-
import * as
|
|
16149
|
-
import * as
|
|
16386
|
+
import * as fs27 from "fs";
|
|
16387
|
+
import * as path34 from "path";
|
|
16150
16388
|
import { createRequire } from "module";
|
|
16151
16389
|
import { pathToFileURL } from "url";
|
|
16152
16390
|
function findProjectRoot(start = process.cwd()) {
|
|
16153
16391
|
let dir = start;
|
|
16154
16392
|
while (true) {
|
|
16155
|
-
if (
|
|
16156
|
-
const parent =
|
|
16393
|
+
if (fs27.existsSync(path34.join(dir, "package.json"))) return dir;
|
|
16394
|
+
const parent = path34.dirname(dir);
|
|
16157
16395
|
if (parent === dir) return start;
|
|
16158
16396
|
dir = parent;
|
|
16159
16397
|
}
|
|
16160
16398
|
}
|
|
16161
16399
|
function resolvePath(projectRoot, candidate) {
|
|
16162
|
-
return
|
|
16400
|
+
return path34.isAbsolute(candidate) ? candidate : path34.join(projectRoot, candidate);
|
|
16163
16401
|
}
|
|
16164
16402
|
function ensureParentDir(filePath) {
|
|
16165
|
-
|
|
16403
|
+
fs27.mkdirSync(path34.dirname(filePath), { recursive: true });
|
|
16166
16404
|
}
|
|
16167
16405
|
function readConfig2(configPath) {
|
|
16168
|
-
if (!
|
|
16406
|
+
if (!fs27.existsSync(configPath)) {
|
|
16169
16407
|
throw new Error(`Docs config not found: ${configPath}`);
|
|
16170
16408
|
}
|
|
16171
|
-
const raw =
|
|
16409
|
+
const raw = fs27.readFileSync(configPath, "utf-8");
|
|
16172
16410
|
const parsed = JSON.parse(raw);
|
|
16173
16411
|
if (parsed.openapi && !Array.isArray(parsed.openapi)) {
|
|
16174
16412
|
throw new Error(`Invalid docs config: 'openapi' must be an array`);
|
|
@@ -16176,7 +16414,7 @@ function readConfig2(configPath) {
|
|
|
16176
16414
|
return parsed;
|
|
16177
16415
|
}
|
|
16178
16416
|
function validateOpenApiSpec(specPath) {
|
|
16179
|
-
const content =
|
|
16417
|
+
const content = fs27.readFileSync(specPath, "utf-8");
|
|
16180
16418
|
const parsed = JSON.parse(content);
|
|
16181
16419
|
if (typeof parsed.openapi !== "string") {
|
|
16182
16420
|
throw new Error(`Invalid OpenAPI spec (${specPath}): missing 'openapi'`);
|
|
@@ -16189,7 +16427,7 @@ function validateOpenApiSpec(specPath) {
|
|
|
16189
16427
|
}
|
|
16190
16428
|
}
|
|
16191
16429
|
async function loadSymxchangeGenerator(projectRoot) {
|
|
16192
|
-
const requireFromProject = createRequire(
|
|
16430
|
+
const requireFromProject = createRequire(path34.join(projectRoot, "package.json"));
|
|
16193
16431
|
const entryPath = requireFromProject.resolve("@mesh-tech/jh-symitar-api");
|
|
16194
16432
|
const mod = await import(pathToFileURL(entryPath).href);
|
|
16195
16433
|
const fn = mod.generateSymxchangeOpenApi;
|
|
@@ -16202,8 +16440,8 @@ async function loadSymxchangeGenerator(projectRoot) {
|
|
|
16202
16440
|
}
|
|
16203
16441
|
async function buildDocs(configPathArg) {
|
|
16204
16442
|
const cwd = process.cwd();
|
|
16205
|
-
const configPath =
|
|
16206
|
-
const projectRoot = findProjectRoot(
|
|
16443
|
+
const configPath = path34.isAbsolute(configPathArg ?? "") ? configPathArg : path34.resolve(cwd, configPathArg ?? "docs/docs.config.json");
|
|
16444
|
+
const projectRoot = findProjectRoot(path34.dirname(configPath));
|
|
16207
16445
|
const config = readConfig2(configPath);
|
|
16208
16446
|
logInfo(`Using docs config: ${configPath}`);
|
|
16209
16447
|
const generatedSpecs = /* @__PURE__ */ new Set();
|
|
@@ -16211,15 +16449,15 @@ async function buildDocs(configPathArg) {
|
|
|
16211
16449
|
if (task.kind === "file") {
|
|
16212
16450
|
const inputPath = resolvePath(projectRoot, task.input);
|
|
16213
16451
|
const outputPath = resolvePath(projectRoot, task.output ?? task.input);
|
|
16214
|
-
if (!
|
|
16452
|
+
if (!fs27.existsSync(inputPath)) {
|
|
16215
16453
|
throw new Error(`OpenAPI source file not found: ${inputPath}`);
|
|
16216
16454
|
}
|
|
16217
16455
|
if (inputPath !== outputPath) {
|
|
16218
16456
|
ensureParentDir(outputPath);
|
|
16219
|
-
|
|
16220
|
-
logSuccess(`Copied OpenAPI spec \u2192 ${
|
|
16457
|
+
fs27.copyFileSync(inputPath, outputPath);
|
|
16458
|
+
logSuccess(`Copied OpenAPI spec \u2192 ${path34.relative(projectRoot, outputPath)}`);
|
|
16221
16459
|
} else {
|
|
16222
|
-
logInfo(`Using OpenAPI spec: ${
|
|
16460
|
+
logInfo(`Using OpenAPI spec: ${path34.relative(projectRoot, inputPath)}`);
|
|
16223
16461
|
}
|
|
16224
16462
|
validateOpenApiSpec(outputPath);
|
|
16225
16463
|
generatedSpecs.add(outputPath);
|
|
@@ -16237,10 +16475,10 @@ async function buildDocs(configPathArg) {
|
|
|
16237
16475
|
servers: task.servers
|
|
16238
16476
|
});
|
|
16239
16477
|
ensureParentDir(outputPath);
|
|
16240
|
-
|
|
16478
|
+
fs27.writeFileSync(outputPath, JSON.stringify(spec, null, 2));
|
|
16241
16479
|
validateOpenApiSpec(outputPath);
|
|
16242
16480
|
generatedSpecs.add(outputPath);
|
|
16243
|
-
logSuccess(`Generated SymXchange OpenAPI \u2192 ${
|
|
16481
|
+
logSuccess(`Generated SymXchange OpenAPI \u2192 ${path34.relative(projectRoot, outputPath)}`);
|
|
16244
16482
|
continue;
|
|
16245
16483
|
}
|
|
16246
16484
|
const exhaustive = task;
|
|
@@ -16248,12 +16486,12 @@ async function buildDocs(configPathArg) {
|
|
|
16248
16486
|
}
|
|
16249
16487
|
for (const relPath of config.validate ?? []) {
|
|
16250
16488
|
const abs = resolvePath(projectRoot, relPath);
|
|
16251
|
-
if (!
|
|
16489
|
+
if (!fs27.existsSync(abs)) {
|
|
16252
16490
|
throw new Error(`OpenAPI spec to validate not found: ${abs}`);
|
|
16253
16491
|
}
|
|
16254
16492
|
validateOpenApiSpec(abs);
|
|
16255
16493
|
generatedSpecs.add(abs);
|
|
16256
|
-
logSuccess(`Validated OpenAPI spec: ${
|
|
16494
|
+
logSuccess(`Validated OpenAPI spec: ${path34.relative(projectRoot, abs)}`);
|
|
16257
16495
|
}
|
|
16258
16496
|
if (generatedSpecs.size === 0) {
|
|
16259
16497
|
logInfo("No docs tasks configured (nothing to do)");
|
|
@@ -16283,20 +16521,20 @@ async function runCliReference(opts) {
|
|
|
16283
16521
|
const outPath = resolvePath(repoRoot2, opts.out);
|
|
16284
16522
|
const markdown = await renderCliReference();
|
|
16285
16523
|
if (opts.check) {
|
|
16286
|
-
const existing =
|
|
16524
|
+
const existing = fs27.existsSync(outPath) ? fs27.readFileSync(outPath, "utf-8") : null;
|
|
16287
16525
|
if (existing === markdown) {
|
|
16288
|
-
logSuccess(`CLI reference is up to date (${
|
|
16526
|
+
logSuccess(`CLI reference is up to date (${path34.relative(repoRoot2, outPath)})`);
|
|
16289
16527
|
return;
|
|
16290
16528
|
}
|
|
16291
16529
|
throw new Error(
|
|
16292
|
-
`${existing === null ? "CLI reference is missing" : "CLI reference is stale"}: ${
|
|
16530
|
+
`${existing === null ? "CLI reference is missing" : "CLI reference is stale"}: ${path34.relative(repoRoot2, outPath)}
|
|
16293
16531
|
The commander tree changed. Regenerate and commit:
|
|
16294
16532
|
pnpm exec mesh docs cli-reference`
|
|
16295
16533
|
);
|
|
16296
16534
|
}
|
|
16297
16535
|
ensureParentDir(outPath);
|
|
16298
|
-
|
|
16299
|
-
logSuccess(`CLI reference \u2192 ${
|
|
16536
|
+
fs27.writeFileSync(outPath, markdown);
|
|
16537
|
+
logSuccess(`CLI reference \u2192 ${path34.relative(repoRoot2, outPath)}`);
|
|
16300
16538
|
}
|
|
16301
16539
|
async function runPortal(opts) {
|
|
16302
16540
|
const repoRoot2 = findRepoRoot2(process.cwd());
|
|
@@ -16376,23 +16614,23 @@ var init_docs = __esm({
|
|
|
16376
16614
|
});
|
|
16377
16615
|
|
|
16378
16616
|
// libs/mesh-cli/src/commands/hub/index.ts
|
|
16379
|
-
import { execFileSync as
|
|
16380
|
-
import * as
|
|
16617
|
+
import { execFileSync as execFileSync24 } from "node:child_process";
|
|
16618
|
+
import * as fs28 from "node:fs";
|
|
16381
16619
|
import * as net12 from "node:net";
|
|
16382
16620
|
import * as os9 from "node:os";
|
|
16383
|
-
import * as
|
|
16621
|
+
import * as path35 from "node:path";
|
|
16384
16622
|
import chalk3 from "chalk";
|
|
16385
16623
|
function devSessionsDir() {
|
|
16386
|
-
return
|
|
16624
|
+
return path35.join(os9.tmpdir(), "mesh-dev-sessions");
|
|
16387
16625
|
}
|
|
16388
16626
|
function listDevSessions(dir = devSessionsDir()) {
|
|
16389
|
-
if (!
|
|
16627
|
+
if (!fs28.existsSync(dir)) return [];
|
|
16390
16628
|
const sessions = [];
|
|
16391
|
-
for (const entry of
|
|
16629
|
+
for (const entry of fs28.readdirSync(dir)) {
|
|
16392
16630
|
if (!entry.endsWith(".json")) continue;
|
|
16393
16631
|
try {
|
|
16394
16632
|
const state = JSON.parse(
|
|
16395
|
-
|
|
16633
|
+
fs28.readFileSync(path35.join(dir, entry), "utf-8")
|
|
16396
16634
|
);
|
|
16397
16635
|
if (state && typeof state === "object" && state.devOutput) {
|
|
16398
16636
|
sessions.push({ name: entry.slice(0, -".json".length), state });
|
|
@@ -16420,8 +16658,8 @@ function pickDevSession(sessions, opts) {
|
|
|
16420
16658
|
);
|
|
16421
16659
|
}
|
|
16422
16660
|
if (opts.cwdAppRoot) {
|
|
16423
|
-
const root =
|
|
16424
|
-
const match = sessions.find((s) =>
|
|
16661
|
+
const root = path35.resolve(opts.cwdAppRoot);
|
|
16662
|
+
const match = sessions.find((s) => path35.resolve(s.state.appRoot) === root);
|
|
16425
16663
|
if (match) return match;
|
|
16426
16664
|
}
|
|
16427
16665
|
if (sessions.length === 1) return sessions[0];
|
|
@@ -16442,7 +16680,7 @@ function parseTmuxEnv(output) {
|
|
|
16442
16680
|
}
|
|
16443
16681
|
function readTmuxSessionEnv(sessionName) {
|
|
16444
16682
|
try {
|
|
16445
|
-
const out =
|
|
16683
|
+
const out = execFileSync24("tmux", ["show-environment", "-t", sessionName], {
|
|
16446
16684
|
encoding: "utf-8",
|
|
16447
16685
|
stdio: ["ignore", "pipe", "ignore"]
|
|
16448
16686
|
});
|
|
@@ -16453,7 +16691,7 @@ function readTmuxSessionEnv(sessionName) {
|
|
|
16453
16691
|
}
|
|
16454
16692
|
function tmuxSessionExists(sessionName) {
|
|
16455
16693
|
try {
|
|
16456
|
-
|
|
16694
|
+
execFileSync24("tmux", ["has-session", "-t", sessionName], { stdio: "ignore" });
|
|
16457
16695
|
return true;
|
|
16458
16696
|
} catch {
|
|
16459
16697
|
return false;
|
|
@@ -16466,6 +16704,10 @@ function forwardedSessionVars(sessionEnv) {
|
|
|
16466
16704
|
}
|
|
16467
16705
|
return out;
|
|
16468
16706
|
}
|
|
16707
|
+
function resolveHubAudience(raw) {
|
|
16708
|
+
if (raw === void 0 || raw === "") return "operator";
|
|
16709
|
+
return raw.trim().toLowerCase() === "operator" ? "operator" : "tenant";
|
|
16710
|
+
}
|
|
16469
16711
|
function assembleHubEnv(session, sessionEnv, opts) {
|
|
16470
16712
|
const warnings = [];
|
|
16471
16713
|
const notes = [];
|
|
@@ -16518,6 +16760,7 @@ function assembleHubEnv(session, sessionEnv, opts) {
|
|
|
16518
16760
|
{ remediation: { command: "mesh dev # relaunch; the session records tunnels.temporal in its state" } }
|
|
16519
16761
|
);
|
|
16520
16762
|
}
|
|
16763
|
+
const audienceEnv = { HUB_AUDIENCE: resolveHubAudience(opts.audience) };
|
|
16521
16764
|
const apiEnv = {
|
|
16522
16765
|
...forwarded,
|
|
16523
16766
|
PORT: String(opts.apiPort),
|
|
@@ -16525,6 +16768,7 @@ function assembleHubEnv(session, sessionEnv, opts) {
|
|
|
16525
16768
|
HUB_TENANT: hubTenant,
|
|
16526
16769
|
HUB_SCOPE_ENV: scopeEnv,
|
|
16527
16770
|
HUB_SCOPE_TENANTS: scopeTenants.join(","),
|
|
16771
|
+
...audienceEnv,
|
|
16528
16772
|
...isLocalPlatform ? localPlatformEnv2(sessionEnv) : {}
|
|
16529
16773
|
};
|
|
16530
16774
|
const uiEnv = {
|
|
@@ -16534,16 +16778,17 @@ function assembleHubEnv(session, sessionEnv, opts) {
|
|
|
16534
16778
|
HUB_TENANT: hubTenant,
|
|
16535
16779
|
// UI namespace parsing + session defaults land on the scoped tenant.
|
|
16536
16780
|
DEFAULT_ORG: scopeTenants[0],
|
|
16537
|
-
DEFAULT_ENV: scopeEnv
|
|
16781
|
+
DEFAULT_ENV: scopeEnv,
|
|
16782
|
+
...audienceEnv
|
|
16538
16783
|
};
|
|
16539
16784
|
return { apiEnv, uiEnv, scope: { hubTenant, scopeEnv, scopeTenants }, temporalAddress, warnings, notes };
|
|
16540
16785
|
}
|
|
16541
16786
|
function isPlatformRoot(dir) {
|
|
16542
|
-
return
|
|
16787
|
+
return fs28.existsSync(path35.join(dir, "apps", "hub", "api", "package.json")) && fs28.existsSync(path35.join(dir, "apps", "hub", "ui", "package.json"));
|
|
16543
16788
|
}
|
|
16544
16789
|
function resolvePlatformDir(explicit, cwd, env = process.env) {
|
|
16545
16790
|
if (explicit) {
|
|
16546
|
-
const resolved =
|
|
16791
|
+
const resolved = path35.resolve(explicit);
|
|
16547
16792
|
if (isPlatformRoot(resolved)) return resolved;
|
|
16548
16793
|
throw new MeshCliError(
|
|
16549
16794
|
`'${resolved}' is not a mesh-platform checkout (apps/hub/{api,ui} not found).`,
|
|
@@ -16551,16 +16796,16 @@ function resolvePlatformDir(explicit, cwd, env = process.env) {
|
|
|
16551
16796
|
);
|
|
16552
16797
|
}
|
|
16553
16798
|
if (env.MESH_PLATFORM_DIR) {
|
|
16554
|
-
const resolved =
|
|
16799
|
+
const resolved = path35.resolve(env.MESH_PLATFORM_DIR);
|
|
16555
16800
|
if (isPlatformRoot(resolved)) return resolved;
|
|
16556
16801
|
logWarn(
|
|
16557
16802
|
`MESH_PLATFORM_DIR='${resolved}' is not a mesh-platform checkout (apps/hub/{api,ui} not found) \u2014 ignoring it.`
|
|
16558
16803
|
);
|
|
16559
16804
|
}
|
|
16560
|
-
let dir =
|
|
16805
|
+
let dir = path35.resolve(cwd);
|
|
16561
16806
|
for (; ; ) {
|
|
16562
16807
|
if (isPlatformRoot(dir)) return dir;
|
|
16563
|
-
const parent =
|
|
16808
|
+
const parent = path35.dirname(dir);
|
|
16564
16809
|
if (parent === dir) break;
|
|
16565
16810
|
dir = parent;
|
|
16566
16811
|
}
|
|
@@ -16599,7 +16844,7 @@ function isPortListening2(port) {
|
|
|
16599
16844
|
});
|
|
16600
16845
|
}
|
|
16601
16846
|
function hubEnvDir() {
|
|
16602
|
-
return
|
|
16847
|
+
return path35.join(os9.tmpdir(), "mesh-dev-sessions", HUB_SESSION);
|
|
16603
16848
|
}
|
|
16604
16849
|
function parsePort(raw, fallback, source) {
|
|
16605
16850
|
if (raw === void 0) return fallback;
|
|
@@ -16622,8 +16867,8 @@ function redactEnv(env) {
|
|
|
16622
16867
|
async function hubDevAction(opts) {
|
|
16623
16868
|
if (opts.kill) {
|
|
16624
16869
|
if (tmuxSessionExists(HUB_SESSION)) {
|
|
16625
|
-
|
|
16626
|
-
|
|
16870
|
+
execFileSync24("tmux", ["kill-session", "-t", HUB_SESSION], { stdio: "ignore" });
|
|
16871
|
+
fs28.rmSync(hubEnvDir(), { recursive: true, force: true });
|
|
16627
16872
|
logSuccess(`Killed Hub session '${HUB_SESSION}'.`);
|
|
16628
16873
|
} else {
|
|
16629
16874
|
logInfo(`No '${HUB_SESSION}' tmux session running.`);
|
|
@@ -16642,7 +16887,15 @@ async function hubDevAction(opts) {
|
|
|
16642
16887
|
);
|
|
16643
16888
|
}
|
|
16644
16889
|
const sessionEnv = readTmuxSessionEnv(session.name);
|
|
16645
|
-
const assembled = assembleHubEnv(session, sessionEnv, {
|
|
16890
|
+
const assembled = assembleHubEnv(session, sessionEnv, {
|
|
16891
|
+
tenants: opts.tenants,
|
|
16892
|
+
uiPort,
|
|
16893
|
+
apiPort,
|
|
16894
|
+
// The flag wins; the ambient variable is the fallback, so an exported
|
|
16895
|
+
// HUB_AUDIENCE reaches a Hub this command spawns rather than being
|
|
16896
|
+
// dropped on the way.
|
|
16897
|
+
audience: opts.audience ?? process.env.HUB_AUDIENCE
|
|
16898
|
+
});
|
|
16646
16899
|
if (opts.printEnv) {
|
|
16647
16900
|
console.log(chalk3.bold("\nhub-api env:"));
|
|
16648
16901
|
for (const [k, v] of Object.entries(redactEnv(assembled.apiEnv))) console.log(` ${k}=${v}`);
|
|
@@ -16671,22 +16924,23 @@ async function hubDevAction(opts) {
|
|
|
16671
16924
|
logInfo(
|
|
16672
16925
|
`Scope : HUB_TENANT=${assembled.scope.hubTenant} HUB_SCOPE_ENV=${assembled.scope.scopeEnv} HUB_SCOPE_TENANTS=${assembled.scope.scopeTenants.join(",")}`
|
|
16673
16926
|
);
|
|
16927
|
+
logInfo(`Audience : ${assembled.apiEnv.HUB_AUDIENCE} (--audience tenant for a client's view)`);
|
|
16674
16928
|
logInfo(`Temporal : ${assembled.temporalAddress}`);
|
|
16675
16929
|
for (const note of assembled.notes) logInfo(note);
|
|
16676
16930
|
for (const warning of assembled.warnings) logWarn(warning);
|
|
16677
|
-
const apiDir =
|
|
16678
|
-
const uiDir =
|
|
16679
|
-
|
|
16931
|
+
const apiDir = path35.join(platformDir, "apps", "hub", "api");
|
|
16932
|
+
const uiDir = path35.join(platformDir, "apps", "hub", "ui");
|
|
16933
|
+
execFileSync24("tmux", ["new-session", "-d", "-s", HUB_SESSION, "-n", "api", "-c", apiDir]);
|
|
16680
16934
|
if (!assembled.apiEnv.DEV_USER_TOKEN_URL && assembled.apiEnv.DEV_USER_ID_TOKEN) {
|
|
16681
16935
|
const platform = session.state.devOutput.platform;
|
|
16682
16936
|
const credContext = `mesh.${platform.env}`;
|
|
16683
16937
|
const tokenPort = await findFreePort4();
|
|
16684
16938
|
const tokenUrl = `http://127.0.0.1:${tokenPort}`;
|
|
16685
|
-
|
|
16686
|
-
|
|
16939
|
+
execFileSync24("tmux", ["new-window", "-t", HUB_SESSION, "-n", "token-server", "-c", platformDir]);
|
|
16940
|
+
execFileSync24("tmux", ["set-option", "-t", `${HUB_SESSION}:token-server`, "remain-on-exit", "on"], {
|
|
16687
16941
|
stdio: "ignore"
|
|
16688
16942
|
});
|
|
16689
|
-
|
|
16943
|
+
execFileSync24("tmux", [
|
|
16690
16944
|
"send-keys",
|
|
16691
16945
|
"-t",
|
|
16692
16946
|
`${HUB_SESSION}:token-server`,
|
|
@@ -16701,15 +16955,15 @@ async function hubDevAction(opts) {
|
|
|
16701
16955
|
logSuccess(`Dev-user token-server: ${tokenUrl} (context ${credContext})`);
|
|
16702
16956
|
}
|
|
16703
16957
|
const launch = (window, dir, env, cmd, createWindow) => {
|
|
16704
|
-
const envFile =
|
|
16958
|
+
const envFile = path35.join(hubEnvDir(), `${window}.env.sh`);
|
|
16705
16959
|
writeEnvFile(envFile, env);
|
|
16706
16960
|
if (createWindow) {
|
|
16707
|
-
|
|
16961
|
+
execFileSync24("tmux", ["new-window", "-t", HUB_SESSION, "-n", window, "-c", dir]);
|
|
16708
16962
|
}
|
|
16709
|
-
|
|
16963
|
+
execFileSync24("tmux", ["set-option", "-t", `${HUB_SESSION}:${window}`, "remain-on-exit", "on"], {
|
|
16710
16964
|
stdio: "ignore"
|
|
16711
16965
|
});
|
|
16712
|
-
|
|
16966
|
+
execFileSync24("tmux", ["send-keys", "-t", `${HUB_SESSION}:${window}`, buildLaunchCommand(envFile, dir, cmd), "Enter"]);
|
|
16713
16967
|
};
|
|
16714
16968
|
launch("api", apiDir, assembled.apiEnv, "pnpm dev", false);
|
|
16715
16969
|
launch("ui", uiDir, assembled.uiEnv, `pnpm dev --port ${uiPort} --strictPort`, true);
|
|
@@ -16733,7 +16987,10 @@ function registerHubCommands(program2) {
|
|
|
16733
16987
|
const hub = program2.command("hub").description("Local Hub over dev-local stacks");
|
|
16734
16988
|
hub.command("dev").description(
|
|
16735
16989
|
"Launch the current-code Hub (api + ui) against a running `mesh dev` session \u2014 env auto-assembled, zero hand-set vars"
|
|
16736
|
-
).option("--session <name>", "dev session to observe (default: auto-detect from cwd)").option("--tenants <list>", "comma-separated HUB_SCOPE_TENANTS override (default: the session's tenant)").option(
|
|
16990
|
+
).option("--session <name>", "dev session to observe (default: auto-detect from cwd)").option("--tenants <list>", "comma-separated HUB_SCOPE_TENANTS override (default: the session's tenant)").option(
|
|
16991
|
+
"--audience <who>",
|
|
16992
|
+
"who the Hub renders for: `operator` (platform staff \u2014 the default here) or `tenant` (a client's operators). Anything else reads as `tenant`"
|
|
16993
|
+
).option("--port <port>", `Hub UI host port (default: $MESH_HUB_DEV_PORT or ${DEFAULT_HUB_UI_PORT})`).option("--api-port <port>", `Hub API port (default: ${DEFAULT_HUB_API_PORT})`).option("--platform-dir <dir>", "mesh-platform checkout to run the Hub from (default: $MESH_PLATFORM_DIR or walk up from cwd)").option("--print-env", "print the assembled env (secrets redacted) and exit without launching").option("--kill", "tear down the running Hub session").action(hubDevAction);
|
|
16737
16994
|
}
|
|
16738
16995
|
var HUB_SESSION, DEFAULT_HUB_UI_PORT, DEFAULT_HUB_API_PORT, FORWARD_PREFIXES, localPlatformEnv2, SENSITIVE_RE;
|
|
16739
16996
|
var init_hub = __esm({
|
|
@@ -16807,9 +17064,9 @@ __export(platform_setup_exports, {
|
|
|
16807
17064
|
validateRegion: () => validateRegion,
|
|
16808
17065
|
validateStateBucket: () => validateStateBucket
|
|
16809
17066
|
});
|
|
16810
|
-
import * as
|
|
16811
|
-
import * as
|
|
16812
|
-
import { execFileSync as
|
|
17067
|
+
import * as fs29 from "fs";
|
|
17068
|
+
import * as path36 from "path";
|
|
17069
|
+
import { execFileSync as execFileSync25 } from "child_process";
|
|
16813
17070
|
function defaultStateBucket(tenant) {
|
|
16814
17071
|
return `${tenant}-mesh-platform-pulumi-state`;
|
|
16815
17072
|
}
|
|
@@ -16838,8 +17095,8 @@ function validateStateBucket(value) {
|
|
|
16838
17095
|
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
17096
|
}
|
|
16840
17097
|
function resolveTargetDir(tenant, flags, cwd) {
|
|
16841
|
-
const dir =
|
|
16842
|
-
if (
|
|
17098
|
+
const dir = path36.resolve(cwd, flags.dir ?? defaultPlatformDir(tenant));
|
|
17099
|
+
if (fs29.existsSync(dir) && fs29.readdirSync(dir).length > 0) {
|
|
16843
17100
|
throw new MeshCliError(`Target directory is not empty: ${dir}`, {
|
|
16844
17101
|
remediation: { command: `mesh init platform ${tenant} --dir <empty-dir>` }
|
|
16845
17102
|
});
|
|
@@ -16893,7 +17150,7 @@ function stateBucketCreateCommand(setup) {
|
|
|
16893
17150
|
return `aws s3api create-bucket --bucket ${setup.stateBucket} --region ${setup.region}${location} --profile ${setup.profile}`;
|
|
16894
17151
|
}
|
|
16895
17152
|
function awsJson(args, profile) {
|
|
16896
|
-
return
|
|
17153
|
+
return execFileSync25("aws", [...args, "--profile", profile], {
|
|
16897
17154
|
encoding: "utf8",
|
|
16898
17155
|
stdio: ["ignore", "pipe", "pipe"]
|
|
16899
17156
|
});
|
|
@@ -16953,7 +17210,7 @@ function renderPlatformNextSteps(setup, opts = {}) {
|
|
|
16953
17210
|
return steps;
|
|
16954
17211
|
}
|
|
16955
17212
|
async function scaffoldPlatformRepo(setup) {
|
|
16956
|
-
if (
|
|
17213
|
+
if (fs29.existsSync(setup.dir) && fs29.readdirSync(setup.dir).length > 0) {
|
|
16957
17214
|
throw new MeshCliError(`Target directory is not empty: ${setup.dir}`, {
|
|
16958
17215
|
remediation: { command: `mesh init platform ${setup.tenant} --dir <empty-dir>` }
|
|
16959
17216
|
});
|
|
@@ -16961,8 +17218,8 @@ async function scaffoldPlatformRepo(setup) {
|
|
|
16961
17218
|
const { copyTemplate: copyTemplate2 } = await Promise.resolve().then(() => (init_create_app(), create_app_exports));
|
|
16962
17219
|
const { findPackageRoot: findPackageRoot2 } = await Promise.resolve().then(() => (init_stack(), stack_exports));
|
|
16963
17220
|
const { syncSkills: syncSkills2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
|
|
16964
|
-
const templateDir =
|
|
16965
|
-
|
|
17221
|
+
const templateDir = path36.join(findPackageRoot2(), "templates", "platform-repo");
|
|
17222
|
+
fs29.mkdirSync(setup.dir, { recursive: true });
|
|
16966
17223
|
copyTemplate2(templateDir, setup.dir, {
|
|
16967
17224
|
tenant: setup.tenant,
|
|
16968
17225
|
env: setup.env,
|
|
@@ -17009,9 +17266,9 @@ var init_platform_setup = __esm({
|
|
|
17009
17266
|
});
|
|
17010
17267
|
|
|
17011
17268
|
// libs/mesh-cli/src/commands/registry-publish.ts
|
|
17012
|
-
import { execFileSync as
|
|
17013
|
-
import * as
|
|
17014
|
-
import * as
|
|
17269
|
+
import { execFileSync as execFileSync26, execSync } from "child_process";
|
|
17270
|
+
import * as fs30 from "fs";
|
|
17271
|
+
import * as path37 from "path";
|
|
17015
17272
|
function repoRoot() {
|
|
17016
17273
|
return execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
|
|
17017
17274
|
}
|
|
@@ -17021,9 +17278,9 @@ function computeSnapshotVersion(root) {
|
|
|
17021
17278
|
return `0.0.0-dev.${stamp}.${sha}`;
|
|
17022
17279
|
}
|
|
17023
17280
|
function setPackageVersion(file, version) {
|
|
17024
|
-
const content =
|
|
17281
|
+
const content = fs30.readFileSync(file, "utf-8");
|
|
17025
17282
|
const next = content.replace(/"version"(\s*:\s*)"[^"]*"/, `"version"$1"${version}"`);
|
|
17026
|
-
|
|
17283
|
+
fs30.writeFileSync(file, next);
|
|
17027
17284
|
}
|
|
17028
17285
|
function dirtyPackageJsons(root) {
|
|
17029
17286
|
const out = execSync("git diff --name-only", { cwd: root, encoding: "utf-8" });
|
|
@@ -17056,8 +17313,8 @@ function registerRegistryPublish(registry) {
|
|
|
17056
17313
|
logError("CodeArtifact login failed. Run: mesh registry login <context>");
|
|
17057
17314
|
process.exit(1);
|
|
17058
17315
|
}
|
|
17059
|
-
const listPath =
|
|
17060
|
-
const all = JSON.parse(
|
|
17316
|
+
const listPath = path37.join(root, "scripts/lib/publishable-packages.json");
|
|
17317
|
+
const all = JSON.parse(fs30.readFileSync(listPath, "utf-8"));
|
|
17061
17318
|
const patterns = (opts.only ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
17062
17319
|
const selected = patterns.length ? all.filter((p) => patterns.some((pat) => p.dir.includes(pat) || p.name.includes(pat))) : all;
|
|
17063
17320
|
if (selected.length === 0) {
|
|
@@ -17069,16 +17326,16 @@ function registerRegistryPublish(registry) {
|
|
|
17069
17326
|
const preDirty = dirtyPackageJsons(root);
|
|
17070
17327
|
const backups = [];
|
|
17071
17328
|
const stamp = (dir) => {
|
|
17072
|
-
const file =
|
|
17073
|
-
if (!
|
|
17074
|
-
backups.push({ file, content:
|
|
17329
|
+
const file = path37.join(root, dir, "package.json");
|
|
17330
|
+
if (!fs30.existsSync(file)) return;
|
|
17331
|
+
backups.push({ file, content: fs30.readFileSync(file, "utf-8") });
|
|
17075
17332
|
setPackageVersion(file, version);
|
|
17076
17333
|
};
|
|
17077
17334
|
try {
|
|
17078
17335
|
for (const p of selected) {
|
|
17079
17336
|
stamp(p.dir);
|
|
17080
17337
|
for (const sub of p.subPackages ?? []) {
|
|
17081
|
-
stamp(
|
|
17338
|
+
stamp(path37.join(p.dir, typeof sub === "string" ? sub : sub.dir));
|
|
17082
17339
|
}
|
|
17083
17340
|
}
|
|
17084
17341
|
const args = [
|
|
@@ -17093,14 +17350,14 @@ function registerRegistryPublish(registry) {
|
|
|
17093
17350
|
...opts.dryRun ? ["--dry-run"] : []
|
|
17094
17351
|
];
|
|
17095
17352
|
logInfo(`Publishing ${selected.length} package(s)...`);
|
|
17096
|
-
|
|
17353
|
+
execFileSync26("bash", args, { cwd: root, stdio: "inherit", env: env ?? process.env });
|
|
17097
17354
|
} finally {
|
|
17098
|
-
for (const b of backups)
|
|
17355
|
+
for (const b of backups) fs30.writeFileSync(b.file, b.content);
|
|
17099
17356
|
logInfo("Restored source package.json versions.");
|
|
17100
17357
|
const collateral = [...dirtyPackageJsons(root)].filter((f) => !preDirty.has(f));
|
|
17101
17358
|
if (collateral.length) {
|
|
17102
17359
|
try {
|
|
17103
|
-
|
|
17360
|
+
execFileSync26("git", ["checkout", "--", ...collateral], { cwd: root, stdio: "inherit" });
|
|
17104
17361
|
logInfo(`Reverted ${collateral.length} package.json file(s) re-vendored by build:publish.`);
|
|
17105
17362
|
} catch {
|
|
17106
17363
|
logError(
|
|
@@ -17152,12 +17409,12 @@ __export(registry_exports, {
|
|
|
17152
17409
|
shouldRemintAfter: () => shouldRemintAfter,
|
|
17153
17410
|
shouldRepairUserNpmrc: () => shouldRepairUserNpmrc
|
|
17154
17411
|
});
|
|
17155
|
-
import { execFileSync as
|
|
17156
|
-
import * as
|
|
17157
|
-
import * as
|
|
17412
|
+
import { execFileSync as execFileSync27 } from "child_process";
|
|
17413
|
+
import * as fs31 from "fs";
|
|
17414
|
+
import * as path38 from "path";
|
|
17158
17415
|
function getEndpoint(env) {
|
|
17159
17416
|
try {
|
|
17160
|
-
const result =
|
|
17417
|
+
const result = execFileSync27("aws", [
|
|
17161
17418
|
"codeartifact",
|
|
17162
17419
|
"get-repository-endpoint",
|
|
17163
17420
|
"--domain",
|
|
@@ -17184,7 +17441,7 @@ function getEndpoint(env) {
|
|
|
17184
17441
|
}
|
|
17185
17442
|
function codeartifactLogin(env) {
|
|
17186
17443
|
try {
|
|
17187
|
-
|
|
17444
|
+
execFileSync27("aws", [
|
|
17188
17445
|
"codeartifact",
|
|
17189
17446
|
"login",
|
|
17190
17447
|
"--tool",
|
|
@@ -17239,7 +17496,7 @@ function resolvePublisherRoleArn({
|
|
|
17239
17496
|
}
|
|
17240
17497
|
function assumeRole2(roleArn) {
|
|
17241
17498
|
try {
|
|
17242
|
-
const result =
|
|
17499
|
+
const result = execFileSync27("aws", [
|
|
17243
17500
|
"sts",
|
|
17244
17501
|
"assume-role",
|
|
17245
17502
|
"--role-arn",
|
|
@@ -17261,7 +17518,7 @@ function assumeRole2(roleArn) {
|
|
|
17261
17518
|
}
|
|
17262
17519
|
function assumeRoleWithWebIdentity2(roleArn, idToken, sessionName) {
|
|
17263
17520
|
try {
|
|
17264
|
-
const result =
|
|
17521
|
+
const result = execFileSync27("aws", [
|
|
17265
17522
|
"sts",
|
|
17266
17523
|
"assume-role-with-web-identity",
|
|
17267
17524
|
"--role-arn",
|
|
@@ -17325,50 +17582,50 @@ function resolveCredentials(context, roleArn) {
|
|
|
17325
17582
|
function findProjectRoot2() {
|
|
17326
17583
|
let dir = process.cwd();
|
|
17327
17584
|
while (true) {
|
|
17328
|
-
if (
|
|
17585
|
+
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
17586
|
return dir;
|
|
17330
17587
|
}
|
|
17331
|
-
const parent =
|
|
17588
|
+
const parent = path38.dirname(dir);
|
|
17332
17589
|
if (parent === dir) return null;
|
|
17333
17590
|
dir = parent;
|
|
17334
17591
|
}
|
|
17335
17592
|
}
|
|
17336
17593
|
function ensureProjectNpmrc(endpoint) {
|
|
17337
17594
|
const projectRoot = findProjectRoot2() ?? process.cwd();
|
|
17338
|
-
const npmrcPath2 =
|
|
17595
|
+
const npmrcPath2 = path38.join(projectRoot, ".npmrc");
|
|
17339
17596
|
const scopeLine = `${CA_NAMESPACE}:registry=${endpoint}`;
|
|
17340
|
-
if (!
|
|
17341
|
-
|
|
17597
|
+
if (!fs31.existsSync(npmrcPath2)) {
|
|
17598
|
+
fs31.writeFileSync(npmrcPath2, scopeLine + "\n", "utf-8");
|
|
17342
17599
|
return { created: true, updated: false, path: npmrcPath2 };
|
|
17343
17600
|
}
|
|
17344
|
-
const content =
|
|
17601
|
+
const content = fs31.readFileSync(npmrcPath2, "utf-8");
|
|
17345
17602
|
const scopeRegex = new RegExp(`^${CA_NAMESPACE.replace("/", "\\/")}:registry=.+$`, "m");
|
|
17346
17603
|
if (scopeRegex.test(content)) {
|
|
17347
17604
|
if (content.includes(scopeLine)) {
|
|
17348
17605
|
return { created: false, updated: false, path: npmrcPath2 };
|
|
17349
17606
|
}
|
|
17350
17607
|
const updated = content.replace(scopeRegex, scopeLine);
|
|
17351
|
-
|
|
17608
|
+
fs31.writeFileSync(npmrcPath2, updated, "utf-8");
|
|
17352
17609
|
return { created: false, updated: true, path: npmrcPath2 };
|
|
17353
17610
|
}
|
|
17354
17611
|
const separator = content.endsWith("\n") ? "" : "\n";
|
|
17355
|
-
|
|
17612
|
+
fs31.writeFileSync(npmrcPath2, content + separator + scopeLine + "\n", "utf-8");
|
|
17356
17613
|
return { created: false, updated: true, path: npmrcPath2 };
|
|
17357
17614
|
}
|
|
17358
17615
|
function applyGrantToUserNpmrc(grant, npmrcPath2 = homeNpmrcPath()) {
|
|
17359
17616
|
let existing = "";
|
|
17360
17617
|
try {
|
|
17361
|
-
existing =
|
|
17618
|
+
existing = fs31.readFileSync(npmrcPath2, "utf-8");
|
|
17362
17619
|
} catch {
|
|
17363
17620
|
}
|
|
17364
17621
|
const content = upsertNpmrcLines(existing, [
|
|
17365
17622
|
{ key: `${grant.scope}:registry`, value: grant.endpoint },
|
|
17366
17623
|
{ key: `${npmrcAuthKeyForEndpoint(grant.endpoint)}:_authToken`, value: grant.authorizationToken }
|
|
17367
17624
|
]);
|
|
17368
|
-
|
|
17369
|
-
|
|
17625
|
+
fs31.mkdirSync(path38.dirname(npmrcPath2), { recursive: true });
|
|
17626
|
+
fs31.writeFileSync(npmrcPath2, content, { mode: 384 });
|
|
17370
17627
|
try {
|
|
17371
|
-
|
|
17628
|
+
fs31.chmodSync(npmrcPath2, 384);
|
|
17372
17629
|
} catch {
|
|
17373
17630
|
}
|
|
17374
17631
|
return { path: npmrcPath2 };
|
|
@@ -17491,7 +17748,7 @@ function shouldRepairUserNpmrc(opts) {
|
|
|
17491
17748
|
function repairUnscopedRegistry(npmrcPath2 = homeNpmrcPath()) {
|
|
17492
17749
|
let original;
|
|
17493
17750
|
try {
|
|
17494
|
-
original =
|
|
17751
|
+
original = fs31.readFileSync(npmrcPath2, "utf-8");
|
|
17495
17752
|
} catch {
|
|
17496
17753
|
return { removed: null };
|
|
17497
17754
|
}
|
|
@@ -17499,8 +17756,8 @@ function repairUnscopedRegistry(npmrcPath2 = homeNpmrcPath()) {
|
|
|
17499
17756
|
if (!removed) return { removed: null };
|
|
17500
17757
|
const backupPath = `${npmrcPath2}.bak-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`;
|
|
17501
17758
|
try {
|
|
17502
|
-
|
|
17503
|
-
|
|
17759
|
+
fs31.writeFileSync(backupPath, original, "utf-8");
|
|
17760
|
+
fs31.writeFileSync(npmrcPath2, content, "utf-8");
|
|
17504
17761
|
} catch (err) {
|
|
17505
17762
|
return { removed: null, error: err instanceof Error ? err.message : String(err) };
|
|
17506
17763
|
}
|
|
@@ -17512,9 +17769,9 @@ function renderRegistrySessionLine(session, now = Date.now()) {
|
|
|
17512
17769
|
}
|
|
17513
17770
|
async function checkExistingToken() {
|
|
17514
17771
|
const npmrcPath2 = homeNpmrcPath();
|
|
17515
|
-
if (!
|
|
17772
|
+
if (!fs31.existsSync(npmrcPath2)) return { valid: false, state: "missing", reason: "no ~/.npmrc" };
|
|
17516
17773
|
const hijackLine = findUnscopedCodeArtifactRegistry(
|
|
17517
|
-
|
|
17774
|
+
fs31.readFileSync(npmrcPath2, "utf-8")
|
|
17518
17775
|
) ?? void 0;
|
|
17519
17776
|
const probe = await probeRegistryToken({ npmrcPath: npmrcPath2 });
|
|
17520
17777
|
if (probe.state === "missing") {
|
|
@@ -17567,9 +17824,9 @@ async function runRegistryStatus(opts) {
|
|
|
17567
17824
|
logInfo(renderRegistrySessionLine(opts?.session ?? readRegistrySession()));
|
|
17568
17825
|
const projectRoot = findProjectRoot2();
|
|
17569
17826
|
if (projectRoot) {
|
|
17570
|
-
const npmrcPath2 =
|
|
17571
|
-
if (
|
|
17572
|
-
const content =
|
|
17827
|
+
const npmrcPath2 = path38.join(projectRoot, ".npmrc");
|
|
17828
|
+
if (fs31.existsSync(npmrcPath2)) {
|
|
17829
|
+
const content = fs31.readFileSync(npmrcPath2, "utf-8");
|
|
17573
17830
|
if (content.includes(`${CA_NAMESPACE}:registry=`)) {
|
|
17574
17831
|
logSuccess(`Project .npmrc configured (${npmrcPath2})`);
|
|
17575
17832
|
} else {
|
|
@@ -17603,7 +17860,7 @@ region = us-east-2`,
|
|
|
17603
17860
|
{ remediation: { command: `aws configure sso --profile ${profile}` } }
|
|
17604
17861
|
);
|
|
17605
17862
|
}
|
|
17606
|
-
const probe = () =>
|
|
17863
|
+
const probe = () => execFileSync27("aws", ["sts", "get-caller-identity", "--profile", profile], {
|
|
17607
17864
|
stdio: ["ignore", "pipe", "pipe"],
|
|
17608
17865
|
timeout: 2e4
|
|
17609
17866
|
});
|
|
@@ -17614,7 +17871,7 @@ region = us-east-2`,
|
|
|
17614
17871
|
} catch {
|
|
17615
17872
|
logInfo(`AWS SSO session for profile '${profile}' is stale \u2014 opening browser login\u2026`);
|
|
17616
17873
|
}
|
|
17617
|
-
|
|
17874
|
+
execFileSync27("aws", ["sso", "login", "--profile", profile], { stdio: "inherit" });
|
|
17618
17875
|
try {
|
|
17619
17876
|
probe();
|
|
17620
17877
|
} catch (err) {
|
|
@@ -17850,9 +18107,9 @@ __export(wizard_exports, {
|
|
|
17850
18107
|
wizardExitCode: () => wizardExitCode,
|
|
17851
18108
|
wizardNextCommands: () => wizardNextCommands
|
|
17852
18109
|
});
|
|
17853
|
-
import * as
|
|
17854
|
-
import * as
|
|
17855
|
-
import { execFileSync as
|
|
18110
|
+
import * as fs32 from "fs";
|
|
18111
|
+
import * as path39 from "path";
|
|
18112
|
+
import { execFileSync as execFileSync28 } from "child_process";
|
|
17856
18113
|
import chalk4 from "chalk";
|
|
17857
18114
|
function isNewPlatform(mode) {
|
|
17858
18115
|
return typeof mode === "object" && "newPlatform" in mode;
|
|
@@ -17929,18 +18186,18 @@ function classifyRepo(cwd) {
|
|
|
17929
18186
|
if (isInsidePlatformMonorepo(cwd)) return { kind: "platform-monorepo", root: resolveTargetRoot(cwd) };
|
|
17930
18187
|
if (shouldBootstrapAppsRepo(cwd)) return { kind: "empty-apps-repo", root: cwd };
|
|
17931
18188
|
const root = resolveTargetRoot(cwd);
|
|
17932
|
-
const inRepo =
|
|
18189
|
+
const inRepo = fs32.existsSync(path39.join(root, ".git"));
|
|
17933
18190
|
if (!inRepo) {
|
|
17934
|
-
const hasContent =
|
|
18191
|
+
const hasContent = fs32.readdirSync(cwd).some((entry) => !entry.startsWith("."));
|
|
17935
18192
|
return { kind: hasContent ? "no-repo" : "empty-dir", root: cwd };
|
|
17936
18193
|
}
|
|
17937
|
-
const hasWorkspace =
|
|
17938
|
-
const hasApps =
|
|
18194
|
+
const hasWorkspace = fs32.existsSync(path39.join(root, "pnpm-workspace.yaml")) || fs32.existsSync(path39.join(root, "pnpm-lock.yaml"));
|
|
18195
|
+
const hasApps = fs32.existsSync(path39.join(root, "apps")) || fs32.existsSync(path39.join(root, "tenants"));
|
|
17939
18196
|
if (hasWorkspace || hasApps) return { kind: "apps-repo", root };
|
|
17940
18197
|
return { kind: "other-repo", root };
|
|
17941
18198
|
}
|
|
17942
18199
|
function gitInit(dir) {
|
|
17943
|
-
|
|
18200
|
+
execFileSync28("git", ["init", "-q"], { cwd: dir, stdio: ["ignore", "ignore", "pipe"] });
|
|
17944
18201
|
}
|
|
17945
18202
|
async function runWizardSteps(ctx, steps) {
|
|
17946
18203
|
const results = [];
|
|
@@ -18161,7 +18418,7 @@ var init_wizard = __esm({
|
|
|
18161
18418
|
return { name, status: "fail", detail: `platform repo not scaffolded: ${err.message.split("\n")[0]}`, fix: `mesh init platform ${ctx.tenant} --dir <empty-dir>` };
|
|
18162
18419
|
}
|
|
18163
18420
|
const bucket = await ensureStateBucket(setup, ctx.seams?.stateBucket);
|
|
18164
|
-
const next = renderPlatformNextSteps(setup, { bucket, relativeDir:
|
|
18421
|
+
const next = renderPlatformNextSteps(setup, { bucket, relativeDir: path39.relative(ctx.cwd, setup.dir) || "." });
|
|
18165
18422
|
return {
|
|
18166
18423
|
name,
|
|
18167
18424
|
status: setup.createStateBucket && !bucket.present ? "warn" : "pass",
|
|
@@ -18259,8 +18516,8 @@ var init_wizard = __esm({
|
|
|
18259
18516
|
}
|
|
18260
18517
|
case "apps-repo": {
|
|
18261
18518
|
const missing = [];
|
|
18262
|
-
if (!
|
|
18263
|
-
if (!
|
|
18519
|
+
if (!fs32.existsSync(path39.join(root, "package.json"))) missing.push("package.json");
|
|
18520
|
+
if (!fs32.existsSync(path39.join(root, "pnpm-workspace.yaml")) && !fs32.existsSync(path39.join(root, "pnpm-lock.yaml"))) {
|
|
18264
18521
|
missing.push("pnpm-workspace.yaml");
|
|
18265
18522
|
}
|
|
18266
18523
|
if (missing.length) {
|
|
@@ -18297,8 +18554,8 @@ var init_wizard = __esm({
|
|
|
18297
18554
|
|
|
18298
18555
|
// libs/mesh-cli/src/commands/init.ts
|
|
18299
18556
|
import chalk5 from "chalk";
|
|
18300
|
-
import * as
|
|
18301
|
-
import * as
|
|
18557
|
+
import * as fs33 from "fs";
|
|
18558
|
+
import * as path40 from "path";
|
|
18302
18559
|
async function setupPrompts() {
|
|
18303
18560
|
const [{ default: input2 }, { default: confirm }] = await Promise.all([
|
|
18304
18561
|
import("@inquirer/input"),
|
|
@@ -18324,7 +18581,7 @@ async function probeHubTenants(hubUrl, accessToken) {
|
|
|
18324
18581
|
}
|
|
18325
18582
|
function readHomeNpmrc() {
|
|
18326
18583
|
try {
|
|
18327
|
-
return
|
|
18584
|
+
return fs33.readFileSync(homeNpmrcPath(), "utf-8");
|
|
18328
18585
|
} catch {
|
|
18329
18586
|
return "";
|
|
18330
18587
|
}
|
|
@@ -18448,9 +18705,9 @@ async function runChecks2(args) {
|
|
|
18448
18705
|
if (local) {
|
|
18449
18706
|
checks.push({ name: "Deployer role", status: "pass", detail: "local context \u2014 no deployer role required" });
|
|
18450
18707
|
} else {
|
|
18451
|
-
const stackFiles =
|
|
18708
|
+
const stackFiles = fs33.existsSync(root) ? fs33.readdirSync(root).filter((f) => /^Pulumi\..*\.yaml$/.test(f)) : [];
|
|
18452
18709
|
const hasRole = stackFiles.some(
|
|
18453
|
-
(f) => /mesh:deployerRole/.test(
|
|
18710
|
+
(f) => /mesh:deployerRole/.test(fs33.readFileSync(path40.join(root, f), "utf-8"))
|
|
18454
18711
|
);
|
|
18455
18712
|
checks.push(
|
|
18456
18713
|
hasRole ? { name: "Deployer role", status: "pass", detail: "mesh:deployerRole configured in stack config" } : {
|
|
@@ -18462,8 +18719,8 @@ async function runChecks2(args) {
|
|
|
18462
18719
|
);
|
|
18463
18720
|
}
|
|
18464
18721
|
const shapeProblems = [];
|
|
18465
|
-
if (!
|
|
18466
|
-
const hasWorkspace =
|
|
18722
|
+
if (!fs33.existsSync(path40.join(root, "package.json"))) shapeProblems.push("package.json");
|
|
18723
|
+
const hasWorkspace = fs33.existsSync(path40.join(root, "pnpm-workspace.yaml")) || fs33.existsSync(path40.join(root, "pnpm-lock.yaml"));
|
|
18467
18724
|
if (!hasWorkspace) shapeProblems.push("pnpm-workspace.yaml");
|
|
18468
18725
|
checks.push(
|
|
18469
18726
|
shapeProblems.length === 0 ? { name: "Repo shape", status: "pass", detail: "pnpm workspace layout present" } : {
|
|
@@ -18519,7 +18776,7 @@ function registerInitCommands(program2) {
|
|
|
18519
18776
|
if (bucket.detail !== "not requested") logInfo(`Pulumi state bucket: ${bucket.detail}`);
|
|
18520
18777
|
console.log("");
|
|
18521
18778
|
console.log("Next steps:");
|
|
18522
|
-
for (const line of renderPlatformNextSteps2(setup, { bucket, relativeDir:
|
|
18779
|
+
for (const line of renderPlatformNextSteps2(setup, { bucket, relativeDir: path40.relative(process.cwd(), setup.dir) || "." })) {
|
|
18523
18780
|
console.log(line ? ` ${line}` : "");
|
|
18524
18781
|
}
|
|
18525
18782
|
console.log("");
|
|
@@ -18587,10 +18844,10 @@ var init_init = __esm({
|
|
|
18587
18844
|
});
|
|
18588
18845
|
|
|
18589
18846
|
// libs/mesh-cli/src/commands/install-shim.ts
|
|
18590
|
-
import { execFileSync as
|
|
18591
|
-
import * as
|
|
18847
|
+
import { execFileSync as execFileSync29 } from "child_process";
|
|
18848
|
+
import * as fs34 from "fs";
|
|
18592
18849
|
import * as os10 from "os";
|
|
18593
|
-
import * as
|
|
18850
|
+
import * as path41 from "path";
|
|
18594
18851
|
function shimScript() {
|
|
18595
18852
|
return `#!/bin/sh
|
|
18596
18853
|
# mesh \u2014 canonical launcher shim (installed by \`mesh install-shim\`).
|
|
@@ -18663,25 +18920,25 @@ exit 1
|
|
|
18663
18920
|
`;
|
|
18664
18921
|
}
|
|
18665
18922
|
function defaultShimDir() {
|
|
18666
|
-
return
|
|
18923
|
+
return path41.join(os10.homedir(), ".local", "bin");
|
|
18667
18924
|
}
|
|
18668
18925
|
function dirOnPath(dir, pathEnv) {
|
|
18669
18926
|
if (!pathEnv) return false;
|
|
18670
|
-
return pathEnv.split(
|
|
18927
|
+
return pathEnv.split(path41.delimiter).some((p) => p === dir);
|
|
18671
18928
|
}
|
|
18672
18929
|
function registerInstallShimCommand(program2) {
|
|
18673
18930
|
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 (
|
|
18931
|
+
const dir = path41.resolve(opts.dir);
|
|
18932
|
+
const target = path41.join(dir, "mesh");
|
|
18933
|
+
if (fs34.existsSync(target) && !opts.force) {
|
|
18677
18934
|
logWarn(`A file already exists at ${target}.`);
|
|
18678
18935
|
logInfo("Re-run with --force to overwrite it, or pass --dir <other-path-on-PATH>.");
|
|
18679
18936
|
return;
|
|
18680
18937
|
}
|
|
18681
18938
|
try {
|
|
18682
|
-
|
|
18683
|
-
|
|
18684
|
-
|
|
18939
|
+
fs34.mkdirSync(dir, { recursive: true });
|
|
18940
|
+
fs34.writeFileSync(target, shimScript(), { mode: 493 });
|
|
18941
|
+
fs34.chmodSync(target, 493);
|
|
18685
18942
|
} catch (err) {
|
|
18686
18943
|
logError(`Could not write the shim to ${target}: ${err.message}`);
|
|
18687
18944
|
process.exitCode = 1;
|
|
@@ -18694,13 +18951,13 @@ function registerInstallShimCommand(program2) {
|
|
|
18694
18951
|
} else {
|
|
18695
18952
|
logInfo("Bare `mesh <cmd>` now runs the local source of whatever workspace you're in.");
|
|
18696
18953
|
}
|
|
18697
|
-
const diagPath =
|
|
18954
|
+
const diagPath = path41.join(os10.tmpdir(), "mesh-shim-selftest.log");
|
|
18698
18955
|
let stdout = "";
|
|
18699
18956
|
let stderr = "";
|
|
18700
18957
|
let status = 0;
|
|
18701
18958
|
let ok = true;
|
|
18702
18959
|
try {
|
|
18703
|
-
stdout =
|
|
18960
|
+
stdout = execFileSync29(target, ["--help"], {
|
|
18704
18961
|
cwd: process.cwd(),
|
|
18705
18962
|
encoding: "utf8",
|
|
18706
18963
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -18727,7 +18984,7 @@ function registerInstallShimCommand(program2) {
|
|
|
18727
18984
|
""
|
|
18728
18985
|
].join("\n");
|
|
18729
18986
|
try {
|
|
18730
|
-
|
|
18987
|
+
fs34.writeFileSync(diagPath, diag);
|
|
18731
18988
|
} catch {
|
|
18732
18989
|
}
|
|
18733
18990
|
if (ok && /Commands:|Usage:/.test(stdout)) {
|
|
@@ -18747,17 +19004,17 @@ var init_install_shim = __esm({
|
|
|
18747
19004
|
});
|
|
18748
19005
|
|
|
18749
19006
|
// libs/mesh-cli/src/commands/local/hub-local.ts
|
|
18750
|
-
import { execFile as execFile3, execFileSync as
|
|
18751
|
-
import * as
|
|
19007
|
+
import { execFile as execFile3, execFileSync as execFileSync30 } from "child_process";
|
|
19008
|
+
import * as fs35 from "fs";
|
|
18752
19009
|
import * as os11 from "os";
|
|
18753
|
-
import * as
|
|
19010
|
+
import * as path42 from "path";
|
|
18754
19011
|
import { promisify as promisify2 } from "util";
|
|
18755
19012
|
function cacheDir() {
|
|
18756
19013
|
return meshCacheDir("hub-local");
|
|
18757
19014
|
}
|
|
18758
19015
|
function npmrcPath() {
|
|
18759
|
-
const p =
|
|
18760
|
-
if (!
|
|
19016
|
+
const p = path42.join(os11.homedir(), ".npmrc");
|
|
19017
|
+
if (!fs35.existsSync(p) || !fs35.readFileSync(p, "utf-8").includes("codeartifact")) {
|
|
18761
19018
|
throw new MeshCliError(
|
|
18762
19019
|
"The local Hub builds from the published @mesh-tech/hub tarball, which needs registry auth.",
|
|
18763
19020
|
{ remediation: { command: REGISTRY_LOGIN_FIX } }
|
|
@@ -18767,7 +19024,7 @@ function npmrcPath() {
|
|
|
18767
19024
|
}
|
|
18768
19025
|
function imageExists(tag) {
|
|
18769
19026
|
try {
|
|
18770
|
-
|
|
19027
|
+
execFileSync30("docker", ["image", "inspect", tag], { stdio: ["ignore", "pipe", "pipe"] });
|
|
18771
19028
|
return true;
|
|
18772
19029
|
} catch {
|
|
18773
19030
|
return false;
|
|
@@ -18776,22 +19033,22 @@ function imageExists(tag) {
|
|
|
18776
19033
|
function ensureHubAuthImage() {
|
|
18777
19034
|
if (imageExists(HUB_AUTH_IMAGE)) return;
|
|
18778
19035
|
logInfo(`Building ${HUB_AUTH_IMAGE} (Hub auth proxy)\u2026`);
|
|
18779
|
-
const hubStackDir =
|
|
18780
|
-
|
|
19036
|
+
const hubStackDir = path42.join(findPackageRoot(), "stack", "hub");
|
|
19037
|
+
execFileSync30(
|
|
18781
19038
|
"docker",
|
|
18782
|
-
["build", "-f",
|
|
19039
|
+
["build", "-f", path42.join(hubStackDir, "Dockerfile.auth"), "-t", HUB_AUTH_IMAGE, hubStackDir],
|
|
18783
19040
|
{ stdio: ["ignore", "inherit", "inherit"], env: { ...process.env, DOCKER_BUILDKIT: "1" } }
|
|
18784
19041
|
);
|
|
18785
19042
|
logSuccess(`Built ${HUB_AUTH_IMAGE}`);
|
|
18786
19043
|
}
|
|
18787
19044
|
function hasRegistryAuth() {
|
|
18788
|
-
const p =
|
|
18789
|
-
return
|
|
19045
|
+
const p = path42.join(os11.homedir(), ".npmrc");
|
|
19046
|
+
return fs35.existsSync(p) && fs35.readFileSync(p, "utf-8").includes("codeartifact");
|
|
18790
19047
|
}
|
|
18791
19048
|
function localHubVersion() {
|
|
18792
19049
|
const versions = HUB_IMAGES.map((name) => {
|
|
18793
19050
|
try {
|
|
18794
|
-
const out =
|
|
19051
|
+
const out = execFileSync30("docker", ["images", name, "--format", "{{.Tag}}"], {
|
|
18795
19052
|
encoding: "utf-8",
|
|
18796
19053
|
stdio: ["ignore", "pipe", "pipe"]
|
|
18797
19054
|
});
|
|
@@ -18817,10 +19074,10 @@ async function fetchTarball() {
|
|
|
18817
19074
|
{ encoding: "utf-8" }
|
|
18818
19075
|
);
|
|
18819
19076
|
const info = JSON.parse(stdout)[0];
|
|
18820
|
-
return { tarball:
|
|
19077
|
+
return { tarball: path42.join(dir, info.filename), version: info.version };
|
|
18821
19078
|
} catch (err) {
|
|
18822
19079
|
const authFailure = isNpmAuthError(err);
|
|
18823
|
-
const cached =
|
|
19080
|
+
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
19081
|
if (!cached) {
|
|
18825
19082
|
if (authFailure) {
|
|
18826
19083
|
throw new MeshCliError(
|
|
@@ -18838,7 +19095,7 @@ async function fetchTarball() {
|
|
|
18838
19095
|
} else {
|
|
18839
19096
|
logInfo(`Registry unavailable \u2014 using the cached hub tarball v${version}`);
|
|
18840
19097
|
}
|
|
18841
|
-
return { tarball:
|
|
19098
|
+
return { tarball: path42.join(dir, cached), version };
|
|
18842
19099
|
} finally {
|
|
18843
19100
|
heartbeat.stop();
|
|
18844
19101
|
}
|
|
@@ -18867,13 +19124,13 @@ async function ensureHubImages() {
|
|
|
18867
19124
|
logInfo(`Local Hub images ready (v${version})`);
|
|
18868
19125
|
return version;
|
|
18869
19126
|
}
|
|
18870
|
-
const context =
|
|
18871
|
-
|
|
18872
|
-
|
|
18873
|
-
|
|
19127
|
+
const context = path42.join(cacheDir(), `context-${version}`);
|
|
19128
|
+
fs35.rmSync(context, { recursive: true, force: true });
|
|
19129
|
+
fs35.mkdirSync(context, { recursive: true });
|
|
19130
|
+
execFileSync30("tar", ["-xzf", tarball, "-C", context, "--strip-components", "1"], {
|
|
18874
19131
|
stdio: ["ignore", "pipe", "pipe"]
|
|
18875
19132
|
});
|
|
18876
|
-
const hubStackDir =
|
|
19133
|
+
const hubStackDir = path42.join(findPackageRoot(), "stack", "hub");
|
|
18877
19134
|
for (const [name, dockerfile] of [
|
|
18878
19135
|
["mesh-local-hub-api", "Dockerfile.api"],
|
|
18879
19136
|
["mesh-local-hub-ui", "Dockerfile.ui"]
|
|
@@ -18881,12 +19138,12 @@ async function ensureHubImages() {
|
|
|
18881
19138
|
const tag = `${name}:${version}`;
|
|
18882
19139
|
if (imageExists(tag)) continue;
|
|
18883
19140
|
logInfo(`Building ${tag} from the published tarball\u2026`);
|
|
18884
|
-
|
|
19141
|
+
execFileSync30(
|
|
18885
19142
|
"docker",
|
|
18886
19143
|
[
|
|
18887
19144
|
"build",
|
|
18888
19145
|
"-f",
|
|
18889
|
-
|
|
19146
|
+
path42.join(hubStackDir, dockerfile),
|
|
18890
19147
|
"-t",
|
|
18891
19148
|
tag,
|
|
18892
19149
|
"--secret",
|
|
@@ -18904,29 +19161,29 @@ function tarballNameForImageVersion(version) {
|
|
|
18904
19161
|
return `mesh-tech-hub-${version.replace(/-r\d+$/, "")}.tgz`;
|
|
18905
19162
|
}
|
|
18906
19163
|
function readHubCompiledAuthz(version) {
|
|
18907
|
-
const context =
|
|
18908
|
-
const file =
|
|
18909
|
-
if (!
|
|
19164
|
+
const context = path42.join(cacheDir(), `context-${version}`);
|
|
19165
|
+
const file = path42.join(context, HUB_COMPILED_AUTHZ_REL);
|
|
19166
|
+
if (!fs35.existsSync(file)) {
|
|
18910
19167
|
const tarball = tarballNameForImageVersion(version);
|
|
18911
|
-
if (!tarball || !
|
|
18912
|
-
|
|
19168
|
+
if (!tarball || !fs35.existsSync(path42.join(cacheDir(), tarball))) return null;
|
|
19169
|
+
fs35.mkdirSync(context, { recursive: true });
|
|
18913
19170
|
try {
|
|
18914
|
-
|
|
19171
|
+
execFileSync30(
|
|
18915
19172
|
"tar",
|
|
18916
|
-
["-xzf",
|
|
19173
|
+
["-xzf", path42.join(cacheDir(), tarball), "-C", context, "--strip-components", "1", `package/${HUB_COMPILED_AUTHZ_REL}`],
|
|
18917
19174
|
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
18918
19175
|
);
|
|
18919
19176
|
} catch {
|
|
18920
19177
|
return null;
|
|
18921
19178
|
}
|
|
18922
|
-
if (!
|
|
19179
|
+
if (!fs35.existsSync(file)) return null;
|
|
18923
19180
|
}
|
|
18924
|
-
const parsed = JSON.parse(
|
|
19181
|
+
const parsed = JSON.parse(fs35.readFileSync(file, "utf-8"));
|
|
18925
19182
|
if (typeof parsed.zed !== "string" || !parsed.metadata || typeof parsed.metadata !== "object") return null;
|
|
18926
19183
|
return { zed: parsed.zed, metadata: parsed.metadata };
|
|
18927
19184
|
}
|
|
18928
19185
|
function readWorkspaceCatalog(repoRoot2) {
|
|
18929
|
-
const text =
|
|
19186
|
+
const text = fs35.readFileSync(path42.join(repoRoot2, "pnpm-workspace.yaml"), "utf-8");
|
|
18930
19187
|
const marker = "\ncatalog:\n";
|
|
18931
19188
|
const at = text.indexOf(marker);
|
|
18932
19189
|
if (at === -1) return {};
|
|
@@ -18941,11 +19198,11 @@ function readWorkspaceCatalog(repoRoot2) {
|
|
|
18941
19198
|
function normalizeHubManifests(contextDir, catalog) {
|
|
18942
19199
|
const DEP_FIELDS = ["dependencies", "optionalDependencies", "peerDependencies"];
|
|
18943
19200
|
const touched = [];
|
|
18944
|
-
for (const entry of
|
|
19201
|
+
for (const entry of fs35.readdirSync(contextDir, { withFileTypes: true })) {
|
|
18945
19202
|
if (!entry.isDirectory()) continue;
|
|
18946
|
-
const manifest =
|
|
18947
|
-
if (!
|
|
18948
|
-
const pkg = JSON.parse(
|
|
19203
|
+
const manifest = path42.join(contextDir, entry.name, "package.json");
|
|
19204
|
+
if (!fs35.existsSync(manifest)) continue;
|
|
19205
|
+
const pkg = JSON.parse(fs35.readFileSync(manifest, "utf-8"));
|
|
18949
19206
|
let changed = false;
|
|
18950
19207
|
if (pkg.devDependencies) {
|
|
18951
19208
|
delete pkg.devDependencies;
|
|
@@ -18974,7 +19231,7 @@ function normalizeHubManifests(contextDir, catalog) {
|
|
|
18974
19231
|
}
|
|
18975
19232
|
}
|
|
18976
19233
|
if (changed) {
|
|
18977
|
-
|
|
19234
|
+
fs35.writeFileSync(manifest, `${JSON.stringify(pkg, null, 2)}
|
|
18978
19235
|
`);
|
|
18979
19236
|
touched.push(`${entry.name}/package.json`);
|
|
18980
19237
|
}
|
|
@@ -18982,15 +19239,15 @@ function normalizeHubManifests(contextDir, catalog) {
|
|
|
18982
19239
|
return touched;
|
|
18983
19240
|
}
|
|
18984
19241
|
async function buildHubImagesFromSource(repoRoot2) {
|
|
18985
|
-
const hubDir =
|
|
18986
|
-
if (!
|
|
19242
|
+
const hubDir = path42.join(repoRoot2, "apps", "hub");
|
|
19243
|
+
if (!fs35.existsSync(path42.join(hubDir, "package.json"))) {
|
|
18987
19244
|
throw new MeshCliError(
|
|
18988
19245
|
`--hub-from-source needs a mesh-platform checkout; no apps/hub under ${repoRoot2}.`,
|
|
18989
19246
|
{ remediation: { command: "Run mesh start from a mesh-platform checkout, or drop --hub-from-source" } }
|
|
18990
19247
|
);
|
|
18991
19248
|
}
|
|
18992
19249
|
const npmrc = npmrcPath();
|
|
18993
|
-
const version = `${JSON.parse(
|
|
19250
|
+
const version = `${JSON.parse(fs35.readFileSync(path42.join(hubDir, "package.json"), "utf-8")).version}-src`;
|
|
18994
19251
|
const build = startHeartbeat("building apps/hub (api + ui) from source");
|
|
18995
19252
|
try {
|
|
18996
19253
|
for (const pkg of ["@mesh-tech/hub-api", "@mesh-tech/hub-ui"]) {
|
|
@@ -18999,27 +19256,27 @@ async function buildHubImagesFromSource(repoRoot2) {
|
|
|
18999
19256
|
} finally {
|
|
19000
19257
|
build.stop();
|
|
19001
19258
|
}
|
|
19002
|
-
const context =
|
|
19003
|
-
|
|
19004
|
-
|
|
19259
|
+
const context = path42.join(cacheDir(), `context-${version}`);
|
|
19260
|
+
fs35.rmSync(context, { recursive: true, force: true });
|
|
19261
|
+
fs35.mkdirSync(context, { recursive: true });
|
|
19005
19262
|
await execFileAsync2("pnpm", ["pack", "--pack-destination", context], { cwd: hubDir, maxBuffer: 64 * 1024 * 1024 });
|
|
19006
|
-
const tarball =
|
|
19263
|
+
const tarball = fs35.readdirSync(context).find((f) => f.endsWith(".tgz"));
|
|
19007
19264
|
if (!tarball) throw new MeshCliError("pnpm pack produced no tarball for apps/hub");
|
|
19008
|
-
|
|
19265
|
+
execFileSync30("tar", ["-xzf", path42.join(context, tarball), "-C", context, "--strip-components", "1"], {
|
|
19009
19266
|
stdio: ["ignore", "pipe", "pipe"]
|
|
19010
19267
|
});
|
|
19011
19268
|
const rewritten = normalizeHubManifests(context, readWorkspaceCatalog(repoRoot2));
|
|
19012
19269
|
if (rewritten.length > 0) logInfo(`Normalized ${rewritten.length} manifest(s) for npm: ${rewritten.join(", ")}`);
|
|
19013
|
-
const hubStackDir =
|
|
19270
|
+
const hubStackDir = path42.join(findPackageRoot(), "stack", "hub");
|
|
19014
19271
|
for (const [name, dockerfile] of [
|
|
19015
19272
|
["mesh-local-hub-api", "Dockerfile.api"],
|
|
19016
19273
|
["mesh-local-hub-ui", "Dockerfile.ui"]
|
|
19017
19274
|
]) {
|
|
19018
19275
|
const tag = `${name}:${version}`;
|
|
19019
19276
|
logInfo(`Building ${tag} from source\u2026`);
|
|
19020
|
-
|
|
19277
|
+
execFileSync30(
|
|
19021
19278
|
"docker",
|
|
19022
|
-
["build", "-f",
|
|
19279
|
+
["build", "-f", path42.join(hubStackDir, dockerfile), "-t", tag, "--secret", `id=npmrc,src=${npmrc}`, context],
|
|
19023
19280
|
{ stdio: ["ignore", "inherit", "inherit"], env: { ...process.env, DOCKER_BUILDKIT: "1" } }
|
|
19024
19281
|
);
|
|
19025
19282
|
logSuccess(`Built ${tag}`);
|
|
@@ -19104,8 +19361,8 @@ var init_seed_hub_catalog = __esm({
|
|
|
19104
19361
|
});
|
|
19105
19362
|
|
|
19106
19363
|
// libs/mesh-cli/src/commands/local/index.ts
|
|
19107
|
-
import * as
|
|
19108
|
-
import * as
|
|
19364
|
+
import * as fs36 from "fs";
|
|
19365
|
+
import * as path43 from "path";
|
|
19109
19366
|
import chalk6 from "chalk";
|
|
19110
19367
|
function crashError(crashed) {
|
|
19111
19368
|
return new MeshCliError(
|
|
@@ -19117,10 +19374,13 @@ function crashError(crashed) {
|
|
|
19117
19374
|
}
|
|
19118
19375
|
);
|
|
19119
19376
|
}
|
|
19120
|
-
async function waitForStack(io = {
|
|
19377
|
+
async function waitForStack(opts, io = {
|
|
19121
19378
|
probe: probeEndpoint,
|
|
19122
19379
|
services: stackServices,
|
|
19123
|
-
|
|
19380
|
+
overlays: () => [
|
|
19381
|
+
{ services: hubOverlayServices(), started: false },
|
|
19382
|
+
{ services: idpsOverlayServices(), started: opts.idpsStarted }
|
|
19383
|
+
]
|
|
19124
19384
|
}) {
|
|
19125
19385
|
const deadline = Date.now() + WAIT_TIMEOUT_MS;
|
|
19126
19386
|
let pending = STACK_ENDPOINTS.filter((e) => e.probe.kind !== "none");
|
|
@@ -19135,10 +19395,7 @@ async function waitForStack(io = {
|
|
|
19135
19395
|
}
|
|
19136
19396
|
}
|
|
19137
19397
|
pending = stillDown;
|
|
19138
|
-
const crashed = crashedServices(io.services(), {
|
|
19139
|
-
overlayServices: io.overlayServices(),
|
|
19140
|
-
overlayStarted: false
|
|
19141
|
-
});
|
|
19398
|
+
const crashed = crashedServices(io.services(), { overlays: io.overlays() });
|
|
19142
19399
|
if (crashed.length > 0) throw crashError(crashed);
|
|
19143
19400
|
if (pending.length === 0) break;
|
|
19144
19401
|
if (Date.now() > deadline) {
|
|
@@ -19222,17 +19479,22 @@ function portMoveHints() {
|
|
|
19222
19479
|
[
|
|
19223
19480
|
Number(hubPort()),
|
|
19224
19481
|
"MESH_HUB_PORT=<free port> mesh start (or mesh start --no-hub, which starts everything else)"
|
|
19482
|
+
],
|
|
19483
|
+
[MOCK_SAML_PORT, "mesh start (without --with-idps \u2014 the mock identity providers are opt-in)"],
|
|
19484
|
+
[
|
|
19485
|
+
MOCK_OIDC_PORT,
|
|
19486
|
+
"mesh start (without --with-idps; 5556 is Dex's own default port, so a Dex of your own is the usual holder)"
|
|
19225
19487
|
]
|
|
19226
19488
|
]);
|
|
19227
19489
|
}
|
|
19228
19490
|
function repoRootForHubSource() {
|
|
19229
19491
|
for (let dir = process.cwd(); ; ) {
|
|
19230
|
-
if (
|
|
19231
|
-
const parent =
|
|
19492
|
+
if (fs36.existsSync(path43.join(dir, "apps", "hub", "package.json"))) return dir;
|
|
19493
|
+
const parent = path43.dirname(dir);
|
|
19232
19494
|
if (parent === dir) break;
|
|
19233
19495
|
dir = parent;
|
|
19234
19496
|
}
|
|
19235
|
-
return
|
|
19497
|
+
return path43.resolve(findPackageRoot(), "..", "..");
|
|
19236
19498
|
}
|
|
19237
19499
|
function registerLocalCommands(program2) {
|
|
19238
19500
|
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 +19503,10 @@ function registerLocalCommands(program2) {
|
|
|
19241
19503
|
).option(
|
|
19242
19504
|
"--hub-from-source",
|
|
19243
19505
|
"build the Hub images from THIS checkout's apps/hub instead of the published tarball (the only way to exercise a Hub change locally)"
|
|
19506
|
+
).option(
|
|
19507
|
+
"--with-idps",
|
|
19508
|
+
"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)",
|
|
19509
|
+
false
|
|
19244
19510
|
).option(
|
|
19245
19511
|
"--takeover",
|
|
19246
19512
|
"re-own a stack that another checkout started (may recreate shared containers with THIS checkout's config)",
|
|
@@ -19268,7 +19534,11 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19268
19534
|
logWarn(`Taking over the running stack (previously driven from ${foreign}).`);
|
|
19269
19535
|
}
|
|
19270
19536
|
if (!opts.skipPortCheck && !stackServices().some((s) => s.state === "running")) {
|
|
19271
|
-
const ports = hostPortsOf([
|
|
19537
|
+
const ports = hostPortsOf([
|
|
19538
|
+
...STACK_ENDPOINTS,
|
|
19539
|
+
...opts.hub ? hubEndpoints() : [],
|
|
19540
|
+
...opts.withIdps ? idpEndpoints() : []
|
|
19541
|
+
]);
|
|
19272
19542
|
const conflicts = await findPortConflicts(ports, `${COMPOSE_PROJECT}-`);
|
|
19273
19543
|
if (conflicts.length > 0) {
|
|
19274
19544
|
throw new MeshCliError(describePortConflicts(conflicts, portMoveHints()), {
|
|
@@ -19313,9 +19583,10 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19313
19583
|
}
|
|
19314
19584
|
}
|
|
19315
19585
|
logInfo("Starting the local Mesh platform (docker compose project: mesh-local)\u2026");
|
|
19316
|
-
|
|
19586
|
+
const idpEnv = opts.withIdps ? mockIdpComposeEnv() : void 0;
|
|
19587
|
+
await composeStreamed(["up", "-d"], { idps: opts.withIdps, env: idpEnv });
|
|
19317
19588
|
compose(["restart", "prometheus", "blackbox-exporter"], { inherit: true });
|
|
19318
|
-
await waitForStack();
|
|
19589
|
+
await waitForStack({ idpsStarted: opts.withIdps });
|
|
19319
19590
|
let hubAuth = readHubAuth();
|
|
19320
19591
|
if (opts.seed) {
|
|
19321
19592
|
logInfo("Seeding local platform (tenant registry, artifacts bucket)\u2026");
|
|
@@ -19323,6 +19594,16 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19323
19594
|
logInfo("Seeding Zitadel (Platform project, Mesh CLI app, Hub auth, test users)\u2026");
|
|
19324
19595
|
const zitadel = await seedZitadel(LOCAL_AWS_CONFIG);
|
|
19325
19596
|
hubAuth = zitadel.hubAuth;
|
|
19597
|
+
if (opts.withIdps) {
|
|
19598
|
+
logInfo("Federating local Zitadel with the mock SAML and OIDC identity providers\u2026");
|
|
19599
|
+
await seedMockIdps();
|
|
19600
|
+
logInfo(
|
|
19601
|
+
`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`
|
|
19602
|
+
);
|
|
19603
|
+
logInfo(
|
|
19604
|
+
"Both are listed in the Zitadel console under Settings \u2192 Identity Providers (owner: Instance): http://localhost:8080/ui/console/org-settings?id=idp"
|
|
19605
|
+
);
|
|
19606
|
+
}
|
|
19326
19607
|
if (hubVersion) {
|
|
19327
19608
|
const compiled = readHubCompiledAuthz(hubVersion);
|
|
19328
19609
|
if (compiled) {
|
|
@@ -19365,19 +19646,23 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19365
19646
|
hubEnv.MESH_HUB_OAUTH2_CLIENT_SECRET = hubAuth.clientSecret;
|
|
19366
19647
|
hubEnv.MESH_HUB_OAUTH2_COOKIE_SECRET = hubAuth.cookieSecret;
|
|
19367
19648
|
}
|
|
19368
|
-
await composeStreamed(["up", "-d"], {
|
|
19649
|
+
await composeStreamed(["up", "-d"], {
|
|
19650
|
+
hub: true,
|
|
19651
|
+
idps: opts.withIdps,
|
|
19652
|
+
env: { ...idpEnv, ...hubEnv }
|
|
19653
|
+
});
|
|
19369
19654
|
if (opts.seed) {
|
|
19370
19655
|
compose(["restart", "hub-api"], { hub: true, env: hubEnv });
|
|
19371
19656
|
}
|
|
19372
|
-
const
|
|
19657
|
+
const overlays = [
|
|
19658
|
+
{ services: hubOverlayServices(), started: true },
|
|
19659
|
+
{ services: idpsOverlayServices(), started: opts.withIdps }
|
|
19660
|
+
];
|
|
19373
19661
|
for (const endpoint of hubEndpoints()) {
|
|
19374
19662
|
logInfo(`Waiting for ${endpoint.label}\u2026`);
|
|
19375
19663
|
let up = await probeEndpoint(endpoint);
|
|
19376
19664
|
for (let i = 0; i < 60 && !up; i++) {
|
|
19377
|
-
const crashed = crashedServices(stackServices(), {
|
|
19378
|
-
overlayServices,
|
|
19379
|
-
overlayStarted: true
|
|
19380
|
-
});
|
|
19665
|
+
const crashed = crashedServices(stackServices(), { overlays });
|
|
19381
19666
|
if (crashed.length > 0) throw crashError(crashed);
|
|
19382
19667
|
await new Promise((resolve20) => setTimeout(resolve20, 2e3));
|
|
19383
19668
|
up = await probeEndpoint(endpoint);
|
|
@@ -19421,11 +19706,20 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19421
19706
|
remediation: { command: "mesh start" }
|
|
19422
19707
|
});
|
|
19423
19708
|
}
|
|
19424
|
-
const
|
|
19425
|
-
const
|
|
19426
|
-
const
|
|
19709
|
+
const hubOverlay = hubOverlayServices();
|
|
19710
|
+
const idpsOverlay = idpsOverlayServices();
|
|
19711
|
+
const idpsStarted = overlayRunning(services, idpsOverlay);
|
|
19712
|
+
const overlays = [
|
|
19713
|
+
{ services: hubOverlay, started: overlayRunning(services, hubOverlay) },
|
|
19714
|
+
{ services: idpsOverlay, started: idpsStarted }
|
|
19715
|
+
];
|
|
19716
|
+
const notStarted = (s) => s.state === "exited" && overlays.some((o) => !o.started && o.services.has(s.name));
|
|
19427
19717
|
const hasHub = hubApiRunning(services);
|
|
19428
|
-
const endpoints =
|
|
19718
|
+
const endpoints = [
|
|
19719
|
+
...STACK_ENDPOINTS,
|
|
19720
|
+
...hasHub ? hubEndpoints() : [],
|
|
19721
|
+
...idpsStarted ? idpEndpoints() : []
|
|
19722
|
+
];
|
|
19429
19723
|
const probes = await Promise.all(
|
|
19430
19724
|
endpoints.map(async (endpoint) => ({
|
|
19431
19725
|
service: endpoint.service,
|
|
@@ -19450,6 +19744,7 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19450
19744
|
services,
|
|
19451
19745
|
endpoints: probes,
|
|
19452
19746
|
fabric,
|
|
19747
|
+
mockIdps: idpsStarted,
|
|
19453
19748
|
awsEnv: localAwsEnv()
|
|
19454
19749
|
})
|
|
19455
19750
|
);
|
|
@@ -19464,7 +19759,7 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19464
19759
|
const idle = notStarted(service);
|
|
19465
19760
|
const icon = ok || oneShotDone ? chalk6.green("\u25CF") : idle ? chalk6.dim("\u25CB") : chalk6.red("\u25CF");
|
|
19466
19761
|
const health = service.health ? ` (${service.health})` : "";
|
|
19467
|
-
const note = idle ? chalk6.dim(" (
|
|
19762
|
+
const note = idle ? chalk6.dim(" (not started this run)") : "";
|
|
19468
19763
|
console.log(` ${icon} ${service.name.padEnd(22)} ${service.state}${health}${note}`);
|
|
19469
19764
|
}
|
|
19470
19765
|
console.log("");
|
|
@@ -19478,8 +19773,13 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
19478
19773
|
const detail = fabric.ok ? "8 KB Advanced-tier round-trip OK" : fabric.error;
|
|
19479
19774
|
console.log(` ${icon} ${"AWS fabric check".padEnd(34)} ${chalk6.dim(detail ?? "")}`);
|
|
19480
19775
|
}
|
|
19776
|
+
if (!idpsStarted) {
|
|
19777
|
+
console.log(
|
|
19778
|
+
` ${chalk6.dim("\u25CB")} ${"Mock IdPs (SAML + OIDC)".padEnd(34)} ${chalk6.dim("not started \u2014 mesh start --with-idps")}`
|
|
19779
|
+
);
|
|
19780
|
+
}
|
|
19481
19781
|
const down = probes.filter((p) => !p.up);
|
|
19482
|
-
const crashed = crashedServices(services, {
|
|
19782
|
+
const crashed = crashedServices(services, { overlays });
|
|
19483
19783
|
if (fabric && !fabric.ok) process.exitCode = 1;
|
|
19484
19784
|
if (down.length > 0 || crashed.length > 0) {
|
|
19485
19785
|
console.log("");
|
|
@@ -19502,6 +19802,7 @@ var init_local = __esm({
|
|
|
19502
19802
|
init_auth_provision();
|
|
19503
19803
|
init_seed();
|
|
19504
19804
|
init_seed_zitadel();
|
|
19805
|
+
init_mock_idps();
|
|
19505
19806
|
init_seed_hub_catalog();
|
|
19506
19807
|
init_helpers();
|
|
19507
19808
|
WAIT_TIMEOUT_MS = 18e4;
|
|
@@ -20492,7 +20793,7 @@ var init_secrets = __esm({
|
|
|
20492
20793
|
import { createHash as createHash4 } from "node:crypto";
|
|
20493
20794
|
import { createReadStream } from "node:fs";
|
|
20494
20795
|
import { readdir, readFile as readFile2, stat } from "node:fs/promises";
|
|
20495
|
-
import { join as
|
|
20796
|
+
import { join as join39, relative as relative11, resolve as resolve17, sep as sep6 } from "node:path";
|
|
20496
20797
|
async function describeSiteHttpError(res, target, site) {
|
|
20497
20798
|
if (res.status === 403) {
|
|
20498
20799
|
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 +20815,7 @@ async function walk(root) {
|
|
|
20514
20815
|
async function visit(dir) {
|
|
20515
20816
|
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
20516
20817
|
if (SKIP_ENTRIES.has(entry.name)) continue;
|
|
20517
|
-
const absolute =
|
|
20818
|
+
const absolute = join39(dir, entry.name);
|
|
20518
20819
|
if (entry.isSymbolicLink()) {
|
|
20519
20820
|
logWarn(`skipping symlink ${relative11(root, absolute)}`);
|
|
20520
20821
|
continue;
|
|
@@ -20709,23 +21010,23 @@ var init_site = __esm({
|
|
|
20709
21010
|
});
|
|
20710
21011
|
|
|
20711
21012
|
// libs/mesh-cli/src/commands/stack.ts
|
|
20712
|
-
import { execFileSync as
|
|
20713
|
-
import * as
|
|
20714
|
-
import * as
|
|
21013
|
+
import { execFileSync as execFileSync31 } from "child_process";
|
|
21014
|
+
import * as path44 from "path";
|
|
21015
|
+
import * as fs37 from "fs";
|
|
20715
21016
|
import { parse as parseYaml5 } from "yaml";
|
|
20716
21017
|
function readTopLevelYamlKey(appRoot, stack, key) {
|
|
20717
|
-
const configFile =
|
|
20718
|
-
if (!
|
|
20719
|
-
const content =
|
|
21018
|
+
const configFile = path44.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
21019
|
+
if (!fs37.existsSync(configFile)) return null;
|
|
21020
|
+
const content = fs37.readFileSync(configFile, "utf-8");
|
|
20720
21021
|
const pattern = new RegExp(`^${key}:\\s*(.+)$`, "m");
|
|
20721
21022
|
const match = content.match(pattern);
|
|
20722
21023
|
if (!match) return null;
|
|
20723
21024
|
return match[1].trim().replace(/^["']|["']$/g, "");
|
|
20724
21025
|
}
|
|
20725
21026
|
function readConfigBlockKey(appRoot, stack, key) {
|
|
20726
|
-
const configFile =
|
|
20727
|
-
if (!
|
|
20728
|
-
const content =
|
|
21027
|
+
const configFile = path44.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
21028
|
+
if (!fs37.existsSync(configFile)) return null;
|
|
21029
|
+
const content = fs37.readFileSync(configFile, "utf-8");
|
|
20729
21030
|
const pattern = new RegExp(`^\\s{2}${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}:\\s*(.+)$`, "m");
|
|
20730
21031
|
const match = content.match(pattern);
|
|
20731
21032
|
if (!match) return null;
|
|
@@ -20785,11 +21086,11 @@ ${records}
|
|
|
20785
21086
|
}
|
|
20786
21087
|
}
|
|
20787
21088
|
function readBaseConfigFromYaml(appRoot, stack) {
|
|
20788
|
-
const file =
|
|
20789
|
-
if (!
|
|
21089
|
+
const file = path44.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
21090
|
+
if (!fs37.existsSync(file)) return {};
|
|
20790
21091
|
let doc;
|
|
20791
21092
|
try {
|
|
20792
|
-
doc = parseYaml5(
|
|
21093
|
+
doc = parseYaml5(fs37.readFileSync(file, "utf-8"));
|
|
20793
21094
|
} catch {
|
|
20794
21095
|
return {};
|
|
20795
21096
|
}
|
|
@@ -20802,7 +21103,7 @@ function readBaseConfigFromYaml(appRoot, stack) {
|
|
|
20802
21103
|
}
|
|
20803
21104
|
function getGitHubUsername() {
|
|
20804
21105
|
try {
|
|
20805
|
-
const result =
|
|
21106
|
+
const result = execFileSync31("gh", ["api", "user", "--jq", ".login"], {
|
|
20806
21107
|
encoding: "utf-8",
|
|
20807
21108
|
stdio: ["pipe", "pipe", "pipe"]
|
|
20808
21109
|
});
|
|
@@ -20811,7 +21112,7 @@ function getGitHubUsername() {
|
|
|
20811
21112
|
} catch {
|
|
20812
21113
|
}
|
|
20813
21114
|
try {
|
|
20814
|
-
const result =
|
|
21115
|
+
const result = execFileSync31("git", ["config", "user.email"], {
|
|
20815
21116
|
encoding: "utf-8",
|
|
20816
21117
|
stdio: ["pipe", "pipe", "pipe"]
|
|
20817
21118
|
});
|
|
@@ -20866,7 +21167,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20866
21167
|
}
|
|
20867
21168
|
}
|
|
20868
21169
|
const baseConfigPath = `${appRoot}/Pulumi.${baseStack}.yaml`;
|
|
20869
|
-
if (!
|
|
21170
|
+
if (!fs37.existsSync(baseConfigPath)) {
|
|
20870
21171
|
logError(`Stack config not found: Pulumi.${baseStack}.yaml`);
|
|
20871
21172
|
process.exit(1);
|
|
20872
21173
|
}
|
|
@@ -20888,8 +21189,8 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20888
21189
|
);
|
|
20889
21190
|
}
|
|
20890
21191
|
}
|
|
20891
|
-
const newConfigPath =
|
|
20892
|
-
const configExists =
|
|
21192
|
+
const newConfigPath = path44.join(appRoot, `Pulumi.${newStack}.yaml`);
|
|
21193
|
+
const configExists = fs37.existsSync(newConfigPath);
|
|
20893
21194
|
const secretsProvider = readTopLevelYamlKey(appRoot, baseStack, "secretsprovider");
|
|
20894
21195
|
const credEnv = await resolvePulumiEnv({ appRoot, stack: baseStack });
|
|
20895
21196
|
const pulumiEnv = { ...process.env, ...credEnv };
|
|
@@ -20897,7 +21198,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20897
21198
|
if (!opts.adopt) {
|
|
20898
21199
|
let existing = [];
|
|
20899
21200
|
try {
|
|
20900
|
-
const raw =
|
|
21201
|
+
const raw = execFileSync31("pulumi", ["stack", "ls", "--json"], {
|
|
20901
21202
|
cwd: appRoot,
|
|
20902
21203
|
encoding: "utf-8",
|
|
20903
21204
|
env: pulumiEnv,
|
|
@@ -20921,7 +21222,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20921
21222
|
logInfo(`Using KMS secrets provider: ${secretsProvider}`);
|
|
20922
21223
|
}
|
|
20923
21224
|
try {
|
|
20924
|
-
|
|
21225
|
+
execFileSync31("pulumi", initArgs, {
|
|
20925
21226
|
cwd: appRoot,
|
|
20926
21227
|
env: pulumiEnv,
|
|
20927
21228
|
stdio: "inherit"
|
|
@@ -20938,7 +21239,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20938
21239
|
}
|
|
20939
21240
|
}
|
|
20940
21241
|
try {
|
|
20941
|
-
|
|
21242
|
+
execFileSync31("pulumi", ["stack", "select", newStack], {
|
|
20942
21243
|
cwd: appRoot,
|
|
20943
21244
|
env: pulumiEnv,
|
|
20944
21245
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -20948,7 +21249,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20948
21249
|
if (!configExists) {
|
|
20949
21250
|
let baseConfig = {};
|
|
20950
21251
|
try {
|
|
20951
|
-
const raw =
|
|
21252
|
+
const raw = execFileSync31(
|
|
20952
21253
|
"pulumi",
|
|
20953
21254
|
["config", "--json", "--stack", baseStack],
|
|
20954
21255
|
{ cwd: appRoot, env: pulumiEnv, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -20966,19 +21267,19 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20966
21267
|
if (key === "mesh:deploy") continue;
|
|
20967
21268
|
try {
|
|
20968
21269
|
if (entry.objectValue !== void 0) {
|
|
20969
|
-
|
|
21270
|
+
execFileSync31(
|
|
20970
21271
|
"pulumi",
|
|
20971
21272
|
["config", "set", key, JSON.stringify(entry.objectValue)],
|
|
20972
21273
|
{ cwd: appRoot, env: pulumiEnv, stdio: ["pipe", "pipe", "pipe"] }
|
|
20973
21274
|
);
|
|
20974
21275
|
} else if (entry.value === "true" || entry.value === "false") {
|
|
20975
|
-
|
|
21276
|
+
execFileSync31(
|
|
20976
21277
|
"pulumi",
|
|
20977
21278
|
["config", "set", "--type", "bool", key, entry.value],
|
|
20978
21279
|
{ cwd: appRoot, env: pulumiEnv, stdio: ["pipe", "pipe", "pipe"] }
|
|
20979
21280
|
);
|
|
20980
21281
|
} else {
|
|
20981
|
-
|
|
21282
|
+
execFileSync31(
|
|
20982
21283
|
"pulumi",
|
|
20983
21284
|
["config", "set", key, entry.value],
|
|
20984
21285
|
{ cwd: appRoot, env: pulumiEnv, stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -20991,7 +21292,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
20991
21292
|
const baseEnv = readConfigBlockKey(appRoot, baseStack, "mesh:coreEnv") ?? (baseTenant && baseStack.startsWith(`${baseTenant}-`) ? baseStack.slice(baseTenant.length + 1) : baseStack);
|
|
20992
21293
|
const setCfg = (args) => {
|
|
20993
21294
|
try {
|
|
20994
|
-
|
|
21295
|
+
execFileSync31("pulumi", ["config", "set", ...args], {
|
|
20995
21296
|
cwd: appRoot,
|
|
20996
21297
|
env: pulumiEnv,
|
|
20997
21298
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -21040,7 +21341,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21040
21341
|
`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
21342
|
);
|
|
21042
21343
|
} else {
|
|
21043
|
-
|
|
21344
|
+
execFileSync31("pulumi", ["config", "set", "--type", "bool", "mesh:deploy", "false"], {
|
|
21044
21345
|
cwd: appRoot,
|
|
21045
21346
|
env: pulumiEnv,
|
|
21046
21347
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -21070,7 +21371,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21070
21371
|
const args = ["stack", "rm", name];
|
|
21071
21372
|
if (opts.yes) args.push("--yes");
|
|
21072
21373
|
try {
|
|
21073
|
-
|
|
21374
|
+
execFileSync31("pulumi", args, { cwd: appRoot, env: pulumiEnv, stdio: "inherit" });
|
|
21074
21375
|
logSuccess(`Removed stack ${name}`);
|
|
21075
21376
|
} catch (err) {
|
|
21076
21377
|
process.exit(err.status ?? 1);
|
|
@@ -21282,12 +21583,12 @@ var init_recover_conversation = __esm({
|
|
|
21282
21583
|
});
|
|
21283
21584
|
|
|
21284
21585
|
// libs/mesh-cli/src/utils/temporal-codec.ts
|
|
21285
|
-
import { execFileSync as
|
|
21586
|
+
import { execFileSync as execFileSync32 } from "child_process";
|
|
21286
21587
|
import { webcrypto as crypto4 } from "node:crypto";
|
|
21287
21588
|
function resolveTemporalEncodingKeyFromK8s(namespace) {
|
|
21288
21589
|
const secretName = `${namespace}-temporal-encoding-key`;
|
|
21289
21590
|
try {
|
|
21290
|
-
const b64 =
|
|
21591
|
+
const b64 = execFileSync32(
|
|
21291
21592
|
"kubectl",
|
|
21292
21593
|
[
|
|
21293
21594
|
"get",
|
|
@@ -21536,9 +21837,9 @@ var init_capture_history = __esm({
|
|
|
21536
21837
|
|
|
21537
21838
|
// libs/mesh-cli/src/commands/temporal.ts
|
|
21538
21839
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
21539
|
-
import { writeFileSync as writeFileSync24, mkdirSync as
|
|
21840
|
+
import { writeFileSync as writeFileSync24, mkdirSync as mkdirSync20 } from "node:fs";
|
|
21540
21841
|
import { homedir as homedir6 } from "node:os";
|
|
21541
|
-
import { dirname as dirname28, join as
|
|
21842
|
+
import { dirname as dirname28, join as join41, resolve as resolve18 } from "node:path";
|
|
21542
21843
|
async function resolveConnection(options) {
|
|
21543
21844
|
if (options.address && options.namespace) {
|
|
21544
21845
|
return { address: options.address, namespace: options.namespace };
|
|
@@ -21966,8 +22267,8 @@ async function captureHistory(workflowId, runId, options) {
|
|
|
21966
22267
|
}
|
|
21967
22268
|
const { serializeHistoryToFixture: serializeHistoryToFixture2 } = await Promise.resolve().then(() => (init_capture_history(), capture_history_exports));
|
|
21968
22269
|
const { fixture, eventCount, decryptedPayloads } = await serializeHistoryToFixture2(events, decrypter);
|
|
21969
|
-
const outPath = options.out ??
|
|
21970
|
-
|
|
22270
|
+
const outPath = options.out ?? join41(homedir6(), ".mesh", "replay-histories", `${sanitizeFileId(workflowId)}.json`);
|
|
22271
|
+
mkdirSync20(dirname28(outPath), { recursive: true });
|
|
21971
22272
|
if (options.out) warnIfNotGitIgnored(options.out);
|
|
21972
22273
|
writeFileSync24(outPath, JSON.stringify(fixture, null, 2) + "\n");
|
|
21973
22274
|
logSuccess(
|
|
@@ -22158,8 +22459,8 @@ var init_temporal = __esm({
|
|
|
22158
22459
|
|
|
22159
22460
|
// libs/mesh-cli/src/commands/tenant.ts
|
|
22160
22461
|
import chalk7 from "chalk";
|
|
22161
|
-
import * as
|
|
22162
|
-
import * as
|
|
22462
|
+
import * as fs38 from "fs";
|
|
22463
|
+
import * as path45 from "path";
|
|
22163
22464
|
import { parseDocument, YAMLMap, isMap } from "yaml";
|
|
22164
22465
|
function validateTenantName(name) {
|
|
22165
22466
|
return /^[a-z][a-z0-9-]*$/.test(name) && !name.endsWith("-");
|
|
@@ -22227,16 +22528,16 @@ function resolveStackConfig(explicitStack) {
|
|
|
22227
22528
|
{ remediation: { command: "mesh tenant add <name> --stack <stack>" } }
|
|
22228
22529
|
);
|
|
22229
22530
|
}
|
|
22230
|
-
const file =
|
|
22231
|
-
if (!
|
|
22531
|
+
const file = path45.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
22532
|
+
if (!fs38.existsSync(file)) {
|
|
22232
22533
|
throw new MeshCliError(`Stack config not found: ${file}`, {
|
|
22233
22534
|
remediation: { command: "mesh tenant add <name> --stack <stack>" }
|
|
22234
22535
|
});
|
|
22235
22536
|
}
|
|
22236
|
-
return { appRoot, stack, file, content:
|
|
22537
|
+
return { appRoot, stack, file, content: fs38.readFileSync(file, "utf-8") };
|
|
22237
22538
|
}
|
|
22238
22539
|
function readProjectName(appRoot) {
|
|
22239
|
-
const projectDoc = parseDocument(
|
|
22540
|
+
const projectDoc = parseDocument(fs38.readFileSync(path45.join(appRoot, "Pulumi.yaml"), "utf-8"));
|
|
22240
22541
|
return String(projectDoc.get("name") ?? "");
|
|
22241
22542
|
}
|
|
22242
22543
|
function looksLikePlatformLayer(projectName) {
|
|
@@ -22279,12 +22580,12 @@ function registerTenantCommands(program2) {
|
|
|
22279
22580
|
if (!result.ok) {
|
|
22280
22581
|
if (result.reason === "exists") {
|
|
22281
22582
|
throw new MeshCliError(
|
|
22282
|
-
`${result.detail} (${
|
|
22583
|
+
`${result.detail} (${path45.basename(resolved.file)}). Edit the existing entry instead of re-adding it.`
|
|
22283
22584
|
);
|
|
22284
22585
|
}
|
|
22285
22586
|
throw new MeshCliError(`${resolved.file}: ${result.detail}`);
|
|
22286
22587
|
}
|
|
22287
|
-
atomicWriteFileSync(resolved.file, result.yaml,
|
|
22588
|
+
atomicWriteFileSync(resolved.file, result.yaml, fs38.statSync(resolved.file).mode & 511);
|
|
22288
22589
|
if (opts.json) {
|
|
22289
22590
|
emitJsonPayload({
|
|
22290
22591
|
ok: true,
|
|
@@ -22297,7 +22598,7 @@ function registerTenantCommands(program2) {
|
|
|
22297
22598
|
return;
|
|
22298
22599
|
}
|
|
22299
22600
|
logInfo(
|
|
22300
|
-
`Tenant '${name}' registered in ${
|
|
22601
|
+
`Tenant '${name}' registered in ${path45.basename(resolved.file)} (mesh:tenants, subdomain '${subdomain}')${result.createdTenantsBlock ? " \u2014 created the mesh:tenants block" : ""}`
|
|
22301
22602
|
);
|
|
22302
22603
|
console.log("");
|
|
22303
22604
|
console.log("Next steps:");
|
|
@@ -22323,7 +22624,7 @@ function registerTenantCommands(program2) {
|
|
|
22323
22624
|
`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
22625
|
);
|
|
22325
22626
|
}
|
|
22326
|
-
logInfo(`No tenants declared in ${
|
|
22627
|
+
logInfo(`No tenants declared in ${path45.basename(resolved.file)}.`);
|
|
22327
22628
|
return;
|
|
22328
22629
|
}
|
|
22329
22630
|
logInfo(`Tenants on stack '${resolved.stack}':`);
|
|
@@ -22345,9 +22646,9 @@ var init_tenant = __esm({
|
|
|
22345
22646
|
|
|
22346
22647
|
// libs/mesh-cli/src/commands/tunnel/index.ts
|
|
22347
22648
|
import { spawn as spawn9 } from "child_process";
|
|
22348
|
-
import * as
|
|
22649
|
+
import * as fs39 from "fs";
|
|
22349
22650
|
import * as os12 from "os";
|
|
22350
|
-
import * as
|
|
22651
|
+
import * as path46 from "path";
|
|
22351
22652
|
import {
|
|
22352
22653
|
SecretsManagerClient as SecretsManagerClient9,
|
|
22353
22654
|
GetSecretValueCommand as GetSecretValueCommand9
|
|
@@ -22367,9 +22668,9 @@ function readPulumiAwsRegion(stage) {
|
|
|
22367
22668
|
const preferred = stage ? `Pulumi.${stage}.yaml` : void 0;
|
|
22368
22669
|
const rank = (f) => f === preferred ? 0 : f === "Pulumi.yaml" ? 2 : 1;
|
|
22369
22670
|
try {
|
|
22370
|
-
const files =
|
|
22671
|
+
const files = fs39.readdirSync(".").filter((f) => f.startsWith("Pulumi.") && f.endsWith(".yaml")).sort((a, b) => rank(a) - rank(b));
|
|
22371
22672
|
for (const f of files) {
|
|
22372
|
-
const m =
|
|
22673
|
+
const m = fs39.readFileSync(f, "utf-8").match(/^\s*aws:region:\s*["']?([^"'\n]+)["']?/m);
|
|
22373
22674
|
if (m?.[1]) return m[1].trim();
|
|
22374
22675
|
}
|
|
22375
22676
|
} catch {
|
|
@@ -22378,14 +22679,14 @@ function readPulumiAwsRegion(stage) {
|
|
|
22378
22679
|
}
|
|
22379
22680
|
function awsProfileSections(name) {
|
|
22380
22681
|
return [
|
|
22381
|
-
[
|
|
22382
|
-
[
|
|
22682
|
+
[path46.join(os12.homedir(), ".aws", "config"), `[profile ${name}]`],
|
|
22683
|
+
[path46.join(os12.homedir(), ".aws", "credentials"), `[${name}]`]
|
|
22383
22684
|
];
|
|
22384
22685
|
}
|
|
22385
22686
|
function awsProfileExists(name) {
|
|
22386
22687
|
for (const [file, header] of awsProfileSections(name)) {
|
|
22387
22688
|
try {
|
|
22388
|
-
const lines =
|
|
22689
|
+
const lines = fs39.readFileSync(file, "utf-8").split("\n");
|
|
22389
22690
|
if (lines.some((l) => l.trim() === header)) return true;
|
|
22390
22691
|
} catch {
|
|
22391
22692
|
}
|
|
@@ -22411,7 +22712,7 @@ function awsProfileRegion(profile) {
|
|
|
22411
22712
|
if (!profile) return void 0;
|
|
22412
22713
|
for (const [file, header] of awsProfileSections(profile)) {
|
|
22413
22714
|
try {
|
|
22414
|
-
const region = parseProfileRegion(
|
|
22715
|
+
const region = parseProfileRegion(fs39.readFileSync(file, "utf-8"), header);
|
|
22415
22716
|
if (region) return region;
|
|
22416
22717
|
} catch {
|
|
22417
22718
|
}
|
|
@@ -22420,14 +22721,14 @@ function awsProfileRegion(profile) {
|
|
|
22420
22721
|
}
|
|
22421
22722
|
function awsDefaultProfileSections() {
|
|
22422
22723
|
return [
|
|
22423
|
-
[
|
|
22424
|
-
[
|
|
22724
|
+
[path46.join(os12.homedir(), ".aws", "config"), "[default]"],
|
|
22725
|
+
[path46.join(os12.homedir(), ".aws", "credentials"), "[default]"]
|
|
22425
22726
|
];
|
|
22426
22727
|
}
|
|
22427
22728
|
function awsDefaultProfileRegion() {
|
|
22428
22729
|
for (const [file, header] of awsDefaultProfileSections()) {
|
|
22429
22730
|
try {
|
|
22430
|
-
const region = parseProfileRegion(
|
|
22731
|
+
const region = parseProfileRegion(fs39.readFileSync(file, "utf-8"), header);
|
|
22431
22732
|
if (region) return region;
|
|
22432
22733
|
} catch {
|
|
22433
22734
|
}
|
|
@@ -22814,8 +23115,8 @@ async function resolveToken(opts) {
|
|
|
22814
23115
|
"no token: pass --token, set VCS_TOKEN, or pass --context <platform-context> (after mesh login)"
|
|
22815
23116
|
);
|
|
22816
23117
|
}
|
|
22817
|
-
async function vcsApi(baseUrl, token,
|
|
22818
|
-
const res = await fetch(`${baseUrl}${
|
|
23118
|
+
async function vcsApi(baseUrl, token, path48, method = "GET", body) {
|
|
23119
|
+
const res = await fetch(`${baseUrl}${path48}`, {
|
|
22819
23120
|
method,
|
|
22820
23121
|
headers: {
|
|
22821
23122
|
authorization: `Bearer ${token}`,
|
|
@@ -22826,7 +23127,7 @@ async function vcsApi(baseUrl, token, path47, method = "GET", body) {
|
|
|
22826
23127
|
const data = await res.json().catch(() => ({}));
|
|
22827
23128
|
if (!res.ok) {
|
|
22828
23129
|
throw new Error(
|
|
22829
|
-
`${method} ${
|
|
23130
|
+
`${method} ${path48} failed (${res.status}): ${String(data.error ?? "unknown error")}`
|
|
22830
23131
|
);
|
|
22831
23132
|
}
|
|
22832
23133
|
return data;
|
|
@@ -22872,8 +23173,8 @@ var init_clone = __esm({
|
|
|
22872
23173
|
|
|
22873
23174
|
// libs/mesh-cli/src/commands/vcs/get.ts
|
|
22874
23175
|
import { writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
|
|
22875
|
-
import { join as
|
|
22876
|
-
async function getCommand(repo,
|
|
23176
|
+
import { join as join44, dirname as dirname29 } from "node:path";
|
|
23177
|
+
async function getCommand(repo, path48, opts) {
|
|
22877
23178
|
let vcsBaseUrl;
|
|
22878
23179
|
let token;
|
|
22879
23180
|
if (opts.target) {
|
|
@@ -22888,18 +23189,18 @@ async function getCommand(repo, path47, opts) {
|
|
|
22888
23189
|
if (!token) throw new Error("no token: pass --target (after mesh login), or --token / --context");
|
|
22889
23190
|
const reader = createVcsFolderReader({ vcsBaseUrl, token });
|
|
22890
23191
|
try {
|
|
22891
|
-
const { ref, files } = await reader.readPath(repo,
|
|
23192
|
+
const { ref, files } = await reader.readPath(repo, path48);
|
|
22892
23193
|
if (files.length === 0) {
|
|
22893
|
-
logInfo(`no files at ${repo}:${
|
|
23194
|
+
logInfo(`no files at ${repo}:${path48}`);
|
|
22894
23195
|
return;
|
|
22895
23196
|
}
|
|
22896
23197
|
if (opts.output) {
|
|
22897
23198
|
for (const f of files) {
|
|
22898
|
-
const abs =
|
|
23199
|
+
const abs = join44(opts.output, f.path);
|
|
22899
23200
|
await mkdir2(dirname29(abs), { recursive: true });
|
|
22900
23201
|
await writeFile2(abs, f.contents);
|
|
22901
23202
|
}
|
|
22902
|
-
logInfo(`wrote ${files.length} file(s) from ${repo}:${
|
|
23203
|
+
logInfo(`wrote ${files.length} file(s) from ${repo}:${path48} (${ref}) \u2192 ${opts.output}`);
|
|
22903
23204
|
} else {
|
|
22904
23205
|
for (const f of files) {
|
|
22905
23206
|
if (files.length > 1) process.stdout.write(`
|
|
@@ -22924,10 +23225,10 @@ var init_get = __esm({
|
|
|
22924
23225
|
});
|
|
22925
23226
|
|
|
22926
23227
|
// libs/mesh-cli/src/commands/vcs/drafts.ts
|
|
22927
|
-
async function call(opts, repo,
|
|
23228
|
+
async function call(opts, repo, path48, method = "GET", body) {
|
|
22928
23229
|
const target = await resolveTarget2({ ...opts, repo });
|
|
22929
23230
|
const token = await resolveToken(opts);
|
|
22930
|
-
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${
|
|
23231
|
+
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${path48}`, method, body);
|
|
22931
23232
|
}
|
|
22932
23233
|
async function draftsListCommand(repo, opts) {
|
|
22933
23234
|
const data = await call(opts, repo, `/drafts${opts.all ? "?all=true" : ""}`);
|
|
@@ -22982,7 +23283,7 @@ var init_drafts = __esm({
|
|
|
22982
23283
|
|
|
22983
23284
|
// libs/mesh-cli/src/commands/vcs/propose.ts
|
|
22984
23285
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
22985
|
-
import { join as
|
|
23286
|
+
import { join as join45 } from "node:path";
|
|
22986
23287
|
function parseStatus(out) {
|
|
22987
23288
|
const tokens = out.split("\0");
|
|
22988
23289
|
const changes = [];
|
|
@@ -23015,13 +23316,13 @@ function parseStatus(out) {
|
|
|
23015
23316
|
}
|
|
23016
23317
|
return changes;
|
|
23017
23318
|
}
|
|
23018
|
-
async function writeOp(cwd,
|
|
23019
|
-
const buf = await readFile3(
|
|
23319
|
+
async function writeOp(cwd, path48) {
|
|
23320
|
+
const buf = await readFile3(join45(cwd, path48));
|
|
23020
23321
|
const asUtf8 = buf.toString("utf8");
|
|
23021
23322
|
if (Buffer.from(asUtf8, "utf8").equals(buf)) {
|
|
23022
|
-
return { op: "write", path:
|
|
23323
|
+
return { op: "write", path: path48, content: asUtf8 };
|
|
23023
23324
|
}
|
|
23024
|
-
return { op: "write", path:
|
|
23325
|
+
return { op: "write", path: path48, content: buf.toString("base64"), encoding: "base64" };
|
|
23025
23326
|
}
|
|
23026
23327
|
async function proposeCommand(opts) {
|
|
23027
23328
|
const cwd = process.cwd();
|
|
@@ -23065,8 +23366,8 @@ async function proposeCommand(opts) {
|
|
|
23065
23366
|
operations,
|
|
23066
23367
|
...opts.mergeParent ? { mergeParent: opts.mergeParent } : {}
|
|
23067
23368
|
};
|
|
23068
|
-
const
|
|
23069
|
-
const data = await vcsApi(target.baseUrl, token,
|
|
23369
|
+
const path48 = opts.revise ? `/v1/repos/${target.repo}/proposals/${opts.revise}/revisions` : `/v1/repos/${target.repo}/proposals`;
|
|
23370
|
+
const data = await vcsApi(target.baseUrl, token, path48, "POST", body);
|
|
23070
23371
|
console.log(
|
|
23071
23372
|
`proposal ${data.proposalId} @ ${data.sha.slice(0, 8)} \u2014 review: mesh vcs show ${target.repo} ${data.proposalId} --url ${target.baseUrl}`
|
|
23072
23373
|
);
|
|
@@ -23081,28 +23382,28 @@ var init_propose = __esm({
|
|
|
23081
23382
|
// libs/mesh-cli/src/commands/vcs/rm.ts
|
|
23082
23383
|
import { mkdtemp as mkdtemp2, rm as rmrf } from "node:fs/promises";
|
|
23083
23384
|
import { tmpdir as tmpdir10 } from "node:os";
|
|
23084
|
-
import { join as
|
|
23385
|
+
import { join as join46 } from "node:path";
|
|
23085
23386
|
function normalize2(p) {
|
|
23086
23387
|
return p.trim().replace(/^\.\//, "").replace(/\/+$/, "");
|
|
23087
23388
|
}
|
|
23088
23389
|
function expandPathsToDeletions(repoFiles, requested) {
|
|
23089
23390
|
const out = /* @__PURE__ */ new Set();
|
|
23090
23391
|
for (const raw of requested) {
|
|
23091
|
-
const
|
|
23092
|
-
if (
|
|
23392
|
+
const path48 = normalize2(raw);
|
|
23393
|
+
if (path48.startsWith("/") || path48.split("/").includes("..")) {
|
|
23093
23394
|
throw new Error(
|
|
23094
23395
|
`"${raw}" is not a repo-relative path \u2014 vcs paths never start with "/" or traverse with "..".`
|
|
23095
23396
|
);
|
|
23096
23397
|
}
|
|
23097
|
-
const exact = repoFiles.filter((f) => f ===
|
|
23398
|
+
const exact = repoFiles.filter((f) => f === path48);
|
|
23098
23399
|
if (exact.length > 0) {
|
|
23099
23400
|
for (const f of exact) out.add(f);
|
|
23100
23401
|
continue;
|
|
23101
23402
|
}
|
|
23102
|
-
const under = repoFiles.filter((f) => f.startsWith(`${
|
|
23403
|
+
const under = repoFiles.filter((f) => f.startsWith(`${path48}/`));
|
|
23103
23404
|
if (under.length === 0) {
|
|
23104
23405
|
throw new Error(
|
|
23105
|
-
`"${raw}" matched no files in the repo \u2014 nothing was proposed. Check the path with: mesh vcs get <repo> ${
|
|
23406
|
+
`"${raw}" matched no files in the repo \u2014 nothing was proposed. Check the path with: mesh vcs get <repo> ${path48}`
|
|
23106
23407
|
);
|
|
23107
23408
|
}
|
|
23108
23409
|
for (const f of under) out.add(f);
|
|
@@ -23113,7 +23414,7 @@ async function rmCommand(repo, paths, opts) {
|
|
|
23113
23414
|
const baseUrl = (opts.url ?? process.env.VCS_URL)?.replace(/\/$/, "");
|
|
23114
23415
|
if (!baseUrl) throw new Error("rm requires --url or VCS_URL");
|
|
23115
23416
|
const token = await resolveToken(opts);
|
|
23116
|
-
const dir = await mkdtemp2(
|
|
23417
|
+
const dir = await mkdtemp2(join46(tmpdir10(), "mesh-vcs-rm-"));
|
|
23117
23418
|
try {
|
|
23118
23419
|
const git = (args, cwd) => gitWithAuth(args, token, cwd);
|
|
23119
23420
|
await git([
|
|
@@ -23138,7 +23439,7 @@ async function rmCommand(repo, paths, opts) {
|
|
|
23138
23439
|
const body = {
|
|
23139
23440
|
baseCommit: head.trim(),
|
|
23140
23441
|
message: opts.message ?? `Delete ${doomed.length} file(s)`,
|
|
23141
|
-
operations: doomed.map((
|
|
23442
|
+
operations: doomed.map((path48) => ({ op: "delete", path: path48 }))
|
|
23142
23443
|
};
|
|
23143
23444
|
const data = await vcsApi(
|
|
23144
23445
|
baseUrl,
|
|
@@ -23164,10 +23465,10 @@ var init_rm = __esm({
|
|
|
23164
23465
|
});
|
|
23165
23466
|
|
|
23166
23467
|
// libs/mesh-cli/src/commands/vcs/review.ts
|
|
23167
|
-
async function call2(opts, repo,
|
|
23468
|
+
async function call2(opts, repo, path48, method = "GET", body) {
|
|
23168
23469
|
const target = await resolveTarget2({ ...opts, repo });
|
|
23169
23470
|
const token = await resolveToken(opts);
|
|
23170
|
-
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${
|
|
23471
|
+
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${path48}`, method, body);
|
|
23171
23472
|
}
|
|
23172
23473
|
async function proposalsCommand(repo, opts) {
|
|
23173
23474
|
console.log(JSON.stringify(await call2(opts, repo, "/proposals"), null, 2));
|
|
@@ -23314,8 +23615,8 @@ function computeHappyPath(nodes, edges) {
|
|
|
23314
23615
|
];
|
|
23315
23616
|
const visited = /* @__PURE__ */ new Set([startNode.id]);
|
|
23316
23617
|
while (queue.length > 0) {
|
|
23317
|
-
const { id, path:
|
|
23318
|
-
if (targetIds.has(id)) return
|
|
23618
|
+
const { id, path: path48 } = queue.shift();
|
|
23619
|
+
if (targetIds.has(id)) return path48;
|
|
23319
23620
|
const neighbors = adjacency.get(id) ?? [];
|
|
23320
23621
|
const hasMainEdge = neighbors.some((e) => e.isMainPath);
|
|
23321
23622
|
const candidates = hasMainEdge ? neighbors.filter((e) => e.isMainPath) : neighbors;
|
|
@@ -23335,7 +23636,7 @@ function computeHappyPath(nodes, edges) {
|
|
|
23335
23636
|
if (!allowExceptional && (neighbor.isExceptional || neighbor.isTimeout || failureEndIds.has(neighbor.to)))
|
|
23336
23637
|
continue;
|
|
23337
23638
|
visited.add(neighbor.to);
|
|
23338
|
-
queue.push({ id: neighbor.to, path: [...
|
|
23639
|
+
queue.push({ id: neighbor.to, path: [...path48, neighbor.to] });
|
|
23339
23640
|
}
|
|
23340
23641
|
}
|
|
23341
23642
|
return null;
|
|
@@ -23620,11 +23921,11 @@ function wrapIntoGroup(workflow, nodeIds, groupId, label, groupType) {
|
|
|
23620
23921
|
}
|
|
23621
23922
|
}
|
|
23622
23923
|
if (found) {
|
|
23623
|
-
const
|
|
23624
|
-
for (let c = found; c !== void 0; c = prev.get(c))
|
|
23625
|
-
for (let i = 0; i <
|
|
23924
|
+
const path48 = [];
|
|
23925
|
+
for (let c = found; c !== void 0; c = prev.get(c)) path48.unshift(c);
|
|
23926
|
+
for (let i = 0; i < path48.length - 1; i++) mainEdgeKeys.add(edgeKey(path48[i], path48[i + 1]));
|
|
23626
23927
|
mainEdgeKeys.add(edgeKey(found, successExit.id));
|
|
23627
|
-
mainBody =
|
|
23928
|
+
mainBody = path48;
|
|
23628
23929
|
mainTail = [successExit.id];
|
|
23629
23930
|
}
|
|
23630
23931
|
}
|
|
@@ -24160,11 +24461,11 @@ function buildProcessManifest(artifact, outcomeNodeIds) {
|
|
|
24160
24461
|
...pointOfNoReturnStage ? { pointOfNoReturnStageId: pointOfNoReturnStage.id } : {}
|
|
24161
24462
|
};
|
|
24162
24463
|
}
|
|
24163
|
-
function formatPath(
|
|
24164
|
-
return
|
|
24464
|
+
function formatPath(path48) {
|
|
24465
|
+
return path48.length > 0 ? z4.core.toDotPath(path48) : "(root)";
|
|
24165
24466
|
}
|
|
24166
24467
|
function issueToDiagnostic(issue) {
|
|
24167
|
-
const
|
|
24468
|
+
const path48 = formatPath(issue.path);
|
|
24168
24469
|
let code = "SCHEMA_INVALID";
|
|
24169
24470
|
if (issue.code === "custom") {
|
|
24170
24471
|
const paramCode = issue.params?.code;
|
|
@@ -24175,8 +24476,8 @@ function issueToDiagnostic(issue) {
|
|
|
24175
24476
|
return {
|
|
24176
24477
|
severity: "error",
|
|
24177
24478
|
code,
|
|
24178
|
-
message: `${
|
|
24179
|
-
path:
|
|
24479
|
+
message: `${path48}: ${issue.message}`,
|
|
24480
|
+
path: path48
|
|
24180
24481
|
};
|
|
24181
24482
|
}
|
|
24182
24483
|
function upgradeV1(artifact) {
|
|
@@ -24343,24 +24644,24 @@ var init_process_artifact = __esm({
|
|
|
24343
24644
|
});
|
|
24344
24645
|
}
|
|
24345
24646
|
const declaredSelectors = new Set(Object.keys(process2.selectors ?? {}));
|
|
24346
|
-
const checkActor = (actorId,
|
|
24647
|
+
const checkActor = (actorId, path48) => {
|
|
24347
24648
|
if (actorId === void 0) return;
|
|
24348
24649
|
if (!Object.prototype.hasOwnProperty.call(process2.actors, actorId)) {
|
|
24349
24650
|
ctx.addIssue({
|
|
24350
24651
|
code: "custom",
|
|
24351
|
-
path:
|
|
24352
|
-
message: `Actor "${actorId}" is referenced at ${z4.core.toDotPath(
|
|
24652
|
+
path: path48,
|
|
24653
|
+
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
24654
|
params: { code: "UNDECLARED_ACTOR" }
|
|
24354
24655
|
});
|
|
24355
24656
|
}
|
|
24356
24657
|
};
|
|
24357
|
-
const checkSelector = (selector,
|
|
24658
|
+
const checkSelector = (selector, path48) => {
|
|
24358
24659
|
if (selector === void 0) return;
|
|
24359
24660
|
if (!declaredSelectors.has(selector)) {
|
|
24360
24661
|
ctx.addIssue({
|
|
24361
24662
|
code: "custom",
|
|
24362
|
-
path:
|
|
24363
|
-
message: `Selector "${selector}" is referenced at ${z4.core.toDotPath(
|
|
24663
|
+
path: path48,
|
|
24664
|
+
message: `Selector "${selector}" is referenced at ${z4.core.toDotPath(path48)} but not declared in process.selectors. Declare the selector or fix the reference.`,
|
|
24364
24665
|
params: { code: "UNDECLARED_SELECTOR" }
|
|
24365
24666
|
});
|
|
24366
24667
|
}
|
|
@@ -24374,20 +24675,20 @@ var init_process_artifact = __esm({
|
|
|
24374
24675
|
outcome: "DUPLICATE_OUTCOME_ID"
|
|
24375
24676
|
};
|
|
24376
24677
|
const idFirstSeenAt = /* @__PURE__ */ new Map();
|
|
24377
|
-
const checkId = (id, kind,
|
|
24678
|
+
const checkId = (id, kind, path48) => {
|
|
24378
24679
|
const first = idFirstSeenAt.get(id);
|
|
24379
24680
|
if (first) {
|
|
24380
24681
|
const kindLabel = kind === first.kind ? kind : "process";
|
|
24381
24682
|
ctx.addIssue({
|
|
24382
24683
|
code: "custom",
|
|
24383
|
-
path:
|
|
24384
|
-
message: `Duplicate ${kindLabel} id "${id}": ${kind} at ${z4.core.toDotPath(
|
|
24684
|
+
path: path48,
|
|
24685
|
+
message: `Duplicate ${kindLabel} id "${id}": ${kind} at ${z4.core.toDotPath(path48)} collides with ${first.kind} at ${z4.core.toDotPath(first.path)}.`,
|
|
24385
24686
|
params: {
|
|
24386
24687
|
code: kind === first.kind ? SAME_KIND_CODE[kind] : "DUPLICATE_PROCESS_ID"
|
|
24387
24688
|
}
|
|
24388
24689
|
});
|
|
24389
24690
|
} else {
|
|
24390
|
-
idFirstSeenAt.set(id, { kind, path:
|
|
24691
|
+
idFirstSeenAt.set(id, { kind, path: path48 });
|
|
24391
24692
|
}
|
|
24392
24693
|
};
|
|
24393
24694
|
process2.stages.forEach((stage, stageIndex) => {
|
|
@@ -24434,13 +24735,13 @@ function lintProcess(artifact, inventory, predicateNames, options = {}) {
|
|
|
24434
24735
|
const internalCommands = process2.internalCommands ?? [];
|
|
24435
24736
|
const internalSet = new Set(internalCommands);
|
|
24436
24737
|
const boundCommandPaths = /* @__PURE__ */ new Map();
|
|
24437
|
-
const checkPredicate = (predicate,
|
|
24738
|
+
const checkPredicate = (predicate, path48) => {
|
|
24438
24739
|
if (!predicateSet.has(predicate)) {
|
|
24439
24740
|
diagnostics.push({
|
|
24440
24741
|
severity: "error",
|
|
24441
24742
|
code: "UNKNOWN_PREDICATE",
|
|
24442
|
-
message: `Predicate "${predicate}" referenced at ${
|
|
24443
|
-
path:
|
|
24743
|
+
message: `Predicate "${predicate}" referenced at ${path48} is not in the predicate registry.`,
|
|
24744
|
+
path: path48
|
|
24444
24745
|
});
|
|
24445
24746
|
}
|
|
24446
24747
|
};
|
|
@@ -24500,19 +24801,19 @@ function lintProcess(artifact, inventory, predicateNames, options = {}) {
|
|
|
24500
24801
|
process2.outcomes.forEach((outcome, outcomeIndex) => {
|
|
24501
24802
|
const whenPath = `process.outcomes[${outcomeIndex}].when`;
|
|
24502
24803
|
outcomeTriggers(outcome).forEach((trigger, triggerIndex) => {
|
|
24503
|
-
const
|
|
24804
|
+
const path48 = Array.isArray(outcome.when) ? `${whenPath}[${triggerIndex}]` : whenPath;
|
|
24504
24805
|
if (trigger.kind === "predicate") {
|
|
24505
|
-
checkPredicate(trigger.name, `${
|
|
24806
|
+
checkPredicate(trigger.name, `${path48}.predicate`);
|
|
24506
24807
|
} else if (trigger.kind === "command") {
|
|
24507
24808
|
if (!boundCommandPaths.has(trigger.name)) {
|
|
24508
|
-
boundCommandPaths.set(trigger.name, `${
|
|
24809
|
+
boundCommandPaths.set(trigger.name, `${path48}.command`);
|
|
24509
24810
|
}
|
|
24510
24811
|
if (!commandNames.has(trigger.name)) {
|
|
24511
24812
|
diagnostics.push({
|
|
24512
24813
|
severity: "error",
|
|
24513
24814
|
code: "BOUND_COMMAND_NOT_IN_INVENTORY",
|
|
24514
|
-
message: `Command "${trigger.name}" triggering outcome "${outcome.id}" (${
|
|
24515
|
-
path: `${
|
|
24815
|
+
message: `Command "${trigger.name}" triggering outcome "${outcome.id}" (${path48}.command) does not exist in the inventory.`,
|
|
24816
|
+
path: `${path48}.command`
|
|
24516
24817
|
});
|
|
24517
24818
|
}
|
|
24518
24819
|
}
|
|
@@ -24624,10 +24925,10 @@ var init_src4 = __esm({
|
|
|
24624
24925
|
});
|
|
24625
24926
|
|
|
24626
24927
|
// libs/mesh-cli/src/commands/workflow.ts
|
|
24627
|
-
import * as
|
|
24628
|
-
import * as
|
|
24928
|
+
import * as fs40 from "fs";
|
|
24929
|
+
import * as path47 from "path";
|
|
24629
24930
|
import { createRequire as createRequire2 } from "module";
|
|
24630
|
-
import { execFileSync as
|
|
24931
|
+
import { execFileSync as execFileSync33 } from "child_process";
|
|
24631
24932
|
function resolveExtractorPath() {
|
|
24632
24933
|
try {
|
|
24633
24934
|
const require2 = createRequire2(import.meta.url);
|
|
@@ -24641,7 +24942,7 @@ function runExtraction(targetPath, extractorPath, explicitProcessPath) {
|
|
|
24641
24942
|
let explicitProcessArtifact;
|
|
24642
24943
|
if (explicitProcessPath) {
|
|
24643
24944
|
try {
|
|
24644
|
-
explicitProcessArtifact = JSON.parse(
|
|
24945
|
+
explicitProcessArtifact = JSON.parse(fs40.readFileSync(explicitProcessPath, "utf-8"));
|
|
24645
24946
|
} catch (err) {
|
|
24646
24947
|
logError(
|
|
24647
24948
|
`Could not read/parse --process ${explicitProcessPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -24682,7 +24983,7 @@ for (const file of files) {
|
|
|
24682
24983
|
process.stdout.write(JSON.stringify(results));
|
|
24683
24984
|
`;
|
|
24684
24985
|
try {
|
|
24685
|
-
const result =
|
|
24986
|
+
const result = execFileSync33("npx", ["tsx", "--eval", script], {
|
|
24686
24987
|
encoding: "utf-8",
|
|
24687
24988
|
stdio: ["pipe", "pipe", "inherit"],
|
|
24688
24989
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -24724,7 +25025,7 @@ for (const file of files) {
|
|
|
24724
25025
|
process.stdout.write(JSON.stringify(results));
|
|
24725
25026
|
`;
|
|
24726
25027
|
try {
|
|
24727
|
-
const result =
|
|
25028
|
+
const result = execFileSync33("npx", ["tsx", "--eval", script], {
|
|
24728
25029
|
encoding: "utf-8",
|
|
24729
25030
|
stdio: ["pipe", "pipe", "inherit"],
|
|
24730
25031
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -24741,7 +25042,7 @@ function runLintExtraction(targetPath, extractorPath, explicitProcessPath) {
|
|
|
24741
25042
|
let explicitProcessArtifact;
|
|
24742
25043
|
if (explicitProcessPath) {
|
|
24743
25044
|
try {
|
|
24744
|
-
explicitProcessArtifact = JSON.parse(
|
|
25045
|
+
explicitProcessArtifact = JSON.parse(fs40.readFileSync(explicitProcessPath, "utf-8"));
|
|
24745
25046
|
} catch (err) {
|
|
24746
25047
|
logError(
|
|
24747
25048
|
`Could not read/parse --process ${explicitProcessPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -24779,7 +25080,7 @@ for (const file of files) {
|
|
|
24779
25080
|
process.stdout.write(JSON.stringify(results));
|
|
24780
25081
|
`;
|
|
24781
25082
|
try {
|
|
24782
|
-
const result =
|
|
25083
|
+
const result = execFileSync33("npx", ["tsx", "--eval", script], {
|
|
24783
25084
|
encoding: "utf-8",
|
|
24784
25085
|
stdio: ["pipe", "pipe", "inherit"],
|
|
24785
25086
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -24849,16 +25150,16 @@ function registerWorkflowCommands(program2) {
|
|
|
24849
25150
|
).action(
|
|
24850
25151
|
async (targetPath, opts) => {
|
|
24851
25152
|
try {
|
|
24852
|
-
const resolvedPath =
|
|
24853
|
-
if (!
|
|
25153
|
+
const resolvedPath = path47.resolve(targetPath);
|
|
25154
|
+
if (!fs40.existsSync(resolvedPath)) {
|
|
24854
25155
|
logError(`Path does not exist: ${resolvedPath}`);
|
|
24855
25156
|
process.exitCode = 1;
|
|
24856
25157
|
return;
|
|
24857
25158
|
}
|
|
24858
25159
|
let resolvedProcessPath;
|
|
24859
25160
|
if (opts.process) {
|
|
24860
|
-
resolvedProcessPath =
|
|
24861
|
-
if (!
|
|
25161
|
+
resolvedProcessPath = path47.resolve(opts.process);
|
|
25162
|
+
if (!fs40.existsSync(resolvedProcessPath)) {
|
|
24862
25163
|
logError(`--process path does not exist: ${resolvedProcessPath}`);
|
|
24863
25164
|
process.exitCode = 1;
|
|
24864
25165
|
return;
|
|
@@ -24907,8 +25208,8 @@ function registerWorkflowCommands(program2) {
|
|
|
24907
25208
|
"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
25209
|
).action(async (targetPath) => {
|
|
24909
25210
|
try {
|
|
24910
|
-
const resolvedPath =
|
|
24911
|
-
if (!
|
|
25211
|
+
const resolvedPath = path47.resolve(targetPath);
|
|
25212
|
+
if (!fs40.existsSync(resolvedPath)) {
|
|
24912
25213
|
logError(`Path does not exist: ${resolvedPath}`);
|
|
24913
25214
|
process.exitCode = 1;
|
|
24914
25215
|
return;
|
|
@@ -24954,16 +25255,16 @@ function registerWorkflowCommands(program2) {
|
|
|
24954
25255
|
"Comma-separated named-selector registry (enables UNKNOWN_SELECTOR checks)"
|
|
24955
25256
|
).action(async (targetPath, opts) => {
|
|
24956
25257
|
try {
|
|
24957
|
-
const resolvedPath =
|
|
24958
|
-
if (!
|
|
25258
|
+
const resolvedPath = path47.resolve(targetPath);
|
|
25259
|
+
if (!fs40.existsSync(resolvedPath)) {
|
|
24959
25260
|
logError(`Path does not exist: ${resolvedPath}`);
|
|
24960
25261
|
process.exitCode = 1;
|
|
24961
25262
|
return;
|
|
24962
25263
|
}
|
|
24963
25264
|
let resolvedProcessPath;
|
|
24964
25265
|
if (opts.process) {
|
|
24965
|
-
resolvedProcessPath =
|
|
24966
|
-
if (!
|
|
25266
|
+
resolvedProcessPath = path47.resolve(opts.process);
|
|
25267
|
+
if (!fs40.existsSync(resolvedProcessPath)) {
|
|
24967
25268
|
logError(`--process path does not exist: ${resolvedProcessPath}`);
|
|
24968
25269
|
process.exitCode = 1;
|
|
24969
25270
|
return;
|