@mesh-tech/mesh-cli 0.34.0 → 0.34.2
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/README.md +3 -2
- package/assets/intent/intent-claude-gate.mjs +1 -1
- package/dist/bin/mesh.js +268 -257
- package/dist/bin/mesh.js.map +3 -3
- package/dist/build-info.json +2 -2
- package/dist/src/commands/dev.js +2 -1
- package/dist/src/commands/init/platform-setup.js +3 -3
- package/dist/src/commands/init.js +2 -2
- package/dist/src/commands/local/helpers.js +2 -1
- package/dist/src/commands/local/seed.js +2 -2
- package/dist/src/commands/secrets/migrate-config.js +4 -11
- package/dist/src/commands/secrets/set.js +2 -6
- package/dist/src/commands/temporal.js +103 -95
- package/dist/src/commands/temporal.js.map +2 -2
- package/dist/src/docs/assemble.js +1 -1
- package/dist/src/docs/cli-reference.js +1 -1
- package/dist/src/index.js +9 -9
- package/dist/src/utils/aws-errors.d.ts +1 -0
- package/dist/src/utils/aws-errors.js +8 -0
- package/dist/src/utils/temporal-codec.js +3 -3
- package/fragments/base/index.ts.hbs +4 -0
- package/package.json +4 -4
- package/skills/core/SKILL.md +10 -7
- package/skills/pull-remote-agent-context/SKILL.md +1 -1
- package/templates/platform-repo/README.md.hbs +3 -2
- package/templates/platform-repo/core/Pulumi.{{tenant}}-{{env}}.yaml.hbs +22 -3
package/dist/build-info.json
CHANGED
package/dist/src/commands/dev.js
CHANGED
|
@@ -1896,7 +1896,8 @@ export function registerDevCommand(program) {
|
|
|
1896
1896
|
if (mode === 'local') {
|
|
1897
1897
|
throw new MeshCliError(`Docker external '${name}' failed to start: ${err instanceof Error ? err.message : err}`, { remediation: { command: `docker compose -f ${decl.compose} up # debug it directly` } });
|
|
1898
1898
|
}
|
|
1899
|
-
logWarn(`External '${name}' credential seeding failed: ${err instanceof Error ? err.message : err}`
|
|
1899
|
+
logWarn(`External '${name}' credential seeding failed: ${err instanceof Error ? err.message : err}` +
|
|
1900
|
+
` — the app will resolve whatever was seeded previously, which may point at a stale port.`);
|
|
1900
1901
|
}
|
|
1901
1902
|
}
|
|
1902
1903
|
if (dockerRunner) {
|
|
@@ -8,7 +8,7 @@ export const PLATFORM_SETUP_DEFAULTS = {
|
|
|
8
8
|
profile: "default",
|
|
9
9
|
};
|
|
10
10
|
export const DOMAIN_REQUIRED_MESSAGE = "--domain is required: the core stack creates the public Route 53 zone <env>.<domain>, " +
|
|
11
|
-
"and a placeholder domain scaffolds a zone
|
|
11
|
+
"and a placeholder domain scaffolds a zone whose certificate can never validate, so ingress never serves HTTPS.";
|
|
12
12
|
export function defaultStateBucket(tenant) {
|
|
13
13
|
return `${tenant}-mesh-platform-pulumi-state`;
|
|
14
14
|
}
|
|
@@ -31,7 +31,7 @@ export function validateDomain(value) {
|
|
|
31
31
|
return "a public domain you control, e.g. q2poc.pub";
|
|
32
32
|
}
|
|
33
33
|
if (/(^|\.)(example\.(com|org|net)|invalid|localhost|test)$/.test(domain)) {
|
|
34
|
-
return `${domain} is a placeholder —
|
|
34
|
+
return `${domain} is a placeholder — its ACM certificate can never validate, because nobody can delegate that zone to you. Use a domain you control.`;
|
|
35
35
|
}
|
|
36
36
|
return true;
|
|
37
37
|
}
|
|
@@ -177,7 +177,7 @@ export function renderPlatformNextSteps(setup, opts = {}) {
|
|
|
177
177
|
if (!opts.bucket?.present) {
|
|
178
178
|
steps.push(`${stateBucketCreateCommand(setup)} # the Pulumi state bucket, once`);
|
|
179
179
|
}
|
|
180
|
-
steps.push(`cd ${dir}`, "pnpm install", `aws sso login --profile ${setup.profile} # if this profile is SSO`, exportCredentialsCommand(setup.profile), `cd core && mesh deploy up # the VPC, EKS, RDS and the public zone ${setup.env}.${setup.domain}`, `# → then delegate the NS records of ${setup.env}.${setup.domain} from ${setup.domain}; the deploy
|
|
180
|
+
steps.push(`cd ${dir}`, "pnpm install", `aws sso login --profile ${setup.profile} # if this profile is SSO`, exportCredentialsCommand(setup.profile), `cd core && mesh deploy up # the VPC, EKS, RDS and the public zone ${setup.env}.${setup.domain}`, `# → then delegate the NS records of ${setup.env}.${setup.domain} from ${setup.domain} at your registrar; the deploy stops at the mesh-gateway Ingress until ACM issues the certificate, then continues`, "cd ../platform && mesh deploy up # Temporal, Zitadel, the Hub (needs Docker — it builds service images)", `mesh login ${setup.tenant}.${setup.env} # your platform sign-in, once it is up`, "", "Then, in your apps repo, for the hello-world app:", ` mesh init --tenant ${setup.tenant} --platform ${setup.env}`, " mesh create-app --name hello --primitives service", " mesh deploy up # from the app directory");
|
|
181
181
|
return steps;
|
|
182
182
|
}
|
|
183
183
|
export async function scaffoldPlatformRepo(setup) {
|
|
@@ -225,7 +225,7 @@ export function registerInitCommands(program) {
|
|
|
225
225
|
.option("--platform <env>", "a deployed platform's environment; signs in to `<tenant>.<env>`")
|
|
226
226
|
.option("--new-platform [env]", `nothing deployed yet — scaffold a tenant platform repo for \`<tenant>.<env>\` (default env: ${PLATFORM_SETUP_DEFAULTS.env}) and print its deploy sequence`)
|
|
227
227
|
.option("--region <region>", `--new-platform: AWS region (default: ${PLATFORM_SETUP_DEFAULTS.region})`)
|
|
228
|
-
.option("--domain <domain>", "--new-platform: base public domain you control; the core stack creates the zone {env}.{domain}. No default — a placeholder scaffolds a zone that can never validate")
|
|
228
|
+
.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 — a placeholder scaffolds a zone that can never validate")
|
|
229
229
|
.option("--state-bucket <bucket>", "--new-platform: Pulumi state S3 bucket (default: {tenant}-mesh-platform-pulumi-state)")
|
|
230
230
|
.option("--create-state-bucket", "--new-platform: create the state bucket (versioned) if it does not exist")
|
|
231
231
|
.option("--no-create-state-bucket", "--new-platform: never create the state bucket; print the aws command instead")
|
|
@@ -246,7 +246,7 @@ export function registerInitCommands(program) {
|
|
|
246
246
|
.description("Scaffold a tenant PLATFORM repo (core + platform Pulumi layers on @mesh-tech/infra-components) that deploys with `mesh deploy` unmodified — the proven mesh-sandbox shape, annotated. On a terminal it ASKS for the values that differ per install (env, region, domain, state bucket, AWS profile), each pre-filled with its default; every answer is also a flag.")
|
|
247
247
|
.option("--env <env>", `environment the first stack targets (default: ${PLATFORM_SETUP_DEFAULTS.env})`)
|
|
248
248
|
.option("--region <region>", `AWS region (default: ${PLATFORM_SETUP_DEFAULTS.region})`)
|
|
249
|
-
.option("--domain <domain>", "base public domain you control — the core stack creates the Route 53 zone {env}.{domain}
|
|
249
|
+
.option("--domain <domain>", "base public domain you control — the core stack creates the Route 53 zone {env}.{domain}, whose NS records you then delegate at your registrar; the deploy stops at the mesh-gateway Ingress until that lets ACM issue the certificate. Required: it has no default, because a placeholder scaffolds a zone nobody can delegate to you")
|
|
250
250
|
.option("--profile <profile>", `AWS profile the stack config references (default: ${PLATFORM_SETUP_DEFAULTS.profile})`)
|
|
251
251
|
.option("--state-bucket <bucket>", "Pulumi state S3 bucket (default: {tenant}-mesh-platform-pulumi-state)")
|
|
252
252
|
.option("--create-state-bucket", "create the state bucket (versioned) if it does not exist — prompted on a terminal")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as net from "net";
|
|
2
2
|
import { execFileSync } from "child_process";
|
|
3
3
|
import { LOCAL_AWS_CONFIG } from "./seed.js";
|
|
4
|
+
import { isAwsErrorCode } from "../../utils/aws-errors.js";
|
|
4
5
|
export async function upsertLocalSecret(secretId, value, client) {
|
|
5
6
|
const { SecretsManagerClient, CreateSecretCommand, PutSecretValueCommand } = await import("@aws-sdk/client-secrets-manager");
|
|
6
7
|
const sm = client ?? new SecretsManagerClient(LOCAL_AWS_CONFIG);
|
|
@@ -9,7 +10,7 @@ export async function upsertLocalSecret(secretId, value, client) {
|
|
|
9
10
|
await sm.send(new CreateSecretCommand({ Name: secretId, SecretString: secretString }));
|
|
10
11
|
}
|
|
11
12
|
catch (err) {
|
|
12
|
-
if (err
|
|
13
|
+
if (isAwsErrorCode(err, "ResourceExistsException")) {
|
|
13
14
|
await sm.send(new PutSecretValueCommand({ SecretId: secretId, SecretString: secretString }));
|
|
14
15
|
}
|
|
15
16
|
else {
|
|
@@ -126,7 +126,7 @@ export async function verifyFabric() {
|
|
|
126
126
|
if (roundTrip.Parameter?.Value !== payload) {
|
|
127
127
|
throw new MeshCliError(`Local AWS fabric failed the ${payload.length}-byte Advanced-tier SSM round-trip (got ${roundTrip.Parameter?.Value?.length ?? 0} bytes back).`, {
|
|
128
128
|
remediation: {
|
|
129
|
-
docs: "
|
|
129
|
+
docs: "packages/mesh-cli/stack/docker-compose.yml — swap the ministack image for motoserver/moto (design §2.5 fallback)",
|
|
130
130
|
},
|
|
131
131
|
});
|
|
132
132
|
}
|
|
@@ -136,7 +136,7 @@ export async function verifyFabric() {
|
|
|
136
136
|
if (missing.length > 0) {
|
|
137
137
|
throw new MeshCliError(`Local AWS fabric's GetParametersByPath missed child parameter(s): ${missing.join(", ")} (splitKeys exports would not resolve).`, {
|
|
138
138
|
remediation: {
|
|
139
|
-
docs: "
|
|
139
|
+
docs: "packages/mesh-cli/stack/docker-compose.yml — swap the ministack image for motoserver/moto (design §2.5 fallback)",
|
|
140
140
|
},
|
|
141
141
|
});
|
|
142
142
|
}
|
|
@@ -2,6 +2,7 @@ import { SSMClient, GetParametersByPathCommand, } from "@aws-sdk/client-ssm";
|
|
|
2
2
|
import { SecretsManagerClient, GetSecretValueCommand, PutSecretValueCommand, CreateSecretCommand, ListSecretsCommand, } from "@aws-sdk/client-secrets-manager";
|
|
3
3
|
import { logInfo, logSuccess, logError } from "../../utils/log.js";
|
|
4
4
|
import { resolveSecretsContext } from "./context.js";
|
|
5
|
+
import { isAwsErrorCode } from "../../utils/aws-errors.js";
|
|
5
6
|
function normalizeEntry(raw) {
|
|
6
7
|
if (raw.type === "group" && raw.fields) {
|
|
7
8
|
return {
|
|
@@ -79,21 +80,13 @@ function extractNonSecretFields(fields, values) {
|
|
|
79
80
|
}
|
|
80
81
|
return result;
|
|
81
82
|
}
|
|
82
|
-
function isResourceNotFound(err) {
|
|
83
|
-
const e = err;
|
|
84
|
-
return (e?.name === "ResourceNotFoundException" ||
|
|
85
|
-
e?.__type === "ResourceNotFoundException" ||
|
|
86
|
-
e?.Code === "ResourceNotFoundException" ||
|
|
87
|
-
e?.code === "ResourceNotFoundException" ||
|
|
88
|
-
(typeof e?.message === "string" && e.message.includes("ResourceNotFoundException")));
|
|
89
|
-
}
|
|
90
83
|
async function readSecret(client, secretId) {
|
|
91
84
|
try {
|
|
92
85
|
const res = await client.send(new GetSecretValueCommand({ SecretId: secretId }));
|
|
93
86
|
return res.SecretString ? JSON.parse(res.SecretString) : null;
|
|
94
87
|
}
|
|
95
88
|
catch (err) {
|
|
96
|
-
if (
|
|
89
|
+
if (isAwsErrorCode(err, "ResourceNotFoundException"))
|
|
97
90
|
return null;
|
|
98
91
|
throw err;
|
|
99
92
|
}
|
|
@@ -104,7 +97,7 @@ async function writeSecret(client, secretId, values, description) {
|
|
|
104
97
|
await client.send(new PutSecretValueCommand({ SecretId: secretId, SecretString: secretString }));
|
|
105
98
|
}
|
|
106
99
|
catch (err) {
|
|
107
|
-
if (
|
|
100
|
+
if (isAwsErrorCode(err, "ResourceNotFoundException")) {
|
|
108
101
|
await client.send(new CreateSecretCommand({
|
|
109
102
|
Name: secretId,
|
|
110
103
|
Description: description,
|
|
@@ -123,7 +116,7 @@ async function secretExists(client, secretId) {
|
|
|
123
116
|
return true;
|
|
124
117
|
}
|
|
125
118
|
catch (err) {
|
|
126
|
-
if (
|
|
119
|
+
if (isAwsErrorCode(err, "ResourceNotFoundException"))
|
|
127
120
|
return false;
|
|
128
121
|
throw err;
|
|
129
122
|
}
|
|
@@ -8,6 +8,7 @@ import { resolveStackOption } from "../../utils/stack-flag.js";
|
|
|
8
8
|
import { resolveSecretsContext } from "./context.js";
|
|
9
9
|
import { findAppRoot, readStackConfig } from "../../utils/pulumi.js";
|
|
10
10
|
import { resolveAwsCredentials } from "../../utils/aws-auth.js";
|
|
11
|
+
import { isAwsErrorCode } from "../../utils/aws-errors.js";
|
|
11
12
|
export async function ensureAwsCredentialsForStack(stack) {
|
|
12
13
|
if (process.env.AWS_ACCESS_KEY_ID || process.env.AWS_SESSION_TOKEN)
|
|
13
14
|
return;
|
|
@@ -244,12 +245,7 @@ export async function setCommand(servicePath, opts) {
|
|
|
244
245
|
console.error("");
|
|
245
246
|
}
|
|
246
247
|
export function isResourceNotFound(err) {
|
|
247
|
-
|
|
248
|
-
return (e?.name === "ResourceNotFoundException" ||
|
|
249
|
-
e?.__type === "ResourceNotFoundException" ||
|
|
250
|
-
e?.Code === "ResourceNotFoundException" ||
|
|
251
|
-
e?.code === "ResourceNotFoundException" ||
|
|
252
|
-
(typeof e?.message === "string" && e.message.includes("ResourceNotFoundException")));
|
|
248
|
+
return isAwsErrorCode(err, "ResourceNotFoundException");
|
|
253
249
|
}
|
|
254
250
|
function deepMerge(target, source) {
|
|
255
251
|
const result = { ...target };
|