@mesh-tech/mesh-cli 0.43.3 → 0.45.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.
Files changed (62) hide show
  1. package/dist/bin/{mesh.auth-preflight-JTUNS42O.js → mesh.auth-preflight-3ASNYA3I.js} +1 -1
  2. package/dist/bin/{mesh.chunk-QE5LUIHN.js → mesh.chunk-252LTIHZ.js} +2 -2
  3. package/dist/bin/{mesh.chunk-TYM27CO3.js → mesh.chunk-4Y3JGAYZ.js} +1 -1
  4. package/dist/bin/{mesh.chunk-OOWKJR4H.js → mesh.chunk-6OGUV2DU.js} +1 -1
  5. package/dist/bin/{mesh.chunk-VCQKLVZJ.js → mesh.chunk-G4TCVQLL.js} +603 -145
  6. package/dist/bin/mesh.chunk-G4TCVQLL.js.map +6 -0
  7. package/dist/bin/{mesh.chunk-ZNM3DDAM.js → mesh.chunk-HPLMVIBO.js} +1 -1
  8. package/dist/bin/{mesh.chunk-QUKWWFZI.js → mesh.chunk-JSY6THRF.js} +1 -1
  9. package/dist/bin/{mesh.chunk-PANTMVC3.js → mesh.chunk-NN3LTNUM.js} +3 -3
  10. package/dist/bin/{mesh.chunk-HB2IZKLP.js → mesh.chunk-SFIJZF3S.js} +786 -276
  11. package/dist/bin/{mesh.chunk-HB2IZKLP.js.map → mesh.chunk-SFIJZF3S.js.map} +3 -3
  12. package/dist/bin/{mesh.chunk-HC7V75J3.js → mesh.chunk-UJAPUO2W.js} +1 -1
  13. package/dist/bin/{mesh.create-app-DVMZDEQP.js → mesh.create-app-BHB3BGH7.js} +3 -3
  14. package/dist/bin/{mesh.dev-token-server-4N6HGQAF.js → mesh.dev-token-server-6TNWX5TY.js} +2 -2
  15. package/dist/bin/mesh.js +9 -9
  16. package/dist/bin/{mesh.login-Q6R5GMVM.js → mesh.login-4O5PMS25.js} +2 -2
  17. package/dist/bin/{mesh.platform-setup-YK6KSOP7.js → mesh.platform-setup-MTY6ICAO.js} +1 -1
  18. package/dist/bin/{mesh.program-GEKNV2LY.js → mesh.program-CMOLQWZI.js} +9 -9
  19. package/dist/bin/{mesh.registry-KA3CNNPZ.js → mesh.registry-BDBH6DRP.js} +4 -4
  20. package/dist/bin/{mesh.registry-identity-DSTAHXUS.js → mesh.registry-identity-QOGDEMZO.js} +3 -3
  21. package/dist/bin/{mesh.review-command-3ZXPS6Y3.js → mesh.review-command-E7V2L5AM.js} +3 -3
  22. package/dist/bin/{mesh.start-HE6P3TCS.js → mesh.start-3MUKXN2U.js} +2 -2
  23. package/dist/bin/{mesh.wizard-QGWPV4XN.js → mesh.wizard-EH3SQEHW.js} +7 -7
  24. package/dist/build-info.json +2 -2
  25. package/dist/src/commands/dev.d.ts +1 -0
  26. package/dist/src/commands/dev.js +57 -1
  27. package/dist/src/commands/temporal.js +146 -42
  28. package/dist/src/commands/temporal.js.map +3 -3
  29. package/dist/src/commands/workflow.d.ts +14 -0
  30. package/dist/src/commands/workflow.js +43 -31
  31. package/dist/src/commands/workstation.d.ts +3 -0
  32. package/dist/src/commands/workstation.js +395 -0
  33. package/dist/src/program.js +2 -0
  34. package/dist/src/utils/temporal-inspect.d.ts +17 -0
  35. package/dist/src/utils/temporal-inspect.js +71 -0
  36. package/dist/src/utils/workstation-machine.d.ts +54 -0
  37. package/dist/src/utils/workstation-machine.js +282 -0
  38. package/dist/src/utils/workstation-routes.d.ts +77 -0
  39. package/dist/src/utils/workstation-routes.js +180 -0
  40. package/fragments/base/README.md.hbs +3 -0
  41. package/package.json +2 -2
  42. package/skills/mesh/SKILL.md +5 -4
  43. package/skills/mesh/references/worktrees.md +4 -1
  44. package/dist/bin/mesh.chunk-VCQKLVZJ.js.map +0 -6
  45. /package/dist/bin/{mesh.auth-preflight-JTUNS42O.js.map → mesh.auth-preflight-3ASNYA3I.js.map} +0 -0
  46. /package/dist/bin/{mesh.chunk-QE5LUIHN.js.map → mesh.chunk-252LTIHZ.js.map} +0 -0
  47. /package/dist/bin/{mesh.chunk-TYM27CO3.js.map → mesh.chunk-4Y3JGAYZ.js.map} +0 -0
  48. /package/dist/bin/{mesh.chunk-OOWKJR4H.js.map → mesh.chunk-6OGUV2DU.js.map} +0 -0
  49. /package/dist/bin/{mesh.chunk-ZNM3DDAM.js.map → mesh.chunk-HPLMVIBO.js.map} +0 -0
  50. /package/dist/bin/{mesh.chunk-QUKWWFZI.js.map → mesh.chunk-JSY6THRF.js.map} +0 -0
  51. /package/dist/bin/{mesh.chunk-PANTMVC3.js.map → mesh.chunk-NN3LTNUM.js.map} +0 -0
  52. /package/dist/bin/{mesh.chunk-HC7V75J3.js.map → mesh.chunk-UJAPUO2W.js.map} +0 -0
  53. /package/dist/bin/{mesh.create-app-DVMZDEQP.js.map → mesh.create-app-BHB3BGH7.js.map} +0 -0
  54. /package/dist/bin/{mesh.dev-token-server-4N6HGQAF.js.map → mesh.dev-token-server-6TNWX5TY.js.map} +0 -0
  55. /package/dist/bin/{mesh.login-Q6R5GMVM.js.map → mesh.login-4O5PMS25.js.map} +0 -0
  56. /package/dist/bin/{mesh.platform-setup-YK6KSOP7.js.map → mesh.platform-setup-MTY6ICAO.js.map} +0 -0
  57. /package/dist/bin/{mesh.program-GEKNV2LY.js.map → mesh.program-CMOLQWZI.js.map} +0 -0
  58. /package/dist/bin/{mesh.registry-KA3CNNPZ.js.map → mesh.registry-BDBH6DRP.js.map} +0 -0
  59. /package/dist/bin/{mesh.registry-identity-DSTAHXUS.js.map → mesh.registry-identity-QOGDEMZO.js.map} +0 -0
  60. /package/dist/bin/{mesh.review-command-3ZXPS6Y3.js.map → mesh.review-command-E7V2L5AM.js.map} +0 -0
  61. /package/dist/bin/{mesh.start-HE6P3TCS.js.map → mesh.start-3MUKXN2U.js.map} +0 -0
  62. /package/dist/bin/{mesh.wizard-QGWPV4XN.js.map → mesh.wizard-EH3SQEHW.js.map} +0 -0
@@ -7,40 +7,48 @@ import {
7
7
  parseInstanceIndex,
8
8
  resolveSecretsContext,
9
9
  setCommand
10
- } from "./mesh.chunk-QUKWWFZI.js";
10
+ } from "./mesh.chunk-JSY6THRF.js";
11
11
  import {
12
12
  cliReferenceStaleness,
13
13
  resolveCliRuntime,
14
14
  runPortalCommand
15
- } from "./mesh.chunk-OOWKJR4H.js";
15
+ } from "./mesh.chunk-6OGUV2DU.js";
16
16
  import {
17
17
  registerAppCommands,
18
18
  registerCreateAppCommand
19
- } from "./mesh.chunk-QE5LUIHN.js";
19
+ } from "./mesh.chunk-252LTIHZ.js";
20
20
  import {
21
21
  PLATFORM_SETUP_DEFAULTS
22
- } from "./mesh.chunk-ZNM3DDAM.js";
22
+ } from "./mesh.chunk-HPLMVIBO.js";
23
23
  import {
24
24
  registerRegistryCommands
25
- } from "./mesh.chunk-PANTMVC3.js";
25
+ } from "./mesh.chunk-NN3LTNUM.js";
26
26
  import {
27
27
  registerSkillsCommands,
28
28
  resolveTargetRoot,
29
29
  syncSkills
30
30
  } from "./mesh.chunk-F4654EPX.js";
