@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.
- package/dist/bin/{mesh.auth-preflight-JTUNS42O.js → mesh.auth-preflight-3ASNYA3I.js} +1 -1
- package/dist/bin/{mesh.chunk-QE5LUIHN.js → mesh.chunk-252LTIHZ.js} +2 -2
- package/dist/bin/{mesh.chunk-TYM27CO3.js → mesh.chunk-4Y3JGAYZ.js} +1 -1
- package/dist/bin/{mesh.chunk-OOWKJR4H.js → mesh.chunk-6OGUV2DU.js} +1 -1
- package/dist/bin/{mesh.chunk-VCQKLVZJ.js → mesh.chunk-G4TCVQLL.js} +603 -145
- package/dist/bin/mesh.chunk-G4TCVQLL.js.map +6 -0
- package/dist/bin/{mesh.chunk-ZNM3DDAM.js → mesh.chunk-HPLMVIBO.js} +1 -1
- package/dist/bin/{mesh.chunk-QUKWWFZI.js → mesh.chunk-JSY6THRF.js} +1 -1
- package/dist/bin/{mesh.chunk-PANTMVC3.js → mesh.chunk-NN3LTNUM.js} +3 -3
- package/dist/bin/{mesh.chunk-HB2IZKLP.js → mesh.chunk-SFIJZF3S.js} +786 -276
- package/dist/bin/{mesh.chunk-HB2IZKLP.js.map → mesh.chunk-SFIJZF3S.js.map} +3 -3
- package/dist/bin/{mesh.chunk-HC7V75J3.js → mesh.chunk-UJAPUO2W.js} +1 -1
- package/dist/bin/{mesh.create-app-DVMZDEQP.js → mesh.create-app-BHB3BGH7.js} +3 -3
- package/dist/bin/{mesh.dev-token-server-4N6HGQAF.js → mesh.dev-token-server-6TNWX5TY.js} +2 -2
- package/dist/bin/mesh.js +9 -9
- package/dist/bin/{mesh.login-Q6R5GMVM.js → mesh.login-4O5PMS25.js} +2 -2
- package/dist/bin/{mesh.platform-setup-YK6KSOP7.js → mesh.platform-setup-MTY6ICAO.js} +1 -1
- package/dist/bin/{mesh.program-GEKNV2LY.js → mesh.program-CMOLQWZI.js} +9 -9
- package/dist/bin/{mesh.registry-KA3CNNPZ.js → mesh.registry-BDBH6DRP.js} +4 -4
- package/dist/bin/{mesh.registry-identity-DSTAHXUS.js → mesh.registry-identity-QOGDEMZO.js} +3 -3
- package/dist/bin/{mesh.review-command-3ZXPS6Y3.js → mesh.review-command-E7V2L5AM.js} +3 -3
- package/dist/bin/{mesh.start-HE6P3TCS.js → mesh.start-3MUKXN2U.js} +2 -2
- package/dist/bin/{mesh.wizard-QGWPV4XN.js → mesh.wizard-EH3SQEHW.js} +7 -7
- package/dist/build-info.json +2 -2
- package/dist/src/commands/dev.d.ts +1 -0
- package/dist/src/commands/dev.js +57 -1
- package/dist/src/commands/temporal.js +146 -42
- package/dist/src/commands/temporal.js.map +3 -3
- package/dist/src/commands/workflow.d.ts +14 -0
- package/dist/src/commands/workflow.js +43 -31
- package/dist/src/commands/workstation.d.ts +3 -0
- package/dist/src/commands/workstation.js +395 -0
- package/dist/src/program.js +2 -0
- package/dist/src/utils/temporal-inspect.d.ts +17 -0
- package/dist/src/utils/temporal-inspect.js +71 -0
- package/dist/src/utils/workstation-machine.d.ts +54 -0
- package/dist/src/utils/workstation-machine.js +282 -0
- package/dist/src/utils/workstation-routes.d.ts +77 -0
- package/dist/src/utils/workstation-routes.js +180 -0
- package/fragments/base/README.md.hbs +3 -0
- package/package.json +2 -2
- package/skills/mesh/SKILL.md +5 -4
- package/skills/mesh/references/worktrees.md +4 -1
- package/dist/bin/mesh.chunk-VCQKLVZJ.js.map +0 -6
- /package/dist/bin/{mesh.auth-preflight-JTUNS42O.js.map → mesh.auth-preflight-3ASNYA3I.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-QE5LUIHN.js.map → mesh.chunk-252LTIHZ.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-TYM27CO3.js.map → mesh.chunk-4Y3JGAYZ.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-OOWKJR4H.js.map → mesh.chunk-6OGUV2DU.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-ZNM3DDAM.js.map → mesh.chunk-HPLMVIBO.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-QUKWWFZI.js.map → mesh.chunk-JSY6THRF.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-PANTMVC3.js.map → mesh.chunk-NN3LTNUM.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-HC7V75J3.js.map → mesh.chunk-UJAPUO2W.js.map} +0 -0
- /package/dist/bin/{mesh.create-app-DVMZDEQP.js.map → mesh.create-app-BHB3BGH7.js.map} +0 -0
- /package/dist/bin/{mesh.dev-token-server-4N6HGQAF.js.map → mesh.dev-token-server-6TNWX5TY.js.map} +0 -0
- /package/dist/bin/{mesh.login-Q6R5GMVM.js.map → mesh.login-4O5PMS25.js.map} +0 -0
- /package/dist/bin/{mesh.platform-setup-YK6KSOP7.js.map → mesh.platform-setup-MTY6ICAO.js.map} +0 -0
- /package/dist/bin/{mesh.program-GEKNV2LY.js.map → mesh.program-CMOLQWZI.js.map} +0 -0
- /package/dist/bin/{mesh.registry-KA3CNNPZ.js.map → mesh.registry-BDBH6DRP.js.map} +0 -0
- /package/dist/bin/{mesh.registry-identity-DSTAHXUS.js.map → mesh.registry-identity-QOGDEMZO.js.map} +0 -0
- /package/dist/bin/{mesh.review-command-3ZXPS6Y3.js.map → mesh.review-command-E7V2L5AM.js.map} +0 -0
- /package/dist/bin/{mesh.start-HE6P3TCS.js.map → mesh.start-3MUKXN2U.js.map} +0 -0
- /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-
|
|
10
|
+
} from "./mesh.chunk-JSY6THRF.js";
|
|
11
11
|
import {
|
|
12
12
|
cliReferenceStaleness,
|
|
13
13
|
resolveCliRuntime,
|
|
14
14
|
runPortalCommand
|
|
15
|
-
} from "./mesh.chunk-
|
|
15
|
+
} from "./mesh.chunk-6OGUV2DU.js";
|
|
16
16
|
import {
|
|
17
17
|
registerAppCommands,
|
|
18
18
|
registerCreateAppCommand
|
|
19
|
-
} from "./mesh.chunk-
|
|
19
|
+
} from "./mesh.chunk-252LTIHZ.js";
|
|
20
20
|
import {
|
|
21
21
|
PLATFORM_SETUP_DEFAULTS
|
|
22
|
-
} from "./mesh.chunk-
|
|
22
|
+
} from "./mesh.chunk-HPLMVIBO.js";
|
|
23
23
|
import {
|
|
24
24
|
registerRegistryCommands
|
|
25
|
-
} from "./mesh.chunk-
|
|
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
|
-
|
|
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-
|
|
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((
|
|
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
|
-
|
|
898
|
+
resolve9(true);
|
|
873
899
|
});
|
|
874
900
|
socket.on("timeout", () => {
|
|
875
901
|
socket.destroy();
|
|
876
|
-
|
|
902
|
+
resolve9(false);
|
|
877
903
|
});
|
|
878
904
|
socket.on("error", () => {
|
|
879
905
|
socket.destroy();
|
|
880
|
-
|
|
906
|
+
resolve9(false);
|
|
881
907
|
});
|
|
882
908
|
socket.connect(port, "localhost");
|
|
883
909
|
});
|
|
884
910
|
}
|
|
885
911
|
function sleep(ms) {
|
|
886
|
-
return new Promise((
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
1018
|
+
resolve9(true);
|
|
993
1019
|
});
|
|
994
1020
|
socket.on("timeout", () => {
|
|
995
1021
|
socket.destroy();
|
|
996
|
-
|
|
1022
|
+
resolve9(false);
|
|
997
1023
|
});
|
|
998
1024
|
socket.on("error", () => {
|
|
999
1025
|
socket.destroy();
|
|
1000
|
-
|
|
1026
|
+
resolve9(false);
|
|
1001
1027
|
});
|
|
1002
1028
|
socket.connect(port, "localhost");
|
|
1003
1029
|
});
|
|
1004
1030
|
}
|
|
1005
1031
|
function sleep2(ms) {
|
|
1006
|
-
return new Promise((
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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((
|
|
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 ?
|
|
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((
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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((
|
|
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((
|
|
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-
|
|
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-
|
|
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
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
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 =
|
|
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((
|
|
6220
|
-
proc.on("exit", () =>
|
|
6221
|
-
proc.on("error", () =>
|
|
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((
|
|
6319
|
-
proc.on("exit", () =>
|
|
6320
|
-
proc.on("error", () =>
|
|
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-
|
|
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,
|
|
6439
|
-
const res = await fetch(`${baseUrl}${
|
|
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} ${
|
|
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,
|
|
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,
|
|
6611
|
+
const { ref, files } = await reader.readPath(repo, path16);
|
|
6500
6612
|
if (files.length === 0) {
|
|
6501
|
-
logInfo(`no files at ${repo}:${
|
|
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}:${
|
|
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,
|
|
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}${
|
|
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,
|
|
6611
|
-
const buf = await readFile2(join17(cwd,
|
|
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:
|
|
6726
|
+
return { op: "write", path: path16, content: asUtf8 };
|
|
6615
6727
|
}
|
|
6616
|
-
return { op: "write", path:
|
|
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
|
|
6661
|
-
const data = await vcsApi(target.baseUrl, token,
|
|
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
|
|
6678
|
-
if (
|
|
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 ===
|
|
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(`${
|
|
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> ${
|
|
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((
|
|
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,
|
|
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}${
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
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,
|
|
7315
|
+
await uploadToS3(opts.upload, opts.app, files);
|
|
7193
7316
|
logSuccess("Upload complete");
|
|
7194
|
-
} else if (opts.
|
|
7195
|
-
logWarn("
|
|
7196
|
-
}
|
|
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
|
|