@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 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 hubOverlayServices() {
1372
- if (!hubOverlayServicesCache) {
1373
- const file = path5.join(stackDir(), HUB_OVERLAY_FILE);
1374
- if (!fs5.existsSync(file)) {
1375
- throw new MeshCliError(`Local stack assets are incomplete: ${file} is missing.`, {
1376
- remediation: { command: "npm install -g @mesh-tech/mesh-cli" }
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
- return hubOverlayServicesCache;
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) && (opts.overlayStarted || !opts.overlayServices.has(s.name))
1563
+ (s) => s.state === "exited" && !ONE_SHOT_SERVICES.has(s.name) && !dormant.has(s.name)
1544
1564
  );
1545
1565
  }
1546
- function hubOverlayRunning(services, overlayServices) {
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, hubOverlayServicesCache, ONE_SHOT_SERVICES;
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(path47, data, mode) {
3807
- const tmpPath = `${path47}.${process.pid}.${atomicWriteCounter++}.tmp`;
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, path47);
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/seed-zitadel.ts
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 = path16.join(fs16.mkdtempSync(path16.join(os5.tmpdir(), "mesh-zitadel-")), "pat.txt");
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 = fs16.readFileSync(tmp, "utf-8").trim();
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
- fs16.rmSync(path16.dirname(tmp), { recursive: true, force: true });
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 path16.join(meshCacheDir("mesh-local"), "hub-auth.json");
6964
+ return path17.join(meshCacheDir("mesh-local"), "hub-auth.json");
6809
6965
  }
6810
6966
  function readHubAuth() {
6811
6967
  try {
6812
- const parsed = JSON.parse(fs16.readFileSync(hubAuthPath(), "utf-8"));
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
- fs16.writeFileSync(hubAuthPath(), JSON.stringify(config, null, 2), { mode: 384 });
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
- 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;
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 fs17 from "fs";
7537
- import * as path17 from "path";
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 path17.join(findPackageRoot(), "assets", "log-shipper.mjs");
7776
+ return path18.join(findPackageRoot(), "assets", "log-shipper.mjs");
7543
7777
  }
7544
7778
  function autoInstrumentationEnv(appRoot, src) {
7545
- const pkgDir = path17.join("node_modules", "@opentelemetry", "auto-instrumentations-node");
7546
- const present = fs17.existsSync(path17.join(appRoot, src, pkgDir)) || fs17.existsSync(path17.join(appRoot, pkgDir));
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 (fs17.existsSync(path17.join(appRoot, "dg.toml"))) return true;
7603
- const pyproject = path17.join(appRoot, "pyproject.toml");
7604
- if (!fs17.existsSync(pyproject)) return false;
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(fs17.readFileSync(pyproject, "utf-8"));
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 (fs17.existsSync(path17.join(appRoot, candidate))) return candidate;
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 = path17.join(dir, "package.json");
7619
- if (!fs17.existsSync(pkgPath)) return false;
7852
+ const pkgPath = path18.join(dir, "package.json");
7853
+ if (!fs18.existsSync(pkgPath)) return false;
7620
7854
  try {
7621
- const pkg = JSON.parse(fs17.readFileSync(pkgPath, "utf-8"));
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 fs17.readdirSync(appRoot, { withFileTypes: true })) {
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(path17.join(appRoot, entry.name))) {
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[path17.basename(appRoot)] = { src: "." };
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 = path17.basename(appRoot);
7884
+ let appName = path18.basename(appRoot);
7651
7885
  try {
7652
- const pkg = JSON.parse(fs17.readFileSync(path17.join(appRoot, "package.json"), "utf-8"));
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 = path17.join(appRoot, "Pulumi.yaml");
7657
- if (fs17.existsSync(pulumiYaml)) {
7658
- const match = fs17.readFileSync(pulumiYaml, "utf-8").match(/^name:\s*(.+)$/m);
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: path17.join(appRoot, ".dagster") },
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 = fs17.existsSync(path17.join(appRoot, "Pulumi.yaml")) || fs17.readdirSync(appRoot).some((f) => /^Pulumi\..+\.yaml$/.test(f));
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 = path17.dirname(appRoot);
7976
+ let dir = path18.dirname(appRoot);
7743
7977
  while (true) {
7744
- if (fs17.existsSync(path17.join(dir, "Pulumi.yaml"))) return true;
7745
- if (fs17.existsSync(path17.join(dir, ".git")) || fs17.existsSync(path17.join(dir, "pnpm-workspace.yaml"))) {
7746
- return fs17.existsSync(path17.join(dir, "Pulumi.yaml"));
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 = path17.dirname(dir);
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 fs17.readdirSync(appRoot)) {
7988
+ for (const file of fs18.readdirSync(appRoot)) {
7755
7989
  if (!/^Pulumi\..*\.yaml$/.test(file)) continue;
7756
- const match = fs17.readFileSync(path17.join(appRoot, file), "utf-8").match(/^\s*mesh:tenant:\s*["']?([A-Za-z0-9-]+)["']?\s*$/m);
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 execFileSync13 } from "child_process";
7793
- import * as fs18 from "fs";
7794
- import * as path18 from "path";
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
- fs18.writeFileSync(path18.join(dir, `${name}.env`), renderDockerEnvFile(env), { mode: 384 });
7817
- const workdir = path18.posix.join("/workspace", service.src === "." ? "" : service.src);
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
- ` - '${path18.dirname(shipper)}:/mesh-assets:ro'`,
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 = path18.join(dir, "compose.yml");
7843
- fs18.writeFileSync(composePath, blocks.join("\n") + "\n");
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", path18.join(sessionDir(sessionName), "compose.yml"), ...args];
8081
+ return ["compose", "-p", sessionName, "-f", path19.join(sessionDir(sessionName), "compose.yml"), ...args];
7848
8082
  }
7849
8083
  function dockerDevUp(sessionName) {
7850
- execFileSync13("docker", composeArgs(sessionName, ["up", "-d"]), {
8084
+ execFileSync14("docker", composeArgs(sessionName, ["up", "-d"]), {
7851
8085
  stdio: ["ignore", "inherit", "inherit"]
7852
8086
  });
7853
8087
  }
7854
8088
  function dockerDevDown(sessionName) {
7855
- execFileSync13("docker", composeArgs(sessionName, ["down", "--remove-orphans"]), {
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 execFileSync13("docker", composeArgs(sessionName, ["ps", "--format", "table {{.Service}} {{.State}} {{.Status}}"]), {
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 execFileSync13("docker", composeArgs(sessionName, ["logs", "--tail", String(tail), service]), {
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
- execFileSync13("docker", composeArgs(sessionName, ["restart", service]), {
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 execFileSync14 } from "node:child_process";
8175
+ import { execFileSync as execFileSync15 } from "node:child_process";
7942
8176
  import * as crypto3 from "node:crypto";
7943
- import * as path19 from "node:path";
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}#${path19.resolve(appRoot)}`);
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 = path19.resolve(gitRunner(["rev-parse", "--show-toplevel"], cwd));
8210
+ worktreeRoot = path20.resolve(gitRunner(["rev-parse", "--show-toplevel"], cwd));
7977
8211
  const commonDir = gitRunner(["rev-parse", "--git-common-dir"], cwd);
7978
- const primaryRoot = path19.resolve(path19.dirname(path19.resolve(cwd, commonDir)));
8212
+ const primaryRoot = path20.resolve(path20.dirname(path20.resolve(cwd, commonDir)));
7979
8213
  isPrimary = worktreeRoot === primaryRoot;
7980
8214
  } catch {
7981
8215
  return {
7982
- worktreeRoot: path19.resolve(cwd),
8216
+ worktreeRoot: path20.resolve(cwd),
7983
8217
  isPrimary: true,
7984
- slug: sanitizeSlug(path19.basename(path19.resolve(cwd))),
7985
- hash: worktreeHash(path19.resolve(cwd)),
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(path19.basename(worktreeRoot));
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) => execFileSync14("git", args, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }).trim();
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 execFileSync15, spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
8076
- import * as fs19 from "fs";
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 path20 from "path";
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(path20.sep) ? wt.worktreeRoot : wt.worktreeRoot + path20.sep;
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 = path20.resolve(appRoot, rebaseServiceSrc(s.src, monorepoRoot));
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 = path20.join(os6.tmpdir(), "mesh-dev-sessions");
8139
- if (!fs19.existsSync(dir)) fs19.mkdirSync(dir, { recursive: true });
8140
- return path20.join(dir, `${sessionName}.json`);
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
- fs19.writeFileSync(getSessionStatePath(sessionName), JSON.stringify(state, null, 2));
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 (!fs19.existsSync(filePath)) return null;
8381
+ if (!fs20.existsSync(filePath)) return null;
8148
8382
  try {
8149
- return JSON.parse(fs19.readFileSync(filePath, "utf-8"));
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 path20.join(os6.tmpdir(), "mesh-dev-sessions", sessionName);
8407
+ return path21.join(os6.tmpdir(), "mesh-dev-sessions", sessionName);
8174
8408
  }
8175
8409
  function getServiceEnvFilePath(sessionName, serviceName) {
8176
- return path20.join(getSessionEnvDir(sessionName), envFileName(serviceName));
8410
+ return path21.join(getSessionEnvDir(sessionName), envFileName(serviceName));
8177
8411
  }
8178
8412
  function removeSessionState(sessionName) {
8179
8413
  try {
8180
- fs19.unlinkSync(getSessionStatePath(sessionName));
8414
+ fs20.unlinkSync(getSessionStatePath(sessionName));
8181
8415
  } catch {
8182
8416
  }
8183
8417
  try {
8184
- fs19.rmSync(getSessionEnvDir(sessionName), { recursive: true, force: true });
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 = path20.parse(dir).root;
8546
+ const root = path21.parse(dir).root;
8313
8547
  while (dir !== root) {
8314
- if (fs19.existsSync(path20.join(dir, "pnpm-workspace.yaml")) || fs19.existsSync(path20.join(dir, "turbo.json"))) {
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 = path20.join(dir, ".git");
8318
- if (fs19.existsSync(gitPath)) {
8551
+ const gitPath = path21.join(dir, ".git");
8552
+ if (fs20.existsSync(gitPath)) {
8319
8553
  return dir;
8320
8554
  }
8321
- dir = path20.dirname(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 = fs19.readdirSync(appDir).filter((f) => f.startsWith("Pulumi.") && f.endsWith(".yaml") && f !== "Pulumi.yaml").map((f) => f.replace(/^Pulumi\./, "").replace(/\.yaml$/, ""));
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: path20.relative(monorepoRoot, appDir),
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 = path20.join(monorepoRoot, searchDir);
8341
- if (!fs19.existsSync(base)) continue;
8342
- for (const tenant of fs19.readdirSync(base)) {
8343
- const appsDir = path20.join(base, tenant, "apps");
8344
- if (!fs19.existsSync(appsDir) || !fs19.statSync(appsDir).isDirectory()) continue;
8345
- for (const app of fs19.readdirSync(appsDir)) {
8346
- const appDir = path20.join(appsDir, app);
8347
- if (!fs19.existsSync(path20.join(appDir, "Pulumi.yaml"))) continue;
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 = path20.join(monorepoRoot, "apps");
8353
- if (fs19.existsSync(flatAppsDir) && fs19.statSync(flatAppsDir).isDirectory()) {
8354
- for (const app of fs19.readdirSync(flatAppsDir)) {
8355
- const appDir = path20.join(flatAppsDir, app);
8356
- if (!fs19.statSync(appDir).isDirectory()) continue;
8357
- if (!fs19.existsSync(path20.join(appDir, "Pulumi.yaml"))) continue;
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 = fs19.readdirSync(appDir).filter((f) => f.startsWith("Pulumi.") && f.endsWith(".yaml") && f !== "Pulumi.yaml");
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 = fs19.readFileSync(path20.join(appDir, stackConfigs[0]), "utf-8");
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 = path20.resolve(appPath);
8376
- if (fs19.existsSync(path20.join(resolved, "Pulumi.yaml"))) return resolved;
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 = path20.resolve(mono, appPath);
8380
- if (fs19.existsSync(path20.join(fromMono, "Pulumi.yaml"))) return fromMono;
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 = path20.parse(dir).root;
8620
+ const root = path21.parse(dir).root;
8387
8621
  while (dir !== root) {
8388
- if (fs19.existsSync(path20.join(dir, "Pulumi.yaml"))) {
8622
+ if (fs20.existsSync(path21.join(dir, "Pulumi.yaml"))) {
8389
8623
  return dir;
8390
8624
  }
8391
- dir = path20.dirname(dir);
8625
+ dir = path21.dirname(dir);
8392
8626
  }
8393
8627
  return process.cwd();
8394
8628
  }
8395
8629
  function getProjectName(appRoot) {
8396
- const yamlPath = path20.join(appRoot, "Pulumi.yaml");
8397
- if (!fs19.existsSync(yamlPath)) return path20.basename(appRoot);
8398
- const content = fs19.readFileSync(yamlPath, "utf-8");
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() ?? path20.basename(appRoot);
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 = execFileSync15("pulumi", ["stack", "--show-name"], {
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 = fs19.readdirSync(appRoot).filter((f) => f.startsWith("Pulumi.") && f.endsWith(".yaml") && f !== "Pulumi.yaml");
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 = execFileSync15("pulumi", ["stack", "--show-name"], {
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
- execFileSync15("pulumi", ["stack", "select", stack], {
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
- execFileSync15("which", ["tmux"], { stdio: "ignore" });
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
- execFileSync15("tmux", ["has-session", "-t", name], { stdio: "ignore" });
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
- execFileSync15("tmux", ["kill-session", "-t", name], { stdio: "ignore" });
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 = path20.join(opts.sessionScratchDir, "aws-config");
8756
+ const configPath = path21.join(opts.sessionScratchDir, "aws-config");
8523
8757
  const region = awsEnv.AWS_REGION ?? awsEnv.AWS_DEFAULT_REGION ?? "";
8524
- fs19.mkdirSync(opts.sessionScratchDir, { recursive: true });
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 = fs19.existsSync(configPath) ? fs19.readFileSync(configPath, "utf8") : "";
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 = path20.join(monorepoRoot, rel2);
8559
- return fs19.existsSync(rebased) ? rebased : src;
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 = path20.dirname(dir)) {
8798
+ for (let dir = serviceDir; ; dir = path21.dirname(dir)) {
8565
8799
  try {
8566
- const manifest = JSON.parse(fs19.readFileSync(path20.join(dir, "package.json"), "utf8"));
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 = path20.dirname(dir);
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 = path20.dirname(dir)) {
8812
+ for (let dir = appRoot; ; dir = path21.dirname(dir)) {
8579
8813
  try {
8580
- if (fs19.realpathSync(path20.join(dir, "node_modules", name)) === pkgRoot) return true;
8814
+ if (fs20.realpathSync(path21.join(dir, "node_modules", name)) === pkgRoot) return true;
8581
8815
  } catch {
8582
8816
  }
8583
- const parent = path20.dirname(dir);
8817
+ const parent = path21.dirname(dir);
8584
8818
  if (parent === dir) return false;
8585
8819
  }
8586
8820
  }
8587
8821
  function monorepoRelativeSrc(src) {
8588
- if (!path20.isAbsolute(src)) return src.replace(/^\.\//, "") || ".";
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
- execFileSync15("tmux", ["set-environment", "-t", sessionName, key, value], { stdio: "ignore" });
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 = execFileSync15(
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 (fs19.existsSync(existing)) {
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
- execFileSync15("which", ["session-manager-plugin"], { stdio: "ignore" });
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
- execFileSync15("tmux", ["new-window", "-t", sessionName, "-n", windowName]);
8969
- execFileSync15(
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
- execFileSync15("tmux", ["send-keys", "-t", `${sessionName}:${windowName}`, ssmCmd, "Enter"]);
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 ?? path20.basename(appRoot);
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
- execFileSync15(
9252
+ execFileSync16(
9019
9253
  "docker",
9020
9254
  [
9021
9255
  "run",
@@ -9031,7 +9265,7 @@ CADDYEOF`
9031
9265
  ],
9032
9266
  { stdio: "pipe" }
9033
9267
  );
9034
- execFileSync15(
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 ?? path20.basename(appRoot);
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 = path20.join(caddyDir, "Caddyfile");
9084
- if (!fs19.existsSync(caddyDir)) fs19.mkdirSync(caddyDir, { recursive: true });
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
- fs19.writeFileSync(caddyfile, caddyLines.join("\n"));
9336
+ fs20.writeFileSync(caddyfile, caddyLines.join("\n"));
9103
9337
  let caddyRunning = false;
9104
9338
  try {
9105
- execFileSync15("pgrep", ["-f", "caddy run.*mesh-dev-caddy"], { stdio: "pipe" });
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
- execFileSync15("caddy", ["reload", "--config", caddyfile, "--adapter", "caddyfile"], {
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
- execFileSync15("which", ["caddy"], { stdio: "pipe" });
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
- execFileSync15("tmux", ["new-session", "-d", "-s", sessionName, "-n", "status", "-c", appRoot]);
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
- execFileSync15("tmux", ["new-window", "-t", sessionName, "-n", "token-server"]);
9274
- execFileSync15(
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
- execFileSync15("tmux", [
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 = path20.resolve(appRoot, rebaseServiceSrc(service.src, monorepoRoot));
9303
- if (worktreeRoot && fs19.existsSync(serviceDir)) {
9304
- const wtRootWithSep = worktreeRoot.endsWith(path20.sep) ? worktreeRoot : worktreeRoot + path20.sep;
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 (!fs19.existsSync(serviceDir)) {
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
- execFileSync15("tmux", ["new-window", "-t", sessionName, "-n", name, "-c", serviceDir]);
9356
- execFileSync15("tmux", ["set-option", "-t", `${sessionName}:${name}`, "remain-on-exit", "on"], {
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
- execFileSync15("tmux", ["send-keys", "-t", `${sessionName}:${name}`, launchCmd, "Enter"]);
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
- execFileSync15("tmux", ["send-keys", "-t", `${sessionName}:status`, statusCmd, "Enter"]);
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 = execFileSync15(
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
- execFileSync15("tmux", ["respawn-pane", "-k", "-t", target], { stdio: "ignore" });
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 (fs19.existsSync(envFilePath)) {
9559
- const serviceDir = path20.resolve(appRoot, rebaseServiceSrc(service.src, findMonorepoRoot()));
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
- execFileSync15("tmux", ["send-keys", "-t", target, restartCmd, "Enter"]);
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 = execFileSync15("tmux", ["capture-pane", "-t", target, "-p", "-S", `-${tail}`], {
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
- fs19.readFileSync(path20.join(appRoot, "package.json"), "utf-8")
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) => fs19.existsSync(path20.join(appRoot, dir, "package.json"))
10223
+ (dir) => fs20.existsSync(path21.join(appRoot, dir, "package.json"))
9990
10224
  );
9991
- if (monorepoRoot && path20.resolve(appRoot) === path20.resolve(monorepoRoot) && !looksLikeStandaloneApp) {
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 execFileSync16 } from "node:child_process";
10468
- import * as fs20 from "node:fs";
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 path21 from "node:path";
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 = path21.resolve(serviceSrc);
10574
- const root = path21.resolve(repoRoot2);
10575
- return src === root || src.startsWith(root + path21.sep);
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 = execFileSync16("lsof", ["-ti", `:${port}`], {
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 = execFileSync16("ps", ["-o", "comm=", "-p", pid], {
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 = execFileSync16(
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 = execFileSync16("ps", ["-eo", "pid=,ppid="], {
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
- execFileSync16("which", ["tmux"], { stdio: "ignore" });
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 = path21.join(ctx.appRoot, `Pulumi.${ctx.stack}.yaml`);
10836
- if (!fs20.existsSync(configPath)) {
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 = fs20.statSync(configPath).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 = execFileSync16("git", ["rev-parse", "--show-toplevel"], {
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 fs21 from "node:fs";
11002
- import * as path22 from "node:path";
11235
+ import * as fs22 from "node:fs";
11236
+ import * as path23 from "node:path";
11003
11237
  function rel(root, abs) {
11004
- return path22.relative(root, abs).split(path22.sep).join("/");
11238
+ return path23.relative(root, abs).split(path23.sep).join("/");
11005
11239
  }
11006
11240
  function isDir(p) {
11007
11241
  try {
11008
- return fs21.statSync(p).isDirectory();
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 fs21.readFileSync(p, "utf8");
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 = fs21.readdirSync(d, { withFileTypes: true });
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 = path22.join(d, e.name);
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(path22.extname(e.name))) continue;
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 = fs21.readdirSync(app, { withFileTypes: true });
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) => path22.join(app, e.name)).sort();
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 = fs21.readdirSync(d, { withFileTypes: true });
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 = path22.join(d, e.name);
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 = path22.join(root, "apps");
11603
+ const appsDir = path23.join(root, "apps");
11370
11604
  if (isDir(appsDir)) {
11371
- for (const e of fs21.readdirSync(appsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
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 = path22.join(appsDir, e.name);
11374
- if (fs21.existsSync(path22.join(d, "index.ts")) || fs21.existsSync(path22.join(d, "Pulumi.yaml"))) apps.push(rel(root, d));
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 (fs21.existsSync(path22.join(root, "index.ts")) && fs21.existsSync(path22.join(root, "Pulumi.yaml"))) apps.push(".");
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 = path22.resolve(root, appRel);
11382
- const index = path22.join(app, "index.ts");
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 = fs21.existsSync(index) || fs21.existsSync(path22.join(app, "Pulumi.yaml"));
11621
+ const hasProgram = fs22.existsSync(index) || fs22.existsSync(path23.join(app, "Pulumi.yaml"));
11388
11622
  if (!hasProgram) return findings;
11389
- if (fs21.existsSync(index)) {
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 = path22.basename(svc);
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)" : path22.basename(appRel);
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(path22.join(dir, "package.json")));
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 = path22.join(root, parent);
11717
+ const dir = path23.join(root, parent);
11484
11718
  if (!isDir(dir)) continue;
11485
- for (const e of fs21.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
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 = path22.join(dir, e.name);
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(path22.resolve(root, a))) throw new MeshCliError(`no such app dir: ${a}`);
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 = path22.resolve(opts.root ?? resolveTargetRoot());
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
- remediation: "end index.ts with `export const app = env.register({ description })`",
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 readFileSync18 } from "node:fs";
12036
+ import { readFileSync as readFileSync19 } from "node:fs";
11799
12037
  import { homedir as homedir3 } from "node:os";
11800
- import path23 from "node:path";
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 = readFileSync18(file, "utf8");
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 = path23.join(homedir3(), ".config", "mesh", "agent-targets.json");
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 join20, dirname as dirname19 } from "node:path";
12294
+ import { join as join21, dirname as dirname19 } from "node:path";
12057
12295
  async function put(dir, rel2, contents, written) {
12058
- const abs = join20(dir, rel2);
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 join21 } from "node:path";
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(join21(tmpdir4(), "mesh-vcs-"));
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, path47) => {
12499
+ const readPath = async (repo, path48) => {
12262
12500
  const dir = await cloneRepo(repo);
12263
- const ref = await resolveFolderRef(dir, path47);
12264
- if (!ref) throw new Error(`path "${path47}" not found on any ref of ${repo}`);
12265
- const files = await readFolderAtRef(dir, ref, path47);
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 fs22 from "fs";
12457
- import * as path24 from "path";
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 ?? path24.join("workflows", bundle.primaryWorkflow);
12481
- fs22.mkdirSync(outputDir, { recursive: true });
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 = path24.join(outputDir, file.filename);
12485
- fs22.writeFileSync(filePath, file.code, "utf-8");
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 = path24.join(outputDir, "README.md");
12491
- fs22.writeFileSync(readmePath, bundle.overview, "utf-8");
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 = path24.join(outputDir, "workflow-ir.json");
12497
- fs22.writeFileSync(irPath, JSON.stringify(bundle.ir, null, 2), "utf-8");
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 = path24.join(outputDir, ".workflow-meta.json");
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
- fs22.writeFileSync(metaPath, JSON.stringify(meta, null, 2), "utf-8");
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 execFileSync17 } from "child_process";
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 = execFileSync17("npm", ["view", pkg, "version"], {
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 fs23 from "fs";
13227
+ import * as fs24 from "fs";
12990
13228
  import * as os7 from "os";
12991
- import * as path25 from "path";
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 = path25.resolve(dir);
12997
- while (cur !== path25.dirname(cur)) {
12998
- if (fs23.existsSync(path25.join(cur, "pnpm-workspace.yaml"))) {
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(fs23.readFileSync(path25.join(cur, "package.json"), "utf-8"));
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 = path25.dirname(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 fs23.existsSync(path25.join(cwd, ".git")) && !isInsidePlatformMonorepo(cwd) && !fs23.existsSync(path25.join(cwd, "package.json")) && !fs23.existsSync(path25.join(cwd, "tenants")) && !fs23.existsSync(path25.join(cwd, "apps"));
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 = path25.join(packageRoot, "templates", "apps-repo");
13255
+ const templateDir = path26.join(packageRoot, "templates", "apps-repo");
13018
13256
  const registryAccount = HUB_ACCOUNTS.mesh;
13019
13257
  const context = {
13020
- repoName: path25.basename(cwd),
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 = fs23.mkdtempSync(path25.join(os7.tmpdir(), "mesh-apps-repo-"));
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 = path25.join(staging, from);
13034
- if (fs23.existsSync(p)) fs23.renameSync(p, path25.join(staging, to));
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 fs23.readdirSync(staging)) {
13038
- const dest = path25.join(cwd, entry);
13039
- if (fs23.existsSync(dest)) continue;
13040
- fs23.cpSync(path25.join(staging, entry), dest, { recursive: true });
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
- fs23.mkdirSync(path25.join(cwd, "apps"), { recursive: true });
13281
+ fs24.mkdirSync(path26.join(cwd, "apps"), { recursive: true });
13044
13282
  created.push("apps/");
13045
13283
  return created;
13046
13284
  } finally {
13047
- fs23.rmSync(staging, { recursive: true, force: true });
13285
+ fs24.rmSync(staging, { recursive: true, force: true });
13048
13286
  }
13049
13287
  }
13050
13288
  function ensureWorkspaceGlobs(root, required) {
13051
- const file = path25.join(root, "pnpm-workspace.yaml");
13052
- if (!fs23.existsSync(file)) return [];
13053
- const text = fs23.readFileSync(file, "utf-8");
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
- fs23.writeFileSync(file, lines.join("\n"));
13315
+ fs24.writeFileSync(file, lines.join("\n"));
13078
13316
  return missing;
13079
13317
  }
13080
13318
  function workspaceGlobForApp(root, appDir) {
13081
- const rel2 = path25.relative(root, appDir).split(path25.sep).join("/");
13319
+ const rel2 = path26.relative(root, appDir).split(path26.sep).join("/");
13082
13320
  if (rel2 === "" || rel2.split("/")[0] === "..") return null;
13083
- return `${path25.posix.dirname(rel2)}/*/*`;
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 = fs23.readdirSync(srcDir, { withFileTypes: true });
13371
+ const entries = fs24.readdirSync(srcDir, { withFileTypes: true });
13134
13372
  for (const entry of entries) {
13135
- const srcPath = path25.join(srcDir, entry.name);
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 = path25.join(destDir, destName);
13381
+ const destPath = path26.join(destDir, destName);
13144
13382
  if (entry.isDirectory()) {
13145
- fs23.mkdirSync(destPath, { recursive: true });
13383
+ fs24.mkdirSync(destPath, { recursive: true });
13146
13384
  copyTemplate(srcPath, destPath, context);
13147
13385
  } else if (entry.name.endsWith(".hbs")) {
13148
- const templateContent = fs23.readFileSync(srcPath, "utf-8");
13386
+ const templateContent = fs24.readFileSync(srcPath, "utf-8");
13149
13387
  const template = Handlebars.compile(templateContent);
13150
13388
  const output = template(context);
13151
- fs23.writeFileSync(destPath, output);
13389
+ fs24.writeFileSync(destPath, output);
13152
13390
  } else {
13153
- fs23.copyFileSync(srcPath, destPath);
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${fs23.existsSync(path25.join(cwd, ".git")) ? "" : " and it is not a git repo"}.`,
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 ? [path25.join(cwd, baseDir, tenant, "apps")] : [
13184
- path25.join(cwd, baseDir, tenant, "apps"),
13185
- path25.join(cwd, "..", tenant, "apps"),
13186
- path25.join(cwd, "apps")
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) => fs23.existsSync(p));
13426
+ let appsDir = possiblePaths.find((p) => fs24.existsSync(p));
13189
13427
  if (!appsDir) {
13190
- appsDir = path25.join(cwd, baseDir, tenant, "apps");
13191
- if (!fs23.existsSync(path25.join(cwd, baseDir, tenant))) {
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 (!fs23.existsSync(appsDir)) {
13435
+ if (!fs24.existsSync(appsDir)) {
13198
13436
  logInfo(`Creating apps directory: ${appsDir}`);
13199
- fs23.mkdirSync(appsDir, { recursive: true });
13437
+ fs24.mkdirSync(appsDir, { recursive: true });
13200
13438
  }
13201
13439
  }
13202
- return path25.join(appsDir, name);
13440
+ return path26.join(appsDir, name);
13203
13441
  }
13204
13442
  function generateComposableApp(appDir, context) {
13205
- const fragmentsDir = path25.join(packageRoot, "fragments");
13206
- const baseDir = path25.join(fragmentsDir, "base");
13207
- if (!fs23.existsSync(baseDir)) {
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 = path25.join(fragmentsDir, "service");
13215
- if (!fs23.existsSync(serviceDir)) {
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 = path25.join(fragmentsDir, "database");
13222
- if (!fs23.existsSync(dbDir)) {
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 = path25.join(fragmentsDir, "temporal");
13229
- if (!fs23.existsSync(temporalDir)) {
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 = path25.join(fragmentsDir, "bucket");
13236
- if (!fs23.existsSync(bucketDir)) {
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 = path25.join(fragmentsDir, "agents");
13242
- if (fs23.existsSync(agentsDir)) {
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 (fs23.existsSync(appDir)) {
13581
+ if (fs24.existsSync(appDir)) {
13344
13582
  logError(`App directory already exists: ${appDir}`);
13345
13583
  process.exit(1);
13346
13584
  }
13347
- const templateDir = path25.join(packageRoot, "templates", template);
13348
- if (!fs23.existsSync(templateDir)) {
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
- fs23.mkdirSync(appDir, { recursive: true });
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
- fs23.rmSync(appDir, { recursive: true, force: true });
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, path25.relative(root, appDir));
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, [path25.relative(root, appDir) || "."]);
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 (fs23.existsSync(appDir)) {
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
- fs23.mkdirSync(appDir, { recursive: true });
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
- fs23.rmSync(appDir, { recursive: true, force: true });
13680
+ fs24.rmSync(appDir, { recursive: true, force: true });
13443
13681
  process.exit(1);
13444
13682
  }
13445
- const nested = fs23.readdirSync(appDir, { withFileTypes: true }).some((entry) => entry.isDirectory() && fs23.existsSync(path25.join(appDir, entry.name, "package.json")));
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 = path25.dirname(__filename);
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 fs24 from "fs";
13854
- import * as path26 from "path";
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 = path26.parse(dir).root;
14099
+ const root = path27.parse(dir).root;
13862
14100
  while (dir !== root) {
13863
- const outputsPath = path26.join(dir, ".sst", "outputs.json");
13864
- if (fs24.existsSync(outputsPath)) {
14101
+ const outputsPath = path27.join(dir, ".sst", "outputs.json");
14102
+ if (fs25.existsSync(outputsPath)) {
13865
14103
  try {
13866
- const content = fs24.readFileSync(outputsPath, "utf-8");
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 = path26.dirname(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 existsSync20, readFileSync as readFileSync21 } from "node:fs";
14141
- import { dirname as dirname22, join as join25, relative as relative7 } from "node:path";
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 = join25(dir, "pnpm-lock.yaml");
14180
- if (existsSync20(candidate)) return candidate;
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 = join25(fromDir, "node_modules", name, "package.json");
14189
- const version = JSON.parse(readFileSync21(pkgPath, "utf8")).version;
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(readFileSync21(lockPath, "utf8"));
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 execFileSync18 } from "child_process";
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
- execFileSync18("pulumi", finalArgs, {
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 existsSync21, readdirSync as readdirSync9, readFileSync as readFileSync22, statSync as statSync5 } from "node:fs";
14425
- import path27 from "node:path";
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 = path27.join(absDir, entry.name);
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
- path27.join(absDir, entry.name),
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 = path27.join(repoRoot2, root.dir);
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 (!existsSync21(path27.join(repoRoot2, normalized))) {
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 = path27.posix.basename(normalized).replace(/\.md$/i, "");
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 = path27.join(absDir, "docs.json");
14797
+ const configPath = path28.join(absDir, "docs.json");
14560
14798
  let raw;
14561
14799
  try {
14562
- raw = JSON.parse(readFileSync22(configPath, "utf-8"));
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 execFileSync19 } from "node:child_process";
14613
- import { mkdirSync as mkdirSync11, readFileSync as readFileSync23, rmSync as rmSync5, writeFileSync as writeFileSync15 } from "node:fs";
14614
- import path28 from "node:path";
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 = path28.posix.basename(source).replace(/\.md$/i, "");
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 path28.posix.normalize(value.replace(/\\/g, "/")).replace(/^\.\//, "").replace(/\/+$/, "");
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(path28.posix.join(sourceDir, rawTarget));
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 = path28.posix.dirname(args.page.source);
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
- mkdirSync11(outDir, { recursive: true });
15134
+ mkdirSync12(outDir, { recursive: true });
14897
15135
  for (const page of pages) {
14898
- const raw = readFileSync23(path28.join(repoRoot2, page.source), "utf-8");
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(path28.join(repoRoot2, rel2)),
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 = path28.join(outDir, page.filePath);
14925
- mkdirSync11(path28.dirname(outFile), { recursive: true });
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 execFileSync19("git", ["rev-parse", "--short", "HEAD"], {
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
- readFileSync23(path28.join(repoRoot2, "libs/app-kit/package.json"), "utf-8")
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) => execFileSync19("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 (path28.posix.basename(file).toLowerCase() === "readme.md") continue;
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(path47) {
15234
- return path47.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
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 path47 = parentPath ? `${parentPath} ${name}` : name;
15506
+ const path48 = parentPath ? `${parentPath} ${name}` : name;
15269
15507
  return {
15270
- path: path47,
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(path47),
15514
+ slug: slugifyCommandPath(path48),
15277
15515
  depth,
15278
- subcommands: (internals.commands ?? []).filter((child) => !isUndocumented(child)).map((child) => extractCommand(child, path47, depth + 1))
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 existsSync22,
15371
- mkdirSync as mkdirSync12,
15608
+ existsSync as existsSync23,
15609
+ mkdirSync as mkdirSync13,
15372
15610
  mkdtempSync as mkdtempSync3,
15373
- readFileSync as readFileSync24,
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 path29 from "node:path";
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()) ? path29.join(args.outDir, PUBLISH_MANIFEST) : path29.join(args.outDir, "..", PUBLISH_MANIFEST);
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 = path29.join(
15407
- path29.dirname(args.configOut),
15644
+ const versionDir = path30.join(
15645
+ path30.dirname(args.configOut),
15408
15646
  VERSION_JSON_DIR
15409
15647
  );
15410
- mkdirSync12(versionDir, { recursive: true });
15648
+ mkdirSync13(versionDir, { recursive: true });
15411
15649
  writeFileSync16(
15412
- path29.join(versionDir, VERSION_JSON),
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(path29.join(tmpdir6(), "mesh-docs-check-"));
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
- mkdirSync12(path29.dirname(args.manifestOut), { recursive: true });
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 = path29.join(repoRoot2, DOCS_APP_DIR);
15536
- const outDir = opts.out ? path29.resolve(repoRoot2, opts.out) : path29.join(appDir, CONTENT_DIR);
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: path29.join(appDir, GENERATED_CONFIG)
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 ${path29.relative(repoRoot2, outDir)} \u2014 build with: pnpm --filter @mesh-tech/docs build`
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 ${path29.join(path29.relative(repoRoot2, appDir), "dist")}`
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 = path29.join(repoRoot2, "docs/portal/generated/cli-reference.md");
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 = existsSync22(outPath) ? readFileSync24(outPath, "utf-8") : null;
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 execFileSync20 } from "child_process";
15611
- import * as fs25 from "fs";
15612
- import * as path30 from "path";
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(fs25.readFileSync(path30.join(dir, "package.json"), "utf-8"));
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 = path30.dirname(dir);
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 = path30.dirname(fileURLToPath3(import.meta.url));
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(fs25.readFileSync(path30.join(root, "package.json"), "utf-8")).version ?? version;
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
- fs25.readFileSync(path30.join(root, "dist", "build-info.json"), "utf-8")
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) => execFileSync20("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 join27, normalize, sep as sep5 } from "node:path";
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(join27(root, candidate));
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 execFileSync21 } from "node:child_process";
15766
- import { existsSync as existsSync23, mkdirSync as mkdirSync13, readFileSync as readFileSync26, renameSync as renameSync3, rmSync as rmSync6, writeFileSync as writeFileSync17 } from "node:fs";
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 path31 from "node:path";
16006
+ import path32 from "node:path";
15769
16007
  function readDocsRegistryAuth(npmrcPath2 = homeNpmrcPath()) {
15770
- if (!existsSync23(npmrcPath2)) return null;
15771
- return parseNpmrcRegistryAuth(readFileSync26(npmrcPath2, "utf-8"));
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 ?? path31.join(homeDir(), ".cache");
15822
- return path31.join(base, "mesh", "docs");
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 = path31.join(cacheRoot, version);
15829
- if (existsSync23(path31.join(targetDir, "dist", "index.html"))) return targetDir;
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
- mkdirSync13(cacheRoot, { recursive: true });
15851
- const tgzPath = path31.join(cacheRoot, `.${version}.tgz`);
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 = path31.join(cacheRoot, `.staging-${version}`);
16091
+ const staging = path32.join(cacheRoot, `.staging-${version}`);
15854
16092
  rmSync6(staging, { recursive: true, force: true });
15855
- mkdirSync13(staging, { recursive: true });
16093
+ mkdirSync14(staging, { recursive: true });
15856
16094
  try {
15857
- execFileSync21("tar", ["-xzf", tgzPath, "-C", staging, "--strip-components", "1"], {
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 (!existsSync23(path31.join(staging, "dist", "index.html"))) {
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 execFileSync22 } from "node:child_process";
15896
- import { appendFileSync as appendFileSync2, existsSync as existsSync24, writeFileSync as writeFileSync18 } from "node:fs";
15897
- import path32 from "node:path";
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
- execFileSync22("tmux", ["-V"], { stdio: ["pipe", "pipe", "pipe"] });
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
- execFileSync22("tmux", ["has-session", "-t", DOCS_TMUX_SESSION], { stdio: ["pipe", "pipe", "pipe"] });
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
- execFileSync22("tmux", ["kill-session", "-t", DOCS_TMUX_SESSION], { stdio: ["pipe", "pipe", "pipe"] });
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
- execFileSync22(
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
- execFileSync22("tmux", ["kill-session", "-t", DOCS_TMUX_SESSION], { stdio: ["pipe", "pipe", "pipe"] });
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 || !existsSync24(path32.join(args.root, "index.html"))) {
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 = path32.join(artifactDir, "dist");
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 = path32.join(args.repoRoot, DOCS_APP_DIR);
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: path32.join(appDir, "content"),
16070
- configOut: path32.join(appDir, "zudoku.config.ts")
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 = path32.join(args.repoRoot, DOCS_APP_DIR, "build.log");
16087
- logInfo(`Preparing the docs from this checkout (assemble + build \u2014 log: ${path32.relative(args.repoRoot, buildLog)})\u2026`);
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: path32.join(appDir, "content"),
16091
- configOut: path32.join(appDir, "zudoku.config.ts")
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 = path32.join(appDir, "dist");
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 fs26 from "fs";
16149
- import * as path33 from "path";
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 (fs26.existsSync(path33.join(dir, "package.json"))) return dir;
16156
- const parent = path33.dirname(dir);
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 path33.isAbsolute(candidate) ? candidate : path33.join(projectRoot, candidate);
16400
+ return path34.isAbsolute(candidate) ? candidate : path34.join(projectRoot, candidate);
16163
16401
  }
16164
16402
  function ensureParentDir(filePath) {
16165
- fs26.mkdirSync(path33.dirname(filePath), { recursive: true });
16403
+ fs27.mkdirSync(path34.dirname(filePath), { recursive: true });
16166
16404
  }
16167
16405
  function readConfig2(configPath) {
16168
- if (!fs26.existsSync(configPath)) {
16406
+ if (!fs27.existsSync(configPath)) {
16169
16407
  throw new Error(`Docs config not found: ${configPath}`);
16170
16408
  }
16171
- const raw = fs26.readFileSync(configPath, "utf-8");
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 = fs26.readFileSync(specPath, "utf-8");
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(path33.join(projectRoot, "package.json"));
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 = path33.isAbsolute(configPathArg ?? "") ? configPathArg : path33.resolve(cwd, configPathArg ?? "docs/docs.config.json");
16206
- const projectRoot = findProjectRoot(path33.dirname(configPath));
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 (!fs26.existsSync(inputPath)) {
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
- fs26.copyFileSync(inputPath, outputPath);
16220
- logSuccess(`Copied OpenAPI spec \u2192 ${path33.relative(projectRoot, outputPath)}`);
16457
+ fs27.copyFileSync(inputPath, outputPath);
16458
+ logSuccess(`Copied OpenAPI spec \u2192 ${path34.relative(projectRoot, outputPath)}`);
16221
16459
  } else {
16222
- logInfo(`Using OpenAPI spec: ${path33.relative(projectRoot, inputPath)}`);
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
- fs26.writeFileSync(outputPath, JSON.stringify(spec, null, 2));
16478
+ fs27.writeFileSync(outputPath, JSON.stringify(spec, null, 2));
16241
16479
  validateOpenApiSpec(outputPath);
16242
16480
  generatedSpecs.add(outputPath);
16243
- logSuccess(`Generated SymXchange OpenAPI \u2192 ${path33.relative(projectRoot, outputPath)}`);
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 (!fs26.existsSync(abs)) {
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: ${path33.relative(projectRoot, abs)}`);
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 = fs26.existsSync(outPath) ? fs26.readFileSync(outPath, "utf-8") : null;
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 (${path33.relative(repoRoot2, outPath)})`);
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"}: ${path33.relative(repoRoot2, outPath)}
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
- fs26.writeFileSync(outPath, markdown);
16299
- logSuccess(`CLI reference \u2192 ${path33.relative(repoRoot2, outPath)}`);
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 execFileSync23 } from "node:child_process";
16380
- import * as fs27 from "node:fs";
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 path34 from "node:path";
16621
+ import * as path35 from "node:path";
16384
16622
  import chalk3 from "chalk";
16385
16623
  function devSessionsDir() {
16386
- return path34.join(os9.tmpdir(), "mesh-dev-sessions");
16624
+ return path35.join(os9.tmpdir(), "mesh-dev-sessions");
16387
16625
  }
16388
16626
  function listDevSessions(dir = devSessionsDir()) {
16389
- if (!fs27.existsSync(dir)) return [];
16627
+ if (!fs28.existsSync(dir)) return [];
16390
16628
  const sessions = [];
16391
- for (const entry of fs27.readdirSync(dir)) {
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
- fs27.readFileSync(path34.join(dir, entry), "utf-8")
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 = path34.resolve(opts.cwdAppRoot);
16424
- const match = sessions.find((s) => path34.resolve(s.state.appRoot) === root);
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 = execFileSync23("tmux", ["show-environment", "-t", sessionName], {
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
- execFileSync23("tmux", ["has-session", "-t", sessionName], { stdio: "ignore" });
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 fs27.existsSync(path34.join(dir, "apps", "hub", "api", "package.json")) && fs27.existsSync(path34.join(dir, "apps", "hub", "ui", "package.json"));
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 = path34.resolve(explicit);
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 = path34.resolve(env.MESH_PLATFORM_DIR);
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 = path34.resolve(cwd);
16805
+ let dir = path35.resolve(cwd);
16561
16806
  for (; ; ) {
16562
16807
  if (isPlatformRoot(dir)) return dir;
16563
- const parent = path34.dirname(dir);
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 path34.join(os9.tmpdir(), "mesh-dev-sessions", HUB_SESSION);
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
- execFileSync23("tmux", ["kill-session", "-t", HUB_SESSION], { stdio: "ignore" });
16626
- fs27.rmSync(hubEnvDir(), { recursive: true, force: true });
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, { tenants: opts.tenants, uiPort, apiPort });
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 = path34.join(platformDir, "apps", "hub", "api");
16678
- const uiDir = path34.join(platformDir, "apps", "hub", "ui");
16679
- execFileSync23("tmux", ["new-session", "-d", "-s", HUB_SESSION, "-n", "api", "-c", apiDir]);
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
- execFileSync23("tmux", ["new-window", "-t", HUB_SESSION, "-n", "token-server", "-c", platformDir]);
16686
- execFileSync23("tmux", ["set-option", "-t", `${HUB_SESSION}:token-server`, "remain-on-exit", "on"], {
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
- execFileSync23("tmux", [
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 = path34.join(hubEnvDir(), `${window}.env.sh`);
16958
+ const envFile = path35.join(hubEnvDir(), `${window}.env.sh`);
16705
16959
  writeEnvFile(envFile, env);
16706
16960
  if (createWindow) {
16707
- execFileSync23("tmux", ["new-window", "-t", HUB_SESSION, "-n", window, "-c", dir]);
16961
+ execFileSync24("tmux", ["new-window", "-t", HUB_SESSION, "-n", window, "-c", dir]);
16708
16962
  }
16709
- execFileSync23("tmux", ["set-option", "-t", `${HUB_SESSION}:${window}`, "remain-on-exit", "on"], {
16963
+ execFileSync24("tmux", ["set-option", "-t", `${HUB_SESSION}:${window}`, "remain-on-exit", "on"], {
16710
16964
  stdio: "ignore"
16711
16965
  });
16712
- execFileSync23("tmux", ["send-keys", "-t", `${HUB_SESSION}:${window}`, buildLaunchCommand(envFile, dir, cmd), "Enter"]);
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("--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);
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 fs28 from "fs";
16811
- import * as path35 from "path";
16812
- import { execFileSync as execFileSync24 } from "child_process";
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 = path35.resolve(cwd, flags.dir ?? defaultPlatformDir(tenant));
16842
- if (fs28.existsSync(dir) && fs28.readdirSync(dir).length > 0) {
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 execFileSync24("aws", [...args, "--profile", profile], {
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 (fs28.existsSync(setup.dir) && fs28.readdirSync(setup.dir).length > 0) {
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 = path35.join(findPackageRoot2(), "templates", "platform-repo");
16965
- fs28.mkdirSync(setup.dir, { recursive: true });
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 execFileSync25, execSync } from "child_process";
17013
- import * as fs29 from "fs";
17014
- import * as path36 from "path";
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 = fs29.readFileSync(file, "utf-8");
17281
+ const content = fs30.readFileSync(file, "utf-8");
17025
17282
  const next = content.replace(/"version"(\s*:\s*)"[^"]*"/, `"version"$1"${version}"`);
17026
- fs29.writeFileSync(file, next);
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 = path36.join(root, "scripts/lib/publishable-packages.json");
17060
- const all = JSON.parse(fs29.readFileSync(listPath, "utf-8"));
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 = path36.join(root, dir, "package.json");
17073
- if (!fs29.existsSync(file)) return;
17074
- backups.push({ file, content: fs29.readFileSync(file, "utf-8") });
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(path36.join(p.dir, typeof sub === "string" ? sub : sub.dir));
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
- execFileSync25("bash", args, { cwd: root, stdio: "inherit", env: env ?? process.env });
17353
+ execFileSync26("bash", args, { cwd: root, stdio: "inherit", env: env ?? process.env });
17097
17354
  } finally {
17098
- for (const b of backups) fs29.writeFileSync(b.file, b.content);
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
- execFileSync25("git", ["checkout", "--", ...collateral], { cwd: root, stdio: "inherit" });
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 execFileSync26 } from "child_process";
17156
- import * as fs30 from "fs";
17157
- import * as path37 from "path";
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 = execFileSync26("aws", [
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
- execFileSync26("aws", [
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 = execFileSync26("aws", [
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 = execFileSync26("aws", [
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 (fs30.existsSync(path37.join(dir, "pnpm-workspace.yaml")) || fs30.existsSync(path37.join(dir, "pnpm-lock.yaml")) || fs30.existsSync(path37.join(dir, "Pulumi.yaml")) || fs30.existsSync(path37.join(dir, ".npmrc"))) {
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 = path37.dirname(dir);
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 = path37.join(projectRoot, ".npmrc");
17595
+ const npmrcPath2 = path38.join(projectRoot, ".npmrc");
17339
17596
  const scopeLine = `${CA_NAMESPACE}:registry=${endpoint}`;
17340
- if (!fs30.existsSync(npmrcPath2)) {
17341
- fs30.writeFileSync(npmrcPath2, scopeLine + "\n", "utf-8");
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 = fs30.readFileSync(npmrcPath2, "utf-8");
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
- fs30.writeFileSync(npmrcPath2, updated, "utf-8");
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
- fs30.writeFileSync(npmrcPath2, content + separator + scopeLine + "\n", "utf-8");
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 = fs30.readFileSync(npmrcPath2, "utf-8");
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
- fs30.mkdirSync(path37.dirname(npmrcPath2), { recursive: true });
17369
- fs30.writeFileSync(npmrcPath2, content, { mode: 384 });
17625
+ fs31.mkdirSync(path38.dirname(npmrcPath2), { recursive: true });
17626
+ fs31.writeFileSync(npmrcPath2, content, { mode: 384 });
17370
17627
  try {
17371
- fs30.chmodSync(npmrcPath2, 384);
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 = fs30.readFileSync(npmrcPath2, "utf-8");
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
- fs30.writeFileSync(backupPath, original, "utf-8");
17503
- fs30.writeFileSync(npmrcPath2, content, "utf-8");
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 (!fs30.existsSync(npmrcPath2)) return { valid: false, state: "missing", reason: "no ~/.npmrc" };
17772
+ if (!fs31.existsSync(npmrcPath2)) return { valid: false, state: "missing", reason: "no ~/.npmrc" };
17516
17773
  const hijackLine = findUnscopedCodeArtifactRegistry(
17517
- fs30.readFileSync(npmrcPath2, "utf-8")
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 = path37.join(projectRoot, ".npmrc");
17571
- if (fs30.existsSync(npmrcPath2)) {
17572
- const content = fs30.readFileSync(npmrcPath2, "utf-8");
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 = () => execFileSync26("aws", ["sts", "get-caller-identity", "--profile", profile], {
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
- execFileSync26("aws", ["sso", "login", "--profile", profile], { stdio: "inherit" });
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 fs31 from "fs";
17854
- import * as path38 from "path";
17855
- import { execFileSync as execFileSync27 } from "child_process";
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 = fs31.existsSync(path38.join(root, ".git"));
18189
+ const inRepo = fs32.existsSync(path39.join(root, ".git"));
17933
18190
  if (!inRepo) {
17934
- const hasContent = fs31.readdirSync(cwd).some((entry) => !entry.startsWith("."));
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 = fs31.existsSync(path38.join(root, "pnpm-workspace.yaml")) || fs31.existsSync(path38.join(root, "pnpm-lock.yaml"));
17938
- const hasApps = fs31.existsSync(path38.join(root, "apps")) || fs31.existsSync(path38.join(root, "tenants"));
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
- execFileSync27("git", ["init", "-q"], { cwd: dir, stdio: ["ignore", "ignore", "pipe"] });
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: path38.relative(ctx.cwd, setup.dir) || "." });
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 (!fs31.existsSync(path38.join(root, "package.json"))) missing.push("package.json");
18263
- if (!fs31.existsSync(path38.join(root, "pnpm-workspace.yaml")) && !fs31.existsSync(path38.join(root, "pnpm-lock.yaml"))) {
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 fs32 from "fs";
18301
- import * as path39 from "path";
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 fs32.readFileSync(homeNpmrcPath(), "utf-8");
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 = fs32.existsSync(root) ? fs32.readdirSync(root).filter((f) => /^Pulumi\..*\.yaml$/.test(f)) : [];
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(fs32.readFileSync(path39.join(root, f), "utf-8"))
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 (!fs32.existsSync(path39.join(root, "package.json"))) shapeProblems.push("package.json");
18466
- const hasWorkspace = fs32.existsSync(path39.join(root, "pnpm-workspace.yaml")) || fs32.existsSync(path39.join(root, "pnpm-lock.yaml"));
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: path39.relative(process.cwd(), setup.dir) || "." })) {
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 execFileSync28 } from "child_process";
18591
- import * as fs33 from "fs";
18847
+ import { execFileSync as execFileSync29 } from "child_process";
18848
+ import * as fs34 from "fs";
18592
18849
  import * as os10 from "os";
18593
- import * as path40 from "path";
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 path40.join(os10.homedir(), ".local", "bin");
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(path40.delimiter).some((p) => p === dir);
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 = path40.resolve(opts.dir);
18675
- const target = path40.join(dir, "mesh");
18676
- if (fs33.existsSync(target) && !opts.force) {
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
- fs33.mkdirSync(dir, { recursive: true });
18683
- fs33.writeFileSync(target, shimScript(), { mode: 493 });
18684
- fs33.chmodSync(target, 493);
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 = path40.join(os10.tmpdir(), "mesh-shim-selftest.log");
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 = execFileSync28(target, ["--help"], {
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
- fs33.writeFileSync(diagPath, diag);
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 execFileSync29 } from "child_process";
18751
- import * as fs34 from "fs";
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 path41 from "path";
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 = path41.join(os11.homedir(), ".npmrc");
18760
- if (!fs34.existsSync(p) || !fs34.readFileSync(p, "utf-8").includes("codeartifact")) {
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
- execFileSync29("docker", ["image", "inspect", tag], { stdio: ["ignore", "pipe", "pipe"] });
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 = path41.join(findPackageRoot(), "stack", "hub");
18780
- execFileSync29(
19036
+ const hubStackDir = path42.join(findPackageRoot(), "stack", "hub");
19037
+ execFileSync30(
18781
19038
  "docker",
18782
- ["build", "-f", path41.join(hubStackDir, "Dockerfile.auth"), "-t", HUB_AUTH_IMAGE, hubStackDir],
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 = path41.join(os11.homedir(), ".npmrc");
18789
- return fs34.existsSync(p) && fs34.readFileSync(p, "utf-8").includes("codeartifact");
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 = execFileSync29("docker", ["images", name, "--format", "{{.Tag}}"], {
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: path41.join(dir, info.filename), version: info.version };
19077
+ return { tarball: path42.join(dir, info.filename), version: info.version };
18821
19078
  } catch (err) {
18822
19079
  const authFailure = isNpmAuthError(err);
18823
- const cached = fs34.readdirSync(dir).filter((f) => f.startsWith("mesh-tech-hub-") && f.endsWith(".tgz")).sort((a, b) => a.localeCompare(b, void 0, { numeric: true })).at(-1);
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: path41.join(dir, cached), version };
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 = path41.join(cacheDir(), `context-${version}`);
18871
- fs34.rmSync(context, { recursive: true, force: true });
18872
- fs34.mkdirSync(context, { recursive: true });
18873
- execFileSync29("tar", ["-xzf", tarball, "-C", context, "--strip-components", "1"], {
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 = path41.join(findPackageRoot(), "stack", "hub");
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
- execFileSync29(
19141
+ execFileSync30(
18885
19142
  "docker",
18886
19143
  [
18887
19144
  "build",
18888
19145
  "-f",
18889
- path41.join(hubStackDir, dockerfile),
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 = path41.join(cacheDir(), `context-${version}`);
18908
- const file = path41.join(context, HUB_COMPILED_AUTHZ_REL);
18909
- if (!fs34.existsSync(file)) {
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 || !fs34.existsSync(path41.join(cacheDir(), tarball))) return null;
18912
- fs34.mkdirSync(context, { recursive: true });
19168
+ if (!tarball || !fs35.existsSync(path42.join(cacheDir(), tarball))) return null;
19169
+ fs35.mkdirSync(context, { recursive: true });
18913
19170
  try {
18914
- execFileSync29(
19171
+ execFileSync30(
18915
19172
  "tar",
18916
- ["-xzf", path41.join(cacheDir(), tarball), "-C", context, "--strip-components", "1", `package/${HUB_COMPILED_AUTHZ_REL}`],
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 (!fs34.existsSync(file)) return null;
19179
+ if (!fs35.existsSync(file)) return null;
18923
19180
  }
18924
- const parsed = JSON.parse(fs34.readFileSync(file, "utf-8"));
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 = fs34.readFileSync(path41.join(repoRoot2, "pnpm-workspace.yaml"), "utf-8");
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 fs34.readdirSync(contextDir, { withFileTypes: true })) {
19201
+ for (const entry of fs35.readdirSync(contextDir, { withFileTypes: true })) {
18945
19202
  if (!entry.isDirectory()) continue;
18946
- const manifest = path41.join(contextDir, entry.name, "package.json");
18947
- if (!fs34.existsSync(manifest)) continue;
18948
- const pkg = JSON.parse(fs34.readFileSync(manifest, "utf-8"));
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
- fs34.writeFileSync(manifest, `${JSON.stringify(pkg, null, 2)}
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 = path41.join(repoRoot2, "apps", "hub");
18986
- if (!fs34.existsSync(path41.join(hubDir, "package.json"))) {
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(fs34.readFileSync(path41.join(hubDir, "package.json"), "utf-8")).version}-src`;
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 = path41.join(cacheDir(), `context-${version}`);
19003
- fs34.rmSync(context, { recursive: true, force: true });
19004
- fs34.mkdirSync(context, { recursive: true });
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 = fs34.readdirSync(context).find((f) => f.endsWith(".tgz"));
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
- execFileSync29("tar", ["-xzf", path41.join(context, tarball), "-C", context, "--strip-components", "1"], {
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 = path41.join(findPackageRoot(), "stack", "hub");
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
- execFileSync29(
19277
+ execFileSync30(
19021
19278
  "docker",
19022
- ["build", "-f", path41.join(hubStackDir, dockerfile), "-t", tag, "--secret", `id=npmrc,src=${npmrc}`, context],
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 fs35 from "fs";
19108
- import * as path42 from "path";
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
- overlayServices: hubOverlayServices
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 (fs35.existsSync(path42.join(dir, "apps", "hub", "package.json"))) return dir;
19231
- const parent = path42.dirname(dir);
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 path42.resolve(findPackageRoot(), "..", "..");
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([...STACK_ENDPOINTS, ...opts.hub ? hubEndpoints() : []]);
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
- await composeStreamed(["up", "-d"]);
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"], { hub: true, env: hubEnv });
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 overlayServices = hubOverlayServices();
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 overlayServices = hubOverlayServices();
19425
- const overlayStarted = hubOverlayRunning(services, overlayServices);
19426
- const notStarted = (s) => !overlayStarted && overlayServices.has(s.name) && s.state === "exited";
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 = hasHub ? [...STACK_ENDPOINTS, ...hubEndpoints()] : STACK_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(" (Hub not started this run)") : "";
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, { overlayServices, overlayStarted });
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 join38, relative as relative11, resolve as resolve17, sep as sep6 } from "node:path";
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 = join38(dir, entry.name);
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 execFileSync30 } from "child_process";
20713
- import * as path43 from "path";
20714
- import * as fs36 from "fs";
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 = path43.join(appRoot, `Pulumi.${stack}.yaml`);
20718
- if (!fs36.existsSync(configFile)) return null;
20719
- const content = fs36.readFileSync(configFile, "utf-8");
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 = path43.join(appRoot, `Pulumi.${stack}.yaml`);
20727
- if (!fs36.existsSync(configFile)) return null;
20728
- const content = fs36.readFileSync(configFile, "utf-8");
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 = path43.join(appRoot, `Pulumi.${stack}.yaml`);
20789
- if (!fs36.existsSync(file)) return {};
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(fs36.readFileSync(file, "utf-8"));
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 = execFileSync30("gh", ["api", "user", "--jq", ".login"], {
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 = execFileSync30("git", ["config", "user.email"], {
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 (!fs36.existsSync(baseConfigPath)) {
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 = path43.join(appRoot, `Pulumi.${newStack}.yaml`);
20892
- const configExists = fs36.existsSync(newConfigPath);
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 = execFileSync30("pulumi", ["stack", "ls", "--json"], {
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
- execFileSync30("pulumi", initArgs, {
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
- execFileSync30("pulumi", ["stack", "select", newStack], {
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 = execFileSync30(
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
- execFileSync30(
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
- execFileSync30(
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
- execFileSync30(
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
- execFileSync30("pulumi", ["config", "set", ...args], {
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
- execFileSync30("pulumi", ["config", "set", "--type", "bool", "mesh:deploy", "false"], {
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
- execFileSync30("pulumi", args, { cwd: appRoot, env: pulumiEnv, stdio: "inherit" });
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 execFileSync31 } from "child_process";
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 = execFileSync31(
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 mkdirSync19 } from "node:fs";
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 join40, resolve as resolve18 } from "node:path";
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 ?? join40(homedir6(), ".mesh", "replay-histories", `${sanitizeFileId(workflowId)}.json`);
21970
- mkdirSync19(dirname28(outPath), { recursive: true });
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 fs37 from "fs";
22162
- import * as path44 from "path";
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 = path44.join(appRoot, `Pulumi.${stack}.yaml`);
22231
- if (!fs37.existsSync(file)) {
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: fs37.readFileSync(file, "utf-8") };
22537
+ return { appRoot, stack, file, content: fs38.readFileSync(file, "utf-8") };
22237
22538
  }
22238
22539
  function readProjectName(appRoot) {
22239
- const projectDoc = parseDocument(fs37.readFileSync(path44.join(appRoot, "Pulumi.yaml"), "utf-8"));
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} (${path44.basename(resolved.file)}). Edit the existing entry instead of re-adding it.`
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, fs37.statSync(resolved.file).mode & 511);
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 ${path44.basename(resolved.file)} (mesh:tenants, subdomain '${subdomain}')${result.createdTenantsBlock ? " \u2014 created the mesh:tenants block" : ""}`
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 ${path44.basename(resolved.file)}.`);
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 fs38 from "fs";
22649
+ import * as fs39 from "fs";
22349
22650
  import * as os12 from "os";
22350
- import * as path45 from "path";
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 = fs38.readdirSync(".").filter((f) => f.startsWith("Pulumi.") && f.endsWith(".yaml")).sort((a, b) => rank(a) - rank(b));
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 = fs38.readFileSync(f, "utf-8").match(/^\s*aws:region:\s*["']?([^"'\n]+)["']?/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
- [path45.join(os12.homedir(), ".aws", "config"), `[profile ${name}]`],
22382
- [path45.join(os12.homedir(), ".aws", "credentials"), `[${name}]`]
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 = fs38.readFileSync(file, "utf-8").split("\n");
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(fs38.readFileSync(file, "utf-8"), header);
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
- [path45.join(os12.homedir(), ".aws", "config"), "[default]"],
22424
- [path45.join(os12.homedir(), ".aws", "credentials"), "[default]"]
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(fs38.readFileSync(file, "utf-8"), header);
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, path47, method = "GET", body) {
22818
- const res = await fetch(`${baseUrl}${path47}`, {
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} ${path47} failed (${res.status}): ${String(data.error ?? "unknown error")}`
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 join43, dirname as dirname29 } from "node:path";
22876
- async function getCommand(repo, path47, opts) {
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, path47);
23192
+ const { ref, files } = await reader.readPath(repo, path48);
22892
23193
  if (files.length === 0) {
22893
- logInfo(`no files at ${repo}:${path47}`);
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 = join43(opts.output, f.path);
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}:${path47} (${ref}) \u2192 ${opts.output}`);
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, path47, method = "GET", body) {
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}${path47}`, method, body);
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 join44 } from "node:path";
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, path47) {
23019
- const buf = await readFile3(join44(cwd, path47));
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: path47, content: asUtf8 };
23323
+ return { op: "write", path: path48, content: asUtf8 };
23023
23324
  }
23024
- return { op: "write", path: path47, content: buf.toString("base64"), encoding: "base64" };
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 path47 = opts.revise ? `/v1/repos/${target.repo}/proposals/${opts.revise}/revisions` : `/v1/repos/${target.repo}/proposals`;
23069
- const data = await vcsApi(target.baseUrl, token, path47, "POST", body);
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 join45 } from "node:path";
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 path47 = normalize2(raw);
23092
- if (path47.startsWith("/") || path47.split("/").includes("..")) {
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 === path47);
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(`${path47}/`));
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> ${path47}`
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(join45(tmpdir10(), "mesh-vcs-rm-"));
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((path47) => ({ op: "delete", path: path47 }))
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, path47, method = "GET", body) {
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}${path47}`, method, body);
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: path47 } = queue.shift();
23318
- if (targetIds.has(id)) return path47;
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: [...path47, neighbor.to] });
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 path47 = [];
23624
- for (let c = found; c !== void 0; c = prev.get(c)) path47.unshift(c);
23625
- for (let i = 0; i < path47.length - 1; i++) mainEdgeKeys.add(edgeKey(path47[i], path47[i + 1]));
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 = path47;
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(path47) {
24164
- return path47.length > 0 ? z4.core.toDotPath(path47) : "(root)";
24464
+ function formatPath(path48) {
24465
+ return path48.length > 0 ? z4.core.toDotPath(path48) : "(root)";
24165
24466
  }
24166
24467
  function issueToDiagnostic(issue) {
24167
- const path47 = formatPath(issue.path);
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: `${path47}: ${issue.message}`,
24179
- path: path47
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, path47) => {
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: path47,
24352
- message: `Actor "${actorId}" is referenced at ${z4.core.toDotPath(path47)} but not declared in process.actors. Declare the actor (label, and optionally category/selector) or fix the reference.`,
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, path47) => {
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: path47,
24363
- message: `Selector "${selector}" is referenced at ${z4.core.toDotPath(path47)} but not declared in process.selectors. Declare the selector or fix the reference.`,
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, path47) => {
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: path47,
24384
- message: `Duplicate ${kindLabel} id "${id}": ${kind} at ${z4.core.toDotPath(path47)} collides with ${first.kind} at ${z4.core.toDotPath(first.path)}.`,
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: path47 });
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, path47) => {
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 ${path47} is not in the predicate registry.`,
24443
- path: path47
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 path47 = Array.isArray(outcome.when) ? `${whenPath}[${triggerIndex}]` : whenPath;
24804
+ const path48 = Array.isArray(outcome.when) ? `${whenPath}[${triggerIndex}]` : whenPath;
24504
24805
  if (trigger.kind === "predicate") {
24505
- checkPredicate(trigger.name, `${path47}.predicate`);
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, `${path47}.command`);
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}" (${path47}.command) does not exist in the inventory.`,
24515
- path: `${path47}.command`
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 fs39 from "fs";
24628
- import * as path46 from "path";
24928
+ import * as fs40 from "fs";
24929
+ import * as path47 from "path";
24629
24930
  import { createRequire as createRequire2 } from "module";
24630
- import { execFileSync as execFileSync32 } from "child_process";
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(fs39.readFileSync(explicitProcessPath, "utf-8"));
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 = execFileSync32("npx", ["tsx", "--eval", script], {
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 = execFileSync32("npx", ["tsx", "--eval", script], {
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(fs39.readFileSync(explicitProcessPath, "utf-8"));
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 = execFileSync32("npx", ["tsx", "--eval", script], {
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 = path46.resolve(targetPath);
24853
- if (!fs39.existsSync(resolvedPath)) {
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 = path46.resolve(opts.process);
24861
- if (!fs39.existsSync(resolvedProcessPath)) {
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 = path46.resolve(targetPath);
24911
- if (!fs39.existsSync(resolvedPath)) {
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 = path46.resolve(targetPath);
24958
- if (!fs39.existsSync(resolvedPath)) {
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 = path46.resolve(opts.process);
24966
- if (!fs39.existsSync(resolvedProcessPath)) {
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;