31
31
  import {
32
+ LAUNCH_AGENTS_MACOS_ONLY,
33
+ LAUNCH_AGENT_LABEL,
32
34
  LOGIN_CONTEXT,
33
35
  MOCK_OIDC_PORT,
34
36
  MOCK_SAML_PORT,
35
37
  TEST_USERS,
36
38
  acquireTemporalBearer,
37
39
  atomicWriteFileSync,
40
+ awsConfigFileOf,
38
41
  buildLaunchCommand,
42
+ caddyDownloadUrl,
43
+ caddyHasRoute53,
44
+ certificateExpiry,
39
45
  credProbeToPreflightError,
46
+ credentialProcessProblem,
40
47
  derivePlatformContext,
41
48
  detectContext,
42
49
  detectLocalTenant,
43
50
  devSessionsRoot,
51
+ discoveryRecordName,
44
52
  ensureKubeconfig,
45
53
  findAppRoot,
46
54
  findRepoRoot,
@@ -51,34 +59,52 @@ import {
51
59
  getValidToken,
52
60
  hubAuthComposeEnv,
53
61
  idpEndpoints,
62
+ isInsideGitTree,
63
+ launchAgentSearchPath,
64
+ launchAgentsSupported,
65
+ listRoutes,
54
66
  mockIdpComposeEnv,
67
+ parseDiscoveryRecord,
55
68
  pickLaunchHostEnv,
56
69
  probeCredentials,
70
+ profileYieldsCredentials,
71
+ proxyEnv,
57
72
  pulumiStackOutput,
73
+ readCredentialProcess,
58
74
  readCredentials,
59
75
  readHubAuth,
60
76
  readStackConfig,
61
77
  readStackPlatform,
78
+ readWorkstationIdentity,
62
79
  reconcileRegistryFromZitadel,
63
80
  registerDevCommand,
64
81
  registerLoginCommand,
65
82
  registerVpnCommands,
66
83
  removeAllAliasContainers,
67
84
  removeLocalAppSpiceDBs,
85
+ renderCredentialProcessProfile,
86
+ renderLaunchAgent,
87
+ renderWorkstationCaddyfile,
68
88
  resolveAwsCredentials,
69
89
  resolveHubPlatformName,
70
90
  resolvePulumiEnv,
71
91
  resolveTemporalAuth,
72
92
  resolveWorktreeIdentity,
93
+ rewriteCredentialProgram,
73
94
  rewriteDatabaseUrl,
74
95
  seedMockIdps,
75
96
  seedZitadel,
97
+ shimFallsBackToGlobal,
76
98
  stackNeedsWorktreeIsolation,
77
99
  tunnelClientAddress,
100
+ upsertManagedAwsConfigSection,
78
101
  waitForPort,
102
+ workstationDir,
103
+ workstationWarnings,
79
104
  worktreeStackName,
80
- writeEnvFile
81
- } from "./mesh.chunk-HB2IZKLP.js";
105
+ writeEnvFile,
106
+ zoneCandidates
107
+ } from "./mesh.chunk-SFIJZF3S.js";
82
108
  import {
83
109
  COMPOSE_PROJECT,
84
110
  DEFAULT_HUB_PORT,
@@ -127,7 +153,7 @@ import {
127
153
  homeNpmrcPath,
128
154
  isNpmAuthError,
129
155
  probeRegistryToken
130
- } from "./mesh.chunk-HC7V75J3.js";
156
+ } from "./mesh.chunk-UJAPUO2W.js";
131
157
  import {
132
158
  createVcsFolderReader,
133
159
  deriveVcsBaseUrl,
@@ -864,26 +890,26 @@ async function startTunnelBackground(instanceId, rdsHost, rdsPort, localPort) {
864
890
  throw new Error(`Tunnel failed to start after ${maxAttempts} seconds`);
865
891
  }
866
892
  function checkPort(port) {
867
- return new Promise((resolve8) => {
893
+ return new Promise((resolve9) => {
868
894
  const socket = new net.Socket();
869
895
  socket.setTimeout(500);
870
896
  socket.on("connect", () => {
871
897
  socket.destroy();
872
- resolve8(true);
898
+ resolve9(true);
873
899
  });
874
900
  socket.on("timeout", () => {
875
901
  socket.destroy();
876
- resolve8(false);
902
+ resolve9(false);
877
903
  });
878
904
  socket.on("error", () => {
879
905
  socket.destroy();
880
- resolve8(false);
906
+ resolve9(false);
881
907
  });
882
908
  socket.connect(port, "localhost");
883
909
  });
884
910
  }
885
911
  function sleep(ms) {
886
- return new Promise((resolve8) => setTimeout(resolve8, ms));
912
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
887
913
  }
888
914
  async function psqlCommand(options) {
889
915
  const platform = platformAxis(options, USAGE4);
@@ -894,13 +920,13 @@ async function psqlCommand(options) {
894
920
  logInfo(`App credentials: tenant=${app.tenant}, stage=${app.stage}, app=${appName}`);
895
921
  }
896
922
  const psqlCheck = spawn2("which", ["psql"]);
897
- await new Promise((resolve8, reject) => {
923
+ await new Promise((resolve9, reject) => {
898
924
  psqlCheck.on("exit", (code) => {
899
925
  if (code !== 0) {
900
926
  logError("psql not found. Install with: brew install postgresql");
901
927
  reject(new Error("psql not found"));
902
928
  } else {
903
- resolve8();
929
+ resolve9();
904
930
  }
905
931
  });
906
932
  });
@@ -984,26 +1010,26 @@ function findSstOutputs() {
984
1010
  return null;
985
1011
  }
986
1012
  function checkPort2(port) {
987
- return new Promise((resolve8) => {
1013
+ return new Promise((resolve9) => {
988
1014
  const socket = new net2.Socket();
989
1015
  socket.setTimeout(500);
990
1016
  socket.on("connect", () => {
991
1017
  socket.destroy();
992
- resolve8(true);
1018
+ resolve9(true);
993
1019
  });
994
1020
  socket.on("timeout", () => {
995
1021
  socket.destroy();
996
- resolve8(false);
1022
+ resolve9(false);
997
1023
  });
998
1024
  socket.on("error", () => {
999
1025
  socket.destroy();
1000
- resolve8(false);
1026
+ resolve9(false);
1001
1027
  });
1002
1028
  socket.connect(port, "localhost");
1003
1029
  });
1004
1030
  }
1005
1031
  function sleep2(ms) {
1006
- return new Promise((resolve8) => setTimeout(resolve8, ms));
1032
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
1007
1033
  }
1008
1034
  async function startTunnelBackground2(instanceId, rdsEndpoint, rdsPort, localPort) {
1009
1035
  logInfo("Starting database tunnel...");
@@ -1542,7 +1568,7 @@ var DOCS_PREVIEW_PORT = "4410";
1542
1568
  var CLI_REFERENCE_PATH = "docs/portal/generated/cli-reference.md";
1543
1569
  async function renderCliReference() {
1544
1570
  const [{ createProgram: createProgram2 }, { extractCliReference, renderCliReferenceMarkdown }] = await Promise.all([
1545
- import("./mesh.program-GEKNV2LY.js"),
1571
+ import("./mesh.program-CMOLQWZI.js"),
1546
1572
  import("./mesh.cli-reference-H3TOPIET.js")
1547
1573
  ]);
1548
1574
  return renderCliReferenceMarkdown(extractCliReference(createProgram2()));
@@ -1614,7 +1640,7 @@ function registerDocsCommand(program) {
1614
1640
  "Serve the Mesh docs locally \u2014 detached in a tmux session by default; the working tree in a mesh-platform checkout, or the published @mesh-tech/docs artifact (role-gated registry) anywhere else"
1615
1641
  ).option("-v, --version <version>", "docs version to serve (== the @mesh-tech/* baseline it describes); default: latest", void 0).option("-p, --port <port>", "port to serve on (0 picks a free one)", "4400").option("--dev", "in a checkout: run the Zudoku dev server (HMR) in the foreground, for authoring", false).option("--foreground", "serve in the foreground (the agent/CI path; automatic when not a TTY)", false).action(
1616
1642
  (opts) => guarded(async () => {
1617
- const { runDocsStart } = await import("./mesh.start-HE6P3TCS.js");
1643
+ const { runDocsStart } = await import("./mesh.start-3MUKXN2U.js");
1618
1644
  await runDocsStart({
1619
1645
  repoRoot: findRepoRoot(process.cwd()),
1620
1646
  version: opts.version,
@@ -1626,13 +1652,13 @@ function registerDocsCommand(program) {
1626
1652
  );
1627
1653
  docs.command("stop").description(`Stop the detached docs server (the tmux session "${"mesh-docs"}")`).action(
1628
1654
  () => guarded(async () => {
1629
- const { runDocsStop } = await import("./mesh.start-HE6P3TCS.js");
1655
+ const { runDocsStop } = await import("./mesh.start-3MUKXN2U.js");
1630
1656
  runDocsStop();
1631
1657
  })()
1632
1658
  );
1633
1659
  docs.command("serve-static", { hidden: true }).option("--root <dir>", "built site root", "").option("--port <port>", "port", "4400").action(
1634
1660
  (opts) => guarded(async () => {
1635
- const { runDocsServeStatic } = await import("./mesh.start-HE6P3TCS.js");
1661
+ const { runDocsServeStatic } = await import("./mesh.start-3MUKXN2U.js");
1636
1662
  await runDocsServeStatic(opts);
1637
1663
  })()
1638
1664
  );
@@ -1675,7 +1701,7 @@ function registerDocsCommand(program) {
1675
1701
  );
1676
1702
  docs.command("list").description("List the published docs versions (each is an @mesh-tech/* baseline)").action(
1677
1703
  () => guarded(async () => {
1678
- const { runDocsList } = await import("./mesh.start-HE6P3TCS.js");
1704
+ const { runDocsList } = await import("./mesh.start-3MUKXN2U.js");
1679
1705
  await runDocsList();
1680
1706
  })()
1681
1707
  );
@@ -1954,24 +1980,24 @@ function resolvePlatformDir(explicit, cwd, env = process.env) {
1954
1980
  );
1955
1981
  }
1956
1982
  async function findFreePort() {
1957
- return new Promise((resolve8, reject) => {
1983
+ return new Promise((resolve9, reject) => {
1958
1984
  const server = net3.createServer();
1959
1985
  server.listen(0, "127.0.0.1", () => {
1960
1986
  const address = server.address();
1961
1987
  server.close(
1962
- () => typeof address === "object" && address ? resolve8(address.port) : reject(new Error("no port"))
1988
+ () => typeof address === "object" && address ? resolve9(address.port) : reject(new Error("no port"))
1963
1989
  );
1964
1990
  });
1965
1991
  server.on("error", reject);
1966
1992
  });
1967
1993
  }
1968
1994
  function isPortListening(port) {
1969
- return new Promise((resolve8) => {
1995
+ return new Promise((resolve9) => {
1970
1996
  const socket = net3.connect({ host: "127.0.0.1", port, timeout: 400 });
1971
1997
  const done = (ok) => {
1972
1998
  socket.removeAllListeners();
1973
1999
  socket.destroy();
1974
- resolve8(ok);
2000
+ resolve9(ok);
1975
2001
  };
1976
2002
  socket.once("connect", () => done(true));
1977
2003
  socket.once("timeout", () => done(false));
@@ -2198,7 +2224,7 @@ async function registryChecks(args) {
2198
2224
  const { fix, profile } = args;
2199
2225
  const probe = args.probe ?? probeRegistryToken;
2200
2226
  const login = args.login ?? (async () => {
2201
- const { runRegistryLogin } = await import("./mesh.registry-KA3CNNPZ.js");
2227
+ const { runRegistryLogin } = await import("./mesh.registry-BDBH6DRP.js");
2202
2228
  await runRegistryLogin(void 0, profile ? { profile } : {});
2203
2229
  });
2204
2230
  const REGISTRY_FIX = registryFixCommand(profile);
@@ -2354,7 +2380,7 @@ function registerInitCommands(program) {
2354
2380
  `nothing deployed yet \u2014 scaffold a tenant platform repo for \`<tenant>.<env>\` (default env: ${PLATFORM_SETUP_DEFAULTS.env}) and print its deploy sequence`
2355
2381
  ).option("--region <region>", `--new-platform: AWS region (default: ${PLATFORM_SETUP_DEFAULTS.region})`).option("--domain <domain>", "--new-platform: base public domain you control; the core stack creates the zone {env}.{domain} and stops at the mesh-gateway Ingress until you delegate its NS records. No default \u2014 a placeholder scaffolds a zone that can never validate").option("--state-bucket <bucket>", "--new-platform: Pulumi state S3 bucket (default: {tenant}-mesh-platform-pulumi-state)").option("--create-state-bucket", "--new-platform: create the state bucket (versioned) if it does not exist").option("--no-create-state-bucket", "--new-platform: never create the state bucket; print the aws command instead").option("--dir <path>", "--new-platform: where to scaffold the platform repo (default: ./{tenant}-mesh-platform)").option("--device", "device-code sign-in for the registry and platform steps (headless / SSH)").option("--profile <aws-profile>", "AWS profile this machine uses: read the registry without the broker (deployers only), and the profile a --new-platform stack config references").option("--skip-repo", "do not bootstrap, check or record anything in the current repo", false).option("--yes", "accept every default and never prompt", false).option("--json", "one JSON document on stdout ({tenant, mode, steps, next}); human output on stderr", false).action(
2356
2382
  async (opts) => {
2357
- const { runInitWizard } = await import("./mesh.wizard-QGWPV4XN.js");
2383
+ const { runInitWizard } = await import("./mesh.wizard-EH3SQEHW.js");
2358
2384
  const code = await runInitWizard(opts);
2359
2385
  if (code !== 0) process.exitCode = code;
2360
2386
  }
@@ -2370,7 +2396,7 @@ function registerInitCommands(program) {
2370
2396
  throw new MeshCliError(`Invalid tenant name '${tenant}' (lowercase alphanumeric + dashes).`);
2371
2397
  }
2372
2398
  const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
2373
- const { resolvePlatformSetup, scaffoldPlatformRepo, ensureStateBucket, renderPlatformNextSteps } = await import("./mesh.platform-setup-YK6KSOP7.js");
2399
+ const { resolvePlatformSetup, scaffoldPlatformRepo, ensureStateBucket, renderPlatformNextSteps } = await import("./mesh.platform-setup-MTY6ICAO.js");
2374
2400
  const setup = await resolvePlatformSetup(tenant, opts, {
2375
2401
  prompts: interactive && !opts.yes ? await setupPrompts() : void 0,
2376
2402
  interactive
@@ -3002,7 +3028,7 @@ async function waitForStack(opts, io = {
3002
3028
  );
3003
3029
  }
3004
3030
  logInfo(`Waiting for ${pending.map((e) => e.label).join(", ")} \u2026`);
3005
- await new Promise((resolve8) => setTimeout(resolve8, WAIT_POLL_MS));
3031
+ await new Promise((resolve9) => setTimeout(resolve9, WAIT_POLL_MS));
3006
3032
  }
3007
3033
  }
3008
3034
  function printEndpoints(hubRunning) {
@@ -3259,7 +3285,7 @@ Re-running start from here may recreate shared containers with this checkout's c
3259
3285
  for (let i = 0; i < 60 && !up; i++) {
3260
3286
  const crashed = crashedServices(stackServices(), { overlays });
3261
3287
  if (crashed.length > 0) throw crashError(crashed);
3262
- await new Promise((resolve8) => setTimeout(resolve8, 2e3));
3288
+ await new Promise((resolve9) => setTimeout(resolve9, 2e3));
3263
3289
  up = await probeEndpoint(endpoint);
3264
3290
  }
3265
3291
  if (!up) {
@@ -3399,7 +3425,7 @@ function registerMcpCommands(program) {
3399
3425
  "--secret <id>",
3400
3426
  "Secrets Manager secret holding the Integration credential (default: the deployed ExternalService's own secret)"
3401
3427
  ).action(async (manifest, opts) => {
3402
- const { runMcpReviewCommand } = await import("./mesh.review-command-3ZXPS6Y3.js");
3428
+ const { runMcpReviewCommand } = await import("./mesh.review-command-E7V2L5AM.js");
3403
3429
  try {
3404
3430
  await runMcpReviewCommand(manifest, opts);
3405
3431
  } catch (error) {
@@ -3434,7 +3460,7 @@ function registerMcpCommands(program) {
3434
3460
  `No pnpm-workspace.yaml above ${serveDir}: the worker image installs this package from a pnpm workspace, so it must be in one.`
3435
3461
  );
3436
3462
  } else if (!membership.member && membership.suggestedGlob) {
3437
- const { ensureWorkspaceGlobs } = await import("./mesh.create-app-DVMZDEQP.js");
3463
+ const { ensureWorkspaceGlobs } = await import("./mesh.create-app-BHB3BGH7.js");
3438
3464
  const added = ensureWorkspaceGlobs(path9.dirname(membership.workspaceFile), [
3439
3465
  membership.suggestedGlob
3440
3466
  ]);
@@ -4790,6 +4816,69 @@ Specify which to base on: mesh stack init --from <stack>`
4790
4816
  });
4791
4817
  }
4792
4818
 
4819
+ // packages/mesh-cli/src/utils/temporal-inspect.ts
4820
+ import { createRequire as createRequire2 } from "node:module";
4821
+ function enumMemberName(member, prefix) {
4822
+ return member.slice(prefix.length).toLowerCase().split("_").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
4823
+ }
4824
+ function eventTypeNames(enumObject = loadEventTypeEnum()) {
4825
+ const names = {};
4826
+ for (const [member, value] of Object.entries(enumObject)) {
4827
+ if (typeof value === "number" && member.startsWith("EVENT_TYPE_") && value !== 0) {
4828
+ names[value] = enumMemberName(member, "EVENT_TYPE_");
4829
+ }
4830
+ }
4831
+ return names;
4832
+ }
4833
+ function loadEventTypeEnum() {
4834
+ try {
4835
+ const require2 = createRequire2(import.meta.url);
4836
+ const fromClient = createRequire2(require2.resolve("@temporalio/client"));
4837
+ const proto = fromClient("@temporalio/proto");
4838
+ return proto.temporal.api.enums.v1.EventType;
4839
+ } catch {
4840
+ return {};
4841
+ }
4842
+ }
4843
+ var LIST_STATUSES = {
4844
+ running: "Running",
4845
+ completed: "Completed",
4846
+ failed: "Failed",
4847
+ canceled: "Canceled",
4848
+ terminated: "Terminated",
4849
+ "continued-as-new": "ContinuedAsNew",
4850
+ "timed-out": "TimedOut"
4851
+ };
4852
+ function quote(value) {
4853
+ return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
4854
+ }
4855
+ function buildListQuery(opts) {
4856
+ const clauses = [];
4857
+ if (opts.type) clauses.push(`WorkflowType = ${quote(opts.type)}`);
4858
+ if (opts.status) {
4859
+ const status = LIST_STATUSES[opts.status.toLowerCase()];
4860
+ if (!status) throw new Error(`--status must be one of: ${Object.keys(LIST_STATUSES).join(", ")}`);
4861
+ clauses.push(`ExecutionStatus = ${quote(status)}`);
4862
+ }
4863
+ if (opts.parent) clauses.push(`ParentWorkflowId = ${quote(opts.parent)}`);
4864
+ if (opts.query) clauses.push(clauses.length > 0 ? `(${opts.query})` : opts.query);
4865
+ return clauses.join(" AND ");
4866
+ }
4867
+ function formatListRows(rows) {
4868
+ const table = [
4869
+ ["WORKFLOW ID", "TYPE", "STATUS", "STARTED", "PARENT"],
4870
+ ...rows.map((r) => [
4871
+ r.workflowId,
4872
+ r.type,
4873
+ r.status,
4874
+ r.startTime ? r.startTime.toISOString().replace(/\.\d{3}Z$/, "Z") : "-",
4875
+ r.parentWorkflowId ?? "-"
4876
+ ])
4877
+ ];
4878
+ const widths = table[0].map((_, i) => Math.max(...table.map((row) => row[i].length)));
4879
+ return table.map((row) => row.map((cell, i) => i === row.length - 1 ? cell : cell.padEnd(widths[i])).join(" "));
4880
+ }
4881
+
4793
4882
  // packages/mesh-cli/src/commands/temporal.ts
4794
4883
  import { spawnSync as spawnSync2 } from "node:child_process";
4795
4884
  import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "node:fs";
@@ -5265,47 +5354,16 @@ async function resolveBearerToken(auth) {
5265
5354
  return void 0;
5266
5355
  }
5267
5356
  }
5268
- var EVENT_TYPE_NAMES = {
5269
- 1: "WorkflowExecutionStarted",
5270
- 2: "WorkflowExecutionCompleted",
5271
- 3: "WorkflowExecutionFailed",
5272
- 4: "WorkflowExecutionTimedOut",
5273
- 5: "WorkflowTaskScheduled",
5274
- 6: "WorkflowTaskStarted",
5275
- 7: "WorkflowTaskCompleted",
5276
- 8: "WorkflowTaskTimedOut",
5277
- 9: "WorkflowTaskFailed",
5278
- 10: "ActivityTaskScheduled",
5279
- 11: "ActivityTaskStarted",
5280
- 12: "ActivityTaskCompleted",
5281
- 13: "ActivityTaskFailed",
5282
- 14: "ActivityTaskTimedOut",
5283
- 15: "ActivityTaskCancelRequested",
5284
- 16: "ActivityTaskCanceled",
5285
- 17: "TimerStarted",
5286
- 18: "TimerFired",
5287
- 19: "TimerCanceled",
5288
- 20: "WorkflowExecutionCancelRequested",
5289
- 21: "WorkflowExecutionCanceled",
5290
- 24: "WorkflowExecutionSignaled",
5291
- // not 22/23 which were removed
5292
- 25: "WorkflowExecutionTerminated",
5293
- 26: "WorkflowExecutionSignaled",
5294
- 29: "WorkflowPropertiesModified",
5295
- 40: "ChildWorkflowExecutionStarted",
5296
- 41: "ChildWorkflowExecutionCompleted",
5297
- 42: "ChildWorkflowExecutionFailed",
5298
- 43: "ChildWorkflowExecutionCanceled",
5299
- 44: "ChildWorkflowExecutionTimedOut",
5300
- 45: "ChildWorkflowExecutionTerminated",
5301
- 46: "WorkflowPropertiesModified",
5302
- 48: "NexusOperationScheduled",
5303
- 49: "NexusOperationStarted",
5304
- 50: "NexusOperationCompleted",
5305
- 51: "NexusOperationFailed",
5306
- 52: "NexusOperationCanceled",
5307
- 53: "NexusOperationTimedOut"
5308
- };
5357
+ var eventTypeNameTable;
5358
+ function eventTypeName(type) {
5359
+ if (!eventTypeNameTable) {
5360
+ eventTypeNameTable = eventTypeNames();
5361
+ if (Object.keys(eventTypeNameTable).length === 0) {
5362
+ logWarn("could not load Temporal's EventType enum; event names will show as Unknown(n)");
5363
+ }
5364
+ }
5365
+ return eventTypeNameTable[type] ?? `Unknown(${type})`;
5366
+ }
5309
5367
  var STATUS_NAMES = {
5310
5368
  0: "UNSPECIFIED",
5311
5369
  1: "RUNNING",
@@ -5438,7 +5496,7 @@ ${totalShown} events shown (workflow ended).`);
5438
5496
  }
5439
5497
  async function printEvent(event, decrypter) {
5440
5498
  const eventType = event.eventType ?? 0;
5441
- const typeName = EVENT_TYPE_NAMES[eventType] ?? `Unknown(${eventType})`;
5499
+ const typeName = eventTypeName(eventType);
5442
5500
  const id = String(event.eventId).padStart(4);
5443
5501
  const detail = extractEventDetail(event);
5444
5502
  const detailStr = detail ? ` \u2014 ${detail}` : "";
@@ -5698,6 +5756,50 @@ function warnIfNotGitIgnored(outPath) {
5698
5756
  This fixture contains DECRYPTED production payloads. Add it to .gitignore or move it outside the repo \u2014 do NOT commit it.`
5699
5757
  );
5700
5758
  }
5759
+ function timestampToDate(ts) {
5760
+ if (!ts || ts.seconds === null || ts.seconds === void 0) return void 0;
5761
+ const seconds = Number(ts.seconds);
5762
+ return Number.isFinite(seconds) ? new Date(seconds * 1e3 + Math.floor((ts.nanos ?? 0) / 1e6)) : void 0;
5763
+ }
5764
+ async function listWorkflows(options) {
5765
+ const query = buildListQuery(options);
5766
+ const limit = Math.max(1, parseInt(options.limit ?? "20", 10) || 20);
5767
+ const conn = await connect2(options);
5768
+ try {
5769
+ const rows = [];
5770
+ let nextPageToken;
5771
+ do {
5772
+ const page = await conn.connection.workflowService.listWorkflowExecutions({
5773
+ namespace: conn.namespace,
5774
+ query,
5775
+ pageSize: Math.min(limit - rows.length, 100),
5776
+ ...nextPageToken ? { nextPageToken } : {}
5777
+ });
5778
+ for (const info of page.executions ?? []) {
5779
+ rows.push({
5780
+ workflowId: info.execution?.workflowId ?? "?",
5781
+ type: info.type?.name ?? "?",
5782
+ status: STATUS_NAMES[info.status ?? 0] ?? String(info.status),
5783
+ startTime: timestampToDate(info.startTime),
5784
+ ...info.parentExecution?.workflowId ? { parentWorkflowId: info.parentExecution.workflowId } : {}
5785
+ });
5786
+ if (rows.length >= limit) break;
5787
+ }
5788
+ nextPageToken = page.nextPageToken?.length ? page.nextPageToken : void 0;
5789
+ } while (nextPageToken && rows.length < limit);
5790
+ if (options.json) {
5791
+ console.log(JSON.stringify(rows, null, 2));
5792
+ return;
5793
+ }
5794
+ if (rows.length === 0) {
5795
+ console.log(`No workflows${query ? ` match ${query}` : ""} in ${conn.namespace}.`);
5796
+ return;
5797
+ }
5798
+ for (const line of formatListRows(rows)) console.log(line);
5799
+ } finally {
5800
+ conn.connection.close();
5801
+ }
5802
+ }
5701
5803
  async function terminateWorkflow(workflowId, runId, options) {
5702
5804
  const conn = await connect2(options);
5703
5805
  try {
@@ -5730,6 +5832,16 @@ async function connect2(options) {
5730
5832
  function registerTemporalCommands(program) {
5731
5833
  const temporal = program.command("temporal").description("Inspect Temporal workflows for the current app/stack");
5732
5834
  const sharedOpts = (cmd) => cmd.option("--stack <stack>", "Pulumi stack name (auto-detected from current directory)").option("--address <addr>", "Temporal server address (default: from stack output)").option("--namespace <ns>", "Temporal namespace (default: from stack output)");
5835
+ sharedOpts(
5836
+ temporal.command("list").description("List workflows in the app's namespace, running first, then most recently closed (find the id the other commands take)").option("--type <workflowType>", "only this workflow type (e.g. agentWorkflow)").option("--status <status>", `only this status: ${Object.keys(LIST_STATUSES).join(", ")}`).option("--parent <workflowId>", "only the children of this workflow").option("--query <visibilityQuery>", "a Temporal visibility query, AND-ed with the flags above").option("-n, --limit <n>", "maximum workflows to list", "20").option("--json", "print JSON")
5837
+ ).action(async (opts) => {
5838
+ try {
5839
+ await listWorkflows(opts);
5840
+ } catch (err) {
5841
+ logError(err instanceof Error ? err.message : String(err));
5842
+ process.exitCode = 1;
5843
+ }
5844
+ });
5733
5845
  sharedOpts(
5734
5846
  temporal.command("describe <workflowId> [runId]").description("Show workflow status and metadata")
5735
5847
  ).action(async (workflowId, runId, opts) => {
@@ -6216,9 +6328,9 @@ async function tunnelServices(serviceNames, options) {
6216
6328
  process.on("SIGTERM", cleanup);
6217
6329
  await Promise.race(
6218
6330
  processes.map(
6219
- (proc) => new Promise((resolve8) => {
6220
- proc.on("exit", () => resolve8());
6221
- proc.on("error", () => resolve8());
6331
+ (proc) => new Promise((resolve9) => {
6332
+ proc.on("exit", () => resolve9());
6333
+ proc.on("error", () => resolve9());
6222
6334
  })
6223
6335
  )
6224
6336
  );
@@ -6315,9 +6427,9 @@ async function tunnelExternal(name, options) {
6315
6427
  };
6316
6428
  process.on("SIGINT", cleanup);
6317
6429
  process.on("SIGTERM", cleanup);
6318
- await new Promise((resolve8) => {
6319
- proc.on("exit", () => resolve8());
6320
- proc.on("error", () => resolve8());
6430
+ await new Promise((resolve9) => {
6431
+ proc.on("exit", () => resolve9());
6432
+ proc.on("error", () => resolve9());
6321
6433
  });
6322
6434
  cleanup();
6323
6435
  }
@@ -6427,7 +6539,7 @@ async function resolveToken(opts) {
6427
6539
  if (opts.token) return opts.token;
6428
6540
  if (process.env.VCS_TOKEN) return process.env.VCS_TOKEN;
6429
6541
  if (opts.context) {
6430
- const { getValidToken: getValidToken2 } = await import("./mesh.login-Q6R5GMVM.js");
6542
+ const { getValidToken: getValidToken2 } = await import("./mesh.login-4O5PMS25.js");
6431
6543
  const token = await getValidToken2(opts.context);
6432
6544
  if (token) return token;
6433
6545
  }
@@ -6435,8 +6547,8 @@ async function resolveToken(opts) {
6435
6547
  "no token: pass --token, set VCS_TOKEN, or pass --context <platform-context> (after mesh login)"
6436
6548
  );
6437
6549
  }
6438
- async function vcsApi(baseUrl, token, path15, method = "GET", body) {
6439
- const res = await fetch(`${baseUrl}${path15}`, {
6550
+ async function vcsApi(baseUrl, token, path16, method = "GET", body) {
6551
+ const res = await fetch(`${baseUrl}${path16}`, {
6440
6552
  method,
6441
6553
  headers: {
6442
6554
  authorization: `Bearer ${token}`,
@@ -6447,7 +6559,7 @@ async function vcsApi(baseUrl, token, path15, method = "GET", body) {
6447
6559
  const data = await res.json().catch(() => ({}));
6448
6560
  if (!res.ok) {
6449
6561
  throw new Error(
6450
- `${method} ${path15} failed (${res.status}): ${String(data.error ?? "unknown error")}`
6562
+ `${method} ${path16} failed (${res.status}): ${String(data.error ?? "unknown error")}`
6451
6563
  );
6452
6564
  }
6453
6565
  return data;
@@ -6481,7 +6593,7 @@ async function cloneCommand(repo, dest, opts) {
6481
6593
  // packages/mesh-cli/src/commands/vcs/get.ts
6482
6594
  import { writeFile, mkdir } from "node:fs/promises";
6483
6595
  import { join as join16, dirname as dirname9 } from "node:path";
6484
- async function getCommand(repo, path15, opts) {
6596
+ async function getCommand(repo, path16, opts) {
6485
6597
  let vcsBaseUrl;
6486
6598
  let token;
6487
6599
  if (opts.target) {
@@ -6496,9 +6608,9 @@ async function getCommand(repo, path15, opts) {
6496
6608
  if (!token) throw new Error("no token: pass --target (after mesh login), or --token / --context");
6497
6609
  const reader = createVcsFolderReader({ vcsBaseUrl, token });
6498
6610
  try {
6499
- const { ref, files } = await reader.readPath(repo, path15);
6611
+ const { ref, files } = await reader.readPath(repo, path16);
6500
6612
  if (files.length === 0) {
6501
- logInfo(`no files at ${repo}:${path15}`);
6613
+ logInfo(`no files at ${repo}:${path16}`);
6502
6614
  return;
6503
6615
  }
6504
6616
  if (opts.output) {
@@ -6507,7 +6619,7 @@ async function getCommand(repo, path15, opts) {
6507
6619
  await mkdir(dirname9(abs), { recursive: true });
6508
6620
  await writeFile(abs, f.contents);
6509
6621
  }
6510
- logInfo(`wrote ${files.length} file(s) from ${repo}:${path15} (${ref}) \u2192 ${opts.output}`);
6622
+ logInfo(`wrote ${files.length} file(s) from ${repo}:${path16} (${ref}) \u2192 ${opts.output}`);
6511
6623
  } else {
6512
6624
  for (const f of files) {
6513
6625
  if (files.length > 1) process.stdout.write(`
@@ -6522,10 +6634,10 @@ async function getCommand(repo, path15, opts) {
6522
6634
  }
6523
6635
 
6524
6636
  // packages/mesh-cli/src/commands/vcs/drafts.ts
6525
- async function call(opts, repo, path15, method = "GET", body) {
6637
+ async function call(opts, repo, path16, method = "GET", body) {
6526
6638
  const target = await resolveTarget2({ ...opts, repo });
6527
6639
  const token = await resolveToken(opts);
6528
- return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${path15}`, method, body);
6640
+ return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${path16}`, method, body);
6529
6641
  }
6530
6642
  async function draftsListCommand(repo, opts) {
6531
6643
  const data = await call(opts, repo, `/drafts${opts.all ? "?all=true" : ""}`);
@@ -6607,13 +6719,13 @@ function parseStatus(out) {
6607
6719
  }
6608
6720
  return changes;
6609
6721
  }
6610
- async function writeOp(cwd, path15) {
6611
- const buf = await readFile2(join17(cwd, path15));
6722
+ async function writeOp(cwd, path16) {
6723
+ const buf = await readFile2(join17(cwd, path16));
6612
6724
  const asUtf8 = buf.toString("utf8");
6613
6725
  if (Buffer.from(asUtf8, "utf8").equals(buf)) {
6614
- return { op: "write", path: path15, content: asUtf8 };
6726
+ return { op: "write", path: path16, content: asUtf8 };
6615
6727
  }
6616
- return { op: "write", path: path15, content: buf.toString("base64"), encoding: "base64" };
6728
+ return { op: "write", path: path16, content: buf.toString("base64"), encoding: "base64" };
6617
6729
  }
6618
6730
  async function proposeCommand(opts) {
6619
6731
  const cwd = process.cwd();
@@ -6657,8 +6769,8 @@ async function proposeCommand(opts) {
6657
6769
  operations,
6658
6770
  ...opts.mergeParent ? { mergeParent: opts.mergeParent } : {}
6659
6771
  };
6660
- const path15 = opts.revise ? `/v1/repos/${target.repo}/proposals/${opts.revise}/revisions` : `/v1/repos/${target.repo}/proposals`;
6661
- const data = await vcsApi(target.baseUrl, token, path15, "POST", body);
6772
+ const path16 = opts.revise ? `/v1/repos/${target.repo}/proposals/${opts.revise}/revisions` : `/v1/repos/${target.repo}/proposals`;
6773
+ const data = await vcsApi(target.baseUrl, token, path16, "POST", body);
6662
6774
  console.log(
6663
6775
  `proposal ${data.proposalId} @ ${data.sha.slice(0, 8)} \u2014 review: mesh vcs show ${target.repo} ${data.proposalId} --url ${target.baseUrl}`
6664
6776
  );
@@ -6674,21 +6786,21 @@ function normalize(p) {
6674
6786
  function expandPathsToDeletions(repoFiles, requested) {
6675
6787
  const out = /* @__PURE__ */ new Set();
6676
6788
  for (const raw of requested) {
6677
- const path15 = normalize(raw);
6678
- if (path15.startsWith("/") || path15.split("/").includes("..")) {
6789
+ const path16 = normalize(raw);
6790
+ if (path16.startsWith("/") || path16.split("/").includes("..")) {
6679
6791
  throw new Error(
6680
6792
  `"${raw}" is not a repo-relative path \u2014 vcs paths never start with "/" or traverse with "..".`
6681
6793
  );
6682
6794
  }
6683
- const exact = repoFiles.filter((f) => f === path15);
6795
+ const exact = repoFiles.filter((f) => f === path16);
6684
6796
  if (exact.length > 0) {
6685
6797
  for (const f of exact) out.add(f);
6686
6798
  continue;
6687
6799
  }
6688
- const under = repoFiles.filter((f) => f.startsWith(`${path15}/`));
6800
+ const under = repoFiles.filter((f) => f.startsWith(`${path16}/`));
6689
6801
  if (under.length === 0) {
6690
6802
  throw new Error(
6691
- `"${raw}" matched no files in the repo \u2014 nothing was proposed. Check the path with: mesh vcs get <repo> ${path15}`
6803
+ `"${raw}" matched no files in the repo \u2014 nothing was proposed. Check the path with: mesh vcs get <repo> ${path16}`
6692
6804
  );
6693
6805
  }
6694
6806
  for (const f of under) out.add(f);
@@ -6724,7 +6836,7 @@ async function rmCommand(repo, paths, opts) {
6724
6836
  const body = {
6725
6837
  baseCommit: head.trim(),
6726
6838
  message: opts.message ?? `Delete ${doomed.length} file(s)`,
6727
- operations: doomed.map((path15) => ({ op: "delete", path: path15 }))
6839
+ operations: doomed.map((path16) => ({ op: "delete", path: path16 }))
6728
6840
  };
6729
6841
  const data = await vcsApi(
6730
6842
  baseUrl,
@@ -6744,10 +6856,10 @@ async function rmCommand(repo, paths, opts) {
6744
6856
  }
6745
6857
 
6746
6858
  // packages/mesh-cli/src/commands/vcs/review.ts
6747
- async function call2(opts, repo, path15, method = "GET", body) {
6859
+ async function call2(opts, repo, path16, method = "GET", body) {
6748
6860
  const target = await resolveTarget2({ ...opts, repo });
6749
6861
  const token = await resolveToken(opts);
6750
- return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${path15}`, method, body);
6862
+ return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${path16}`, method, body);
6751
6863
  }
6752
6864
  async function proposalsCommand(repo, opts) {
6753
6865
  console.log(JSON.stringify(await call2(opts, repo, "/proposals"), null, 2));
@@ -6837,7 +6949,7 @@ function registerVcsCommands(program) {
6837
6949
  // packages/mesh-cli/src/commands/workflow.ts
6838
6950
  import * as fs13 from "fs";
6839
6951
  import * as path14 from "path";
6840
- import { createRequire as createRequire2 } from "module";
6952
+ import { createRequire as createRequire3 } from "module";
6841
6953
  import { execFileSync as execFileSync8 } from "child_process";
6842
6954
  var DISCOVERY_HELPERS_SRC = `
6843
6955
  function discoverAux(filePath, source) {
@@ -6931,7 +7043,7 @@ function discoverProcessArtifact(filePath, source) {
6931
7043
  `;
6932
7044
  function resolveExtractorPath() {
6933
7045
  try {
6934
- const require2 = createRequire2(import.meta.url);
7046
+ const require2 = createRequire3(import.meta.url);
6935
7047
  const resolved = require2.resolve("@mesh-tech/workflow-viz/ast-extractor");
6936
7048
  return resolved;
6937
7049
  } catch {
@@ -6959,7 +7071,7 @@ const target = ${JSON.stringify(targetPath)};
6959
7071
  const explicitProcessArtifact = ${JSON.stringify(explicitProcessArtifact ?? null)};
6960
7072
  const stat = statSync(target);
6961
7073
  const files = stat.isDirectory()
6962
- ? readdirSync(target).filter(f => f.endsWith(".ts") && f !== "index.ts").map(f => join(target, f))
7074
+ ? readdirSync(target).filter(f => f.endsWith(".ts") && f !== "index.ts" && !/\\.(test|spec|d)\\.ts$/.test(f)).map(f => join(target, f))
6963
7075
  : [target];
6964
7076
 
6965
7077
  const results = [];
@@ -7005,7 +7117,7 @@ ${DISCOVERY_HELPERS_SRC}
7005
7117
  const target = ${JSON.stringify(targetPath)};
7006
7118
  const stat = statSync(target);
7007
7119
  const files = stat.isDirectory()
7008
- ? readdirSync(target).filter(f => f.endsWith(".ts") && f !== "index.ts").map(f => join(target, f))
7120
+ ? readdirSync(target).filter(f => f.endsWith(".ts") && f !== "index.ts" && !/\\.(test|spec|d)\\.ts$/.test(f)).map(f => join(target, f))
7009
7121
  : [target];
7010
7122
 
7011
7123
  const results = [];
@@ -7059,7 +7171,7 @@ const target = ${JSON.stringify(targetPath)};
7059
7171
  const explicitProcessArtifact = ${JSON.stringify(explicitProcessArtifact ?? null)};
7060
7172
  const stat = statSync(target);
7061
7173
  const files = stat.isDirectory()
7062
- ? readdirSync(target).filter(f => f.endsWith(".ts") && f !== "index.ts").map(f => join(target, f))
7174
+ ? readdirSync(target).filter(f => f.endsWith(".ts") && f !== "index.ts" && !/\\.(test|spec|d)\\.ts$/.test(f)).map(f => join(target, f))
7063
7175
  : [target];
7064
7176
 
7065
7177
  const results = [];
@@ -7093,22 +7205,7 @@ process.stdout.write(JSON.stringify(results));
7093
7205
  return null;
7094
7206
  }
7095
7207
  }
7096
- async function uploadToS3(bucket, appName, workflows) {
7097
- const { S3Client, PutObjectCommand } = await import("@aws-sdk/client-s3");
7098
- const s3 = new S3Client({ region: process.env.AWS_REGION ?? "us-east-2" });
7099
- for (const wf of workflows) {
7100
- const key = `workflow-ir/${appName}/${wf.workflowType}.json`;
7101
- const body = JSON.stringify(wf.ir, null, 2);
7102
- logInfo(` Uploading s3://${bucket}/${key} (${body.length} bytes)`);
7103
- await s3.send(
7104
- new PutObjectCommand({
7105
- Bucket: bucket,
7106
- Key: key,
7107
- Body: body,
7108
- ContentType: "application/json"
7109
- })
7110
- );
7111
- }
7208
+ function workflowIrFiles(appName, workflows, root) {
7112
7209
  const manifest = {
7113
7210
  extractedAt: (/* @__PURE__ */ new Date()).toISOString(),
7114
7211
  app: appName,
@@ -7116,23 +7213,33 @@ async function uploadToS3(bucket, appName, workflows) {
7116
7213
  workflows.map((wf) => [
7117
7214
  wf.workflowType,
7118
7215
  {
7119
- sourceFile: wf.sourceFile,
7216
+ sourceFile: path14.relative(root, wf.sourceFile) || path14.basename(wf.sourceFile),
7120
7217
  nodeCount: wf.ir.nodes.length,
7121
7218
  edgeCount: wf.ir.edges.length
7122
7219
  }
7123
7220
  ])
7124
7221
  )
7125
7222
  };
7126
- const manifestKey = `workflow-ir/${appName}/_manifest.json`;
7127
- logInfo(` Uploading s3://${bucket}/${manifestKey}`);
7128
- await s3.send(
7129
- new PutObjectCommand({
7130
- Bucket: bucket,
7131
- Key: manifestKey,
7132
- Body: JSON.stringify(manifest, null, 2),
7133
- ContentType: "application/json"
7134
- })
7135
- );
7223
+ return [
7224
+ ...workflows.map((wf) => ({ name: `${wf.workflowType}.json`, body: JSON.stringify(wf.ir, null, 2) })),
7225
+ { name: "_manifest.json", body: JSON.stringify(manifest, null, 2) }
7226
+ ];
7227
+ }
7228
+ async function uploadToS3(bucket, appName, files) {
7229
+ const { S3Client, PutObjectCommand } = await import("@aws-sdk/client-s3");
7230
+ const s3 = new S3Client({ region: process.env.AWS_REGION ?? "us-east-2", followRegionRedirects: true });
7231
+ for (const file of files) {
7232
+ const key = `workflow-ir/${appName}/${file.name}`;
7233
+ logInfo(` Uploading s3://${bucket}/${key} (${file.body.length} bytes)`);
7234
+ await s3.send(
7235
+ new PutObjectCommand({
7236
+ Bucket: bucket,
7237
+ Key: key,
7238
+ Body: file.body,
7239
+ ContentType: "application/json"
7240
+ })
7241
+ );
7242
+ }
7136
7243
  }
7137
7244
  function parseNameList(value) {
7138
7245
  return value ? value.split(",").map((name) => name.trim()).filter((name) => name.length > 0) : void 0;
@@ -7144,6 +7251,9 @@ function registerWorkflowCommands(program) {
7144
7251
  ).option("--app <name>", "Application name (used as S3 key prefix)").option(
7145
7252
  "--upload <bucket>",
7146
7253
  "S3 bucket to upload extracted IR (requires --app)"
7254
+ ).option(
7255
+ "--out <dir>",
7256
+ "Write the files the upload would write (one JSON per workflow type, plus _manifest.json) to a directory (requires --app)"
7147
7257
  ).option(
7148
7258
  "--process <path>",
7149
7259
  "Path to a process artifact JSON file (docs/plans/2026-07-05-process-artifact-design.md \xA71); renders substeps/actors/outcomes in place of a BUSINESS_STAGES map. Absent this flag, a sibling process/*.process.json is auto-discovered per workflow file."
@@ -7185,15 +7295,29 @@ function registerWorkflowCommands(program) {
7185
7295
  ` ${wf.workflowType} (${wf.ir.nodes.length} nodes, ${wf.ir.edges.length} edges)`
7186
7296
  );
7187
7297
  }
7188
- if (opts.upload && opts.app) {
7298
+ if ((opts.upload || opts.out) && !opts.app) {
7299
+ logError("--upload and --out need --app (the IR's key prefix)");
7300
+ process.exitCode = 1;
7301
+ return;
7302
+ }
7303
+ const root = fs13.statSync(resolvedPath).isDirectory() ? resolvedPath : path14.dirname(resolvedPath);
7304
+ const files = opts.app ? workflowIrFiles(opts.app, results, root) : [];
7305
+ if (opts.out) {
7306
+ const outDir = path14.resolve(opts.out);
7307
+ fs13.mkdirSync(outDir, { recursive: true });
7308
+ for (const file of files) fs13.writeFileSync(path14.join(outDir, file.name), file.body);
7309
+ logSuccess(`Wrote ${files.length} file(s) to ${outDir}`);
7310
+ }
7311
+ if (opts.upload) {
7189
7312
  logInfo(
7190
7313
  `Uploading ${results.length} workflow IR(s) to s3://${opts.upload}/workflow-ir/${opts.app}/`
7191
7314
  );
7192
- await uploadToS3(opts.upload, opts.app, results);
7315
+ await uploadToS3(opts.upload, opts.app, files);
7193
7316
  logSuccess("Upload complete");
7194
- } else if (opts.upload || opts.app) {
7195
- logWarn("Both --app and --upload required for S3 upload");
7196
- } else {
7317
+ } else if (opts.app && !opts.out) {
7318
+ logWarn("--app does nothing without --upload or --out");
7319
+ }
7320
+ if (!opts.upload && !opts.out) {
7197
7321
  console.log(JSON.stringify(results.map((r) => r.ir), null, 2));
7198
7322
  }
7199
7323
  } catch (error) {
@@ -7352,6 +7476,339 @@ ${inventory.workflowType} (${sourceFile})`);
7352
7476
  });
7353
7477
  }
7354
7478
 
7479
+ // packages/mesh-cli/src/commands/workstation.ts
7480
+ import { execFileSync as execFileSync9, spawn as spawn6, spawnSync as spawnSync3 } from "child_process";
7481
+ import { promises as dns } from "dns";
7482
+ import * as fs14 from "fs";
7483
+ import * as os4 from "os";
7484
+ import * as path15 from "path";
7485
+ function tmuxSessionAlive(name) {
7486
+ try {
7487
+ execFileSync9("tmux", ["has-session", "-t", `=${name}`], { stdio: "ignore" });
7488
+ return true;
7489
+ } catch {
7490
+ return false;
7491
+ }
7492
+ }
7493
+ function profileProblem(proxy) {
7494
+ if (!proxy.awsProfile) return void 0;
7495
+ let text;
7496
+ try {
7497
+ text = fs14.readFileSync(awsConfigFileOf(proxy), "utf8");
7498
+ } catch (e) {
7499
+ return `cannot read ${awsConfigFileOf(proxy)}: ${e.message}`;
7500
+ }
7501
+ return credentialProcessProblem(readCredentialProcess(text, proxy.awsProfile), {
7502
+ exists: (p) => fs14.existsSync(p),
7503
+ isInsideGitTree
7504
+ });
7505
+ }
7506
+ function adminPortInUse() {
7507
+ try {
7508
+ execFileSync9("lsof", ["-nP", "-iTCP@127.0.0.1:2119", "-sTCP:LISTEN"], { stdio: "ignore" });
7509
+ return true;
7510
+ } catch {
7511
+ return false;
7512
+ }
7513
+ }
7514
+ function launchAgentPath() {
7515
+ return path15.join(os4.homedir(), "Library", "LaunchAgents", `${LAUNCH_AGENT_LABEL}.plist`);
7516
+ }
7517
+ function launchctl(args) {
7518
+ return launchctlRun(args).ok;
7519
+ }
7520
+ function launchctlRun(args) {
7521
+ const r = spawnSync3("launchctl", args, { encoding: "utf8" });
7522
+ return { ok: r.status === 0, output: `${r.stdout ?? ""}${r.stderr ?? ""}`.trim() };
7523
+ }
7524
+ function sleepMs(ms) {
7525
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
7526
+ }
7527
+ function reloadLaunchAgent(domain, plist) {
7528
+ const service = `${domain}/${LAUNCH_AGENT_LABEL}`;
7529
+ launchctl(["bootout", service]);
7530
+ for (let i = 0; i < 50 && launchctl(["print", service]); i++) sleepMs(100);
7531
+ let last = { ok: false, output: "" };
7532
+ for (let attempt = 0; attempt < 5; attempt++) {
7533
+ last = launchctlRun(["bootstrap", domain, plist]);
7534
+ if (last.ok) return last;
7535
+ sleepMs(500);
7536
+ }
7537
+ return last;
7538
+ }
7539
+ var WORKSTATION_PROFILE = "mesh-workstation";
7540
+ function fail(message) {
7541
+ logError(message);
7542
+ process.exit(1);
7543
+ }
7544
+ async function lookupTxt(resolver, record) {
7545
+ try {
7546
+ return (await resolver.resolveTxt(record)).map((chunks) => chunks.join(""));
7547
+ } catch (e) {
7548
+ return e.code ?? e.message;
7549
+ }
7550
+ }
7551
+ async function lookupTxtAtZone(platform, record) {
7552
+ for (const zone of zoneCandidates(platform)) {
7553
+ let servers;
7554
+ try {
7555
+ servers = await dns.resolveNs(zone);
7556
+ } catch {
7557
+ continue;
7558
+ }
7559
+ const ips = (await Promise.all(servers.map((ns) => dns.resolve4(ns).catch(() => [])))).flat();
7560
+ if (ips.length === 0) continue;
7561
+ const resolver = new dns.Resolver();
7562
+ resolver.setServers(ips);
7563
+ return lookupTxt(resolver, record);
7564
+ }
7565
+ return "no name servers found";
7566
+ }
7567
+ function firstDiscovery(values) {
7568
+ if (typeof values === "string") return void 0;
7569
+ return values.map((v) => parseDiscoveryRecord(v)).find((p) => typeof p !== "string");
7570
+ }
7571
+ async function discoverWorkstation(name, platform) {
7572
+ const record = discoveryRecordName(name, platform);
7573
+ const viaResolver = await lookupTxt(dns, record);
7574
+ const found = firstDiscovery(viaResolver);
7575
+ if (found) return found;
7576
+ const viaZone = await lookupTxtAtZone(platform, record);
7577
+ const direct = firstDiscovery(viaZone);
7578
+ if (direct) {
7579
+ logInfo(`Your resolver has not seen ${record} yet; the zone's name servers answered`);
7580
+ return direct;
7581
+ }
7582
+ const why = typeof viaZone === "string" ? viaZone : "no v=1 record";
7583
+ fail(`No discovery record ${record} (${why}): is "${name}" in the platform's workstation stack, and deployed?`);
7584
+ }
7585
+ function requireFallbackShim(cli) {
7586
+ let text;
7587
+ try {
7588
+ text = fs14.readFileSync(cli, "utf8");
7589
+ } catch {
7590
+ fail(`No mesh shim at ${cli}. Install one: npm i -g @mesh-tech/mesh-cli && mesh install-shim (or pass --cli <path>)`);
7591
+ }
7592
+ if (!shimFallsBackToGlobal(text)) {
7593
+ fail(`${cli} is an older shim that fails outside a workspace, where renewal runs. Update it: mesh install-shim --force`);
7594
+ }
7595
+ }
7596
+ async function ensureCaddy(dir) {
7597
+ const caddy = path15.join(dir, "bin", "caddy");
7598
+ const hasRoute53 = (bin) => {
7599
+ try {
7600
+ return caddyHasRoute53(execFileSync9(bin, ["list-modules"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }));
7601
+ } catch {
7602
+ return false;
7603
+ }
7604
+ };
7605
+ if (fs14.existsSync(caddy) && hasRoute53(caddy)) return caddy;
7606
+ const url = caddyDownloadUrl(process.platform, process.arch);
7607
+ logInfo(`Downloading Caddy with the Route 53 module (${url})...`);
7608
+ const resp = await fetch(url);
7609
+ if (!resp.ok) fail(`Caddy download failed: HTTP ${resp.status}. Build it instead (xcaddy build --with github.com/caddy-dns/route53) and pass --caddy`);
7610
+ fs14.mkdirSync(path15.dirname(caddy), { recursive: true });
7611
+ const tmp = `${caddy}.download`;
7612
+ fs14.writeFileSync(tmp, Buffer.from(await resp.arrayBuffer()), { mode: 493 });
7613
+ if (!hasRoute53(tmp)) {
7614
+ fs14.rmSync(tmp, { force: true });
7615
+ fail("The downloaded Caddy has no dns.providers.route53 module");
7616
+ }
7617
+ fs14.renameSync(tmp, caddy);
7618
+ logSuccess(`Caddy: ${caddy}`);
7619
+ return caddy;
7620
+ }
7621
+ function writeCaddyfile(dir, identity) {
7622
+ const caddyfile = path15.join(dir, "Caddyfile");
7623
+ fs14.mkdirSync(path15.join(dir, "routes"), { recursive: true });
7624
+ fs14.writeFileSync(caddyfile, renderWorkstationCaddyfile(identity, dir));
7625
+ return caddyfile;
7626
+ }
7627
+ function requireIdentity(dir) {
7628
+ const identity = readWorkstationIdentity(dir);
7629
+ if (!identity) {
7630
+ logError(`This machine is not a workstation (no ${path15.join(dir, "workstation.json")}). Run: mesh workstation init`);
7631
+ process.exit(1);
7632
+ }
7633
+ return identity;
7634
+ }
7635
+ function registerWorkstationCommands(program) {
7636
+ const ws = program.command("workstation").description("HTTPS names on this machine for the services it runs (dev servers, local stacks)");
7637
+ ws.command("init").description("Make this machine a workstation: its name, certificate credentials and proxy binary").requiredOption("--name <label>", "this machine's host label in the workstation stack (e.g. mbp)").option("--platform <domain>", "the platform it is named under (e.g. dev.acme.example.com): the rest is discovered").option("--domain <domain>", "without --platform: <name>.<platform zone>").option("--zone-id <id>", "the Route 53 zone (default: discovered)").option("--region <region>", "AWS region for Route 53 (default: discovered, else us-east-2)").option("--aws-profile <profile>", "use this existing profile instead of writing one").option("--aws-config-file <file>", "the AWS config file holding --aws-profile").option("--caddy <path>", "Caddy built with github.com/caddy-dns/route53 (default: downloaded)").option("--cli <path>", "the mesh CLI the profile runs (default: the shim, ~/.local/bin/mesh)").option("--allow-checkout-cli", "accept a credential_process inside a git checkout (renewal breaks when it is removed)").option("--force", "overwrite an existing workstation.json").action(async (opts) => {
7638
+ const dir = workstationDir();
7639
+ const file = path15.join(dir, "workstation.json");
7640
+ if (fs14.existsSync(file) && !opts.force) fail(`${file} exists; --force to replace it`);
7641
+ fs14.mkdirSync(dir, { recursive: true });
7642
+ let domain;
7643
+ let zoneId = opts.zoneId;
7644
+ let region = opts.region;
7645
+ let roleArn;
7646
+ if (opts.platform) {
7647
+ domain = `${opts.name}.${opts.platform.replace(/\.$/, "")}`;
7648
+ if (opts.domain && opts.domain !== domain) fail(`--domain ${opts.domain} is not ${domain} (--name under --platform)`);
7649
+ const found = await discoverWorkstation(opts.name, opts.platform);
7650
+ roleArn = found.roleArn;
7651
+ zoneId ??= found.zoneId;
7652
+ region ??= found.region;
7653
+ logInfo(`Discovered ${domain}: zone ${found.zoneId}, role ${found.roleArn.split("/").pop()}`);
7654
+ } else {
7655
+ if (!opts.domain || !zoneId) fail("Give --platform <domain> (everything else is discovered), or --domain and --zone-id");
7656
+ domain = opts.domain;
7657
+ }
7658
+ if (!domain.startsWith(`${opts.name}.`)) fail(`--domain must be under --name: ${opts.name}.<zone>`);
7659
+ region ??= "us-east-2";
7660
+ const cli = path15.resolve(opts.cli ?? path15.join(os4.homedir(), ".local", "bin", "mesh"));
7661
+ let awsProfile = opts.awsProfile;
7662
+ let awsConfigFile = opts.awsConfigFile ? path15.resolve(opts.awsConfigFile) : void 0;
7663
+ if (!awsProfile) {
7664
+ if (!opts.platform || !roleArn) fail("Without --platform, give --aws-profile (a mesh login --export profile)");
7665
+ if (!opts.cli) requireFallbackShim(cli);
7666
+ awsProfile = WORKSTATION_PROFILE;
7667
+ awsConfigFile = path15.join(dir, "aws-config");
7668
+ const profile = renderCredentialProcessProfile({ profileName: awsProfile, context: opts.platform, roleArn, region, meshBin: cli });
7669
+ const existing = fs14.existsSync(awsConfigFile) ? fs14.readFileSync(awsConfigFile, "utf8") : "";
7670
+ fs14.writeFileSync(awsConfigFile, upsertManagedAwsConfigSection(existing, `workstation ${opts.platform}`, profile));
7671
+ logSuccess(`${awsConfigFile}: [profile ${awsProfile}] runs ${cli}`);
7672
+ } else if (opts.cli) {
7673
+ const configFile = awsConfigFile ?? path15.join(os4.homedir(), ".aws", "config");
7674
+ fs14.writeFileSync(configFile, rewriteCredentialProgram(fs14.readFileSync(configFile, "utf8"), awsProfile, cli));
7675
+ logSuccess(`${configFile}: [profile ${awsProfile}] now runs ${cli}`);
7676
+ }
7677
+ const caddy = opts.caddy ? path15.resolve(opts.caddy) : await ensureCaddy(dir);
7678
+ const identity = {
7679
+ name: opts.name,
7680
+ domain,
7681
+ proxy: {
7682
+ zoneId,
7683
+ region,
7684
+ awsProfile,
7685
+ ...awsConfigFile ? { awsConfigFile } : {},
7686
+ caddy
7687
+ }
7688
+ };
7689
+ const proxy = identity.proxy;
7690
+ const problem = profileProblem(proxy);
7691
+ if (problem && !opts.allowCheckoutCli) {
7692
+ logError(`The profile ${awsProfile} will not keep renewing the certificate: ${problem}.`);
7693
+ logInfo(" Point it at a mesh CLI outside any checkout: --cli <path>, or --allow-checkout-cli to accept it.");
7694
+ process.exit(1);
7695
+ }
7696
+ if (problem) logWarn(`Accepted (--allow-checkout-cli): ${problem}.`);
7697
+ if (!profileYieldsCredentials(proxy)) {
7698
+ if (!opts.platform) fail(`The profile ${awsProfile} yields no AWS credentials yet: run its mesh login, then init again`);
7699
+ logInfo(`Signing in to ${opts.platform} for the certificate role...`);
7700
+ const login = spawnSync3(process.execPath, [...process.execArgv, process.argv[1], "login", opts.platform], { stdio: "inherit" });
7701
+ if (login.status !== 0 || !profileYieldsCredentials(proxy)) {
7702
+ fail(`The profile ${awsProfile} still yields no credentials for ${roleArn}: is your Zitadel user one of the stack's subjects?`);
7703
+ }
7704
+ }
7705
+ fs14.mkdirSync(path15.join(dir, "routes"), { recursive: true });
7706
+ fs14.writeFileSync(file, JSON.stringify(identity, null, 2) + "\n");
7707
+ logSuccess(`Workstation ${opts.name}: https://*.${domain} (${file})`);
7708
+ logInfo("Keep its proxy running with: mesh workstation proxy --install");
7709
+ });
7710
+ ws.command("proxy").description("Run the workstation's proxy (Caddy) in the foreground: certificate, routes, reloads").option("--print", "print the Caddyfile and the command instead of running").option("--install", "run it as a LaunchAgent (starts now, at login, and again if it exits)").option("--uninstall", "stop the LaunchAgent and remove it").action((opts) => {
7711
+ const dir = workstationDir();
7712
+ const domain = `gui/${os4.userInfo().uid}`;
7713
+ if ((opts.install || opts.uninstall) && !launchAgentsSupported()) {
7714
+ logError(LAUNCH_AGENTS_MACOS_ONLY);
7715
+ process.exit(1);
7716
+ }
7717
+ if (opts.uninstall) {
7718
+ launchctl(["bootout", `${domain}/${LAUNCH_AGENT_LABEL}`]);
7719
+ fs14.rmSync(launchAgentPath(), { force: true });
7720
+ logSuccess(`Removed the ${LAUNCH_AGENT_LABEL} LaunchAgent`);
7721
+ return;
7722
+ }
7723
+ const identity = requireIdentity(dir);
7724
+ if (!identity.proxy) {
7725
+ logError("workstation.json has no proxy settings. Run: mesh workstation init --force \u2026");
7726
+ process.exit(1);
7727
+ }
7728
+ const proxy = identity.proxy;
7729
+ const caddyfile = writeCaddyfile(dir, { ...identity, proxy });
7730
+ const caddy = proxy.caddy ?? "caddy";
7731
+ const args = ["run", "--watch", "--config", caddyfile, "--adapter", "caddyfile"];
7732
+ if (opts.print) {
7733
+ console.log(fs14.readFileSync(caddyfile, "utf8"));
7734
+ console.log(`${caddy} ${args.join(" ")}`);
7735
+ return;
7736
+ }
7737
+ if (opts.install) {
7738
+ if (!launchctl(["print", `${domain}/${LAUNCH_AGENT_LABEL}`]) && adminPortInUse()) {
7739
+ logError("Another workstation proxy is running (127.0.0.1:2119 answers). Stop it, then run --install again.");
7740
+ process.exit(1);
7741
+ }
7742
+ const problem = profileProblem(proxy);
7743
+ if (problem) logWarn(`The profile will not keep renewing the certificate: ${problem}.`);
7744
+ const env = proxyEnv({ PATH: launchAgentSearchPath(process.env.PATH, process.execPath), HOME: os4.homedir() }, proxy);
7745
+ const plist = renderLaunchAgent({ caddy, caddyfile, dir, env });
7746
+ fs14.mkdirSync(path15.dirname(launchAgentPath()), { recursive: true });
7747
+ fs14.writeFileSync(launchAgentPath(), plist);
7748
+ const loaded = reloadLaunchAgent(domain, launchAgentPath());
7749
+ if (!loaded.ok) {
7750
+ logError(`launchctl bootstrap failed for ${launchAgentPath()}${loaded.output ? `: ${loaded.output}` : ""}`);
7751
+ process.exit(1);
7752
+ }
7753
+ logSuccess(`LaunchAgent ${LAUNCH_AGENT_LABEL}: serving https://*.${identity.domain} (log: ${path15.join(dir, "proxy.log")})`);
7754
+ return;
7755
+ }
7756
+ logInfo(`Serving https://*.${identity.domain} \u2014 routes in ${path15.join(dir, "routes")}`);
7757
+ const child = spawn6(caddy, args, { stdio: "inherit", env: proxyEnv(process.env, identity.proxy) });
7758
+ child.on("error", (e) => {
7759
+ logError(`Could not start ${caddy}: ${e.message}. Build it with: xcaddy build --with github.com/caddy-dns/route53`);
7760
+ process.exit(1);
7761
+ });
7762
+ child.on("exit", (code) => process.exit(code ?? 1));
7763
+ });
7764
+ ws.command("routes").description("List the HTTPS names this workstation serves").option("--prune", "remove routes of mesh dev sessions that are no longer running").option("--json", "print JSON").action((opts) => {
7765
+ const dir = workstationDir();
7766
+ requireIdentity(dir);
7767
+ let routes = listRoutes(dir).map((r) => ({
7768
+ ...r,
7769
+ alive: r.session ? tmuxSessionAlive(r.session) : void 0
7770
+ }));
7771
+ if (opts.prune) {
7772
+ for (const r of routes.filter((r2) => r2.session && !r2.alive)) {
7773
+ fs14.rmSync(r.file, { force: true });
7774
+ logInfo(`Removed ${r.hostname} (session ${r.session} is not running)`);
7775
+ }
7776
+ routes = routes.filter((r) => !r.session || r.alive);
7777
+ }
7778
+ if (opts.json) {
7779
+ console.log(JSON.stringify(routes, null, 2));
7780
+ return;
7781
+ }
7782
+ if (routes.length === 0) {
7783
+ logInfo("No routes.");
7784
+ return;
7785
+ }
7786
+ for (const r of routes) {
7787
+ const owner = r.session ? `mesh dev ${r.session}${r.alive ? "" : " (not running)"}` : "stack";
7788
+ console.log(` https://${r.hostname.padEnd(56)} \u2192 :${String(r.port).padEnd(6)} ${owner}`);
7789
+ }
7790
+ if (routes.some((r) => r.session && !r.alive)) logWarn("Clear routes of stopped sessions with: mesh workstation routes --prune");
7791
+ });
7792
+ ws.command("status").description("Is this workstation healthy: proxy running, certificate fresh, renewal credentials alive").action(() => {
7793
+ const dir = workstationDir();
7794
+ const identity = requireIdentity(dir);
7795
+ const expiry = certificateExpiry(dir, identity.domain);
7796
+ const launchd = launchAgentsSupported();
7797
+ const agent = launchd && launchctl(["print", `gui/${os4.userInfo().uid}/${LAUNCH_AGENT_LABEL}`]);
7798
+ const problem = identity.proxy ? profileProblem(identity.proxy) : void 0;
7799
+ const credentialOk = identity.proxy ? profileYieldsCredentials(identity.proxy) : true;
7800
+ console.log(` workstation ${identity.name} (*.${identity.domain})`);
7801
+ const proxyLine = !launchd ? LAUNCH_AGENTS_MACOS_ONLY : agent ? `LaunchAgent ${LAUNCH_AGENT_LABEL}` : "no LaunchAgent (mesh workstation proxy --install)";
7802
+ console.log(` proxy ${proxyLine}`);
7803
+ console.log(` certificate ${expiry ? `expires ${expiry.toISOString().slice(0, 10)}` : "none issued yet"}`);
7804
+ console.log(` credentials ${credentialOk ? "ok" : "FAILING"}${identity.proxy?.awsProfile ? ` (profile ${identity.proxy.awsProfile})` : ""}`);
7805
+ console.log(` routes ${listRoutes(dir).length}`);
7806
+ const warnings = workstationWarnings({ now: /* @__PURE__ */ new Date(), certExpiry: expiry, credentialOk, credentialProblem: problem });
7807
+ for (const w of warnings) logWarn(w);
7808
+ if (warnings.length > 0) process.exitCode = 1;
7809
+ });
7810
+ }
7811
+
7355
7812
  // packages/mesh-cli/src/program.ts
7356
7813
  var CLI_NAME = "mesh";
7357
7814
  var CLI_DESCRIPTION = "Build, run and deploy apps on a Mesh platform";
@@ -7385,6 +7842,7 @@ function createProgram(options = {}) {
7385
7842
  registerInitCommands(program);
7386
7843
  registerTenantCommands(program);
7387
7844
  registerInstallShimCommand(program);
7845
+ registerWorkstationCommands(program);
7388
7846
  return program;
7389
7847
  }
7390
7848