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