@mesh-tech/mesh-cli 0.38.1 → 0.40.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-AQJ5TQES.js → mesh.auth-preflight-AUFQ2FGD.js} +1 -1
- package/dist/bin/{mesh.chunk-I6NXLXGC.js → mesh.chunk-2ASXJ5DO.js} +235 -581
- package/dist/bin/mesh.chunk-2ASXJ5DO.js.map +6 -0
- package/dist/bin/{mesh.chunk-IU2IWH6O.js → mesh.chunk-6AIG5OJM.js} +3 -3
- package/dist/bin/{mesh.chunk-KN4BZOYH.js → mesh.chunk-6SSOVZOI.js} +1 -1
- package/dist/bin/{mesh.chunk-LMYPTJ2F.js → mesh.chunk-7HTKSUWR.js} +1900 -577
- package/dist/bin/mesh.chunk-7HTKSUWR.js.map +6 -0
- package/dist/bin/{mesh.chunk-2YRWJH5X.js → mesh.chunk-F44A3ACW.js} +4 -4
- package/dist/bin/{mesh.chunk-2YRWJH5X.js.map → mesh.chunk-F44A3ACW.js.map} +1 -1
- package/dist/bin/{mesh.chunk-BF2SH6XT.js → mesh.chunk-HJGMOEUG.js} +1 -1
- package/dist/bin/{mesh.chunk-TZAGJTKU.js → mesh.chunk-NSQJEX36.js} +1 -1
- package/dist/bin/{mesh.chunk-HPYZWPRM.js → mesh.chunk-PZVI7V3J.js} +1 -1
- package/dist/bin/mesh.chunk-TDCH4SFQ.js +419 -0
- package/dist/bin/mesh.chunk-TDCH4SFQ.js.map +6 -0
- package/dist/bin/mesh.chunk-YE2WIY3Y.js +473 -0
- package/dist/bin/mesh.chunk-YE2WIY3Y.js.map +6 -0
- package/dist/bin/{mesh.create-app-NGXACFAU.js → mesh.create-app-Z3RKSTBO.js} +3 -3
- package/dist/bin/{mesh.dev-token-server-YP2VBP2S.js → mesh.dev-token-server-XG26C6IQ.js} +2 -2
- package/dist/bin/mesh.generate-XSM4C6FQ.js +10 -0
- package/dist/bin/mesh.js +9 -8
- package/dist/bin/mesh.js.map +1 -1
- package/dist/bin/{mesh.login-7SIAKFXJ.js → mesh.login-3AWVGPCM.js} +2 -2
- package/dist/bin/{mesh.platform-setup-CJXE3BCP.js → mesh.platform-setup-2ZDMHRCI.js} +1 -1
- package/dist/bin/{mesh.program-BIDQBSSI.js → mesh.program-K5JQXEHX.js} +9 -8
- package/dist/bin/{mesh.registry-7P4MGXEK.js → mesh.registry-JLQYFUNN.js} +4 -4
- package/dist/bin/{mesh.registry-identity-JW4KO7N7.js → mesh.registry-identity-3AR27UGO.js} +3 -3
- package/dist/bin/mesh.registry-identity-3AR27UGO.js.map +6 -0
- package/dist/bin/mesh.review-command-LUVZQN2T.js +238 -0
- package/dist/bin/mesh.review-command-LUVZQN2T.js.map +6 -0
- package/dist/bin/{mesh.start-MPQFIEMH.js → mesh.start-KZ5L6SOJ.js} +2 -2
- package/dist/bin/{mesh.wizard-ZJE4S6PC.js → mesh.wizard-FCTT55KI.js} +7 -7
- package/dist/bin/mesh.workspace-membership-DI3YQGEK.js +65 -0
- package/dist/bin/mesh.workspace-membership-DI3YQGEK.js.map +6 -0
- package/dist/build-info.json +2 -2
- package/dist/src/commands/app-check.js +2 -2
- package/dist/src/commands/dev-doctor.d.ts +22 -0
- package/dist/src/commands/dev-doctor.js +149 -0
- package/dist/src/commands/dev-env-leaks.d.ts +24 -0
- package/dist/src/commands/dev-env-leaks.js +178 -0
- package/dist/src/commands/dev-launch.d.ts +17 -1
- package/dist/src/commands/dev-launch.js +130 -5
- package/dist/src/commands/dev-readiness.d.ts +49 -0
- package/dist/src/commands/dev-readiness.js +78 -0
- package/dist/src/commands/dev.d.ts +60 -0
- package/dist/src/commands/dev.js +574 -140
- package/dist/src/commands/hub/index.js +10 -7
- package/dist/src/commands/local/app-authz.d.ts +118 -0
- package/dist/src/commands/local/app-authz.js +295 -0
- package/dist/src/commands/local/auth-provision.d.ts +1 -0
- package/dist/src/commands/local/auth-provision.js +12 -1
- package/dist/src/commands/local/index.js +2 -0
- package/dist/src/commands/mcp/generate.d.ts +11 -0
- package/dist/src/commands/mcp/generate.js +78 -0
- package/dist/src/commands/mcp/index.d.ts +2 -0
- package/dist/src/commands/mcp/index.js +70 -0
- package/dist/src/commands/mcp/manifest-file.d.ts +5 -0
- package/dist/src/commands/mcp/manifest-file.js +24 -0
- package/dist/src/commands/mcp/review-command.d.ts +24 -0
- package/dist/src/commands/mcp/review-command.js +66 -0
- package/dist/src/commands/mcp/review.d.ts +41 -0
- package/dist/src/commands/mcp/review.js +140 -0
- package/dist/src/commands/mcp/workspace-membership.d.ts +7 -0
- package/dist/src/commands/mcp/workspace-membership.js +77 -0
- package/dist/src/commands/secrets/reindex.js +2 -7
- package/dist/src/commands/secrets/set.d.ts +22 -1
- package/dist/src/commands/secrets/set.js +31 -8
- package/dist/src/commands/temporal.js +51 -5
- package/dist/src/commands/temporal.js.map +2 -2
- package/dist/src/program.js +2 -0
- package/dist/src/utils/aws-auth.d.ts +4 -0
- package/dist/src/utils/aws-auth.js +7 -3
- package/dist/src/utils/dev-sessions-root.d.ts +3 -0
- package/dist/src/utils/dev-sessions-root.js +45 -0
- package/dist/src/utils/kubeconfig.js +2 -2
- package/dist/src/utils/tailscale.js +7 -1
- package/dist/src/utils/temporal-auth.js +2 -1
- package/dist/src/utils/workflow-fingerprint.js +23 -12
- package/fragments/base/index.ts.hbs +4 -1
- package/package.json +7 -5
- package/skills/mesh/SKILL.md +10 -6
- package/templates/api-auth/api/src/schema.ts.hbs +17 -0
- package/templates/api-auth/index.ts.hbs +1 -0
- package/templates/api-auth/package.json.hbs +3 -0
- package/templates/api-role-gating/api/src/schema.ts.hbs +10 -0
- package/templates/api-role-gating/index.ts.hbs +1 -0
- package/templates/external-service/index.ts.hbs +1 -0
- package/templates/workflow/index.ts.hbs +2 -0
- package/dist/bin/mesh.chunk-I6NXLXGC.js.map +0 -6
- package/dist/bin/mesh.chunk-LMYPTJ2F.js.map +0 -6
- /package/dist/bin/{mesh.auth-preflight-AQJ5TQES.js.map → mesh.auth-preflight-AUFQ2FGD.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-IU2IWH6O.js.map → mesh.chunk-6AIG5OJM.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-KN4BZOYH.js.map → mesh.chunk-6SSOVZOI.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-BF2SH6XT.js.map → mesh.chunk-HJGMOEUG.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-TZAGJTKU.js.map → mesh.chunk-NSQJEX36.js.map} +0 -0
- /package/dist/bin/{mesh.chunk-HPYZWPRM.js.map → mesh.chunk-PZVI7V3J.js.map} +0 -0
- /package/dist/bin/{mesh.create-app-NGXACFAU.js.map → mesh.create-app-Z3RKSTBO.js.map} +0 -0
- /package/dist/bin/{mesh.dev-token-server-YP2VBP2S.js.map → mesh.dev-token-server-XG26C6IQ.js.map} +0 -0
- /package/dist/bin/{mesh.login-7SIAKFXJ.js.map → mesh.generate-XSM4C6FQ.js.map} +0 -0
- /package/dist/bin/{mesh.platform-setup-CJXE3BCP.js.map → mesh.login-3AWVGPCM.js.map} +0 -0
- /package/dist/bin/{mesh.program-BIDQBSSI.js.map → mesh.platform-setup-2ZDMHRCI.js.map} +0 -0
- /package/dist/bin/{mesh.registry-7P4MGXEK.js.map → mesh.program-K5JQXEHX.js.map} +0 -0
- /package/dist/bin/{mesh.registry-identity-JW4KO7N7.js.map → mesh.registry-JLQYFUNN.js.map} +0 -0
- /package/dist/bin/{mesh.start-MPQFIEMH.js.map → mesh.start-KZ5L6SOJ.js.map} +0 -0
- /package/dist/bin/{mesh.wizard-ZJE4S6PC.js.map → mesh.wizard-FCTT55KI.js.map} +0 -0
|
@@ -1,18 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildInstanceIndexValue,
|
|
3
|
+
discoverStackExternalServices,
|
|
4
|
+
instanceIndexSecretId,
|
|
5
|
+
instanceKeyFromSecretName,
|
|
6
|
+
isResourceNotFound,
|
|
7
|
+
parseInstanceIndex,
|
|
8
|
+
resolveSecretsContext,
|
|
9
|
+
setCommand
|
|
10
|
+
} from "./mesh.chunk-YE2WIY3Y.js";
|
|
1
11
|
import {
|
|
2
12
|
cliReferenceStaleness,
|
|
3
13
|
resolveCliRuntime,
|
|
4
14
|
runPortalCommand
|
|
5
|
-
} from "./mesh.chunk-
|
|
15
|
+
} from "./mesh.chunk-PZVI7V3J.js";
|
|
6
16
|
import {
|
|
7
17
|
registerAppCommands,
|
|
8
18
|
registerCreateAppCommand
|
|
9
|
-
} from "./mesh.chunk-
|
|
19
|
+
} from "./mesh.chunk-F44A3ACW.js";
|
|
10
20
|
import {
|
|
11
21
|
PLATFORM_SETUP_DEFAULTS
|
|
12
|
-
} from "./mesh.chunk-
|
|
22
|
+
} from "./mesh.chunk-NSQJEX36.js";
|
|
13
23
|
import {
|
|
14
24
|
registerRegistryCommands
|
|
15
|
-
} from "./mesh.chunk-
|
|
25
|
+
} from "./mesh.chunk-6AIG5OJM.js";
|
|
16
26
|
import {
|
|
17
27
|
registerSkillsCommands,
|
|
18
28
|
resolveTargetRoot,
|
|
@@ -30,6 +40,7 @@ import {
|
|
|
30
40
|
derivePlatformContext,
|
|
31
41
|
detectContext,
|
|
32
42
|
detectLocalTenant,
|
|
43
|
+
devSessionsRoot,
|
|
33
44
|
ensureKubeconfig,
|
|
34
45
|
findAppRoot,
|
|
35
46
|
findRepoRoot,
|
|
@@ -40,6 +51,7 @@ import {
|
|
|
40
51
|
getValidToken,
|
|
41
52
|
idpEndpoints,
|
|
42
53
|
mockIdpComposeEnv,
|
|
54
|
+
pickLaunchHostEnv,
|
|
43
55
|
probeCredentials,
|
|
44
56
|
pulumiStackOutput,
|
|
45
57
|
readCredentials,
|
|
@@ -51,10 +63,10 @@ import {
|
|
|
51
63
|
registerLoginCommand,
|
|
52
64
|
registerVpnCommands,
|
|
53
65
|
removeAllAliasContainers,
|
|
66
|
+
removeLocalAppSpiceDBs,
|
|
54
67
|
resolveAwsCredentials,
|
|
55
68
|
resolveHubPlatformName,
|
|
56
69
|
resolvePulumiEnv,
|
|
57
|
-
resolveStackOption,
|
|
58
70
|
resolveTemporalAuth,
|
|
59
71
|
resolveWorktreeIdentity,
|
|
60
72
|
rewriteDatabaseUrl,
|
|
@@ -65,7 +77,7 @@ import {
|
|
|
65
77
|
waitForPort,
|
|
66
78
|
worktreeStackName,
|
|
67
79
|
writeEnvFile
|
|
68
|
-
} from "./mesh.chunk-
|
|
80
|
+
} from "./mesh.chunk-7HTKSUWR.js";
|
|
69
81
|
import {
|
|
70
82
|
COMPOSE_PROJECT,
|
|
71
83
|
DEFAULT_HUB_PORT,
|
|
@@ -114,7 +126,7 @@ import {
|
|
|
114
126
|
homeNpmrcPath,
|
|
115
127
|
isNpmAuthError,
|
|
116
128
|
probeRegistryToken
|
|
117
|
-
} from "./mesh.chunk-
|
|
129
|
+
} from "./mesh.chunk-6SSOVZOI.js";
|
|
118
130
|
import {
|
|
119
131
|
createVcsFolderReader,
|
|
120
132
|
deriveVcsBaseUrl,
|
|
@@ -913,7 +925,7 @@ async function psqlCommand(options) {
|
|
|
913
925
|
const databaseUrl = await getDatabaseUrl(app.tenant, app.stage, { app: appName });
|
|
914
926
|
const parsed = new URL(databaseUrl);
|
|
915
927
|
const username = parsed.username;
|
|
916
|
-
const
|
|
928
|
+
const password = decodeURIComponent(parsed.password);
|
|
917
929
|
const database = parsed.pathname.slice(1);
|
|
918
930
|
console.log("");
|
|
919
931
|
logInfo(`Connecting to ${database} as ${username}...`);
|
|
@@ -923,7 +935,7 @@ async function psqlCommand(options) {
|
|
|
923
935
|
["-h", "localhost", "-p", "5432", "-U", username, "-d", database],
|
|
924
936
|
{
|
|
925
937
|
stdio: "inherit",
|
|
926
|
-
env: { ...process.env, PGPASSWORD:
|
|
938
|
+
env: { ...process.env, PGPASSWORD: password }
|
|
927
939
|
}
|
|
928
940
|
);
|
|
929
941
|
psql.on("exit", (code) => {
|
|
@@ -1529,7 +1541,7 @@ var DOCS_PREVIEW_PORT = "4410";
|
|
|
1529
1541
|
var CLI_REFERENCE_PATH = "docs/portal/generated/cli-reference.md";
|
|
1530
1542
|
async function renderCliReference() {
|
|
1531
1543
|
const [{ createProgram: createProgram2 }, { extractCliReference, renderCliReferenceMarkdown }] = await Promise.all([
|
|
1532
|
-
import("./mesh.program-
|
|
1544
|
+
import("./mesh.program-K5JQXEHX.js"),
|
|
1533
1545
|
import("./mesh.cli-reference-H3TOPIET.js")
|
|
1534
1546
|
]);
|
|
1535
1547
|
return renderCliReferenceMarkdown(extractCliReference(createProgram2()));
|
|
@@ -1601,7 +1613,7 @@ function registerDocsCommand(program) {
|
|
|
1601
1613
|
"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"
|
|
1602
1614
|
).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(
|
|
1603
1615
|
(opts) => guarded(async () => {
|
|
1604
|
-
const { runDocsStart } = await import("./mesh.start-
|
|
1616
|
+
const { runDocsStart } = await import("./mesh.start-KZ5L6SOJ.js");
|
|
1605
1617
|
await runDocsStart({
|
|
1606
1618
|
repoRoot: findRepoRoot(process.cwd()),
|
|
1607
1619
|
version: opts.version,
|
|
@@ -1613,13 +1625,13 @@ function registerDocsCommand(program) {
|
|
|
1613
1625
|
);
|
|
1614
1626
|
docs.command("stop").description(`Stop the detached docs server (the tmux session "${"mesh-docs"}")`).action(
|
|
1615
1627
|
() => guarded(async () => {
|
|
1616
|
-
const { runDocsStop } = await import("./mesh.start-
|
|
1628
|
+
const { runDocsStop } = await import("./mesh.start-KZ5L6SOJ.js");
|
|
1617
1629
|
runDocsStop();
|
|
1618
1630
|
})()
|
|
1619
1631
|
);
|
|
1620
1632
|
docs.command("serve-static", { hidden: true }).option("--root <dir>", "built site root", "").option("--port <port>", "port", "4400").action(
|
|
1621
1633
|
(opts) => guarded(async () => {
|
|
1622
|
-
const { runDocsServeStatic } = await import("./mesh.start-
|
|
1634
|
+
const { runDocsServeStatic } = await import("./mesh.start-KZ5L6SOJ.js");
|
|
1623
1635
|
await runDocsServeStatic(opts);
|
|
1624
1636
|
})()
|
|
1625
1637
|
);
|
|
@@ -1662,7 +1674,7 @@ function registerDocsCommand(program) {
|
|
|
1662
1674
|
);
|
|
1663
1675
|
docs.command("list").description("List the published docs versions (each is an @mesh-tech/* baseline)").action(
|
|
1664
1676
|
() => guarded(async () => {
|
|
1665
|
-
const { runDocsList } = await import("./mesh.start-
|
|
1677
|
+
const { runDocsList } = await import("./mesh.start-KZ5L6SOJ.js");
|
|
1666
1678
|
await runDocsList();
|
|
1667
1679
|
})()
|
|
1668
1680
|
);
|
|
@@ -1672,7 +1684,6 @@ function registerDocsCommand(program) {
|
|
|
1672
1684
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
1673
1685
|
import * as fs4 from "node:fs";
|
|
1674
1686
|
import * as net3 from "node:net";
|
|
1675
|
-
import * as os from "node:os";
|
|
1676
1687
|
import * as path4 from "node:path";
|
|
1677
1688
|
import chalk from "chalk";
|
|
1678
1689
|
var HUB_SESSION_PREFIX = "mesh-hub-dev";
|
|
@@ -1705,7 +1716,7 @@ function killInstructions(targets) {
|
|
|
1705
1716
|
var DEFAULT_HUB_UI_PORT = Number(DEFAULT_HUB_PORT);
|
|
1706
1717
|
var DEFAULT_HUB_API_PORT = 3002;
|
|
1707
1718
|
function devSessionsDir() {
|
|
1708
|
-
return
|
|
1719
|
+
return devSessionsRoot();
|
|
1709
1720
|
}
|
|
1710
1721
|
function listDevSessions(dir = devSessionsDir()) {
|
|
1711
1722
|
if (!fs4.existsSync(dir)) return [];
|
|
@@ -1967,7 +1978,7 @@ function isPortListening(port) {
|
|
|
1967
1978
|
});
|
|
1968
1979
|
}
|
|
1969
1980
|
function hubEnvDir(sessionName) {
|
|
1970
|
-
return path4.join(
|
|
1981
|
+
return path4.join(devSessionsRoot(), sessionName);
|
|
1971
1982
|
}
|
|
1972
1983
|
function parsePort(raw, fallback, source) {
|
|
1973
1984
|
if (raw === void 0) return fallback;
|
|
@@ -2067,6 +2078,7 @@ ${killInstructions(targets).join("\n")}`,
|
|
|
2067
2078
|
const apiDir = path4.join(platformDir, "apps", "hub", "api");
|
|
2068
2079
|
const uiDir = path4.join(platformDir, "apps", "hub", "ui");
|
|
2069
2080
|
execFileSync2("tmux", ["new-session", "-d", "-s", hubSession, "-n", "api", "-c", apiDir]);
|
|
2081
|
+
const hostEnv = pickLaunchHostEnv(process.env);
|
|
2070
2082
|
if (!assembled.apiEnv.DEV_USER_TOKEN_URL && assembled.apiEnv.DEV_USER_ID_TOKEN) {
|
|
2071
2083
|
const platform = session.state.devOutput.platform;
|
|
2072
2084
|
const credContext = `mesh.${platform.env}`;
|
|
@@ -2076,11 +2088,19 @@ ${killInstructions(targets).join("\n")}`,
|
|
|
2076
2088
|
execFileSync2("tmux", ["set-option", "-t", `${hubSession}:token-server`, "remain-on-exit", "on"], {
|
|
2077
2089
|
stdio: "ignore"
|
|
2078
2090
|
});
|
|
2091
|
+
const tokenServerEnvFile = path4.join(hubEnvDir(hubSession), "token-server.env.sh");
|
|
2092
|
+
writeEnvFile(tokenServerEnvFile, hostEnv);
|
|
2079
2093
|
execFileSync2("tmux", [
|
|
2080
2094
|
"send-keys",
|
|
2081
2095
|
"-t",
|
|
2082
2096
|
`${hubSession}:token-server`,
|
|
2083
|
-
|
|
2097
|
+
buildLaunchCommand(
|
|
2098
|
+
tokenServerEnvFile,
|
|
2099
|
+
platformDir,
|
|
2100
|
+
`npx mesh dev __token-server ${tokenPort} ${credContext}`,
|
|
2101
|
+
void 0,
|
|
2102
|
+
hostEnv
|
|
2103
|
+
),
|
|
2084
2104
|
"Enter"
|
|
2085
2105
|
]);
|
|
2086
2106
|
for (let i = 0; i < 15 && !await isPortListening(tokenPort); i++) {
|
|
@@ -2092,14 +2112,14 @@ ${killInstructions(targets).join("\n")}`,
|
|
|
2092
2112
|
}
|
|
2093
2113
|
const launch = (window, dir, env, cmd, createWindow) => {
|
|
2094
2114
|
const envFile = path4.join(hubEnvDir(hubSession), `${window}.env.sh`);
|
|
2095
|
-
writeEnvFile(envFile, env);
|
|
2115
|
+
writeEnvFile(envFile, { ...hostEnv, ...env });
|
|
2096
2116
|
if (createWindow) {
|
|
2097
2117
|
execFileSync2("tmux", ["new-window", "-t", hubSession, "-n", window, "-c", dir]);
|
|
2098
2118
|
}
|
|
2099
2119
|
execFileSync2("tmux", ["set-option", "-t", `${hubSession}:${window}`, "remain-on-exit", "on"], {
|
|
2100
2120
|
stdio: "ignore"
|
|
2101
2121
|
});
|
|
2102
|
-
execFileSync2("tmux", ["send-keys", "-t", `${hubSession}:${window}`, buildLaunchCommand(envFile, dir, cmd), "Enter"]);
|
|
2122
|
+
execFileSync2("tmux", ["send-keys", "-t", `${hubSession}:${window}`, buildLaunchCommand(envFile, dir, cmd, void 0, hostEnv), "Enter"]);
|
|
2103
2123
|
};
|
|
2104
2124
|
launch("api", apiDir, assembled.apiEnv, "pnpm dev", false);
|
|
2105
2125
|
launch("ui", uiDir, assembled.uiEnv, `pnpm dev --port ${uiPort} --strictPort`, true);
|
|
@@ -2140,11 +2160,11 @@ import chalk2 from "chalk";
|
|
|
2140
2160
|
import * as fs5 from "fs";
|
|
2141
2161
|
import * as path5 from "path";
|
|
2142
2162
|
async function setupPrompts() {
|
|
2143
|
-
const [{ default:
|
|
2163
|
+
const [{ default: input }, { default: confirm }] = await Promise.all([
|
|
2144
2164
|
import("@inquirer/input"),
|
|
2145
2165
|
import("@inquirer/confirm")
|
|
2146
2166
|
]);
|
|
2147
|
-
return { input: (args) =>
|
|
2167
|
+
return { input: (args) => input(args), confirm: (args) => confirm(args) };
|
|
2148
2168
|
}
|
|
2149
2169
|
var LOCAL_HUB_API = "http://localhost:4568";
|
|
2150
2170
|
function isLocalContext(context) {
|
|
@@ -2177,7 +2197,7 @@ async function registryChecks(args) {
|
|
|
2177
2197
|
const { fix, profile } = args;
|
|
2178
2198
|
const probe = args.probe ?? probeRegistryToken;
|
|
2179
2199
|
const login = args.login ?? (async () => {
|
|
2180
|
-
const { runRegistryLogin } = await import("./mesh.registry-
|
|
2200
|
+
const { runRegistryLogin } = await import("./mesh.registry-JLQYFUNN.js");
|
|
2181
2201
|
await runRegistryLogin(void 0, profile ? { profile } : {});
|
|
2182
2202
|
});
|
|
2183
2203
|
const REGISTRY_FIX = registryFixCommand(profile);
|
|
@@ -2333,7 +2353,7 @@ function registerInitCommands(program) {
|
|
|
2333
2353
|
`nothing deployed yet \u2014 scaffold a tenant platform repo for \`<tenant>.<env>\` (default env: ${PLATFORM_SETUP_DEFAULTS.env}) and print its deploy sequence`
|
|
2334
2354
|
).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(
|
|
2335
2355
|
async (opts) => {
|
|
2336
|
-
const { runInitWizard } = await import("./mesh.wizard-
|
|
2356
|
+
const { runInitWizard } = await import("./mesh.wizard-FCTT55KI.js");
|
|
2337
2357
|
const code = await runInitWizard(opts);
|
|
2338
2358
|
if (code !== 0) process.exitCode = code;
|
|
2339
2359
|
}
|
|
@@ -2349,7 +2369,7 @@ function registerInitCommands(program) {
|
|
|
2349
2369
|
throw new MeshCliError(`Invalid tenant name '${tenant}' (lowercase alphanumeric + dashes).`);
|
|
2350
2370
|
}
|
|
2351
2371
|
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
2352
|
-
const { resolvePlatformSetup, scaffoldPlatformRepo, ensureStateBucket, renderPlatformNextSteps } = await import("./mesh.platform-setup-
|
|
2372
|
+
const { resolvePlatformSetup, scaffoldPlatformRepo, ensureStateBucket, renderPlatformNextSteps } = await import("./mesh.platform-setup-2ZDMHRCI.js");
|
|
2353
2373
|
const setup = await resolvePlatformSetup(tenant, opts, {
|
|
2354
2374
|
prompts: interactive && !opts.yes ? await setupPrompts() : void 0,
|
|
2355
2375
|
interactive
|
|
@@ -2415,7 +2435,7 @@ function registerInitCommands(program) {
|
|
|
2415
2435
|
// packages/mesh-cli/src/commands/install-shim.ts
|
|
2416
2436
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
2417
2437
|
import * as fs6 from "fs";
|
|
2418
|
-
import * as
|
|
2438
|
+
import * as os from "os";
|
|
2419
2439
|
import * as path6 from "path";
|
|
2420
2440
|
function shimScript() {
|
|
2421
2441
|
return `#!/bin/sh
|
|
@@ -2489,7 +2509,7 @@ exit 1
|
|
|
2489
2509
|
`;
|
|
2490
2510
|
}
|
|
2491
2511
|
function defaultShimDir() {
|
|
2492
|
-
return path6.join(
|
|
2512
|
+
return path6.join(os.homedir(), ".local", "bin");
|
|
2493
2513
|
}
|
|
2494
2514
|
function dirOnPath(dir, pathEnv) {
|
|
2495
2515
|
if (!pathEnv) return false;
|
|
@@ -2520,7 +2540,7 @@ function registerInstallShimCommand(program) {
|
|
|
2520
2540
|
} else {
|
|
2521
2541
|
logInfo("Bare `mesh <cmd>` now runs the local source of whatever workspace you're in.");
|
|
2522
2542
|
}
|
|
2523
|
-
const diagPath = path6.join(
|
|
2543
|
+
const diagPath = path6.join(os.tmpdir(), "mesh-shim-selftest.log");
|
|
2524
2544
|
let stdout = "";
|
|
2525
2545
|
let stderr = "";
|
|
2526
2546
|
let status = 0;
|
|
@@ -2574,7 +2594,7 @@ import chalk3 from "chalk";
|
|
|
2574
2594
|
// packages/mesh-cli/src/commands/local/hub-local.ts
|
|
2575
2595
|
import { execFile, execFileSync as execFileSync4 } from "child_process";
|
|
2576
2596
|
import * as fs7 from "fs";
|
|
2577
|
-
import * as
|
|
2597
|
+
import * as os2 from "os";
|
|
2578
2598
|
import * as path7 from "path";
|
|
2579
2599
|
import { promisify } from "util";
|
|
2580
2600
|
var execFileAsync = promisify(execFile);
|
|
@@ -2585,7 +2605,7 @@ function cacheDir() {
|
|
|
2585
2605
|
return meshCacheDir("hub-local");
|
|
2586
2606
|
}
|
|
2587
2607
|
function npmrcPath() {
|
|
2588
|
-
const p = path7.join(
|
|
2608
|
+
const p = path7.join(os2.homedir(), ".npmrc");
|
|
2589
2609
|
if (!fs7.existsSync(p) || !fs7.readFileSync(p, "utf-8").includes("codeartifact")) {
|
|
2590
2610
|
throw new MeshCliError(
|
|
2591
2611
|
"The local Hub builds from the published @mesh-tech/hub tarball, which needs registry auth.",
|
|
@@ -2615,7 +2635,7 @@ function ensureHubAuthImage() {
|
|
|
2615
2635
|
logSuccess(`Built ${HUB_AUTH_IMAGE}`);
|
|
2616
2636
|
}
|
|
2617
2637
|
function hasRegistryAuth() {
|
|
2618
|
-
const p = path7.join(
|
|
2638
|
+
const p = path7.join(os2.homedir(), ".npmrc");
|
|
2619
2639
|
return fs7.existsSync(p) && fs7.readFileSync(p, "utf-8").includes("codeartifact");
|
|
2620
2640
|
}
|
|
2621
2641
|
function localHubVersion() {
|
|
@@ -2870,8 +2890,8 @@ function withHubCatalogRefs(pointer, metadataRef) {
|
|
|
2870
2890
|
};
|
|
2871
2891
|
}
|
|
2872
2892
|
async function publishHubAuthzCatalog(compiled, awsConfig) {
|
|
2873
|
-
const { SSMClient:
|
|
2874
|
-
const ssm = new
|
|
2893
|
+
const { SSMClient: SSMClient3, GetParameterCommand, PutParameterCommand } = await import("@aws-sdk/client-ssm");
|
|
2894
|
+
const ssm = new SSMClient3(awsConfig);
|
|
2875
2895
|
await ssm.send(
|
|
2876
2896
|
new PutParameterCommand({
|
|
2877
2897
|
Name: HUB_OPS_HUB_METADATA_PARAM,
|
|
@@ -3238,6 +3258,7 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
3238
3258
|
{ remediation: { command: "mesh stop --force # stop it anyway" } }
|
|
3239
3259
|
);
|
|
3240
3260
|
}
|
|
3261
|
+
removeLocalAppSpiceDBs();
|
|
3241
3262
|
const aliases = removeAllAliasContainers();
|
|
3242
3263
|
if (aliases.length > 0) logInfo(`Removed ${aliases.length} local docs alias container(s).`);
|
|
3243
3264
|
const args = ["down"];
|
|
@@ -3342,6 +3363,72 @@ Re-running start from here may recreate shared containers with this checkout's c
|
|
|
3342
3363
|
});
|
|
3343
3364
|
}
|
|
3344
3365
|
|
|
3366
|
+
// packages/mesh-cli/src/commands/mcp/index.ts
|
|
3367
|
+
import * as path9 from "node:path";
|
|
3368
|
+
function registerMcpCommands(program) {
|
|
3369
|
+
const mcp = program.command("mcp").description("Manifest-driven MCP Integrations (reviewed tool catalogs)");
|
|
3370
|
+
mcp.command("review <manifest>").description(
|
|
3371
|
+
"Fetch a manifest's MCP server tools/list with the Integration's credential, diff it against the checked-in snapshot, and write the snapshot on confirmation"
|
|
3372
|
+
).option("--yes", "Write without prompting").option("--dry-run", "Report the diff and write nothing").option("--stack <stack>", "Pulumi stack name (override detection)").option("-t, --tenant <tenant>", "Tenant to address (override detection)").option("--region <region>", "AWS region (default: us-east-2)").option(
|
|
3373
|
+
"--secret <id>",
|
|
3374
|
+
"Secrets Manager secret holding the Integration credential (default: the deployed ExternalService's own secret)"
|
|
3375
|
+
).action(async (manifest, opts) => {
|
|
3376
|
+
const { runMcpReviewCommand } = await import("./mesh.review-command-LUVZQN2T.js");
|
|
3377
|
+
try {
|
|
3378
|
+
await runMcpReviewCommand(manifest, opts);
|
|
3379
|
+
} catch (error) {
|
|
3380
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
3381
|
+
process.exit(1);
|
|
3382
|
+
}
|
|
3383
|
+
});
|
|
3384
|
+
mcp.command("generate <manifest>").description(
|
|
3385
|
+
"Write the worker package mesh.apps.McpIntegration deploys (package.json, main.ts, openapi.json) from a manifest and its reviewed snapshot; commit it with the lockfile"
|
|
3386
|
+
).option("--out <dir>", "Package directory (default: <manifest dir>/.mesh-mcp/<name>)").option(
|
|
3387
|
+
"--refresh-versions",
|
|
3388
|
+
"Re-resolve every dependency version instead of keeping the committed ones"
|
|
3389
|
+
).action(async (manifest, opts) => {
|
|
3390
|
+
const { generateMcpServeDir } = await import("./mesh.generate-XSM4C6FQ.js");
|
|
3391
|
+
const { workspaceMembership } = await import("./mesh.workspace-membership-DI3YQGEK.js");
|
|
3392
|
+
try {
|
|
3393
|
+
const { serveDir, written } = generateMcpServeDir(manifest, {
|
|
3394
|
+
...opts.out ? { out: opts.out } : {},
|
|
3395
|
+
...opts.refreshVersions ? { refreshVersions: true } : {}
|
|
3396
|
+
});
|
|
3397
|
+
if (written.length === 0) {
|
|
3398
|
+
logInfo(`${serveDir} is current.`);
|
|
3399
|
+
} else {
|
|
3400
|
+
logInfo(`Wrote ${written.join(", ")} in ${serveDir}.`);
|
|
3401
|
+
if (written.includes("package.json")) {
|
|
3402
|
+
logInfo("Run `pnpm install` so the lockfile records it, then commit both.");
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
const membership = workspaceMembership(serveDir);
|
|
3406
|
+
if (!membership.workspaceFile) {
|
|
3407
|
+
logWarn(
|
|
3408
|
+
`No pnpm-workspace.yaml above ${serveDir}: the worker image installs this package from a pnpm workspace, so it must be in one.`
|
|
3409
|
+
);
|
|
3410
|
+
} else if (!membership.member && membership.suggestedGlob) {
|
|
3411
|
+
const { ensureWorkspaceGlobs } = await import("./mesh.create-app-Z3RKSTBO.js");
|
|
3412
|
+
const added = ensureWorkspaceGlobs(path9.dirname(membership.workspaceFile), [
|
|
3413
|
+
membership.suggestedGlob
|
|
3414
|
+
]);
|
|
3415
|
+
if (added.length > 0) {
|
|
3416
|
+
logInfo(
|
|
3417
|
+
`${membership.workspaceFile}: added ${added.join(", ")} so \`pnpm install\` records the package.`
|
|
3418
|
+
);
|
|
3419
|
+
} else {
|
|
3420
|
+
logWarn(
|
|
3421
|
+
`${serveDir} is not a member of the workspace in ${membership.workspaceFile}, so \`pnpm install\` will not record it. Add "${membership.suggestedGlob}" to its packages.`
|
|
3422
|
+
);
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
} catch (error) {
|
|
3426
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
3427
|
+
process.exit(1);
|
|
3428
|
+
}
|
|
3429
|
+
});
|
|
3430
|
+
}
|
|
3431
|
+
|
|
3345
3432
|
// packages/mesh-cli/src/commands/secrets/index.ts
|
|
3346
3433
|
import { Option } from "commander";
|
|
3347
3434
|
|
|
@@ -3461,441 +3548,14 @@ async function execCommand2(args) {
|
|
|
3461
3548
|
});
|
|
3462
3549
|
}
|
|
3463
3550
|
|
|
3464
|
-
// packages/mesh-cli/src/commands/secrets/set.ts
|
|
3465
|
-
import {
|
|
3466
|
-
SSMClient,
|
|
3467
|
-
GetParametersByPathCommand
|
|
3468
|
-
} from "@aws-sdk/client-ssm";
|
|
3469
|
-
import {
|
|
3470
|
-
SecretsManagerClient as SecretsManagerClient4,
|
|
3471
|
-
GetSecretValueCommand as GetSecretValueCommand4,
|
|
3472
|
-
PutSecretValueCommand,
|
|
3473
|
-
CreateSecretCommand
|
|
3474
|
-
} from "@aws-sdk/client-secrets-manager";
|
|
3475
|
-
import input from "@inquirer/input";
|
|
3476
|
-
import password from "@inquirer/password";
|
|
3477
|
-
|
|
3478
|
-
// packages/secrets/src/index.ts
|
|
3479
|
-
import {
|
|
3480
|
-
SecretsManagerClient as SecretsManagerClient3,
|
|
3481
|
-
GetSecretValueCommand as GetSecretValueCommand3
|
|
3482
|
-
} from "@aws-sdk/client-secrets-manager";
|
|
3483
|
-
var INSTANCE_INDEX_SUFFIX = ".index";
|
|
3484
|
-
function instanceIndexSecretId(secretPrefix) {
|
|
3485
|
-
return `${secretPrefix}/${INSTANCE_INDEX_SUFFIX}`;
|
|
3486
|
-
}
|
|
3487
|
-
function isInstanceKey(key) {
|
|
3488
|
-
return key.length > 0 && !key.includes("/") && !key.startsWith(".") && !key.endsWith(".config");
|
|
3489
|
-
}
|
|
3490
|
-
function instanceKeyFromSecretName(secretPrefix, secretName) {
|
|
3491
|
-
if (!secretName.startsWith(`${secretPrefix}/`)) return null;
|
|
3492
|
-
const key = secretName.slice(secretPrefix.length + 1);
|
|
3493
|
-
return isInstanceKey(key) ? key : null;
|
|
3494
|
-
}
|
|
3495
|
-
function parseInstanceIndex(secretString) {
|
|
3496
|
-
let parsed;
|
|
3497
|
-
try {
|
|
3498
|
-
parsed = JSON.parse(secretString);
|
|
3499
|
-
} catch {
|
|
3500
|
-
parsed = void 0;
|
|
3501
|
-
}
|
|
3502
|
-
const instances = parsed?.instances;
|
|
3503
|
-
if (!Array.isArray(instances) || !instances.every((k) => typeof k === "string")) {
|
|
3504
|
-
throw new Error(
|
|
3505
|
-
`Malformed instance index (expected {"instances": string[]}). Rebuild it with: mesh secrets reindex external/<name>`
|
|
3506
|
-
);
|
|
3507
|
-
}
|
|
3508
|
-
return instances.filter(isInstanceKey);
|
|
3509
|
-
}
|
|
3510
|
-
function buildInstanceIndexValue(keys) {
|
|
3511
|
-
const instances = [...new Set([...keys].filter(isInstanceKey))].sort();
|
|
3512
|
-
const index = { version: 1, instances };
|
|
3513
|
-
return JSON.stringify(index);
|
|
3514
|
-
}
|
|
3515
|
-
|
|
3516
|
-
// packages/mesh-cli/src/commands/secrets/context.ts
|
|
3517
|
-
function resolveSecretsContext(opts, stackOpt = resolveStackOption(opts)) {
|
|
3518
|
-
return detectContext(stackOpt, { tenant: opts.tenant, stack: stackOpt });
|
|
3519
|
-
}
|
|
3520
|
-
|
|
3521
|
-
// packages/mesh-cli/src/commands/secrets/set.ts
|
|
3522
|
-
async function ensureAwsCredentialsForStack(stack) {
|
|
3523
|
-
if (process.env.AWS_ACCESS_KEY_ID || process.env.AWS_SESSION_TOKEN) return;
|
|
3524
|
-
if (!stack) return;
|
|
3525
|
-
const appRoot = findAppRoot(process.cwd());
|
|
3526
|
-
if (!appRoot) return;
|
|
3527
|
-
const roleArn = readStackConfig(appRoot, stack, "mesh:deployerRole");
|
|
3528
|
-
if (!roleArn) return;
|
|
3529
|
-
const resolved = await resolveAwsCredentials(roleArn, appRoot, stack);
|
|
3530
|
-
if (resolved) {
|
|
3531
|
-
Object.assign(process.env, resolved.env);
|
|
3532
|
-
delete process.env.AWS_PROFILE;
|
|
3533
|
-
}
|
|
3534
|
-
}
|
|
3535
|
-
function normalizeEntry(raw) {
|
|
3536
|
-
if (raw.type === "group" && raw.fields) {
|
|
3537
|
-
return {
|
|
3538
|
-
type: "group",
|
|
3539
|
-
name: raw.name ?? "",
|
|
3540
|
-
description: raw.description ?? "",
|
|
3541
|
-
fields: normalizeFields(raw.fields)
|
|
3542
|
-
};
|
|
3543
|
-
}
|
|
3544
|
-
return {
|
|
3545
|
-
type: "field",
|
|
3546
|
-
name: raw.name ?? "",
|
|
3547
|
-
description: raw.description ?? "",
|
|
3548
|
-
secret: raw.secret ?? false,
|
|
3549
|
-
optional: raw.optional ?? false
|
|
3550
|
-
};
|
|
3551
|
-
}
|
|
3552
|
-
function normalizeFields(raw) {
|
|
3553
|
-
return Object.fromEntries(
|
|
3554
|
-
Object.entries(raw).map(([key, value]) => [key, normalizeEntry(value)])
|
|
3555
|
-
);
|
|
3556
|
-
}
|
|
3557
|
-
async function discoverExternalServices(ssmClient, tenant, platformEnv) {
|
|
3558
|
-
const services = /* @__PURE__ */ new Map();
|
|
3559
|
-
const basePath = `/mesh-platform/${tenant}/${platformEnv}`;
|
|
3560
|
-
let nextToken;
|
|
3561
|
-
do {
|
|
3562
|
-
const response = await ssmClient.send(
|
|
3563
|
-
new GetParametersByPathCommand({
|
|
3564
|
-
Path: basePath,
|
|
3565
|
-
Recursive: true,
|
|
3566
|
-
NextToken: nextToken
|
|
3567
|
-
})
|
|
3568
|
-
);
|
|
3569
|
-
for (const param of response.Parameters ?? []) {
|
|
3570
|
-
if (!param.Name || !param.Value) continue;
|
|
3571
|
-
const metaMatch = param.Name.match(
|
|
3572
|
-
/\/external-services\/([^/]+)\/meta$/
|
|
3573
|
-
);
|
|
3574
|
-
if (metaMatch?.[1]) {
|
|
3575
|
-
const serviceName = metaMatch[1];
|
|
3576
|
-
const meta = JSON.parse(param.Value);
|
|
3577
|
-
const existing = services.get(serviceName);
|
|
3578
|
-
services.set(serviceName, { ...existing, meta });
|
|
3579
|
-
}
|
|
3580
|
-
const credMatch = param.Name.match(
|
|
3581
|
-
/\/external-services\/([^/]+)\/credentials$/
|
|
3582
|
-
);
|
|
3583
|
-
if (credMatch?.[1]) {
|
|
3584
|
-
const serviceName = credMatch[1];
|
|
3585
|
-
const raw = JSON.parse(param.Value);
|
|
3586
|
-
const schema = {
|
|
3587
|
-
fields: normalizeFields(raw.fields),
|
|
3588
|
-
keyedBy: raw.keyedBy
|
|
3589
|
-
};
|
|
3590
|
-
const existing = services.get(serviceName);
|
|
3591
|
-
if (existing) {
|
|
3592
|
-
existing.schema = schema;
|
|
3593
|
-
} else {
|
|
3594
|
-
services.set(serviceName, { meta: {}, schema });
|
|
3595
|
-
}
|
|
3596
|
-
}
|
|
3597
|
-
}
|
|
3598
|
-
nextToken = response.NextToken;
|
|
3599
|
-
} while (nextToken);
|
|
3600
|
-
return services;
|
|
3601
|
-
}
|
|
3602
|
-
async function promptFields(fields, existing, result, opts, depth = 0) {
|
|
3603
|
-
for (const [fieldKey, entry] of Object.entries(fields)) {
|
|
3604
|
-
if (entry.type === "group") {
|
|
3605
|
-
const indent = " ".repeat(depth);
|
|
3606
|
-
console.error("");
|
|
3607
|
-
console.error(`${indent}\u2500\u2500 ${entry.name} \u2500\u2500`);
|
|
3608
|
-
const existingGroup = existing[fieldKey] ?? {};
|
|
3609
|
-
const resultGroup = {};
|
|
3610
|
-
await promptFields(entry.fields, existingGroup, resultGroup, opts, depth + 1);
|
|
3611
|
-
result[fieldKey] = resultGroup;
|
|
3612
|
-
} else {
|
|
3613
|
-
if (entry.optional && !opts.all) {
|
|
3614
|
-
const existingVal2 = existing[fieldKey];
|
|
3615
|
-
if (existingVal2 !== void 0 && existingVal2 !== "") {
|
|
3616
|
-
result[fieldKey] = existingVal2;
|
|
3617
|
-
}
|
|
3618
|
-
continue;
|
|
3619
|
-
}
|
|
3620
|
-
const existingVal = existing[fieldKey];
|
|
3621
|
-
const hasExisting = !!existingVal && existingVal !== "";
|
|
3622
|
-
const message = entry.description ? `${entry.name} (${entry.description})` : entry.name;
|
|
3623
|
-
const label = entry.optional ? `${message} [optional]` : message;
|
|
3624
|
-
let value;
|
|
3625
|
-
if (entry.secret) {
|
|
3626
|
-
value = await password({ message: label, mask: "*" });
|
|
3627
|
-
if (!value && hasExisting) {
|
|
3628
|
-
value = existingVal;
|
|
3629
|
-
}
|
|
3630
|
-
} else {
|
|
3631
|
-
value = await input({
|
|
3632
|
-
message: label,
|
|
3633
|
-
default: hasExisting ? existingVal : void 0
|
|
3634
|
-
});
|
|
3635
|
-
}
|
|
3636
|
-
result[fieldKey] = value || (hasExisting ? existingVal : "");
|
|
3637
|
-
}
|
|
3638
|
-
}
|
|
3639
|
-
}
|
|
3640
|
-
function displaySummary(fields, values, depth = 0) {
|
|
3641
|
-
const indent = " ".repeat(depth);
|
|
3642
|
-
for (const [key, entry] of Object.entries(fields)) {
|
|
3643
|
-
if (entry.type === "group") {
|
|
3644
|
-
console.error(`${indent}${entry.name}:`);
|
|
3645
|
-
const group = values[key] ?? {};
|
|
3646
|
-
displaySummary(entry.fields, group, depth + 1);
|
|
3647
|
-
} else {
|
|
3648
|
-
const val = values[key];
|
|
3649
|
-
if (!val) continue;
|
|
3650
|
-
const display = entry.secret ? "********" : String(val);
|
|
3651
|
-
console.error(`${indent}${entry.name}: ${display}`);
|
|
3652
|
-
}
|
|
3653
|
-
}
|
|
3654
|
-
}
|
|
3655
|
-
async function setCommand(servicePath, opts) {
|
|
3656
|
-
const stackOpt = resolveStackOption(opts);
|
|
3657
|
-
const context = resolveSecretsContext(opts, stackOpt);
|
|
3658
|
-
const region = opts.region ?? process.env.AWS_REGION ?? "us-east-2";
|
|
3659
|
-
await ensureAwsCredentialsForStack(stackOpt ?? context.stage);
|
|
3660
|
-
const ssmClient = new SSMClient({ region });
|
|
3661
|
-
const smClient = new SecretsManagerClient4({ region });
|
|
3662
|
-
const services = await discoverExternalServices(
|
|
3663
|
-
ssmClient,
|
|
3664
|
-
context.tenant,
|
|
3665
|
-
context.platformEnv
|
|
3666
|
-
);
|
|
3667
|
-
if (services.size === 0) {
|
|
3668
|
-
logError(
|
|
3669
|
-
'No external services found. Deploy an ExternalService first:\n new mesh.apps.ExternalService("symitar", { env, credentials: { ... } })'
|
|
3670
|
-
);
|
|
3671
|
-
process.exit(1);
|
|
3672
|
-
}
|
|
3673
|
-
let serviceName;
|
|
3674
|
-
if (servicePath) {
|
|
3675
|
-
serviceName = servicePath.replace(/^external\//, "");
|
|
3676
|
-
}
|
|
3677
|
-
if (!serviceName || !services.has(serviceName)) {
|
|
3678
|
-
if (serviceName) {
|
|
3679
|
-
logError(`External service "${serviceName}" not found.`);
|
|
3680
|
-
}
|
|
3681
|
-
console.error("\nAvailable external services:");
|
|
3682
|
-
for (const [name, svc2] of services) {
|
|
3683
|
-
const desc = svc2.meta?.description ? ` \u2014 ${svc2.meta.description}` : "";
|
|
3684
|
-
const type = svc2.meta?.type ? ` (${svc2.meta.type})` : "";
|
|
3685
|
-
console.error(` ${name}${type}${desc}`);
|
|
3686
|
-
}
|
|
3687
|
-
console.error(`
|
|
3688
|
-
Usage: mesh secrets set external/<name>`);
|
|
3689
|
-
process.exit(serviceName ? 1 : 0);
|
|
3690
|
-
}
|
|
3691
|
-
const svc = services.get(serviceName);
|
|
3692
|
-
const schema = svc.schema;
|
|
3693
|
-
if (!schema) {
|
|
3694
|
-
logError(`No credential schema found for "${serviceName}".`);
|
|
3695
|
-
process.exit(1);
|
|
3696
|
-
}
|
|
3697
|
-
const secretPrefix = svc.meta.secretPrefix;
|
|
3698
|
-
const secretId = opts.key ? `${secretPrefix}/${opts.key}` : secretPrefix;
|
|
3699
|
-
if (schema.keyedBy && !opts.key) {
|
|
3700
|
-
logError(
|
|
3701
|
-
`"${serviceName}" is multi-instance (keyed by ${schema.keyedBy}). Specify an instance:
|
|
3702
|
-
mesh secrets set external/${serviceName} --key=<${schema.keyedBy}>`
|
|
3703
|
-
);
|
|
3704
|
-
process.exit(1);
|
|
3705
|
-
}
|
|
3706
|
-
if (opts.key && !isInstanceKey(opts.key)) {
|
|
3707
|
-
logError(
|
|
3708
|
-
`Invalid instance key "${opts.key}": keys must not contain "/", start with ".", or end with ".config" \u2014 those names are reserved for the index and config mirrors.`
|
|
3709
|
-
);
|
|
3710
|
-
process.exit(1);
|
|
3711
|
-
}
|
|
3712
|
-
let existing = {};
|
|
3713
|
-
try {
|
|
3714
|
-
const response = await smClient.send(
|
|
3715
|
-
new GetSecretValueCommand4({ SecretId: secretId })
|
|
3716
|
-
);
|
|
3717
|
-
if (response.SecretString) {
|
|
3718
|
-
existing = JSON.parse(response.SecretString);
|
|
3719
|
-
}
|
|
3720
|
-
} catch (err) {
|
|
3721
|
-
if (!isResourceNotFound(err)) {
|
|
3722
|
-
throw err;
|
|
3723
|
-
}
|
|
3724
|
-
}
|
|
3725
|
-
if (opts.json) {
|
|
3726
|
-
let values2;
|
|
3727
|
-
try {
|
|
3728
|
-
values2 = JSON.parse(opts.json);
|
|
3729
|
-
} catch {
|
|
3730
|
-
logError(`Invalid JSON input. Provide valid JSON, e.g.: --json='{"key": "value"}'`);
|
|
3731
|
-
return;
|
|
3732
|
-
}
|
|
3733
|
-
const merged2 = deepMerge(existing, values2);
|
|
3734
|
-
await writeSecret(smClient, secretId, merged2, svc.meta);
|
|
3735
|
-
await writeConfigMirror(smClient, secretId, schema, merged2, svc.meta);
|
|
3736
|
-
if (opts.key) {
|
|
3737
|
-
await addKeyToInstanceIndex(smClient, secretPrefix, opts.key, serviceName);
|
|
3738
|
-
}
|
|
3739
|
-
logSuccess(`Credentials written to ${secretId}`);
|
|
3740
|
-
return;
|
|
3741
|
-
}
|
|
3742
|
-
console.error("");
|
|
3743
|
-
logInfo(`Setting credentials for: ${svc.meta.description || serviceName}`);
|
|
3744
|
-
if (opts.key) {
|
|
3745
|
-
logInfo(`Instance: ${opts.key}`);
|
|
3746
|
-
}
|
|
3747
|
-
logInfo(`Secret: ${secretId}`);
|
|
3748
|
-
const values = {};
|
|
3749
|
-
await promptFields(schema.fields, existing, values, { all: !!opts.all });
|
|
3750
|
-
console.error("");
|
|
3751
|
-
const merged = deepMerge(existing, values);
|
|
3752
|
-
await writeSecret(smClient, secretId, merged, svc.meta);
|
|
3753
|
-
await writeConfigMirror(smClient, secretId, schema, merged, svc.meta);
|
|
3754
|
-
if (opts.key) {
|
|
3755
|
-
await addKeyToInstanceIndex(smClient, secretPrefix, opts.key, serviceName);
|
|
3756
|
-
}
|
|
3757
|
-
logSuccess(`Credentials written to ${secretId}`);
|
|
3758
|
-
console.error("\nStored fields:");
|
|
3759
|
-
displaySummary(schema.fields, merged);
|
|
3760
|
-
console.error("");
|
|
3761
|
-
}
|
|
3762
|
-
function isResourceNotFound(err) {
|
|
3763
|
-
return isAwsErrorCode(err, "ResourceNotFoundException");
|
|
3764
|
-
}
|
|
3765
|
-
function deepMerge(target, source) {
|
|
3766
|
-
const result = { ...target };
|
|
3767
|
-
for (const [key, value] of Object.entries(source)) {
|
|
3768
|
-
if (value !== null && typeof value === "object" && !Array.isArray(value) && typeof result[key] === "object" && result[key] !== null && !Array.isArray(result[key])) {
|
|
3769
|
-
result[key] = deepMerge(
|
|
3770
|
-
result[key],
|
|
3771
|
-
value
|
|
3772
|
-
);
|
|
3773
|
-
} else {
|
|
3774
|
-
result[key] = value;
|
|
3775
|
-
}
|
|
3776
|
-
}
|
|
3777
|
-
return result;
|
|
3778
|
-
}
|
|
3779
|
-
async function writeSecret(client, secretId, values, meta) {
|
|
3780
|
-
const secretString = JSON.stringify(values);
|
|
3781
|
-
try {
|
|
3782
|
-
await client.send(
|
|
3783
|
-
new PutSecretValueCommand({
|
|
3784
|
-
SecretId: secretId,
|
|
3785
|
-
SecretString: secretString
|
|
3786
|
-
})
|
|
3787
|
-
);
|
|
3788
|
-
} catch (err) {
|
|
3789
|
-
if (isResourceNotFound(err)) {
|
|
3790
|
-
await client.send(
|
|
3791
|
-
new CreateSecretCommand({
|
|
3792
|
-
Name: secretId,
|
|
3793
|
-
Description: `External service credentials for ${meta.name} (instance)`,
|
|
3794
|
-
SecretString: secretString,
|
|
3795
|
-
Tags: [
|
|
3796
|
-
{ Key: "mesh:type", Value: "external-service" },
|
|
3797
|
-
{ Key: "mesh:service", Value: meta.name }
|
|
3798
|
-
]
|
|
3799
|
-
})
|
|
3800
|
-
);
|
|
3801
|
-
} else {
|
|
3802
|
-
throw err;
|
|
3803
|
-
}
|
|
3804
|
-
}
|
|
3805
|
-
}
|
|
3806
|
-
function extractNonSecretFields(fields, values) {
|
|
3807
|
-
const result = {};
|
|
3808
|
-
for (const [key, entry] of Object.entries(fields)) {
|
|
3809
|
-
if (entry.type === "group") {
|
|
3810
|
-
const groupValues = values[key] ?? {};
|
|
3811
|
-
const filtered = extractNonSecretFields(entry.fields, groupValues);
|
|
3812
|
-
if (Object.keys(filtered).length > 0) {
|
|
3813
|
-
result[key] = filtered;
|
|
3814
|
-
}
|
|
3815
|
-
} else if (!entry.secret && values[key] !== void 0) {
|
|
3816
|
-
result[key] = values[key];
|
|
3817
|
-
}
|
|
3818
|
-
}
|
|
3819
|
-
return result;
|
|
3820
|
-
}
|
|
3821
|
-
async function addKeyToInstanceIndex(client, secretPrefix, key, serviceName) {
|
|
3822
|
-
const indexId = instanceIndexSecretId(secretPrefix);
|
|
3823
|
-
try {
|
|
3824
|
-
let keys = [];
|
|
3825
|
-
try {
|
|
3826
|
-
const res = await client.send(new GetSecretValueCommand4({ SecretId: indexId }));
|
|
3827
|
-
keys = parseInstanceIndex(res.SecretString ?? "");
|
|
3828
|
-
} catch (err) {
|
|
3829
|
-
if (!isResourceNotFound(err)) throw err;
|
|
3830
|
-
}
|
|
3831
|
-
if (keys.includes(key)) return;
|
|
3832
|
-
const secretString = buildInstanceIndexValue([...keys, key]);
|
|
3833
|
-
try {
|
|
3834
|
-
await client.send(
|
|
3835
|
-
new PutSecretValueCommand({ SecretId: indexId, SecretString: secretString })
|
|
3836
|
-
);
|
|
3837
|
-
} catch (err) {
|
|
3838
|
-
if (!isResourceNotFound(err)) throw err;
|
|
3839
|
-
await client.send(
|
|
3840
|
-
new CreateSecretCommand({
|
|
3841
|
-
Name: indexId,
|
|
3842
|
-
Description: `Instance-key index for ${serviceName} (read by listInstances(); maintained by mesh secrets set/reindex and the Hub)`,
|
|
3843
|
-
SecretString: secretString,
|
|
3844
|
-
Tags: [
|
|
3845
|
-
{ Key: "mesh:type", Value: "external-service-index" },
|
|
3846
|
-
{ Key: "mesh:service", Value: serviceName }
|
|
3847
|
-
]
|
|
3848
|
-
})
|
|
3849
|
-
);
|
|
3850
|
-
logInfo(
|
|
3851
|
-
`Created ${indexId} OUT OF BAND \u2014 the declaring stack does not manage it. Deploy the declaring stack (it creates the index) before writing keys, or import this secret into the stack before its next deploy.`
|
|
3852
|
-
);
|
|
3853
|
-
}
|
|
3854
|
-
} catch (err) {
|
|
3855
|
-
logInfo(
|
|
3856
|
-
`Warning: failed to record instance "${key}" in ${indexId} \u2014 listInstances() will not see it until you run: mesh secrets reindex external/${serviceName} (${err})`
|
|
3857
|
-
);
|
|
3858
|
-
}
|
|
3859
|
-
}
|
|
3860
|
-
async function writeConfigMirror(client, secretId, schema, merged, meta) {
|
|
3861
|
-
const configId = `${secretId}/.config`;
|
|
3862
|
-
const configValues = extractNonSecretFields(schema.fields, merged);
|
|
3863
|
-
const secretString = JSON.stringify(configValues);
|
|
3864
|
-
try {
|
|
3865
|
-
try {
|
|
3866
|
-
await client.send(
|
|
3867
|
-
new PutSecretValueCommand({
|
|
3868
|
-
SecretId: configId,
|
|
3869
|
-
SecretString: secretString
|
|
3870
|
-
})
|
|
3871
|
-
);
|
|
3872
|
-
} catch (err) {
|
|
3873
|
-
if (isResourceNotFound(err)) {
|
|
3874
|
-
await client.send(
|
|
3875
|
-
new CreateSecretCommand({
|
|
3876
|
-
Name: configId,
|
|
3877
|
-
Description: `Non-secret credential fields for ${meta.name} (Hub display)`,
|
|
3878
|
-
SecretString: secretString,
|
|
3879
|
-
Tags: [{ Key: "mesh:type", Value: "external-service-config" }]
|
|
3880
|
-
})
|
|
3881
|
-
);
|
|
3882
|
-
} else {
|
|
3883
|
-
throw err;
|
|
3884
|
-
}
|
|
3885
|
-
}
|
|
3886
|
-
} catch (err) {
|
|
3887
|
-
logInfo(`Warning: failed to write .config mirror to ${configId}: ${err}`);
|
|
3888
|
-
}
|
|
3889
|
-
}
|
|
3890
|
-
|
|
3891
3551
|
// packages/mesh-cli/src/commands/secrets/reindex.ts
|
|
3892
|
-
import { SSMClient
|
|
3552
|
+
import { SSMClient } from "@aws-sdk/client-ssm";
|
|
3893
3553
|
import {
|
|
3894
|
-
SecretsManagerClient as
|
|
3554
|
+
SecretsManagerClient as SecretsManagerClient3,
|
|
3895
3555
|
ListSecretsCommand,
|
|
3896
|
-
GetSecretValueCommand as
|
|
3897
|
-
PutSecretValueCommand
|
|
3898
|
-
CreateSecretCommand
|
|
3556
|
+
GetSecretValueCommand as GetSecretValueCommand3,
|
|
3557
|
+
PutSecretValueCommand,
|
|
3558
|
+
CreateSecretCommand
|
|
3899
3559
|
} from "@aws-sdk/client-secrets-manager";
|
|
3900
3560
|
async function scanInstanceKeys(client, secretPrefix) {
|
|
3901
3561
|
const keys = [];
|
|
@@ -3919,17 +3579,10 @@ function indexAlreadyMatches(missing, stale, indexExists, malformed) {
|
|
|
3919
3579
|
return missing.length === 0 && stale.length === 0 && indexExists && !malformed;
|
|
3920
3580
|
}
|
|
3921
3581
|
async function reindexCommand(servicePath, opts) {
|
|
3922
|
-
const stackOpt = resolveStackOption(opts);
|
|
3923
|
-
const context = resolveSecretsContext(opts, stackOpt);
|
|
3924
3582
|
const region = opts.region ?? process.env.AWS_REGION ?? "us-east-2";
|
|
3925
|
-
|
|
3926
|
-
const
|
|
3927
|
-
const smClient = new
|
|
3928
|
-
const services = await discoverExternalServices(
|
|
3929
|
-
ssmClient,
|
|
3930
|
-
context.tenant,
|
|
3931
|
-
context.platformEnv
|
|
3932
|
-
);
|
|
3583
|
+
const ssmClient = new SSMClient({ region });
|
|
3584
|
+
const { services } = await discoverStackExternalServices(opts, ssmClient);
|
|
3585
|
+
const smClient = new SecretsManagerClient3({ region });
|
|
3933
3586
|
const serviceName = servicePath?.replace(/^external\//, "");
|
|
3934
3587
|
if (!serviceName || !services.has(serviceName)) {
|
|
3935
3588
|
if (serviceName) {
|
|
@@ -3959,7 +3612,7 @@ Usage: mesh secrets reindex external/<name>`);
|
|
|
3959
3612
|
let indexExists = true;
|
|
3960
3613
|
let malformed = false;
|
|
3961
3614
|
try {
|
|
3962
|
-
const res = await smClient.send(new
|
|
3615
|
+
const res = await smClient.send(new GetSecretValueCommand3({ SecretId: indexId }));
|
|
3963
3616
|
try {
|
|
3964
3617
|
listed = parseInstanceIndex(res.SecretString ?? "");
|
|
3965
3618
|
} catch {
|
|
@@ -3992,12 +3645,12 @@ async function writeInstanceIndex(client, secretPrefix, serviceName, keys) {
|
|
|
3992
3645
|
const secretString = buildInstanceIndexValue(keys);
|
|
3993
3646
|
try {
|
|
3994
3647
|
await client.send(
|
|
3995
|
-
new
|
|
3648
|
+
new PutSecretValueCommand({ SecretId: indexId, SecretString: secretString })
|
|
3996
3649
|
);
|
|
3997
3650
|
} catch (err) {
|
|
3998
3651
|
if (!isResourceNotFound(err)) throw err;
|
|
3999
3652
|
await client.send(
|
|
4000
|
-
new
|
|
3653
|
+
new CreateSecretCommand({
|
|
4001
3654
|
Name: indexId,
|
|
4002
3655
|
Description: `Instance-key index for ${serviceName} (read by listInstances(); maintained by mesh secrets set/reindex and the Hub)`,
|
|
4003
3656
|
SecretString: secretString,
|
|
@@ -4015,23 +3668,23 @@ async function writeInstanceIndex(client, secretPrefix, serviceName, keys) {
|
|
|
4015
3668
|
|
|
4016
3669
|
// packages/mesh-cli/src/commands/secrets/migrate-config.ts
|
|
4017
3670
|
import {
|
|
4018
|
-
SSMClient as
|
|
4019
|
-
GetParametersByPathCommand
|
|
3671
|
+
SSMClient as SSMClient2,
|
|
3672
|
+
GetParametersByPathCommand
|
|
4020
3673
|
} from "@aws-sdk/client-ssm";
|
|
4021
3674
|
import {
|
|
4022
|
-
SecretsManagerClient as
|
|
4023
|
-
GetSecretValueCommand as
|
|
4024
|
-
PutSecretValueCommand as
|
|
4025
|
-
CreateSecretCommand as
|
|
3675
|
+
SecretsManagerClient as SecretsManagerClient4,
|
|
3676
|
+
GetSecretValueCommand as GetSecretValueCommand4,
|
|
3677
|
+
PutSecretValueCommand as PutSecretValueCommand2,
|
|
3678
|
+
CreateSecretCommand as CreateSecretCommand2,
|
|
4026
3679
|
ListSecretsCommand as ListSecretsCommand2
|
|
4027
3680
|
} from "@aws-sdk/client-secrets-manager";
|
|
4028
|
-
function
|
|
3681
|
+
function normalizeEntry(raw) {
|
|
4029
3682
|
if (raw.type === "group" && raw.fields) {
|
|
4030
3683
|
return {
|
|
4031
3684
|
type: "group",
|
|
4032
3685
|
name: raw.name ?? "",
|
|
4033
3686
|
description: raw.description ?? "",
|
|
4034
|
-
fields:
|
|
3687
|
+
fields: normalizeFields(raw.fields)
|
|
4035
3688
|
};
|
|
4036
3689
|
}
|
|
4037
3690
|
return {
|
|
@@ -4042,18 +3695,18 @@ function normalizeEntry2(raw) {
|
|
|
4042
3695
|
optional: raw.optional ?? false
|
|
4043
3696
|
};
|
|
4044
3697
|
}
|
|
4045
|
-
function
|
|
3698
|
+
function normalizeFields(raw) {
|
|
4046
3699
|
return Object.fromEntries(
|
|
4047
|
-
Object.entries(raw).map(([key, value]) => [key,
|
|
3700
|
+
Object.entries(raw).map(([key, value]) => [key, normalizeEntry(value)])
|
|
4048
3701
|
);
|
|
4049
3702
|
}
|
|
4050
|
-
async function
|
|
3703
|
+
async function discoverExternalServices(ssmClient, tenant, platformEnv) {
|
|
4051
3704
|
const services = /* @__PURE__ */ new Map();
|
|
4052
3705
|
const basePath = `/mesh-platform/${tenant}/${platformEnv}`;
|
|
4053
3706
|
let nextToken;
|
|
4054
3707
|
do {
|
|
4055
3708
|
const response = await ssmClient.send(
|
|
4056
|
-
new
|
|
3709
|
+
new GetParametersByPathCommand({
|
|
4057
3710
|
Path: basePath,
|
|
4058
3711
|
Recursive: true,
|
|
4059
3712
|
NextToken: nextToken
|
|
@@ -4073,7 +3726,7 @@ async function discoverExternalServices2(ssmClient, tenant, platformEnv) {
|
|
|
4073
3726
|
const serviceName = credMatch[1];
|
|
4074
3727
|
const raw = JSON.parse(param.Value);
|
|
4075
3728
|
const schema = {
|
|
4076
|
-
fields:
|
|
3729
|
+
fields: normalizeFields(raw.fields),
|
|
4077
3730
|
keyedBy: raw.keyedBy
|
|
4078
3731
|
};
|
|
4079
3732
|
const existing = services.get(serviceName);
|
|
@@ -4088,12 +3741,12 @@ async function discoverExternalServices2(ssmClient, tenant, platformEnv) {
|
|
|
4088
3741
|
} while (nextToken);
|
|
4089
3742
|
return services;
|
|
4090
3743
|
}
|
|
4091
|
-
function
|
|
3744
|
+
function extractNonSecretFields(fields, values) {
|
|
4092
3745
|
const result = {};
|
|
4093
3746
|
for (const [key, entry] of Object.entries(fields)) {
|
|
4094
3747
|
if (entry.type === "group") {
|
|
4095
3748
|
const groupValues = values[key] ?? {};
|
|
4096
|
-
const filtered =
|
|
3749
|
+
const filtered = extractNonSecretFields(entry.fields, groupValues);
|
|
4097
3750
|
if (Object.keys(filtered).length > 0) {
|
|
4098
3751
|
result[key] = filtered;
|
|
4099
3752
|
}
|
|
@@ -4105,20 +3758,20 @@ function extractNonSecretFields2(fields, values) {
|
|
|
4105
3758
|
}
|
|
4106
3759
|
async function readSecret(client, secretId) {
|
|
4107
3760
|
try {
|
|
4108
|
-
const res = await client.send(new
|
|
3761
|
+
const res = await client.send(new GetSecretValueCommand4({ SecretId: secretId }));
|
|
4109
3762
|
return res.SecretString ? JSON.parse(res.SecretString) : null;
|
|
4110
3763
|
} catch (err) {
|
|
4111
3764
|
if (isAwsErrorCode(err, "ResourceNotFoundException")) return null;
|
|
4112
3765
|
throw err;
|
|
4113
3766
|
}
|
|
4114
3767
|
}
|
|
4115
|
-
async function
|
|
3768
|
+
async function writeSecret(client, secretId, values, description) {
|
|
4116
3769
|
const secretString = JSON.stringify(values);
|
|
4117
3770
|
try {
|
|
4118
|
-
await client.send(new
|
|
3771
|
+
await client.send(new PutSecretValueCommand2({ SecretId: secretId, SecretString: secretString }));
|
|
4119
3772
|
} catch (err) {
|
|
4120
3773
|
if (isAwsErrorCode(err, "ResourceNotFoundException")) {
|
|
4121
|
-
await client.send(new
|
|
3774
|
+
await client.send(new CreateSecretCommand2({
|
|
4122
3775
|
Name: secretId,
|
|
4123
3776
|
Description: description,
|
|
4124
3777
|
SecretString: secretString,
|
|
@@ -4131,7 +3784,7 @@ async function writeSecret2(client, secretId, values, description) {
|
|
|
4131
3784
|
}
|
|
4132
3785
|
async function secretExists(client, secretId) {
|
|
4133
3786
|
try {
|
|
4134
|
-
await client.send(new
|
|
3787
|
+
await client.send(new GetSecretValueCommand4({ SecretId: secretId }));
|
|
4135
3788
|
return true;
|
|
4136
3789
|
} catch (err) {
|
|
4137
3790
|
if (isAwsErrorCode(err, "ResourceNotFoundException")) return false;
|
|
@@ -4182,7 +3835,7 @@ async function migrateService(smClient, meta, schema, opts) {
|
|
|
4182
3835
|
skipped++;
|
|
4183
3836
|
return;
|
|
4184
3837
|
}
|
|
4185
|
-
const configValues =
|
|
3838
|
+
const configValues = extractNonSecretFields(schema.fields, values);
|
|
4186
3839
|
if (opts.dryRun) {
|
|
4187
3840
|
const fieldCount = Object.keys(configValues).length;
|
|
4188
3841
|
logInfo(` DRY-RUN ${label} \u2192 ${configId} (${fieldCount} non-secret fields)`);
|
|
@@ -4190,7 +3843,7 @@ async function migrateService(smClient, meta, schema, opts) {
|
|
|
4190
3843
|
return;
|
|
4191
3844
|
}
|
|
4192
3845
|
const desc = `Non-secret credential fields for ${meta.name} (Hub display)`;
|
|
4193
|
-
await
|
|
3846
|
+
await writeSecret(smClient, configId, configValues, desc);
|
|
4194
3847
|
logSuccess(` OK ${label} \u2192 ${configId}`);
|
|
4195
3848
|
migrated++;
|
|
4196
3849
|
} catch (err) {
|
|
@@ -4210,12 +3863,12 @@ async function migrateService(smClient, meta, schema, opts) {
|
|
|
4210
3863
|
async function migrateConfigCommand(opts) {
|
|
4211
3864
|
const context = resolveSecretsContext(opts);
|
|
4212
3865
|
const region = opts.region ?? process.env.AWS_REGION ?? "us-east-2";
|
|
4213
|
-
const ssmClient = new
|
|
4214
|
-
const smClient = new
|
|
3866
|
+
const ssmClient = new SSMClient2({ region });
|
|
3867
|
+
const smClient = new SecretsManagerClient4({ region });
|
|
4215
3868
|
logInfo(`Migrating .config mirrors for ${context.tenant}/${context.platformEnv}`);
|
|
4216
3869
|
if (opts.dryRun) logInfo("DRY-RUN mode \u2014 no writes");
|
|
4217
3870
|
if (opts.force) logInfo("FORCE mode \u2014 overwrite existing .config");
|
|
4218
|
-
const services = await
|
|
3871
|
+
const services = await discoverExternalServices(ssmClient, context.tenant, context.platformEnv);
|
|
4219
3872
|
if (services.size === 0) {
|
|
4220
3873
|
logInfo("No external services found.");
|
|
4221
3874
|
return;
|
|
@@ -4479,13 +4132,13 @@ function registerSiteCommands(program) {
|
|
|
4479
4132
|
|
|
4480
4133
|
// packages/mesh-cli/src/commands/stack.ts
|
|
4481
4134
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
4482
|
-
import * as
|
|
4135
|
+
import * as path11 from "path";
|
|
4483
4136
|
import * as fs10 from "fs";
|
|
4484
4137
|
import { parse as parseYaml2 } from "yaml";
|
|
4485
4138
|
|
|
4486
4139
|
// packages/mesh-cli/src/commands/stack-status.ts
|
|
4487
4140
|
import * as fs9 from "fs";
|
|
4488
|
-
import * as
|
|
4141
|
+
import * as path10 from "path";
|
|
4489
4142
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
4490
4143
|
var INFRA_PACKAGE = "@mesh-tech/infra-components";
|
|
4491
4144
|
var HUB_PACKAGE2 = "@mesh-tech/hub";
|
|
@@ -4503,10 +4156,10 @@ function targetForStack(projectDir, stack) {
|
|
|
4503
4156
|
return { stack, kind: "app", tenant: tenant2, env: env2, coreTenant: tenant2, coreEnv: env2 };
|
|
4504
4157
|
}
|
|
4505
4158
|
const declared = readStackConfig(projectDir, stack, "mesh:tenant");
|
|
4506
|
-
const layerDir = ["core", "platform"].includes(
|
|
4159
|
+
const layerDir = ["core", "platform"].includes(path10.basename(projectDir));
|
|
4507
4160
|
if (!declared && !layerDir) return null;
|
|
4508
4161
|
const { tenant, env } = splitLayerStack(stack, declared);
|
|
4509
|
-
const isCore =
|
|
4162
|
+
const isCore = path10.basename(projectDir) === "core";
|
|
4510
4163
|
return {
|
|
4511
4164
|
stack,
|
|
4512
4165
|
kind: "layer",
|
|
@@ -4522,13 +4175,13 @@ function findStatusTargets(cwd, stack) {
|
|
|
4522
4175
|
let projectDir = project;
|
|
4523
4176
|
let repoRoot = null;
|
|
4524
4177
|
if (!projectDir) {
|
|
4525
|
-
const platformDir =
|
|
4526
|
-
if (fs9.existsSync(
|
|
4178
|
+
const platformDir = path10.join(cwd, "platform");
|
|
4179
|
+
if (fs9.existsSync(path10.join(platformDir, "Pulumi.yaml"))) {
|
|
4527
4180
|
projectDir = platformDir;
|
|
4528
4181
|
repoRoot = cwd;
|
|
4529
4182
|
}
|
|
4530
|
-
} else if (["core", "platform"].includes(
|
|
4531
|
-
repoRoot =
|
|
4183
|
+
} else if (["core", "platform"].includes(path10.basename(projectDir))) {
|
|
4184
|
+
repoRoot = path10.dirname(projectDir);
|
|
4532
4185
|
}
|
|
4533
4186
|
if (!projectDir) return [];
|
|
4534
4187
|
const stacks = stack ? [stack] : findStackConfigs(projectDir);
|
|
@@ -4537,10 +4190,10 @@ function findStatusTargets(cwd, stack) {
|
|
|
4537
4190
|
const target = targetForStack(projectDir, name);
|
|
4538
4191
|
if (!target) continue;
|
|
4539
4192
|
if (repoRoot && target.kind === "layer") {
|
|
4540
|
-
const core =
|
|
4541
|
-
const platform =
|
|
4542
|
-
if (fs9.existsSync(
|
|
4543
|
-
if (fs9.existsSync(
|
|
4193
|
+
const core = path10.join(repoRoot, "core");
|
|
4194
|
+
const platform = path10.join(repoRoot, "platform");
|
|
4195
|
+
if (fs9.existsSync(path10.join(core, "package.json"))) target.coreDir = core;
|
|
4196
|
+
if (fs9.existsSync(path10.join(platform, "package.json"))) target.platformDir = platform;
|
|
4544
4197
|
}
|
|
4545
4198
|
targets.push(target);
|
|
4546
4199
|
}
|
|
@@ -4549,7 +4202,7 @@ function findStatusTargets(cwd, stack) {
|
|
|
4549
4202
|
function pinnedVersion(dir, pkg) {
|
|
4550
4203
|
if (!dir) return null;
|
|
4551
4204
|
try {
|
|
4552
|
-
const manifest = JSON.parse(fs9.readFileSync(
|
|
4205
|
+
const manifest = JSON.parse(fs9.readFileSync(path10.join(dir, "package.json"), "utf-8"));
|
|
4553
4206
|
const spec = manifest.dependencies?.[pkg] ?? manifest.devDependencies?.[pkg];
|
|
4554
4207
|
return typeof spec === "string" ? spec.replace(/^[\^~=v]+/, "") : null;
|
|
4555
4208
|
} catch {
|
|
@@ -4669,8 +4322,8 @@ function latestPublished(pkg, cwd) {
|
|
|
4669
4322
|
async function readRegistration(name, region, auth) {
|
|
4670
4323
|
const { credentials, profile, signInHint } = auth;
|
|
4671
4324
|
try {
|
|
4672
|
-
const { SSMClient:
|
|
4673
|
-
const client = new
|
|
4325
|
+
const { SSMClient: SSMClient3, GetParameterCommand } = await import("@aws-sdk/client-ssm");
|
|
4326
|
+
const client = new SSMClient3({
|
|
4674
4327
|
region,
|
|
4675
4328
|
...profile && !credentials?.AWS_ACCESS_KEY_ID ? { profile } : {},
|
|
4676
4329
|
...credentials?.AWS_ACCESS_KEY_ID ? {
|
|
@@ -4741,7 +4394,7 @@ async function runStackStatus(cwd, opts) {
|
|
|
4741
4394
|
|
|
4742
4395
|
// packages/mesh-cli/src/commands/stack.ts
|
|
4743
4396
|
function readTopLevelYamlKey(appRoot, stack, key) {
|
|
4744
|
-
const configFile =
|
|
4397
|
+
const configFile = path11.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
4745
4398
|
if (!fs10.existsSync(configFile)) return null;
|
|
4746
4399
|
const content = fs10.readFileSync(configFile, "utf-8");
|
|
4747
4400
|
const pattern = new RegExp(`^${key}:\\s*(.+)$`, "m");
|
|
@@ -4750,7 +4403,7 @@ function readTopLevelYamlKey(appRoot, stack, key) {
|
|
|
4750
4403
|
return match[1].trim().replace(/^["']|["']$/g, "");
|
|
4751
4404
|
}
|
|
4752
4405
|
function readConfigBlockKey(appRoot, stack, key) {
|
|
4753
|
-
const configFile =
|
|
4406
|
+
const configFile = path11.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
4754
4407
|
if (!fs10.existsSync(configFile)) return null;
|
|
4755
4408
|
const content = fs10.readFileSync(configFile, "utf-8");
|
|
4756
4409
|
const pattern = new RegExp(`^\\s{2}${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}:\\s*(.+)$`, "m");
|
|
@@ -4812,7 +4465,7 @@ ${records}
|
|
|
4812
4465
|
}
|
|
4813
4466
|
}
|
|
4814
4467
|
function readBaseConfigFromYaml(appRoot, stack) {
|
|
4815
|
-
const file =
|
|
4468
|
+
const file = path11.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
4816
4469
|
if (!fs10.existsSync(file)) return {};
|
|
4817
4470
|
let doc;
|
|
4818
4471
|
try {
|
|
@@ -4915,7 +4568,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
4915
4568
|
);
|
|
4916
4569
|
}
|
|
4917
4570
|
}
|
|
4918
|
-
const newConfigPath =
|
|
4571
|
+
const newConfigPath = path11.join(appRoot, `Pulumi.${newStack}.yaml`);
|
|
4919
4572
|
const configExists = fs10.existsSync(newConfigPath);
|
|
4920
4573
|
const secretsProvider = readTopLevelYamlKey(appRoot, baseStack, "secretsprovider");
|
|
4921
4574
|
const credEnv = await resolvePulumiEnv({ appRoot, stack: baseStack });
|
|
@@ -5115,7 +4768,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
5115
4768
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
5116
4769
|
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "node:fs";
|
|
5117
4770
|
import { homedir as homedir3 } from "node:os";
|
|
5118
|
-
import { dirname as
|
|
4771
|
+
import { dirname as dirname8, join as join13, resolve as resolve6 } from "node:path";
|
|
5119
4772
|
|
|
5120
4773
|
// packages/mesh-cli/src/utils/recover-conversation.ts
|
|
5121
4774
|
async function classifyHistoryEvents(rawEvents, decodePayload) {
|
|
@@ -5803,8 +5456,8 @@ function extractEventPayloads(event) {
|
|
|
5803
5456
|
if (failure?.message) groups.push({ label: "failure", payloads: [{ __failure: failure }] });
|
|
5804
5457
|
}
|
|
5805
5458
|
if (event.nexusOperationScheduledEventAttributes) {
|
|
5806
|
-
const
|
|
5807
|
-
if (
|
|
5459
|
+
const input = event.nexusOperationScheduledEventAttributes.input;
|
|
5460
|
+
if (input) pushIfAny("input", [input]);
|
|
5808
5461
|
}
|
|
5809
5462
|
if (event.nexusOperationCompletedEventAttributes) {
|
|
5810
5463
|
const result = event.nexusOperationCompletedEventAttributes.result;
|
|
@@ -5987,7 +5640,7 @@ async function captureHistory(workflowId, runId, options) {
|
|
|
5987
5640
|
const { serializeHistoryToFixture } = await import("./mesh.capture-history-A4IAVVIR.js");
|
|
5988
5641
|
const { fixture, eventCount, decryptedPayloads } = await serializeHistoryToFixture(events, decrypter);
|
|
5989
5642
|
const outPath = options.out ?? join13(homedir3(), ".mesh", "replay-histories", `${sanitizeFileId(workflowId)}.json`);
|
|
5990
|
-
mkdirSync5(
|
|
5643
|
+
mkdirSync5(dirname8(outPath), { recursive: true });
|
|
5991
5644
|
if (options.out) warnIfNotGitIgnored(options.out);
|
|
5992
5645
|
writeFileSync5(outPath, JSON.stringify(fixture, null, 2) + "\n");
|
|
5993
5646
|
logSuccess(
|
|
@@ -6006,7 +5659,7 @@ function sanitizeFileId(id) {
|
|
|
6006
5659
|
function warnIfNotGitIgnored(outPath) {
|
|
6007
5660
|
const abs = resolve6(outPath);
|
|
6008
5661
|
try {
|
|
6009
|
-
const res = spawnSync2("git", ["-C",
|
|
5662
|
+
const res = spawnSync2("git", ["-C", dirname8(abs), "check-ignore", "-q", abs], {
|
|
6010
5663
|
stdio: "ignore"
|
|
6011
5664
|
});
|
|
6012
5665
|
if (res.status !== 1) return;
|
|
@@ -6116,7 +5769,7 @@ function registerTemporalCommands(program) {
|
|
|
6116
5769
|
// packages/mesh-cli/src/commands/tenant.ts
|
|
6117
5770
|
import chalk4 from "chalk";
|
|
6118
5771
|
import * as fs11 from "fs";
|
|
6119
|
-
import * as
|
|
5772
|
+
import * as path12 from "path";
|
|
6120
5773
|
import { parseDocument, YAMLMap, isMap } from "yaml";
|
|
6121
5774
|
function validateTenantName(name) {
|
|
6122
5775
|
return /^[a-z][a-z0-9-]*$/.test(name) && !name.endsWith("-");
|
|
@@ -6184,7 +5837,7 @@ function resolveStackConfig(explicitStack) {
|
|
|
6184
5837
|
{ remediation: { command: "mesh tenant add <name> --stack <stack>" } }
|
|
6185
5838
|
);
|
|
6186
5839
|
}
|
|
6187
|
-
const file =
|
|
5840
|
+
const file = path12.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
6188
5841
|
if (!fs11.existsSync(file)) {
|
|
6189
5842
|
throw new MeshCliError(`Stack config not found: ${file}`, {
|
|
6190
5843
|
remediation: { command: "mesh tenant add <name> --stack <stack>" }
|
|
@@ -6193,7 +5846,7 @@ function resolveStackConfig(explicitStack) {
|
|
|
6193
5846
|
return { appRoot, stack, file, content: fs11.readFileSync(file, "utf-8") };
|
|
6194
5847
|
}
|
|
6195
5848
|
function readProjectName(appRoot) {
|
|
6196
|
-
const projectDoc = parseDocument(fs11.readFileSync(
|
|
5849
|
+
const projectDoc = parseDocument(fs11.readFileSync(path12.join(appRoot, "Pulumi.yaml"), "utf-8"));
|
|
6197
5850
|
return String(projectDoc.get("name") ?? "");
|
|
6198
5851
|
}
|
|
6199
5852
|
function looksLikePlatformLayer(projectName) {
|
|
@@ -6236,7 +5889,7 @@ function registerTenantCommands(program) {
|
|
|
6236
5889
|
if (!result.ok) {
|
|
6237
5890
|
if (result.reason === "exists") {
|
|
6238
5891
|
throw new MeshCliError(
|
|
6239
|
-
`${result.detail} (${
|
|
5892
|
+
`${result.detail} (${path12.basename(resolved.file)}). Edit the existing entry instead of re-adding it.`
|
|
6240
5893
|
);
|
|
6241
5894
|
}
|
|
6242
5895
|
throw new MeshCliError(`${resolved.file}: ${result.detail}`);
|
|
@@ -6254,7 +5907,7 @@ function registerTenantCommands(program) {
|
|
|
6254
5907
|
return;
|
|
6255
5908
|
}
|
|
6256
5909
|
logInfo(
|
|
6257
|
-
`Tenant '${name}' registered in ${
|
|
5910
|
+
`Tenant '${name}' registered in ${path12.basename(resolved.file)} (mesh:tenants, subdomain '${subdomain}')${result.createdTenantsBlock ? " \u2014 created the mesh:tenants block" : ""}`
|
|
6258
5911
|
);
|
|
6259
5912
|
console.log("");
|
|
6260
5913
|
console.log("Next steps:");
|
|
@@ -6280,7 +5933,7 @@ function registerTenantCommands(program) {
|
|
|
6280
5933
|
`Project '${projectName}' does not look like a platform layer \u2014 tenants are declared on the tenant platform repo's PLATFORM stack (e.g. mesh-sandbox/platform).`
|
|
6281
5934
|
);
|
|
6282
5935
|
}
|
|
6283
|
-
logInfo(`No tenants declared in ${
|
|
5936
|
+
logInfo(`No tenants declared in ${path12.basename(resolved.file)}.`);
|
|
6284
5937
|
return;
|
|
6285
5938
|
}
|
|
6286
5939
|
logInfo(`Tenants on stack '${resolved.stack}':`);
|
|
@@ -6294,11 +5947,11 @@ function registerTenantCommands(program) {
|
|
|
6294
5947
|
// packages/mesh-cli/src/commands/tunnel/index.ts
|
|
6295
5948
|
import { spawn as spawn5 } from "child_process";
|
|
6296
5949
|
import * as fs12 from "fs";
|
|
6297
|
-
import * as
|
|
6298
|
-
import * as
|
|
5950
|
+
import * as os3 from "os";
|
|
5951
|
+
import * as path13 from "path";
|
|
6299
5952
|
import {
|
|
6300
|
-
SecretsManagerClient as
|
|
6301
|
-
GetSecretValueCommand as
|
|
5953
|
+
SecretsManagerClient as SecretsManagerClient5,
|
|
5954
|
+
GetSecretValueCommand as GetSecretValueCommand5
|
|
6302
5955
|
} from "@aws-sdk/client-secrets-manager";
|
|
6303
5956
|
function resolveTenantEnv(options) {
|
|
6304
5957
|
if (options.tenant && options.env) {
|
|
@@ -6326,8 +5979,8 @@ function readPulumiAwsRegion(stage) {
|
|
|
6326
5979
|
}
|
|
6327
5980
|
function awsProfileSections(name) {
|
|
6328
5981
|
return [
|
|
6329
|
-
[
|
|
6330
|
-
[
|
|
5982
|
+
[path13.join(os3.homedir(), ".aws", "config"), `[profile ${name}]`],
|
|
5983
|
+
[path13.join(os3.homedir(), ".aws", "credentials"), `[${name}]`]
|
|
6331
5984
|
];
|
|
6332
5985
|
}
|
|
6333
5986
|
function awsProfileExists(name) {
|
|
@@ -6368,8 +6021,8 @@ function awsProfileRegion(profile) {
|
|
|
6368
6021
|
}
|
|
6369
6022
|
function awsDefaultProfileSections() {
|
|
6370
6023
|
return [
|
|
6371
|
-
[
|
|
6372
|
-
[
|
|
6024
|
+
[path13.join(os3.homedir(), ".aws", "config"), "[default]"],
|
|
6025
|
+
[path13.join(os3.homedir(), ".aws", "credentials"), "[default]"]
|
|
6373
6026
|
];
|
|
6374
6027
|
}
|
|
6375
6028
|
function awsDefaultProfileRegion() {
|
|
@@ -6431,11 +6084,11 @@ function getEffectivePort(serviceName, options) {
|
|
|
6431
6084
|
return config.localPort;
|
|
6432
6085
|
}
|
|
6433
6086
|
}
|
|
6434
|
-
function parseServices(
|
|
6435
|
-
if (SERVICE_GROUPS[
|
|
6436
|
-
return SERVICE_GROUPS[
|
|
6087
|
+
function parseServices(input) {
|
|
6088
|
+
if (SERVICE_GROUPS[input]) {
|
|
6089
|
+
return SERVICE_GROUPS[input];
|
|
6437
6090
|
}
|
|
6438
|
-
return
|
|
6091
|
+
return input.split(",").map((s) => s.trim());
|
|
6439
6092
|
}
|
|
6440
6093
|
function spawnSsmTunnel(instanceId, service, localPort) {
|
|
6441
6094
|
return spawn5(
|
|
@@ -6582,10 +6235,10 @@ async function tunnelExternal(name, options) {
|
|
|
6582
6235
|
const { appTenant, appStage } = resolveCredentialAxis(options);
|
|
6583
6236
|
const secretId = externalSecretId(appTenant, appStage, name, key);
|
|
6584
6237
|
const setHint = `mesh secrets set external/${name}${key ? ` --key=${key}` : ""}`;
|
|
6585
|
-
const sm = new
|
|
6238
|
+
const sm = new SecretsManagerClient5({});
|
|
6586
6239
|
let creds;
|
|
6587
6240
|
try {
|
|
6588
|
-
const out = await sm.send(new
|
|
6241
|
+
const out = await sm.send(new GetSecretValueCommand5({ SecretId: secretId }));
|
|
6589
6242
|
creds = JSON.parse(out.SecretString ?? "{}");
|
|
6590
6243
|
} catch (err) {
|
|
6591
6244
|
logError(
|
|
@@ -6748,7 +6401,7 @@ async function resolveToken(opts) {
|
|
|
6748
6401
|
if (opts.token) return opts.token;
|
|
6749
6402
|
if (process.env.VCS_TOKEN) return process.env.VCS_TOKEN;
|
|
6750
6403
|
if (opts.context) {
|
|
6751
|
-
const { getValidToken: getValidToken2 } = await import("./mesh.login-
|
|
6404
|
+
const { getValidToken: getValidToken2 } = await import("./mesh.login-3AWVGPCM.js");
|
|
6752
6405
|
const token = await getValidToken2(opts.context);
|
|
6753
6406
|
if (token) return token;
|
|
6754
6407
|
}
|
|
@@ -6756,8 +6409,8 @@ async function resolveToken(opts) {
|
|
|
6756
6409
|
"no token: pass --token, set VCS_TOKEN, or pass --context <platform-context> (after mesh login)"
|
|
6757
6410
|
);
|
|
6758
6411
|
}
|
|
6759
|
-
async function vcsApi(baseUrl, token,
|
|
6760
|
-
const res = await fetch(`${baseUrl}${
|
|
6412
|
+
async function vcsApi(baseUrl, token, path15, method = "GET", body) {
|
|
6413
|
+
const res = await fetch(`${baseUrl}${path15}`, {
|
|
6761
6414
|
method,
|
|
6762
6415
|
headers: {
|
|
6763
6416
|
authorization: `Bearer ${token}`,
|
|
@@ -6768,7 +6421,7 @@ async function vcsApi(baseUrl, token, path14, method = "GET", body) {
|
|
|
6768
6421
|
const data = await res.json().catch(() => ({}));
|
|
6769
6422
|
if (!res.ok) {
|
|
6770
6423
|
throw new Error(
|
|
6771
|
-
`${method} ${
|
|
6424
|
+
`${method} ${path15} failed (${res.status}): ${String(data.error ?? "unknown error")}`
|
|
6772
6425
|
);
|
|
6773
6426
|
}
|
|
6774
6427
|
return data;
|
|
@@ -6801,8 +6454,8 @@ async function cloneCommand(repo, dest, opts) {
|
|
|
6801
6454
|
|
|
6802
6455
|
// packages/mesh-cli/src/commands/vcs/get.ts
|
|
6803
6456
|
import { writeFile, mkdir } from "node:fs/promises";
|
|
6804
|
-
import { join as join16, dirname as
|
|
6805
|
-
async function getCommand(repo,
|
|
6457
|
+
import { join as join16, dirname as dirname9 } from "node:path";
|
|
6458
|
+
async function getCommand(repo, path15, opts) {
|
|
6806
6459
|
let vcsBaseUrl;
|
|
6807
6460
|
let token;
|
|
6808
6461
|
if (opts.target) {
|
|
@@ -6817,18 +6470,18 @@ async function getCommand(repo, path14, opts) {
|
|
|
6817
6470
|
if (!token) throw new Error("no token: pass --target (after mesh login), or --token / --context");
|
|
6818
6471
|
const reader = createVcsFolderReader({ vcsBaseUrl, token });
|
|
6819
6472
|
try {
|
|
6820
|
-
const { ref, files } = await reader.readPath(repo,
|
|
6473
|
+
const { ref, files } = await reader.readPath(repo, path15);
|
|
6821
6474
|
if (files.length === 0) {
|
|
6822
|
-
logInfo(`no files at ${repo}:${
|
|
6475
|
+
logInfo(`no files at ${repo}:${path15}`);
|
|
6823
6476
|
return;
|
|
6824
6477
|
}
|
|
6825
6478
|
if (opts.output) {
|
|
6826
6479
|
for (const f of files) {
|
|
6827
6480
|
const abs = join16(opts.output, f.path);
|
|
6828
|
-
await mkdir(
|
|
6481
|
+
await mkdir(dirname9(abs), { recursive: true });
|
|
6829
6482
|
await writeFile(abs, f.contents);
|
|
6830
6483
|
}
|
|
6831
|
-
logInfo(`wrote ${files.length} file(s) from ${repo}:${
|
|
6484
|
+
logInfo(`wrote ${files.length} file(s) from ${repo}:${path15} (${ref}) \u2192 ${opts.output}`);
|
|
6832
6485
|
} else {
|
|
6833
6486
|
for (const f of files) {
|
|
6834
6487
|
if (files.length > 1) process.stdout.write(`
|
|
@@ -6843,10 +6496,10 @@ async function getCommand(repo, path14, opts) {
|
|
|
6843
6496
|
}
|
|
6844
6497
|
|
|
6845
6498
|
// packages/mesh-cli/src/commands/vcs/drafts.ts
|
|
6846
|
-
async function call(opts, repo,
|
|
6499
|
+
async function call(opts, repo, path15, method = "GET", body) {
|
|
6847
6500
|
const target = await resolveTarget2({ ...opts, repo });
|
|
6848
6501
|
const token = await resolveToken(opts);
|
|
6849
|
-
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${
|
|
6502
|
+
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${path15}`, method, body);
|
|
6850
6503
|
}
|
|
6851
6504
|
async function draftsListCommand(repo, opts) {
|
|
6852
6505
|
const data = await call(opts, repo, `/drafts${opts.all ? "?all=true" : ""}`);
|
|
@@ -6928,13 +6581,13 @@ function parseStatus(out) {
|
|
|
6928
6581
|
}
|
|
6929
6582
|
return changes;
|
|
6930
6583
|
}
|
|
6931
|
-
async function writeOp(cwd,
|
|
6932
|
-
const buf = await readFile2(join17(cwd,
|
|
6584
|
+
async function writeOp(cwd, path15) {
|
|
6585
|
+
const buf = await readFile2(join17(cwd, path15));
|
|
6933
6586
|
const asUtf8 = buf.toString("utf8");
|
|
6934
6587
|
if (Buffer.from(asUtf8, "utf8").equals(buf)) {
|
|
6935
|
-
return { op: "write", path:
|
|
6588
|
+
return { op: "write", path: path15, content: asUtf8 };
|
|
6936
6589
|
}
|
|
6937
|
-
return { op: "write", path:
|
|
6590
|
+
return { op: "write", path: path15, content: buf.toString("base64"), encoding: "base64" };
|
|
6938
6591
|
}
|
|
6939
6592
|
async function proposeCommand(opts) {
|
|
6940
6593
|
const cwd = process.cwd();
|
|
@@ -6978,8 +6631,8 @@ async function proposeCommand(opts) {
|
|
|
6978
6631
|
operations,
|
|
6979
6632
|
...opts.mergeParent ? { mergeParent: opts.mergeParent } : {}
|
|
6980
6633
|
};
|
|
6981
|
-
const
|
|
6982
|
-
const data = await vcsApi(target.baseUrl, token,
|
|
6634
|
+
const path15 = opts.revise ? `/v1/repos/${target.repo}/proposals/${opts.revise}/revisions` : `/v1/repos/${target.repo}/proposals`;
|
|
6635
|
+
const data = await vcsApi(target.baseUrl, token, path15, "POST", body);
|
|
6983
6636
|
console.log(
|
|
6984
6637
|
`proposal ${data.proposalId} @ ${data.sha.slice(0, 8)} \u2014 review: mesh vcs show ${target.repo} ${data.proposalId} --url ${target.baseUrl}`
|
|
6985
6638
|
);
|
|
@@ -6987,7 +6640,7 @@ async function proposeCommand(opts) {
|
|
|
6987
6640
|
|
|
6988
6641
|
// packages/mesh-cli/src/commands/vcs/rm.ts
|
|
6989
6642
|
import { mkdtemp, rm as rmrf } from "node:fs/promises";
|
|
6990
|
-
import { tmpdir as
|
|
6643
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
6991
6644
|
import { join as join18 } from "node:path";
|
|
6992
6645
|
function normalize(p) {
|
|
6993
6646
|
return p.trim().replace(/^\.\//, "").replace(/\/+$/, "");
|
|
@@ -6995,21 +6648,21 @@ function normalize(p) {
|
|
|
6995
6648
|
function expandPathsToDeletions(repoFiles, requested) {
|
|
6996
6649
|
const out = /* @__PURE__ */ new Set();
|
|
6997
6650
|
for (const raw of requested) {
|
|
6998
|
-
const
|
|
6999
|
-
if (
|
|
6651
|
+
const path15 = normalize(raw);
|
|
6652
|
+
if (path15.startsWith("/") || path15.split("/").includes("..")) {
|
|
7000
6653
|
throw new Error(
|
|
7001
6654
|
`"${raw}" is not a repo-relative path \u2014 vcs paths never start with "/" or traverse with "..".`
|
|
7002
6655
|
);
|
|
7003
6656
|
}
|
|
7004
|
-
const exact = repoFiles.filter((f) => f ===
|
|
6657
|
+
const exact = repoFiles.filter((f) => f === path15);
|
|
7005
6658
|
if (exact.length > 0) {
|
|
7006
6659
|
for (const f of exact) out.add(f);
|
|
7007
6660
|
continue;
|
|
7008
6661
|
}
|
|
7009
|
-
const under = repoFiles.filter((f) => f.startsWith(`${
|
|
6662
|
+
const under = repoFiles.filter((f) => f.startsWith(`${path15}/`));
|
|
7010
6663
|
if (under.length === 0) {
|
|
7011
6664
|
throw new Error(
|
|
7012
|
-
`"${raw}" matched no files in the repo \u2014 nothing was proposed. Check the path with: mesh vcs get <repo> ${
|
|
6665
|
+
`"${raw}" matched no files in the repo \u2014 nothing was proposed. Check the path with: mesh vcs get <repo> ${path15}`
|
|
7013
6666
|
);
|
|
7014
6667
|
}
|
|
7015
6668
|
for (const f of under) out.add(f);
|
|
@@ -7020,7 +6673,7 @@ async function rmCommand(repo, paths, opts) {
|
|
|
7020
6673
|
const baseUrl = (opts.url ?? process.env.VCS_URL)?.replace(/\/$/, "");
|
|
7021
6674
|
if (!baseUrl) throw new Error("rm requires --url or VCS_URL");
|
|
7022
6675
|
const token = await resolveToken(opts);
|
|
7023
|
-
const dir = await mkdtemp(join18(
|
|
6676
|
+
const dir = await mkdtemp(join18(tmpdir2(), "mesh-vcs-rm-"));
|
|
7024
6677
|
try {
|
|
7025
6678
|
const git = (args, cwd) => gitWithAuth(args, token, cwd);
|
|
7026
6679
|
await git([
|
|
@@ -7045,7 +6698,7 @@ async function rmCommand(repo, paths, opts) {
|
|
|
7045
6698
|
const body = {
|
|
7046
6699
|
baseCommit: head.trim(),
|
|
7047
6700
|
message: opts.message ?? `Delete ${doomed.length} file(s)`,
|
|
7048
|
-
operations: doomed.map((
|
|
6701
|
+
operations: doomed.map((path15) => ({ op: "delete", path: path15 }))
|
|
7049
6702
|
};
|
|
7050
6703
|
const data = await vcsApi(
|
|
7051
6704
|
baseUrl,
|
|
@@ -7065,10 +6718,10 @@ async function rmCommand(repo, paths, opts) {
|
|
|
7065
6718
|
}
|
|
7066
6719
|
|
|
7067
6720
|
// packages/mesh-cli/src/commands/vcs/review.ts
|
|
7068
|
-
async function call2(opts, repo,
|
|
6721
|
+
async function call2(opts, repo, path15, method = "GET", body) {
|
|
7069
6722
|
const target = await resolveTarget2({ ...opts, repo });
|
|
7070
6723
|
const token = await resolveToken(opts);
|
|
7071
|
-
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${
|
|
6724
|
+
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${path15}`, method, body);
|
|
7072
6725
|
}
|
|
7073
6726
|
async function proposalsCommand(repo, opts) {
|
|
7074
6727
|
console.log(JSON.stringify(await call2(opts, repo, "/proposals"), null, 2));
|
|
@@ -7157,7 +6810,7 @@ function registerVcsCommands(program) {
|
|
|
7157
6810
|
|
|
7158
6811
|
// packages/mesh-cli/src/commands/workflow.ts
|
|
7159
6812
|
import * as fs13 from "fs";
|
|
7160
|
-
import * as
|
|
6813
|
+
import * as path14 from "path";
|
|
7161
6814
|
import { createRequire as createRequire2 } from "module";
|
|
7162
6815
|
import { execFileSync as execFileSync8 } from "child_process";
|
|
7163
6816
|
var DISCOVERY_HELPERS_SRC = `
|
|
@@ -7471,7 +7124,7 @@ function registerWorkflowCommands(program) {
|
|
|
7471
7124
|
).action(
|
|
7472
7125
|
async (targetPath, opts) => {
|
|
7473
7126
|
try {
|
|
7474
|
-
const resolvedPath =
|
|
7127
|
+
const resolvedPath = path14.resolve(targetPath);
|
|
7475
7128
|
if (!fs13.existsSync(resolvedPath)) {
|
|
7476
7129
|
logError(`Path does not exist: ${resolvedPath}`);
|
|
7477
7130
|
process.exitCode = 1;
|
|
@@ -7479,7 +7132,7 @@ function registerWorkflowCommands(program) {
|
|
|
7479
7132
|
}
|
|
7480
7133
|
let resolvedProcessPath;
|
|
7481
7134
|
if (opts.process) {
|
|
7482
|
-
resolvedProcessPath =
|
|
7135
|
+
resolvedProcessPath = path14.resolve(opts.process);
|
|
7483
7136
|
if (!fs13.existsSync(resolvedProcessPath)) {
|
|
7484
7137
|
logError(`--process path does not exist: ${resolvedProcessPath}`);
|
|
7485
7138
|
process.exitCode = 1;
|
|
@@ -7529,7 +7182,7 @@ function registerWorkflowCommands(program) {
|
|
|
7529
7182
|
"Extract the as-built command/query/activity inventory from Temporal workflow source\n\nThe inventory ({ workflowType, commands, queries, activities }) is the process-\nconformance lint's code-side input \u2014 it is never hand-edited. Supports single\nfiles or directories."
|
|
7530
7183
|
).action(async (targetPath) => {
|
|
7531
7184
|
try {
|
|
7532
|
-
const resolvedPath =
|
|
7185
|
+
const resolvedPath = path14.resolve(targetPath);
|
|
7533
7186
|
if (!fs13.existsSync(resolvedPath)) {
|
|
7534
7187
|
logError(`Path does not exist: ${resolvedPath}`);
|
|
7535
7188
|
process.exitCode = 1;
|
|
@@ -7576,7 +7229,7 @@ function registerWorkflowCommands(program) {
|
|
|
7576
7229
|
"Comma-separated named-selector registry (enables UNKNOWN_SELECTOR checks)"
|
|
7577
7230
|
).action(async (targetPath, opts) => {
|
|
7578
7231
|
try {
|
|
7579
|
-
const resolvedPath =
|
|
7232
|
+
const resolvedPath = path14.resolve(targetPath);
|
|
7580
7233
|
if (!fs13.existsSync(resolvedPath)) {
|
|
7581
7234
|
logError(`Path does not exist: ${resolvedPath}`);
|
|
7582
7235
|
process.exitCode = 1;
|
|
@@ -7584,7 +7237,7 @@ function registerWorkflowCommands(program) {
|
|
|
7584
7237
|
}
|
|
7585
7238
|
let resolvedProcessPath;
|
|
7586
7239
|
if (opts.process) {
|
|
7587
|
-
resolvedProcessPath =
|
|
7240
|
+
resolvedProcessPath = path14.resolve(opts.process);
|
|
7588
7241
|
if (!fs13.existsSync(resolvedProcessPath)) {
|
|
7589
7242
|
logError(`--process path does not exist: ${resolvedProcessPath}`);
|
|
7590
7243
|
process.exitCode = 1;
|
|
@@ -7691,6 +7344,7 @@ function createProgram(options = {}) {
|
|
|
7691
7344
|
registerStackCommand(program);
|
|
7692
7345
|
registerTunnelCommands(program);
|
|
7693
7346
|
registerSecretsCommands(program);
|
|
7347
|
+
registerMcpCommands(program);
|
|
7694
7348
|
registerArtifactsCommands(program);
|
|
7695
7349
|
registerConversationsCommands(program);
|
|
7696
7350
|
registerVpnCommands(program);
|