@mesh-tech/mesh-cli 0.34.3 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/app-skill/SKILL.md +1 -1
- package/dist/bin/mesh.js +567 -195
- package/dist/bin/mesh.js.map +3 -3
- package/dist/build-info.json +2 -2
- package/dist/src/commands/cluster.js +2 -2
- package/dist/src/commands/dev.js +4 -2
- package/dist/src/commands/login.d.ts +1 -0
- package/dist/src/commands/login.js +23 -20
- package/dist/src/commands/skills.d.ts +7 -2
- package/dist/src/commands/skills.js +84 -15
- package/dist/src/commands/stack-status.d.ts +65 -0
- package/dist/src/commands/stack-status.js +285 -0
- package/dist/src/commands/stack.js +15 -1
- package/dist/src/commands/temporal.js +45 -17
- package/dist/src/commands/temporal.js.map +1 -1
- package/dist/src/program.d.ts +1 -1
- package/dist/src/program.js +1 -1
- package/dist/src/utils/aws-auth.d.ts +1 -0
- package/dist/src/utils/aws-auth.js +10 -1
- package/dist/src/utils/first-party-contexts.d.ts +3 -0
- package/dist/src/utils/first-party-contexts.js +12 -0
- package/dist/src/utils/pulumi-run.d.ts +1 -1
- package/dist/src/utils/pulumi-run.js +16 -6
- package/fragments/base/index.ts.hbs +3 -2
- package/package.json +2 -2
- package/skills/{core → mesh}/SKILL.md +106 -100
- package/skills/mesh/references/programmatic-api.md +35 -0
- package/skills/mesh/references/worktrees.md +53 -0
- package/skills/pull-remote-agent-context/SKILL.md +1 -1
- package/templates/api-auth/README.md.hbs +3 -2
package/dist/bin/mesh.js
CHANGED
|
@@ -1712,8 +1712,10 @@ var init_stack = __esm({
|
|
|
1712
1712
|
var skills_exports = {};
|
|
1713
1713
|
__export(skills_exports, {
|
|
1714
1714
|
INTENT_RANGE: () => INTENT_RANGE,
|
|
1715
|
+
installedSkillName: () => installedSkillName,
|
|
1715
1716
|
listPackageSkills: () => listPackageSkills,
|
|
1716
1717
|
registerSkillsCommands: () => registerSkillsCommands,
|
|
1718
|
+
renderManagedSkill: () => renderManagedSkill,
|
|
1717
1719
|
resolveTargetRoot: () => resolveTargetRoot,
|
|
1718
1720
|
seedAppSkill: () => seedAppSkill,
|
|
1719
1721
|
syncSkills: () => syncSkills
|
|
@@ -1738,15 +1740,36 @@ function cliAsset(...segments) {
|
|
|
1738
1740
|
function listBaseSkills() {
|
|
1739
1741
|
const dir = cliAsset("skills");
|
|
1740
1742
|
if (!fs6.existsSync(dir)) return [];
|
|
1741
|
-
return fs6.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && fs6.existsSync(path6.join(dir, entry.name, "SKILL.md"))).map((entry) => ({
|
|
1743
|
+
return fs6.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && fs6.existsSync(path6.join(dir, entry.name, "SKILL.md"))).map((entry) => ({
|
|
1744
|
+
name: installedSkillName([entry.name]),
|
|
1745
|
+
// The CLI's own skill shipped as `skills/core/` and installed as `mesh-core/`.
|
|
1746
|
+
legacyName: entry.name === "mesh" ? "mesh-core" : `mesh-${entry.name}`,
|
|
1747
|
+
source: path6.join(dir, entry.name, "SKILL.md")
|
|
1748
|
+
}));
|
|
1749
|
+
}
|
|
1750
|
+
function installedSkillName(segments) {
|
|
1751
|
+
const parts = ["mesh"];
|
|
1752
|
+
for (const segment of segments) {
|
|
1753
|
+
if (segment === "core") continue;
|
|
1754
|
+
if (segment === parts[parts.length - 1]) continue;
|
|
1755
|
+
parts.push(segment);
|
|
1756
|
+
}
|
|
1757
|
+
return parts.join("-");
|
|
1742
1758
|
}
|
|
1743
|
-
function renderManagedSkill(source) {
|
|
1759
|
+
function renderManagedSkill(source, name) {
|
|
1744
1760
|
const raw = fs6.readFileSync(source, "utf-8");
|
|
1745
1761
|
const frontmatter = raw.match(/^(---\n[\s\S]*?\n---\n)/)?.[1];
|
|
1746
|
-
if (!frontmatter) return
|
|
1762
|
+
if (!frontmatter) return `---
|
|
1763
|
+
name: ${name}
|
|
1764
|
+
---
|
|
1765
|
+
|
|
1766
|
+
${MANAGED_MARKER}
|
|
1747
1767
|
|
|
1748
1768
|
${raw}`;
|
|
1749
|
-
|
|
1769
|
+
const named = /^name:.*$/m.test(frontmatter) ? frontmatter.replace(/^name:.*$/m, `name: ${name}`) : frontmatter.replace(/^---\n/, `---
|
|
1770
|
+
name: ${name}
|
|
1771
|
+
`);
|
|
1772
|
+
return `${named}
|
|
1750
1773
|
${MANAGED_MARKER}
|
|
1751
1774
|
${raw.slice(frontmatter.length)}`;
|
|
1752
1775
|
}
|
|
@@ -1785,13 +1808,31 @@ function listPackageSkills(root) {
|
|
|
1785
1808
|
for (const domain of fs6.readdirSync(skillsDir, { withFileTypes: true })) {
|
|
1786
1809
|
const source = path6.join(skillsDir, domain.name, "SKILL.md");
|
|
1787
1810
|
if (!fs6.existsSync(source)) continue;
|
|
1788
|
-
const name =
|
|
1789
|
-
if (!byName.has(name))
|
|
1811
|
+
const name = installedSkillName([pkg.name, domain.name]);
|
|
1812
|
+
if (!byName.has(name)) {
|
|
1813
|
+
byName.set(name, {
|
|
1814
|
+
name,
|
|
1815
|
+
legacyName: `mesh-${pkg.name}-${domain.name}`,
|
|
1816
|
+
dir: path6.join(skillsDir, domain.name),
|
|
1817
|
+
source
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1790
1820
|
}
|
|
1791
1821
|
}
|
|
1792
1822
|
}
|
|
1793
1823
|
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
1794
1824
|
}
|
|
1825
|
+
function extrasInSync(sourceDir, targetDir) {
|
|
1826
|
+
for (const entry of fs6.readdirSync(sourceDir, { withFileTypes: true, recursive: true })) {
|
|
1827
|
+
if (!entry.isFile()) continue;
|
|
1828
|
+
const rel2 = path6.relative(sourceDir, path6.join(entry.parentPath, entry.name));
|
|
1829
|
+
if (rel2 === "SKILL.md") continue;
|
|
1830
|
+
const installed = path6.join(targetDir, rel2);
|
|
1831
|
+
if (!fs6.existsSync(installed)) return false;
|
|
1832
|
+
if (!fs6.readFileSync(installed).equals(fs6.readFileSync(path6.join(sourceDir, rel2)))) return false;
|
|
1833
|
+
}
|
|
1834
|
+
return true;
|
|
1835
|
+
}
|
|
1795
1836
|
function copySkillExtras(sourceDir, targetDir) {
|
|
1796
1837
|
for (const entry of fs6.readdirSync(sourceDir, { withFileTypes: true })) {
|
|
1797
1838
|
if (entry.name === "SKILL.md") continue;
|
|
@@ -1809,25 +1850,36 @@ function seedAppSkill(root, appName, appRelPath) {
|
|
|
1809
1850
|
}
|
|
1810
1851
|
function planSync(root) {
|
|
1811
1852
|
const items = [];
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
const
|
|
1815
|
-
const
|
|
1853
|
+
const baseSkills = listBaseSkills();
|
|
1854
|
+
for (const skill of baseSkills) {
|
|
1855
|
+
const targetDir = path6.join(root, ".claude", "skills", skill.name);
|
|
1856
|
+
const target = path6.join(targetDir, "SKILL.md");
|
|
1857
|
+
const sourceDir = path6.dirname(skill.source);
|
|
1858
|
+
const desired = renderManagedSkill(skill.source, skill.name);
|
|
1859
|
+
const label = `.claude/skills/${skill.name}/SKILL.md (base skill)`;
|
|
1816
1860
|
if (!fs6.existsSync(target)) {
|
|
1817
1861
|
items.push({
|
|
1818
1862
|
label,
|
|
1819
1863
|
state: "write",
|
|
1820
1864
|
apply: () => {
|
|
1821
|
-
fs6.mkdirSync(
|
|
1865
|
+
fs6.mkdirSync(targetDir, { recursive: true });
|
|
1822
1866
|
fs6.writeFileSync(target, desired);
|
|
1867
|
+
copySkillExtras(sourceDir, targetDir);
|
|
1823
1868
|
}
|
|
1824
1869
|
});
|
|
1825
1870
|
} else {
|
|
1826
1871
|
const current = fs6.readFileSync(target, "utf-8");
|
|
1827
|
-
if (current === desired) {
|
|
1872
|
+
if (current === desired && extrasInSync(sourceDir, targetDir)) {
|
|
1828
1873
|
items.push({ label, state: "ok" });
|
|
1829
1874
|
} else if (current.includes(MANAGED_MARKER)) {
|
|
1830
|
-
items.push({
|
|
1875
|
+
items.push({
|
|
1876
|
+
label,
|
|
1877
|
+
state: "write",
|
|
1878
|
+
apply: () => {
|
|
1879
|
+
fs6.writeFileSync(target, desired);
|
|
1880
|
+
copySkillExtras(sourceDir, targetDir);
|
|
1881
|
+
}
|
|
1882
|
+
});
|
|
1831
1883
|
} else {
|
|
1832
1884
|
items.push({ label: `${label} \u2014 exists without the managed marker, leaving as-is`, state: "skip" });
|
|
1833
1885
|
}
|
|
@@ -1837,7 +1889,7 @@ function planSync(root) {
|
|
|
1837
1889
|
for (const skill of packageSkills) {
|
|
1838
1890
|
const targetDir = path6.join(root, ".claude", "skills", skill.name);
|
|
1839
1891
|
const target = path6.join(targetDir, "SKILL.md");
|
|
1840
|
-
const desired = renderManagedSkill(skill.source);
|
|
1892
|
+
const desired = renderManagedSkill(skill.source, skill.name);
|
|
1841
1893
|
const label = `.claude/skills/${skill.name}/SKILL.md (platform skill)`;
|
|
1842
1894
|
if (!fs6.existsSync(target)) {
|
|
1843
1895
|
items.push({
|
|
@@ -1870,6 +1922,22 @@ function planSync(root) {
|
|
|
1870
1922
|
if (packageSkills.length === 0 && meshTechScopeDirs(root).length === 0) {
|
|
1871
1923
|
logInfo("No @mesh-tech packages installed yet \u2014 run `pnpm install`, then `mesh skills sync` again for the platform skills.");
|
|
1872
1924
|
}
|
|
1925
|
+
for (const skill of [...baseSkills, ...packageSkills]) {
|
|
1926
|
+
if (skill.legacyName === skill.name) continue;
|
|
1927
|
+
const legacyDir = path6.join(root, ".claude", "skills", skill.legacyName);
|
|
1928
|
+
const legacyFile = path6.join(legacyDir, "SKILL.md");
|
|
1929
|
+
if (!fs6.existsSync(legacyFile)) continue;
|
|
1930
|
+
const label = `.claude/skills/${skill.legacyName}/ (renamed to ${skill.name})`;
|
|
1931
|
+
if (fs6.readFileSync(legacyFile, "utf-8").includes(MANAGED_MARKER)) {
|
|
1932
|
+
items.push({
|
|
1933
|
+
label: `${label} \u2014 removing the old copy`,
|
|
1934
|
+
state: "write",
|
|
1935
|
+
apply: () => fs6.rmSync(legacyDir, { recursive: true, force: true })
|
|
1936
|
+
});
|
|
1937
|
+
} else {
|
|
1938
|
+
items.push({ label: `${label} \u2014 exists without the managed marker, leaving as-is`, state: "skip" });
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1873
1941
|
const hookSource = cliAsset("assets", "intent", "intent-claude-gate.mjs");
|
|
1874
1942
|
const hookTarget = path6.join(root, HOOK_RELATIVE);
|
|
1875
1943
|
const hookDesired = fs6.readFileSync(hookSource, "utf-8");
|
|
@@ -2260,12 +2328,19 @@ var init_app_check_resolve = __esm({
|
|
|
2260
2328
|
});
|
|
2261
2329
|
|
|
2262
2330
|
// packages/mesh-cli/src/utils/first-party-contexts.ts
|
|
2331
|
+
function loginContextForPlatform(platform) {
|
|
2332
|
+
if (!Object.hasOwn(FIRST_PARTY_PLATFORM_CONTEXTS, platform)) return platform;
|
|
2333
|
+
return FIRST_PARTY_PLATFORM_CONTEXTS[platform] || platform;
|
|
2334
|
+
}
|
|
2263
2335
|
function firstPartyDomainFor(context) {
|
|
2264
2336
|
if (!Object.hasOwn(FIRST_PARTY_CONTEXTS, context)) return null;
|
|
2265
2337
|
const domain = FIRST_PARTY_CONTEXTS[context];
|
|
2266
2338
|
return typeof domain === "string" && domain ? domain : null;
|
|
2267
2339
|
}
|
|
2268
|
-
|
|
2340
|
+
function isPlatformLoginAlias(context) {
|
|
2341
|
+
return Object.values(FIRST_PARTY_PLATFORM_CONTEXTS).includes(context);
|
|
2342
|
+
}
|
|
2343
|
+
var FIRST_PARTY_CONTEXTS, FIRST_PARTY_PLATFORM_CONTEXTS;
|
|
2269
2344
|
var init_first_party_contexts = __esm({
|
|
2270
2345
|
"packages/mesh-cli/src/utils/first-party-contexts.ts"() {
|
|
2271
2346
|
"use strict";
|
|
@@ -2276,7 +2351,15 @@ var init_first_party_contexts = __esm({
|
|
|
2276
2351
|
// platform lives in a different AWS account with no registry; the
|
|
2277
2352
|
// platform-dev stack in the registry-owning account is the developer front
|
|
2278
2353
|
// door. mesh-sandbox#32 / #3587.)
|
|
2279
|
-
"mesh.dev": "dev.platform.meshtech.io"
|
|
2354
|
+
"mesh.dev": "dev.platform.meshtech.io",
|
|
2355
|
+
// Verified 2026-09-25: https://cli.dev.mesh-platform.trabian.com/.well-known/mesh.json
|
|
2356
|
+
// answers anonymously with the `mesh` tenant's dev platform issuer
|
|
2357
|
+
// (identity.dev.mesh-platform.trabian.com) — the platform every `mesh`/dev
|
|
2358
|
+
// tenant environment and its `*-apps-deployer` role live on.
|
|
2359
|
+
"mesh-platform.dev": "dev.mesh-platform.trabian.com"
|
|
2360
|
+
});
|
|
2361
|
+
FIRST_PARTY_PLATFORM_CONTEXTS = Object.freeze({
|
|
2362
|
+
"mesh.dev": "mesh-platform.dev"
|
|
2280
2363
|
});
|
|
2281
2364
|
}
|
|
2282
2365
|
});
|
|
@@ -3909,6 +3992,7 @@ __export(login_exports, {
|
|
|
3909
3992
|
clearContextConfig: () => clearContextConfig,
|
|
3910
3993
|
clearCredentials: () => clearCredentials,
|
|
3911
3994
|
decodeJwtPayload: () => decodeJwtPayload,
|
|
3995
|
+
deployableTenants: () => deployableTenants,
|
|
3912
3996
|
deviceLoginWithReissue: () => deviceLoginWithReissue,
|
|
3913
3997
|
discoverConfigForContext: () => discoverConfigForContext,
|
|
3914
3998
|
discoverConfigFromWellKnown: () => discoverConfigFromWellKnown,
|
|
@@ -4090,11 +4174,11 @@ function readAllCredentials() {
|
|
|
4090
4174
|
function readCredentials(context) {
|
|
4091
4175
|
return readAllCredentials()[context] ?? null;
|
|
4092
4176
|
}
|
|
4093
|
-
function atomicWriteFileSync(
|
|
4094
|
-
const tmpPath = `${
|
|
4177
|
+
function atomicWriteFileSync(path50, data, mode) {
|
|
4178
|
+
const tmpPath = `${path50}.${process.pid}.${atomicWriteCounter++}.tmp`;
|
|
4095
4179
|
try {
|
|
4096
4180
|
fs11.writeFileSync(tmpPath, data, { mode });
|
|
4097
|
-
fs11.renameSync(tmpPath,
|
|
4181
|
+
fs11.renameSync(tmpPath, path50);
|
|
4098
4182
|
} catch (err) {
|
|
4099
4183
|
try {
|
|
4100
4184
|
fs11.unlinkSync(tmpPath);
|
|
@@ -4225,12 +4309,7 @@ function login(context, config) {
|
|
|
4225
4309
|
const idPayload = decodeJwtPayload(tokens.id_token);
|
|
4226
4310
|
const email = idPayload.email ?? idPayload.preferred_username ?? "unknown";
|
|
4227
4311
|
const sub = idPayload.sub;
|
|
4228
|
-
|
|
4229
|
-
try {
|
|
4230
|
-
const accessPayload = decodeJwtPayload(tokens.access_token);
|
|
4231
|
-
tenants = accessPayload["urn:mesh:tenants"] ?? [];
|
|
4232
|
-
} catch {
|
|
4233
|
-
}
|
|
4312
|
+
const tenants = deployableTenants(tokens.id_token, tokens.access_token);
|
|
4234
4313
|
writeCredentials(context, {
|
|
4235
4314
|
idToken: tokens.id_token,
|
|
4236
4315
|
accessToken: tokens.access_token,
|
|
@@ -4346,12 +4425,7 @@ async function attemptDeviceCode(context, config) {
|
|
|
4346
4425
|
const idPayload = decodeJwtPayload(tokens.id_token);
|
|
4347
4426
|
const email = idPayload.email ?? idPayload.preferred_username ?? "unknown";
|
|
4348
4427
|
const sub = idPayload.sub;
|
|
4349
|
-
|
|
4350
|
-
try {
|
|
4351
|
-
const accessPayload = decodeJwtPayload(tokens.access_token);
|
|
4352
|
-
tenants = accessPayload["urn:mesh:tenants"] ?? [];
|
|
4353
|
-
} catch {
|
|
4354
|
-
}
|
|
4428
|
+
const tenants = deployableTenants(tokens.id_token, tokens.access_token);
|
|
4355
4429
|
writeCredentials(context, {
|
|
4356
4430
|
idToken: tokens.id_token,
|
|
4357
4431
|
accessToken: tokens.access_token,
|
|
@@ -4524,12 +4598,10 @@ async function showStatus(context, config) {
|
|
|
4524
4598
|
);
|
|
4525
4599
|
return;
|
|
4526
4600
|
}
|
|
4527
|
-
|
|
4601
|
+
const tenants = deployableTenants(creds.idToken, creds.accessToken);
|
|
4528
4602
|
let audience = [];
|
|
4529
4603
|
try {
|
|
4530
|
-
|
|
4531
|
-
tenants = accessPayload["urn:mesh:tenants"] ?? [];
|
|
4532
|
-
audience = tokenAudience(accessPayload);
|
|
4604
|
+
audience = tokenAudience(decodeJwtPayload(creds.accessToken));
|
|
4533
4605
|
} catch {
|
|
4534
4606
|
}
|
|
4535
4607
|
logSuccess(`Logged in as ${creds.email ?? "unknown"} (${context})`);
|
|
@@ -4552,6 +4624,19 @@ async function showStatus(context, config) {
|
|
|
4552
4624
|
);
|
|
4553
4625
|
}
|
|
4554
4626
|
}
|
|
4627
|
+
function deployableTenants(idToken, accessToken) {
|
|
4628
|
+
for (const token of [idToken, accessToken]) {
|
|
4629
|
+
if (!token) continue;
|
|
4630
|
+
let claim;
|
|
4631
|
+
try {
|
|
4632
|
+
claim = decodeJwtPayload(token)[DEPLOY_TENANTS_CLAIM];
|
|
4633
|
+
} catch {
|
|
4634
|
+
continue;
|
|
4635
|
+
}
|
|
4636
|
+
if (Array.isArray(claim)) return claim.filter((t) => typeof t === "string");
|
|
4637
|
+
}
|
|
4638
|
+
return [];
|
|
4639
|
+
}
|
|
4555
4640
|
function tokenAudience(payload) {
|
|
4556
4641
|
const aud = payload.aud;
|
|
4557
4642
|
if (typeof aud === "string") return [aud];
|
|
@@ -4828,7 +4913,7 @@ async function ensureLogin(context, opts = {}) {
|
|
|
4828
4913
|
}
|
|
4829
4914
|
async function discoverConfigGuarded(context, opts = {}) {
|
|
4830
4915
|
let config = null;
|
|
4831
|
-
if (parseTenantEnv(context)) {
|
|
4916
|
+
if (parseTenantEnv(context) && !isPlatformLoginAlias(context)) {
|
|
4832
4917
|
config = await discoverConfigFromSsm(context, opts);
|
|
4833
4918
|
}
|
|
4834
4919
|
if (!config) {
|
|
@@ -4974,7 +5059,7 @@ function readAllContextConfigs() {
|
|
|
4974
5059
|
async function discoverConfigForContext(context) {
|
|
4975
5060
|
return getContextConfig(context) ?? await discoverConfigGuarded(context);
|
|
4976
5061
|
}
|
|
4977
|
-
var CONFIG_DIR, CONFIG_FILE, CREDENTIALS_FILE, REDIRECT_PORT, REDIRECT_URI, BASE_SCOPES, atomicWriteCounter, MAX_DEVICE_CODES, RESERVED_REGISTRY_CONTEXT, NO_REGISTRY_DEPRECATED, REGISTRY_SEPARATE_HINT;
|
|
5062
|
+
var CONFIG_DIR, CONFIG_FILE, CREDENTIALS_FILE, REDIRECT_PORT, REDIRECT_URI, BASE_SCOPES, atomicWriteCounter, MAX_DEVICE_CODES, DEPLOY_TENANTS_CLAIM, RESERVED_REGISTRY_CONTEXT, NO_REGISTRY_DEPRECATED, REGISTRY_SEPARATE_HINT;
|
|
4978
5063
|
var init_login = __esm({
|
|
4979
5064
|
"packages/mesh-cli/src/commands/login.ts"() {
|
|
4980
5065
|
"use strict";
|
|
@@ -4994,6 +5079,7 @@ var init_login = __esm({
|
|
|
4994
5079
|
BASE_SCOPES = "openid email profile offline_access urn:zitadel:iam:org:project:id:zitadel:aud";
|
|
4995
5080
|
atomicWriteCounter = 0;
|
|
4996
5081
|
MAX_DEVICE_CODES = 3;
|
|
5082
|
+
DEPLOY_TENANTS_CLAIM = "urn:mesh:tenants";
|
|
4997
5083
|
RESERVED_REGISTRY_CONTEXT = "registry";
|
|
4998
5084
|
NO_REGISTRY_DEPRECATED = "--no-registry is deprecated and ignored: mesh login no longer touches the registry.";
|
|
4999
5085
|
REGISTRY_SEPARATE_HINT = "Package registry access is separate from platform sign-in \u2014 run: mesh registry login";
|
|
@@ -5498,7 +5584,7 @@ import {
|
|
|
5498
5584
|
GetCallerIdentityCommand,
|
|
5499
5585
|
STSClient
|
|
5500
5586
|
} from "@aws-sdk/client-sts";
|
|
5501
|
-
function
|
|
5587
|
+
function readStackPlatform(appRoot, stack) {
|
|
5502
5588
|
const configFile = path13.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
5503
5589
|
if (!fs13.existsSync(configFile)) return null;
|
|
5504
5590
|
const content = fs13.readFileSync(configFile, "utf-8");
|
|
@@ -5517,6 +5603,12 @@ function derivePlatformContext(appRoot, stack) {
|
|
|
5517
5603
|
}
|
|
5518
5604
|
return null;
|
|
5519
5605
|
}
|
|
5606
|
+
function derivePlatformContext(appRoot, stack) {
|
|
5607
|
+
const explicit = readStackConfig(appRoot, stack, "mesh:loginContext");
|
|
5608
|
+
if (explicit) return explicit;
|
|
5609
|
+
const platform = readStackPlatform(appRoot, stack);
|
|
5610
|
+
return platform ? loginContextForPlatform(platform) : null;
|
|
5611
|
+
}
|
|
5520
5612
|
function quoteCredProcessToken(token) {
|
|
5521
5613
|
return /\s/.test(token) ? `"${token}"` : token;
|
|
5522
5614
|
}
|
|
@@ -5818,6 +5910,8 @@ var init_aws_auth = __esm({
|
|
|
5818
5910
|
init_log();
|
|
5819
5911
|
init_auth_preflight();
|
|
5820
5912
|
init_login();
|
|
5913
|
+
init_first_party_contexts();
|
|
5914
|
+
init_pulumi();
|
|
5821
5915
|
DEFAULT_REGION = process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? "us-east-2";
|
|
5822
5916
|
MANAGED_START_PREFIX = `# >>> mesh-cli managed profile `;
|
|
5823
5917
|
MANAGED_START = (context) => `${MANAGED_START_PREFIX}${context} >>>`;
|
|
@@ -5868,7 +5962,9 @@ var init_vpn_join = __esm({
|
|
|
5868
5962
|
});
|
|
5869
5963
|
|
|
5870
5964
|
// packages/mesh-cli/src/utils/pulumi-run.ts
|
|
5871
|
-
function credProbeToPreflightError(probe, context) {
|
|
5965
|
+
function credProbeToPreflightError(probe, context, platform) {
|
|
5966
|
+
const aliasNote = platform && platform !== context && loginContextForPlatform(platform) === context ? `
|
|
5967
|
+
This stack deploys to platform ${platform}, which signs in as ${context} \u2014 a \`mesh login ${platform}\` session is a different platform and is not trusted here.` : "";
|
|
5872
5968
|
switch (probe.state) {
|
|
5873
5969
|
case "ok":
|
|
5874
5970
|
return null;
|
|
@@ -5876,19 +5972,21 @@ function credProbeToPreflightError(probe, context) {
|
|
|
5876
5972
|
return {
|
|
5877
5973
|
fatal: true,
|
|
5878
5974
|
message: `Not logged in for ${context}. Run:
|
|
5879
|
-
mesh login ${context} --device`
|
|
5975
|
+
mesh login ${context} --device` + aliasNote
|
|
5880
5976
|
};
|
|
5881
5977
|
case "expired-session":
|
|
5882
5978
|
return {
|
|
5883
5979
|
fatal: true,
|
|
5884
5980
|
message: `Your mesh login session for ${context} expired. Run:
|
|
5885
|
-
mesh login ${context} --device`
|
|
5981
|
+
mesh login ${context} --device` + aliasNote
|
|
5886
5982
|
};
|
|
5887
5983
|
case "assume-denied":
|
|
5888
5984
|
return {
|
|
5889
5985
|
fatal: true,
|
|
5890
5986
|
message: `Logged in, but couldn't assume the deployer role \u2014 ${probe.detail}
|
|
5891
|
-
|
|
5987
|
+
If you signed in to another platform, sign in to this stack's:
|
|
5988
|
+
mesh login ${context} --device
|
|
5989
|
+
Otherwise check mesh:deployerRole in the stack config and your IAM access.` + aliasNote
|
|
5892
5990
|
};
|
|
5893
5991
|
case "stale-env-override":
|
|
5894
5992
|
return {
|
|
@@ -5918,7 +6016,7 @@ async function resolvePulumiEnv(opts) {
|
|
|
5918
6016
|
const context = derivePlatformContext(appRoot, stack);
|
|
5919
6017
|
if (!hasAmbientCreds && context) {
|
|
5920
6018
|
const probe = await probeCredentials(context, roleArn);
|
|
5921
|
-
const preflight = credProbeToPreflightError(probe, context);
|
|
6019
|
+
const preflight = credProbeToPreflightError(probe, context, readStackPlatform(appRoot, stack));
|
|
5922
6020
|
if (preflight?.fatal) {
|
|
5923
6021
|
logError(preflight.message);
|
|
5924
6022
|
process.exit(1);
|
|
@@ -5942,6 +6040,7 @@ var init_pulumi_run = __esm({
|
|
|
5942
6040
|
init_log();
|
|
5943
6041
|
init_pulumi();
|
|
5944
6042
|
init_aws_auth();
|
|
6043
|
+
init_first_party_contexts();
|
|
5945
6044
|
init_login();
|
|
5946
6045
|
}
|
|
5947
6046
|
});
|
|
@@ -10777,7 +10876,7 @@ function registerDevCommand(program2) {
|
|
|
10777
10876
|
}
|
|
10778
10877
|
const resolved = deployerRole ? await resolveAwsCredentials(deployerRole, appRoot, stack) : null;
|
|
10779
10878
|
if (deployerRole && !resolved && !process.env.AWS_ACCESS_KEY_ID) {
|
|
10780
|
-
const pf = ctx ? credProbeToPreflightError(await probeCredentials(ctx, deployerRole), ctx) : null;
|
|
10879
|
+
const pf = ctx ? credProbeToPreflightError(await probeCredentials(ctx, deployerRole), ctx, readStackPlatform(appRoot, stack)) : null;
|
|
10781
10880
|
logError(
|
|
10782
10881
|
pf?.message ?? `Couldn't resolve AWS credentials to restart '${service}'. Run: mesh login ${ctx ?? "mesh.dev"} --device`
|
|
10783
10882
|
);
|
|
@@ -12870,11 +12969,11 @@ function createVcsFolderReader(opts) {
|
|
|
12870
12969
|
}
|
|
12871
12970
|
return p;
|
|
12872
12971
|
};
|
|
12873
|
-
const readPath = async (repo,
|
|
12972
|
+
const readPath = async (repo, path50) => {
|
|
12874
12973
|
const dir = await cloneRepo(repo);
|
|
12875
|
-
const ref = await resolveFolderRef(dir,
|
|
12876
|
-
if (!ref) throw new Error(`path "${
|
|
12877
|
-
const files = await readFolderAtRef(dir, ref,
|
|
12974
|
+
const ref = await resolveFolderRef(dir, path50);
|
|
12975
|
+
if (!ref) throw new Error(`path "${path50}" not found on any ref of ${repo}`);
|
|
12976
|
+
const files = await readFolderAtRef(dir, ref, path50);
|
|
12878
12977
|
return { ref, files };
|
|
12879
12978
|
};
|
|
12880
12979
|
const cleanup = async () => {
|
|
@@ -13194,7 +13293,7 @@ Use --stack <name> (the deployed stack, e.g. dev).` : "No stack configs found in
|
|
|
13194
13293
|
const ctx = derivePlatformContext(appRoot, stack);
|
|
13195
13294
|
const resolved = deployerRole ? await resolveAwsCredentials(deployerRole, appRoot, stack) : null;
|
|
13196
13295
|
if (deployerRole && !resolved && !process.env.AWS_ACCESS_KEY_ID) {
|
|
13197
|
-
const pf = ctx ? credProbeToPreflightError(await probeCredentials(ctx, deployerRole), ctx) : null;
|
|
13296
|
+
const pf = ctx ? credProbeToPreflightError(await probeCredentials(ctx, deployerRole), ctx, readStackPlatform(appRoot, stack)) : null;
|
|
13198
13297
|
throw new Error(
|
|
13199
13298
|
pf?.message ?? `Couldn't resolve AWS credentials. Run: mesh login ${ctx ?? "mesh.dev"} --device`
|
|
13200
13299
|
);
|
|
@@ -15249,7 +15348,7 @@ var init_discover = __esm({
|
|
|
15249
15348
|
|
|
15250
15349
|
// packages/mesh-cli/src/docs/assemble.ts
|
|
15251
15350
|
import { execFileSync as execFileSync20 } from "node:child_process";
|
|
15252
|
-
import { mkdirSync as mkdirSync12, readFileSync as readFileSync25, rmSync as
|
|
15351
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync25, rmSync as rmSync6, writeFileSync as writeFileSync15 } from "node:fs";
|
|
15253
15352
|
import path30 from "node:path";
|
|
15254
15353
|
import { parse as parseYaml5 } from "yaml";
|
|
15255
15354
|
function splitFrontMatter(markdown) {
|
|
@@ -15531,7 +15630,7 @@ function assemblePortal(options) {
|
|
|
15531
15630
|
const routes = new Set(pages.map((p) => p.route));
|
|
15532
15631
|
const brokenLinks = [];
|
|
15533
15632
|
const externalLinks = [];
|
|
15534
|
-
|
|
15633
|
+
rmSync6(outDir, { recursive: true, force: true });
|
|
15535
15634
|
mkdirSync12(outDir, { recursive: true });
|
|
15536
15635
|
for (const page of pages) {
|
|
15537
15636
|
const raw = readFileSync25(path30.join(repoRoot2, page.source), "utf-8");
|
|
@@ -15869,8 +15968,8 @@ function formatDefault(value, paths = currentMachinePaths()) {
|
|
|
15869
15968
|
if (typeof value === "boolean" || typeof value === "number") return String(value);
|
|
15870
15969
|
return normalizeMachinePaths(JSON.stringify(value), paths);
|
|
15871
15970
|
}
|
|
15872
|
-
function slugifyCommandPath(
|
|
15873
|
-
return
|
|
15971
|
+
function slugifyCommandPath(path50) {
|
|
15972
|
+
return path50.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
15874
15973
|
}
|
|
15875
15974
|
function extractOptions(command) {
|
|
15876
15975
|
const options = command.options ?? [];
|
|
@@ -15904,17 +16003,17 @@ function isUndocumented(command) {
|
|
|
15904
16003
|
function extractCommand(command, parentPath, depth) {
|
|
15905
16004
|
const internals = command;
|
|
15906
16005
|
const name = internals._name ?? "";
|
|
15907
|
-
const
|
|
16006
|
+
const path50 = parentPath ? `${parentPath} ${name}` : name;
|
|
15908
16007
|
return {
|
|
15909
|
-
path:
|
|
16008
|
+
path: path50,
|
|
15910
16009
|
name,
|
|
15911
16010
|
aliases: [...internals._aliases ?? []],
|
|
15912
16011
|
description: internals._description ?? "",
|
|
15913
16012
|
args: extractArgs(command),
|
|
15914
16013
|
options: extractOptions(command),
|
|
15915
|
-
slug: slugifyCommandPath(
|
|
16014
|
+
slug: slugifyCommandPath(path50),
|
|
15916
16015
|
depth,
|
|
15917
|
-
subcommands: (internals.commands ?? []).filter((child) => !isUndocumented(child)).map((child) => extractCommand(child,
|
|
16016
|
+
subcommands: (internals.commands ?? []).filter((child) => !isUndocumented(child)).map((child) => extractCommand(child, path50, depth + 1))
|
|
15918
16017
|
};
|
|
15919
16018
|
}
|
|
15920
16019
|
function extractCliReference(program2) {
|
|
@@ -16402,7 +16501,7 @@ var init_serve = __esm({
|
|
|
16402
16501
|
|
|
16403
16502
|
// packages/mesh-cli/src/docs/registry-docs.ts
|
|
16404
16503
|
import { execFileSync as execFileSync22 } from "node:child_process";
|
|
16405
|
-
import { existsSync as existsSync25, mkdirSync as mkdirSync14, readFileSync as readFileSync28, renameSync as renameSync3, rmSync as
|
|
16504
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync14, readFileSync as readFileSync28, renameSync as renameSync3, rmSync as rmSync7, writeFileSync as writeFileSync17 } from "node:fs";
|
|
16406
16505
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
16407
16506
|
import path33 from "node:path";
|
|
16408
16507
|
function readDocsRegistryAuth(npmrcPath2 = homeNpmrcPath()) {
|
|
@@ -16490,20 +16589,20 @@ async function fetchDocsArtifact(auth, version, cacheRoot = docsCacheRoot(), fet
|
|
|
16490
16589
|
const tgzPath = path33.join(cacheRoot, `.${version}.tgz`);
|
|
16491
16590
|
writeFileSync17(tgzPath, Buffer.from(await tgzResponse.arrayBuffer()));
|
|
16492
16591
|
const staging = path33.join(cacheRoot, `.staging-${version}`);
|
|
16493
|
-
|
|
16592
|
+
rmSync7(staging, { recursive: true, force: true });
|
|
16494
16593
|
mkdirSync14(staging, { recursive: true });
|
|
16495
16594
|
try {
|
|
16496
16595
|
execFileSync22("tar", ["-xzf", tgzPath, "-C", staging, "--strip-components", "1"], {
|
|
16497
16596
|
stdio: ["pipe", "pipe", "pipe"]
|
|
16498
16597
|
});
|
|
16499
16598
|
} finally {
|
|
16500
|
-
|
|
16599
|
+
rmSync7(tgzPath, { force: true });
|
|
16501
16600
|
}
|
|
16502
16601
|
if (!existsSync25(path33.join(staging, "dist", "index.html"))) {
|
|
16503
|
-
|
|
16602
|
+
rmSync7(staging, { recursive: true, force: true });
|
|
16504
16603
|
throw new Error(`${DOCS_PACKAGE}@${version} unpacked without a dist/index.html \u2014 the artifact is malformed`);
|
|
16505
16604
|
}
|
|
16506
|
-
|
|
16605
|
+
rmSync7(targetDir, { recursive: true, force: true });
|
|
16507
16606
|
renameSync3(staging, targetDir);
|
|
16508
16607
|
return targetDir;
|
|
16509
16608
|
}
|
|
@@ -21455,24 +21554,290 @@ var init_site = __esm({
|
|
|
21455
21554
|
}
|
|
21456
21555
|
});
|
|
21457
21556
|
|
|
21458
|
-
// packages/mesh-cli/src/commands/stack.ts
|
|
21459
|
-
import { execFileSync as execFileSync31 } from "child_process";
|
|
21460
|
-
import * as path45 from "path";
|
|
21557
|
+
// packages/mesh-cli/src/commands/stack-status.ts
|
|
21461
21558
|
import * as fs38 from "fs";
|
|
21559
|
+
import * as path45 from "path";
|
|
21560
|
+
import { execFileSync as execFileSync31 } from "child_process";
|
|
21561
|
+
function splitLayerStack(stack, tenant) {
|
|
21562
|
+
if (tenant && stack.startsWith(`${tenant}-`)) return { tenant, env: stack.slice(tenant.length + 1) };
|
|
21563
|
+
const cut = stack.indexOf("-");
|
|
21564
|
+
if (cut <= 0) return { tenant: tenant ?? stack, env: stack };
|
|
21565
|
+
return { tenant: tenant ?? stack.slice(0, cut), env: stack.slice(cut + 1) };
|
|
21566
|
+
}
|
|
21567
|
+
function targetForStack(projectDir, stack) {
|
|
21568
|
+
const platform = readStackPlatform(projectDir, stack);
|
|
21569
|
+
if (platform) {
|
|
21570
|
+
const [tenant2, env2] = platform.split(".");
|
|
21571
|
+
return { stack, kind: "app", tenant: tenant2, env: env2, coreTenant: tenant2, coreEnv: env2 };
|
|
21572
|
+
}
|
|
21573
|
+
const declared = readStackConfig(projectDir, stack, "mesh:tenant");
|
|
21574
|
+
const layerDir = ["core", "platform"].includes(path45.basename(projectDir));
|
|
21575
|
+
if (!declared && !layerDir) return null;
|
|
21576
|
+
const { tenant, env } = splitLayerStack(stack, declared);
|
|
21577
|
+
const isCore = path45.basename(projectDir) === "core";
|
|
21578
|
+
return {
|
|
21579
|
+
stack,
|
|
21580
|
+
kind: "layer",
|
|
21581
|
+
tenant,
|
|
21582
|
+
env,
|
|
21583
|
+
coreTenant: readStackConfig(projectDir, stack, "mesh:coreTenant") ?? tenant,
|
|
21584
|
+
coreEnv: readStackConfig(projectDir, stack, "mesh:coreEnv") ?? env,
|
|
21585
|
+
...isCore ? { coreDir: projectDir } : { platformDir: projectDir }
|
|
21586
|
+
};
|
|
21587
|
+
}
|
|
21588
|
+
function findStatusTargets(cwd, stack) {
|
|
21589
|
+
const project = findAppRoot(cwd);
|
|
21590
|
+
let projectDir = project;
|
|
21591
|
+
let repoRoot2 = null;
|
|
21592
|
+
if (!projectDir) {
|
|
21593
|
+
const platformDir = path45.join(cwd, "platform");
|
|
21594
|
+
if (fs38.existsSync(path45.join(platformDir, "Pulumi.yaml"))) {
|
|
21595
|
+
projectDir = platformDir;
|
|
21596
|
+
repoRoot2 = cwd;
|
|
21597
|
+
}
|
|
21598
|
+
} else if (["core", "platform"].includes(path45.basename(projectDir))) {
|
|
21599
|
+
repoRoot2 = path45.dirname(projectDir);
|
|
21600
|
+
}
|
|
21601
|
+
if (!projectDir) return [];
|
|
21602
|
+
const stacks = stack ? [stack] : findStackConfigs(projectDir);
|
|
21603
|
+
const targets = [];
|
|
21604
|
+
for (const name of stacks) {
|
|
21605
|
+
const target = targetForStack(projectDir, name);
|
|
21606
|
+
if (!target) continue;
|
|
21607
|
+
if (repoRoot2 && target.kind === "layer") {
|
|
21608
|
+
const core = path45.join(repoRoot2, "core");
|
|
21609
|
+
const platform = path45.join(repoRoot2, "platform");
|
|
21610
|
+
if (fs38.existsSync(path45.join(core, "package.json"))) target.coreDir = core;
|
|
21611
|
+
if (fs38.existsSync(path45.join(platform, "package.json"))) target.platformDir = platform;
|
|
21612
|
+
}
|
|
21613
|
+
targets.push(target);
|
|
21614
|
+
}
|
|
21615
|
+
return targets;
|
|
21616
|
+
}
|
|
21617
|
+
function pinnedVersion(dir, pkg) {
|
|
21618
|
+
if (!dir) return null;
|
|
21619
|
+
try {
|
|
21620
|
+
const manifest = JSON.parse(fs38.readFileSync(path45.join(dir, "package.json"), "utf-8"));
|
|
21621
|
+
const spec = manifest.dependencies?.[pkg] ?? manifest.devDependencies?.[pkg];
|
|
21622
|
+
return typeof spec === "string" ? spec.replace(/^[\^~=v]+/, "") : null;
|
|
21623
|
+
} catch {
|
|
21624
|
+
return null;
|
|
21625
|
+
}
|
|
21626
|
+
}
|
|
21627
|
+
function compareVersions2(a, b) {
|
|
21628
|
+
const parse4 = (v) => v.split(/[.+-]/).slice(0, 3).map((n) => Number.parseInt(n, 10) || 0);
|
|
21629
|
+
const [x, y] = [parse4(a), parse4(b)];
|
|
21630
|
+
for (let i = 0; i < 3; i++) {
|
|
21631
|
+
const diff = (x[i] ?? 0) - (y[i] ?? 0);
|
|
21632
|
+
if (diff) return diff;
|
|
21633
|
+
}
|
|
21634
|
+
return 0;
|
|
21635
|
+
}
|
|
21636
|
+
function layerState(deployed, latest) {
|
|
21637
|
+
if (!deployed) return "not-deployed";
|
|
21638
|
+
if (!latest) return "unknown";
|
|
21639
|
+
return compareVersions2(deployed, latest) < 0 ? "behind" : "current";
|
|
21640
|
+
}
|
|
21641
|
+
function parseRegistration(raw) {
|
|
21642
|
+
try {
|
|
21643
|
+
const data = JSON.parse(raw);
|
|
21644
|
+
const out = {};
|
|
21645
|
+
if (typeof data.build?.infraVersion === "string") out.infraVersion = data.build.infraVersion;
|
|
21646
|
+
if (typeof data.hub?.hubVersion === "string") out.hubVersion = data.hub.hubVersion;
|
|
21647
|
+
return out;
|
|
21648
|
+
} catch {
|
|
21649
|
+
return {};
|
|
21650
|
+
}
|
|
21651
|
+
}
|
|
21652
|
+
function buildRows(target, deployed, latest) {
|
|
21653
|
+
const corePath = `/mesh-platform/${target.coreTenant}/${target.coreEnv}/core`;
|
|
21654
|
+
const platformPath = `/mesh-platform/${target.tenant}/${target.env}/platform`;
|
|
21655
|
+
const row = (layer, registration, source, field, pinned, latestVersion) => {
|
|
21656
|
+
const value = source && !(source instanceof Error) ? source[field] ?? null : null;
|
|
21657
|
+
const predatesExport = !!source && !(source instanceof Error) && value === null;
|
|
21658
|
+
const note = source instanceof Error ? source.message : source === null ? "no registration \u2014 never deployed, or not readable with these credentials" : predatesExport ? "registration predates version export \u2014 last deployed with an infra-components older than any current release" : void 0;
|
|
21659
|
+
return {
|
|
21660
|
+
layer,
|
|
21661
|
+
registration,
|
|
21662
|
+
pinned,
|
|
21663
|
+
deployed: value,
|
|
21664
|
+
latest: latestVersion,
|
|
21665
|
+
state: source instanceof Error ? "unknown" : predatesExport ? "behind" : layerState(value, latestVersion),
|
|
21666
|
+
undeployedPin: !!pinned && !!value && pinned !== value,
|
|
21667
|
+
...note ? { note } : {}
|
|
21668
|
+
};
|
|
21669
|
+
};
|
|
21670
|
+
return [
|
|
21671
|
+
row("core", corePath, deployed.core, "infraVersion", pinnedVersion(target.coreDir, INFRA_PACKAGE), latest.infra),
|
|
21672
|
+
row(
|
|
21673
|
+
"platform",
|
|
21674
|
+
platformPath,
|
|
21675
|
+
deployed.platform,
|
|
21676
|
+
"infraVersion",
|
|
21677
|
+
pinnedVersion(target.platformDir, INFRA_PACKAGE),
|
|
21678
|
+
latest.infra
|
|
21679
|
+
),
|
|
21680
|
+
row("hub", platformPath, deployed.platform, "hubVersion", pinnedVersion(target.platformDir, HUB_PACKAGE2), latest.hub)
|
|
21681
|
+
];
|
|
21682
|
+
}
|
|
21683
|
+
function renderStatus(reports, cli) {
|
|
21684
|
+
const lines = [];
|
|
21685
|
+
const show = (v) => v ?? "\u2014";
|
|
21686
|
+
for (const { target, rows } of reports) {
|
|
21687
|
+
const what = target.kind === "app" ? `App stack ${target.stack} \u2192 platform ${target.tenant}/${target.env}` : `Platform ${target.tenant}/${target.env} (stack ${target.stack}) on core ${target.coreTenant}/${target.coreEnv}`;
|
|
21688
|
+
lines.push(what);
|
|
21689
|
+
lines.push(` ${"layer".padEnd(9)} ${"pinned".padEnd(10)} ${"deployed".padEnd(10)} ${"latest".padEnd(10)} state`);
|
|
21690
|
+
for (const r of rows) {
|
|
21691
|
+
const flag = r.undeployedPin ? " (pin not deployed)" : "";
|
|
21692
|
+
lines.push(
|
|
21693
|
+
` ${r.layer.padEnd(9)} ${show(r.pinned).padEnd(10)} ${show(r.deployed).padEnd(10)} ${show(r.latest).padEnd(10)} ${r.state}${flag}`
|
|
21694
|
+
);
|
|
21695
|
+
if (r.note) lines.push(` ${r.registration}: ${r.note}`);
|
|
21696
|
+
}
|
|
21697
|
+
if (rows.some((r) => r.state === "behind" || r.undeployedPin)) {
|
|
21698
|
+
lines.push(...upgradeSteps(target, rows));
|
|
21699
|
+
}
|
|
21700
|
+
lines.push("");
|
|
21701
|
+
}
|
|
21702
|
+
lines.push(
|
|
21703
|
+
`CLI ${CLI_PACKAGE} ${cli.running}` + (cli.latest ? ` (latest ${cli.latest})${cli.behind ? " \u2014 behind: pnpm add -D @mesh-tech/mesh-cli@latest" : ""}` : " (latest unknown)")
|
|
21704
|
+
);
|
|
21705
|
+
return lines.join("\n");
|
|
21706
|
+
}
|
|
21707
|
+
function upgradeSteps(target, rows) {
|
|
21708
|
+
const latest = rows.find((r) => r.latest)?.latest;
|
|
21709
|
+
if (target.kind === "app") {
|
|
21710
|
+
return [
|
|
21711
|
+
" This platform is behind. Its operator upgrades it from the org's platform repo:",
|
|
21712
|
+
" run `mesh stack status` there, then upgrade core and platform together."
|
|
21713
|
+
];
|
|
21714
|
+
}
|
|
21715
|
+
const to = latest ? `@${latest}` : "@latest";
|
|
21716
|
+
return [
|
|
21717
|
+
" To upgrade (both layers \u2014 deploying platform/ alone leaves core on the old version):",
|
|
21718
|
+
` 1. core/ and platform/: set ${INFRA_PACKAGE}${to} (and ${HUB_PACKAGE2}${to} in platform/), then pnpm install`,
|
|
21719
|
+
` 2. cd core && mesh deploy preview --stack ${target.coreTenant}-${target.coreEnv} # review: this layer is the VPC/EKS/RDS`,
|
|
21720
|
+
` 3. mesh deploy up --stack ${target.coreTenant}-${target.coreEnv} && cd ../platform && mesh deploy up --stack ${target.stack}`,
|
|
21721
|
+
" 4. mesh stack status # both layers now report the new version"
|
|
21722
|
+
];
|
|
21723
|
+
}
|
|
21724
|
+
function latestPublished(pkg, cwd) {
|
|
21725
|
+
try {
|
|
21726
|
+
const out = execFileSync31("npm", ["view", pkg, "version"], {
|
|
21727
|
+
cwd,
|
|
21728
|
+
encoding: "utf-8",
|
|
21729
|
+
timeout: 2e4,
|
|
21730
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
21731
|
+
}).trim();
|
|
21732
|
+
return /^\d+\.\d+\.\d+$/.test(out) ? out : null;
|
|
21733
|
+
} catch {
|
|
21734
|
+
return null;
|
|
21735
|
+
}
|
|
21736
|
+
}
|
|
21737
|
+
async function readRegistration(name, region, auth) {
|
|
21738
|
+
const { credentials, profile, signInHint } = auth;
|
|
21739
|
+
try {
|
|
21740
|
+
const { SSMClient: SSMClient5, GetParameterCommand: GetParameterCommand2 } = await import("@aws-sdk/client-ssm");
|
|
21741
|
+
const client = new SSMClient5({
|
|
21742
|
+
region,
|
|
21743
|
+
...profile && !credentials?.AWS_ACCESS_KEY_ID ? { profile } : {},
|
|
21744
|
+
...credentials?.AWS_ACCESS_KEY_ID ? {
|
|
21745
|
+
credentials: {
|
|
21746
|
+
accessKeyId: credentials.AWS_ACCESS_KEY_ID,
|
|
21747
|
+
secretAccessKey: credentials.AWS_SECRET_ACCESS_KEY ?? "",
|
|
21748
|
+
sessionToken: credentials.AWS_SESSION_TOKEN
|
|
21749
|
+
}
|
|
21750
|
+
} : {}
|
|
21751
|
+
});
|
|
21752
|
+
const resp = await client.send(new GetParameterCommand2({ Name: name }));
|
|
21753
|
+
return resp.Parameter?.Value ? parseRegistration(resp.Parameter.Value) : null;
|
|
21754
|
+
} catch (err) {
|
|
21755
|
+
const e = err;
|
|
21756
|
+
const kind = e.name || e.__type || e.message || String(err);
|
|
21757
|
+
if (/ParameterNotFound/.test(kind)) return null;
|
|
21758
|
+
if (/credential|ExpiredToken|AccessDenied|UnrecognizedClient|security token/i.test(`${kind} ${e.message ?? ""}`)) {
|
|
21759
|
+
return new Error(`could not read \u2014 no AWS credentials for this account (${signInHint})`);
|
|
21760
|
+
}
|
|
21761
|
+
return new Error(`could not read \u2014 ${e.message ?? kind}`);
|
|
21762
|
+
}
|
|
21763
|
+
}
|
|
21764
|
+
async function runStackStatus(cwd, opts) {
|
|
21765
|
+
const targets = findStatusTargets(cwd, opts.stack);
|
|
21766
|
+
if (targets.length === 0) {
|
|
21767
|
+
logWarn(
|
|
21768
|
+
"No Mesh stack found here. Run from an app directory (a Pulumi.<stack>.yaml naming mesh:platform),\n or from your org's Mesh platform repo (its root, core/ or platform/)."
|
|
21769
|
+
);
|
|
21770
|
+
return true;
|
|
21771
|
+
}
|
|
21772
|
+
const infraLatest = latestPublished(INFRA_PACKAGE, cwd);
|
|
21773
|
+
const hubLatest = latestPublished(HUB_PACKAGE2, cwd);
|
|
21774
|
+
const running = resolveCliRuntime({ vcs: false }).version;
|
|
21775
|
+
const cliLatest = latestPublished(CLI_PACKAGE, cwd);
|
|
21776
|
+
const cli = { running, latest: cliLatest, behind: !!cliLatest && compareVersions2(running, cliLatest) < 0 };
|
|
21777
|
+
if (!infraLatest) logInfo("Registry lookup failed \u2014 `latest` is unknown. Run `mesh registry login` and retry.");
|
|
21778
|
+
const reports = [];
|
|
21779
|
+
for (const target of targets) {
|
|
21780
|
+
const projectDir = findAppRoot(cwd) ?? target.platformDir ?? cwd;
|
|
21781
|
+
const region = opts.region ?? readStackConfig(projectDir, target.stack, "aws:region") ?? "us-east-2";
|
|
21782
|
+
const ambient = !!process.env.AWS_ACCESS_KEY_ID || !!process.env.AWS_PROFILE;
|
|
21783
|
+
let profile = opts.profile;
|
|
21784
|
+
let credentials;
|
|
21785
|
+
if (!profile && !ambient) {
|
|
21786
|
+
profile = readStackConfig(projectDir, target.stack, "aws:profile") ?? void 0;
|
|
21787
|
+
if (!profile && target.kind === "app") {
|
|
21788
|
+
const role = readStackConfig(projectDir, target.stack, "mesh:deployerRole");
|
|
21789
|
+
if (role) credentials = (await resolveAwsCredentials(role, projectDir, target.stack))?.env;
|
|
21790
|
+
}
|
|
21791
|
+
}
|
|
21792
|
+
const loginContext = target.kind === "app" ? derivePlatformContext(projectDir, target.stack) : null;
|
|
21793
|
+
const signInHint = loginContext ? `sign in with \`mesh login ${loginContext} --device\`, or pass --profile` : "set AWS_PROFILE or pass --profile with access to the core's account";
|
|
21794
|
+
const auth = { credentials, profile, signInHint };
|
|
21795
|
+
const [core, platform] = await Promise.all([
|
|
21796
|
+
readRegistration(`/mesh-platform/${target.coreTenant}/${target.coreEnv}/core`, region, auth),
|
|
21797
|
+
readRegistration(`/mesh-platform/${target.tenant}/${target.env}/platform`, region, auth)
|
|
21798
|
+
]);
|
|
21799
|
+
reports.push({ target, rows: buildRows(target, { core, platform }, { infra: infraLatest, hub: hubLatest }) });
|
|
21800
|
+
}
|
|
21801
|
+
if (opts.json) {
|
|
21802
|
+
process.stdout.write(JSON.stringify({ platforms: reports, cli }, null, 2) + "\n");
|
|
21803
|
+
} else {
|
|
21804
|
+
process.stdout.write(renderStatus(reports, cli) + "\n");
|
|
21805
|
+
}
|
|
21806
|
+
const behind = cli.behind || reports.some((r) => r.rows.some((row) => row.state === "behind" || row.undeployedPin));
|
|
21807
|
+
return !behind;
|
|
21808
|
+
}
|
|
21809
|
+
var INFRA_PACKAGE, HUB_PACKAGE2, CLI_PACKAGE;
|
|
21810
|
+
var init_stack_status = __esm({
|
|
21811
|
+
"packages/mesh-cli/src/commands/stack-status.ts"() {
|
|
21812
|
+
"use strict";
|
|
21813
|
+
init_log();
|
|
21814
|
+
init_pulumi();
|
|
21815
|
+
init_aws_auth();
|
|
21816
|
+
init_build_info();
|
|
21817
|
+
INFRA_PACKAGE = "@mesh-tech/infra-components";
|
|
21818
|
+
HUB_PACKAGE2 = "@mesh-tech/hub";
|
|
21819
|
+
CLI_PACKAGE = "@mesh-tech/mesh-cli";
|
|
21820
|
+
}
|
|
21821
|
+
});
|
|
21822
|
+
|
|
21823
|
+
// packages/mesh-cli/src/commands/stack.ts
|
|
21824
|
+
import { execFileSync as execFileSync32 } from "child_process";
|
|
21825
|
+
import * as path46 from "path";
|
|
21826
|
+
import * as fs39 from "fs";
|
|
21462
21827
|
import { parse as parseYaml6 } from "yaml";
|
|
21463
21828
|
function readTopLevelYamlKey(appRoot, stack, key) {
|
|
21464
|
-
const configFile =
|
|
21465
|
-
if (!
|
|
21466
|
-
const content =
|
|
21829
|
+
const configFile = path46.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
21830
|
+
if (!fs39.existsSync(configFile)) return null;
|
|
21831
|
+
const content = fs39.readFileSync(configFile, "utf-8");
|
|
21467
21832
|
const pattern = new RegExp(`^${key}:\\s*(.+)$`, "m");
|
|
21468
21833
|
const match = content.match(pattern);
|
|
21469
21834
|
if (!match) return null;
|
|
21470
21835
|
return match[1].trim().replace(/^["']|["']$/g, "");
|
|
21471
21836
|
}
|
|
21472
21837
|
function readConfigBlockKey(appRoot, stack, key) {
|
|
21473
|
-
const configFile =
|
|
21474
|
-
if (!
|
|
21475
|
-
const content =
|
|
21838
|
+
const configFile = path46.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
21839
|
+
if (!fs39.existsSync(configFile)) return null;
|
|
21840
|
+
const content = fs39.readFileSync(configFile, "utf-8");
|
|
21476
21841
|
const pattern = new RegExp(`^\\s{2}${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}:\\s*(.+)$`, "m");
|
|
21477
21842
|
const match = content.match(pattern);
|
|
21478
21843
|
if (!match) return null;
|
|
@@ -21532,11 +21897,11 @@ ${records}
|
|
|
21532
21897
|
}
|
|
21533
21898
|
}
|
|
21534
21899
|
function readBaseConfigFromYaml(appRoot, stack) {
|
|
21535
|
-
const file =
|
|
21536
|
-
if (!
|
|
21900
|
+
const file = path46.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
21901
|
+
if (!fs39.existsSync(file)) return {};
|
|
21537
21902
|
let doc;
|
|
21538
21903
|
try {
|
|
21539
|
-
doc = parseYaml6(
|
|
21904
|
+
doc = parseYaml6(fs39.readFileSync(file, "utf-8"));
|
|
21540
21905
|
} catch {
|
|
21541
21906
|
return {};
|
|
21542
21907
|
}
|
|
@@ -21549,7 +21914,7 @@ function readBaseConfigFromYaml(appRoot, stack) {
|
|
|
21549
21914
|
}
|
|
21550
21915
|
function getGitHubUsername() {
|
|
21551
21916
|
try {
|
|
21552
|
-
const result =
|
|
21917
|
+
const result = execFileSync32("gh", ["api", "user", "--jq", ".login"], {
|
|
21553
21918
|
encoding: "utf-8",
|
|
21554
21919
|
stdio: ["pipe", "pipe", "pipe"]
|
|
21555
21920
|
});
|
|
@@ -21558,7 +21923,7 @@ function getGitHubUsername() {
|
|
|
21558
21923
|
} catch {
|
|
21559
21924
|
}
|
|
21560
21925
|
try {
|
|
21561
|
-
const result =
|
|
21926
|
+
const result = execFileSync32("git", ["config", "user.email"], {
|
|
21562
21927
|
encoding: "utf-8",
|
|
21563
21928
|
stdio: ["pipe", "pipe", "pipe"]
|
|
21564
21929
|
});
|
|
@@ -21570,7 +21935,7 @@ function getGitHubUsername() {
|
|
|
21570
21935
|
return null;
|
|
21571
21936
|
}
|
|
21572
21937
|
function registerStackCommand(program2) {
|
|
21573
|
-
const stack = program2.command("stack").description("Manage personal Pulumi stacks");
|
|
21938
|
+
const stack = program2.command("stack").description("Manage personal Pulumi stacks and check a Mesh instance against the latest release");
|
|
21574
21939
|
stack.command("init").description("Create a personal dev stack (dev-{github-username})").option("--from <stack>", "Base stack to copy config from").option("--name <name>", "Override stack name (default: dev-{username})").option("--adopt", "resume an EXISTING stack with this name (skips the availability check)", false).option(
|
|
21575
21940
|
"--worktree",
|
|
21576
21941
|
"Isolate this stack per git worktree \u2014 append the worktree token to the name so concurrent worktrees deploy to distinct stacks (no SSM/namespace collisions)"
|
|
@@ -21613,7 +21978,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21613
21978
|
}
|
|
21614
21979
|
}
|
|
21615
21980
|
const baseConfigPath = `${appRoot}/Pulumi.${baseStack}.yaml`;
|
|
21616
|
-
if (!
|
|
21981
|
+
if (!fs39.existsSync(baseConfigPath)) {
|
|
21617
21982
|
logError(`Stack config not found: Pulumi.${baseStack}.yaml`);
|
|
21618
21983
|
process.exit(1);
|
|
21619
21984
|
}
|
|
@@ -21635,8 +22000,8 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21635
22000
|
);
|
|
21636
22001
|
}
|
|
21637
22002
|
}
|
|
21638
|
-
const newConfigPath =
|
|
21639
|
-
const configExists =
|
|
22003
|
+
const newConfigPath = path46.join(appRoot, `Pulumi.${newStack}.yaml`);
|
|
22004
|
+
const configExists = fs39.existsSync(newConfigPath);
|
|
21640
22005
|
const secretsProvider = readTopLevelYamlKey(appRoot, baseStack, "secretsprovider");
|
|
21641
22006
|
const credEnv = await resolvePulumiEnv({ appRoot, stack: baseStack });
|
|
21642
22007
|
const pulumiEnv = { ...process.env, ...credEnv };
|
|
@@ -21644,7 +22009,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21644
22009
|
if (!opts.adopt) {
|
|
21645
22010
|
let existing = [];
|
|
21646
22011
|
try {
|
|
21647
|
-
const raw =
|
|
22012
|
+
const raw = execFileSync32("pulumi", ["stack", "ls", "--json"], {
|
|
21648
22013
|
cwd: appRoot,
|
|
21649
22014
|
encoding: "utf-8",
|
|
21650
22015
|
env: pulumiEnv,
|
|
@@ -21668,7 +22033,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21668
22033
|
logInfo(`Using KMS secrets provider: ${secretsProvider}`);
|
|
21669
22034
|
}
|
|
21670
22035
|
try {
|
|
21671
|
-
|
|
22036
|
+
execFileSync32("pulumi", initArgs, {
|
|
21672
22037
|
cwd: appRoot,
|
|
21673
22038
|
env: pulumiEnv,
|
|
21674
22039
|
stdio: "inherit"
|
|
@@ -21685,7 +22050,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21685
22050
|
}
|
|
21686
22051
|
}
|
|
21687
22052
|
try {
|
|
21688
|
-
|
|
22053
|
+
execFileSync32("pulumi", ["stack", "select", newStack], {
|
|
21689
22054
|
cwd: appRoot,
|
|
21690
22055
|
env: pulumiEnv,
|
|
21691
22056
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -21695,7 +22060,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21695
22060
|
if (!configExists) {
|
|
21696
22061
|
let baseConfig = {};
|
|
21697
22062
|
try {
|
|
21698
|
-
const raw =
|
|
22063
|
+
const raw = execFileSync32(
|
|
21699
22064
|
"pulumi",
|
|
21700
22065
|
["config", "--json", "--stack", baseStack],
|
|
21701
22066
|
{ cwd: appRoot, env: pulumiEnv, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -21713,19 +22078,19 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21713
22078
|
if (key === "mesh:deploy") continue;
|
|
21714
22079
|
try {
|
|
21715
22080
|
if (entry.objectValue !== void 0) {
|
|
21716
|
-
|
|
22081
|
+
execFileSync32(
|
|
21717
22082
|
"pulumi",
|
|
21718
22083
|
["config", "set", key, JSON.stringify(entry.objectValue)],
|
|
21719
22084
|
{ cwd: appRoot, env: pulumiEnv, stdio: ["pipe", "pipe", "pipe"] }
|
|
21720
22085
|
);
|
|
21721
22086
|
} else if (entry.value === "true" || entry.value === "false") {
|
|
21722
|
-
|
|
22087
|
+
execFileSync32(
|
|
21723
22088
|
"pulumi",
|
|
21724
22089
|
["config", "set", "--type", "bool", key, entry.value],
|
|
21725
22090
|
{ cwd: appRoot, env: pulumiEnv, stdio: ["pipe", "pipe", "pipe"] }
|
|
21726
22091
|
);
|
|
21727
22092
|
} else {
|
|
21728
|
-
|
|
22093
|
+
execFileSync32(
|
|
21729
22094
|
"pulumi",
|
|
21730
22095
|
["config", "set", key, entry.value],
|
|
21731
22096
|
{ cwd: appRoot, env: pulumiEnv, stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -21738,7 +22103,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21738
22103
|
const baseEnv = readConfigBlockKey(appRoot, baseStack, "mesh:coreEnv") ?? (baseTenant && baseStack.startsWith(`${baseTenant}-`) ? baseStack.slice(baseTenant.length + 1) : baseStack);
|
|
21739
22104
|
const setCfg = (args) => {
|
|
21740
22105
|
try {
|
|
21741
|
-
|
|
22106
|
+
execFileSync32("pulumi", ["config", "set", ...args], {
|
|
21742
22107
|
cwd: appRoot,
|
|
21743
22108
|
env: pulumiEnv,
|
|
21744
22109
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -21787,7 +22152,7 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21787
22152
|
`Configured Pulumi.${newStack}.yaml (personal platform env on core '${baseEnv}'${opts.parentZone ? `, DNS zone ${newStack.startsWith(`${baseTenant}-`) ? newStack.slice(baseTenant.length + 1) : newStack}.${opts.parentZone}` : ""})`
|
|
21788
22153
|
);
|
|
21789
22154
|
} else {
|
|
21790
|
-
|
|
22155
|
+
execFileSync32("pulumi", ["config", "set", "--type", "bool", "mesh:deploy", "false"], {
|
|
21791
22156
|
cwd: appRoot,
|
|
21792
22157
|
env: pulumiEnv,
|
|
21793
22158
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -21817,12 +22182,18 @@ Specify which to base on: mesh stack init --from <stack>`
|
|
|
21817
22182
|
const args = ["stack", "rm", name];
|
|
21818
22183
|
if (opts.yes) args.push("--yes");
|
|
21819
22184
|
try {
|
|
21820
|
-
|
|
22185
|
+
execFileSync32("pulumi", args, { cwd: appRoot, env: pulumiEnv, stdio: "inherit" });
|
|
21821
22186
|
logSuccess(`Removed stack ${name}`);
|
|
21822
22187
|
} catch (err) {
|
|
21823
22188
|
process.exit(err.status ?? 1);
|
|
21824
22189
|
}
|
|
21825
22190
|
});
|
|
22191
|
+
stack.command("status").description(
|
|
22192
|
+
"Read-only drift check: for each platform this directory deploys (a platform repo's core/platform stacks) or deploys apps to (an app's mesh:platform), compare the pinned, deployed (the core and platform SSM registrations written by the last successful deploy) and latest published @mesh-tech/infra-components and @mesh-tech/hub, plus this CLI against the latest @mesh-tech/mesh-cli, and print the upgrade steps when anything is behind. Changes nothing."
|
|
22193
|
+
).option("--stack <name>", "check one stack (default: every Pulumi.<stack>.yaml here)").option("--profile <profile>", "AWS profile to read the SSM registrations with (default: AWS_PROFILE, else the stack's aws:profile, else an app stack's deployer role)").option("--region <region>", "AWS region of the registrations (default: the stack's aws:region, else us-east-2)").option("--json", "print the report as JSON", false).option("--check", "exit 1 when any layer or the CLI is behind, or a pin is not deployed", false).action(async (opts) => {
|
|
22194
|
+
const ok = await runStackStatus(process.cwd(), opts);
|
|
22195
|
+
if (opts.check && !ok) process.exit(1);
|
|
22196
|
+
});
|
|
21826
22197
|
}
|
|
21827
22198
|
var init_stack2 = __esm({
|
|
21828
22199
|
"packages/mesh-cli/src/commands/stack.ts"() {
|
|
@@ -21831,6 +22202,7 @@ var init_stack2 = __esm({
|
|
|
21831
22202
|
init_pulumi();
|
|
21832
22203
|
init_worktree_identity();
|
|
21833
22204
|
init_pulumi_run();
|
|
22205
|
+
init_stack_status();
|
|
21834
22206
|
}
|
|
21835
22207
|
});
|
|
21836
22208
|
|
|
@@ -22029,12 +22401,12 @@ var init_recover_conversation = __esm({
|
|
|
22029
22401
|
});
|
|
22030
22402
|
|
|
22031
22403
|
// packages/mesh-cli/src/utils/temporal-codec.ts
|
|
22032
|
-
import { execFileSync as
|
|
22404
|
+
import { execFileSync as execFileSync33 } from "child_process";
|
|
22033
22405
|
import { webcrypto as crypto4 } from "node:crypto";
|
|
22034
22406
|
function resolveTemporalEncodingKeyFromK8s(namespace) {
|
|
22035
22407
|
const secretName = `${namespace}-temporal-encoding-key`;
|
|
22036
22408
|
try {
|
|
22037
|
-
const b64 =
|
|
22409
|
+
const b64 = execFileSync33(
|
|
22038
22410
|
"kubectl",
|
|
22039
22411
|
[
|
|
22040
22412
|
"get",
|
|
@@ -22285,7 +22657,7 @@ var init_capture_history = __esm({
|
|
|
22285
22657
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
22286
22658
|
import { writeFileSync as writeFileSync24, mkdirSync as mkdirSync20 } from "node:fs";
|
|
22287
22659
|
import { homedir as homedir6 } from "node:os";
|
|
22288
|
-
import { dirname as
|
|
22660
|
+
import { dirname as dirname30, join as join43, resolve as resolve19 } from "node:path";
|
|
22289
22661
|
async function resolveConnection(options) {
|
|
22290
22662
|
if (options.address && options.namespace) {
|
|
22291
22663
|
return { address: options.address, namespace: options.namespace };
|
|
@@ -22713,8 +23085,8 @@ async function captureHistory(workflowId, runId, options) {
|
|
|
22713
23085
|
}
|
|
22714
23086
|
const { serializeHistoryToFixture: serializeHistoryToFixture2 } = await Promise.resolve().then(() => (init_capture_history(), capture_history_exports));
|
|
22715
23087
|
const { fixture, eventCount, decryptedPayloads } = await serializeHistoryToFixture2(events, decrypter);
|
|
22716
|
-
const outPath = options.out ??
|
|
22717
|
-
mkdirSync20(
|
|
23088
|
+
const outPath = options.out ?? join43(homedir6(), ".mesh", "replay-histories", `${sanitizeFileId(workflowId)}.json`);
|
|
23089
|
+
mkdirSync20(dirname30(outPath), { recursive: true });
|
|
22718
23090
|
if (options.out) warnIfNotGitIgnored(options.out);
|
|
22719
23091
|
writeFileSync24(outPath, JSON.stringify(fixture, null, 2) + "\n");
|
|
22720
23092
|
logSuccess(
|
|
@@ -22733,7 +23105,7 @@ function sanitizeFileId(id) {
|
|
|
22733
23105
|
function warnIfNotGitIgnored(outPath) {
|
|
22734
23106
|
const abs = resolve19(outPath);
|
|
22735
23107
|
try {
|
|
22736
|
-
const res = spawnSync4("git", ["-C",
|
|
23108
|
+
const res = spawnSync4("git", ["-C", dirname30(abs), "check-ignore", "-q", abs], {
|
|
22737
23109
|
stdio: "ignore"
|
|
22738
23110
|
});
|
|
22739
23111
|
if (res.status !== 1) return;
|
|
@@ -22905,8 +23277,8 @@ var init_temporal = __esm({
|
|
|
22905
23277
|
|
|
22906
23278
|
// packages/mesh-cli/src/commands/tenant.ts
|
|
22907
23279
|
import chalk7 from "chalk";
|
|
22908
|
-
import * as
|
|
22909
|
-
import * as
|
|
23280
|
+
import * as fs40 from "fs";
|
|
23281
|
+
import * as path47 from "path";
|
|
22910
23282
|
import { parseDocument, YAMLMap, isMap } from "yaml";
|
|
22911
23283
|
function validateTenantName(name) {
|
|
22912
23284
|
return /^[a-z][a-z0-9-]*$/.test(name) && !name.endsWith("-");
|
|
@@ -22974,16 +23346,16 @@ function resolveStackConfig(explicitStack) {
|
|
|
22974
23346
|
{ remediation: { command: "mesh tenant add <name> --stack <stack>" } }
|
|
22975
23347
|
);
|
|
22976
23348
|
}
|
|
22977
|
-
const file =
|
|
22978
|
-
if (!
|
|
23349
|
+
const file = path47.join(appRoot, `Pulumi.${stack}.yaml`);
|
|
23350
|
+
if (!fs40.existsSync(file)) {
|
|
22979
23351
|
throw new MeshCliError(`Stack config not found: ${file}`, {
|
|
22980
23352
|
remediation: { command: "mesh tenant add <name> --stack <stack>" }
|
|
22981
23353
|
});
|
|
22982
23354
|
}
|
|
22983
|
-
return { appRoot, stack, file, content:
|
|
23355
|
+
return { appRoot, stack, file, content: fs40.readFileSync(file, "utf-8") };
|
|
22984
23356
|
}
|
|
22985
23357
|
function readProjectName(appRoot) {
|
|
22986
|
-
const projectDoc = parseDocument(
|
|
23358
|
+
const projectDoc = parseDocument(fs40.readFileSync(path47.join(appRoot, "Pulumi.yaml"), "utf-8"));
|
|
22987
23359
|
return String(projectDoc.get("name") ?? "");
|
|
22988
23360
|
}
|
|
22989
23361
|
function looksLikePlatformLayer(projectName) {
|
|
@@ -23026,12 +23398,12 @@ function registerTenantCommands(program2) {
|
|
|
23026
23398
|
if (!result.ok) {
|
|
23027
23399
|
if (result.reason === "exists") {
|
|
23028
23400
|
throw new MeshCliError(
|
|
23029
|
-
`${result.detail} (${
|
|
23401
|
+
`${result.detail} (${path47.basename(resolved.file)}). Edit the existing entry instead of re-adding it.`
|
|
23030
23402
|
);
|
|
23031
23403
|
}
|
|
23032
23404
|
throw new MeshCliError(`${resolved.file}: ${result.detail}`);
|
|
23033
23405
|
}
|
|
23034
|
-
atomicWriteFileSync(resolved.file, result.yaml,
|
|
23406
|
+
atomicWriteFileSync(resolved.file, result.yaml, fs40.statSync(resolved.file).mode & 511);
|
|
23035
23407
|
if (opts.json) {
|
|
23036
23408
|
emitJsonPayload({
|
|
23037
23409
|
ok: true,
|
|
@@ -23044,7 +23416,7 @@ function registerTenantCommands(program2) {
|
|
|
23044
23416
|
return;
|
|
23045
23417
|
}
|
|
23046
23418
|
logInfo(
|
|
23047
|
-
`Tenant '${name}' registered in ${
|
|
23419
|
+
`Tenant '${name}' registered in ${path47.basename(resolved.file)} (mesh:tenants, subdomain '${subdomain}')${result.createdTenantsBlock ? " \u2014 created the mesh:tenants block" : ""}`
|
|
23048
23420
|
);
|
|
23049
23421
|
console.log("");
|
|
23050
23422
|
console.log("Next steps:");
|
|
@@ -23070,7 +23442,7 @@ function registerTenantCommands(program2) {
|
|
|
23070
23442
|
`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).`
|
|
23071
23443
|
);
|
|
23072
23444
|
}
|
|
23073
|
-
logInfo(`No tenants declared in ${
|
|
23445
|
+
logInfo(`No tenants declared in ${path47.basename(resolved.file)}.`);
|
|
23074
23446
|
return;
|
|
23075
23447
|
}
|
|
23076
23448
|
logInfo(`Tenants on stack '${resolved.stack}':`);
|
|
@@ -23092,9 +23464,9 @@ var init_tenant = __esm({
|
|
|
23092
23464
|
|
|
23093
23465
|
// packages/mesh-cli/src/commands/tunnel/index.ts
|
|
23094
23466
|
import { spawn as spawn9 } from "child_process";
|
|
23095
|
-
import * as
|
|
23467
|
+
import * as fs41 from "fs";
|
|
23096
23468
|
import * as os12 from "os";
|
|
23097
|
-
import * as
|
|
23469
|
+
import * as path48 from "path";
|
|
23098
23470
|
import {
|
|
23099
23471
|
SecretsManagerClient as SecretsManagerClient9,
|
|
23100
23472
|
GetSecretValueCommand as GetSecretValueCommand9
|
|
@@ -23114,9 +23486,9 @@ function readPulumiAwsRegion(stage) {
|
|
|
23114
23486
|
const preferred = stage ? `Pulumi.${stage}.yaml` : void 0;
|
|
23115
23487
|
const rank = (f) => f === preferred ? 0 : f === "Pulumi.yaml" ? 2 : 1;
|
|
23116
23488
|
try {
|
|
23117
|
-
const files =
|
|
23489
|
+
const files = fs41.readdirSync(".").filter((f) => f.startsWith("Pulumi.") && f.endsWith(".yaml")).sort((a, b) => rank(a) - rank(b));
|
|
23118
23490
|
for (const f of files) {
|
|
23119
|
-
const m =
|
|
23491
|
+
const m = fs41.readFileSync(f, "utf-8").match(/^\s*aws:region:\s*["']?([^"'\n]+)["']?/m);
|
|
23120
23492
|
if (m?.[1]) return m[1].trim();
|
|
23121
23493
|
}
|
|
23122
23494
|
} catch {
|
|
@@ -23125,14 +23497,14 @@ function readPulumiAwsRegion(stage) {
|
|
|
23125
23497
|
}
|
|
23126
23498
|
function awsProfileSections(name) {
|
|
23127
23499
|
return [
|
|
23128
|
-
[
|
|
23129
|
-
[
|
|
23500
|
+
[path48.join(os12.homedir(), ".aws", "config"), `[profile ${name}]`],
|
|
23501
|
+
[path48.join(os12.homedir(), ".aws", "credentials"), `[${name}]`]
|
|
23130
23502
|
];
|
|
23131
23503
|
}
|
|
23132
23504
|
function awsProfileExists(name) {
|
|
23133
23505
|
for (const [file, header] of awsProfileSections(name)) {
|
|
23134
23506
|
try {
|
|
23135
|
-
const lines =
|
|
23507
|
+
const lines = fs41.readFileSync(file, "utf-8").split("\n");
|
|
23136
23508
|
if (lines.some((l) => l.trim() === header)) return true;
|
|
23137
23509
|
} catch {
|
|
23138
23510
|
}
|
|
@@ -23158,7 +23530,7 @@ function awsProfileRegion(profile) {
|
|
|
23158
23530
|
if (!profile) return void 0;
|
|
23159
23531
|
for (const [file, header] of awsProfileSections(profile)) {
|
|
23160
23532
|
try {
|
|
23161
|
-
const region = parseProfileRegion(
|
|
23533
|
+
const region = parseProfileRegion(fs41.readFileSync(file, "utf-8"), header);
|
|
23162
23534
|
if (region) return region;
|
|
23163
23535
|
} catch {
|
|
23164
23536
|
}
|
|
@@ -23167,14 +23539,14 @@ function awsProfileRegion(profile) {
|
|
|
23167
23539
|
}
|
|
23168
23540
|
function awsDefaultProfileSections() {
|
|
23169
23541
|
return [
|
|
23170
|
-
[
|
|
23171
|
-
[
|
|
23542
|
+
[path48.join(os12.homedir(), ".aws", "config"), "[default]"],
|
|
23543
|
+
[path48.join(os12.homedir(), ".aws", "credentials"), "[default]"]
|
|
23172
23544
|
];
|
|
23173
23545
|
}
|
|
23174
23546
|
function awsDefaultProfileRegion() {
|
|
23175
23547
|
for (const [file, header] of awsDefaultProfileSections()) {
|
|
23176
23548
|
try {
|
|
23177
|
-
const region = parseProfileRegion(
|
|
23549
|
+
const region = parseProfileRegion(fs41.readFileSync(file, "utf-8"), header);
|
|
23178
23550
|
if (region) return region;
|
|
23179
23551
|
} catch {
|
|
23180
23552
|
}
|
|
@@ -23561,8 +23933,8 @@ async function resolveToken(opts) {
|
|
|
23561
23933
|
"no token: pass --token, set VCS_TOKEN, or pass --context <platform-context> (after mesh login)"
|
|
23562
23934
|
);
|
|
23563
23935
|
}
|
|
23564
|
-
async function vcsApi(baseUrl, token,
|
|
23565
|
-
const res = await fetch(`${baseUrl}${
|
|
23936
|
+
async function vcsApi(baseUrl, token, path50, method = "GET", body) {
|
|
23937
|
+
const res = await fetch(`${baseUrl}${path50}`, {
|
|
23566
23938
|
method,
|
|
23567
23939
|
headers: {
|
|
23568
23940
|
authorization: `Bearer ${token}`,
|
|
@@ -23573,7 +23945,7 @@ async function vcsApi(baseUrl, token, path49, method = "GET", body) {
|
|
|
23573
23945
|
const data = await res.json().catch(() => ({}));
|
|
23574
23946
|
if (!res.ok) {
|
|
23575
23947
|
throw new Error(
|
|
23576
|
-
`${method} ${
|
|
23948
|
+
`${method} ${path50} failed (${res.status}): ${String(data.error ?? "unknown error")}`
|
|
23577
23949
|
);
|
|
23578
23950
|
}
|
|
23579
23951
|
return data;
|
|
@@ -23619,8 +23991,8 @@ var init_clone = __esm({
|
|
|
23619
23991
|
|
|
23620
23992
|
// packages/mesh-cli/src/commands/vcs/get.ts
|
|
23621
23993
|
import { writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
|
|
23622
|
-
import { join as
|
|
23623
|
-
async function getCommand(repo,
|
|
23994
|
+
import { join as join46, dirname as dirname31 } from "node:path";
|
|
23995
|
+
async function getCommand(repo, path50, opts) {
|
|
23624
23996
|
let vcsBaseUrl;
|
|
23625
23997
|
let token;
|
|
23626
23998
|
if (opts.target) {
|
|
@@ -23635,18 +24007,18 @@ async function getCommand(repo, path49, opts) {
|
|
|
23635
24007
|
if (!token) throw new Error("no token: pass --target (after mesh login), or --token / --context");
|
|
23636
24008
|
const reader = createVcsFolderReader({ vcsBaseUrl, token });
|
|
23637
24009
|
try {
|
|
23638
|
-
const { ref, files } = await reader.readPath(repo,
|
|
24010
|
+
const { ref, files } = await reader.readPath(repo, path50);
|
|
23639
24011
|
if (files.length === 0) {
|
|
23640
|
-
logInfo(`no files at ${repo}:${
|
|
24012
|
+
logInfo(`no files at ${repo}:${path50}`);
|
|
23641
24013
|
return;
|
|
23642
24014
|
}
|
|
23643
24015
|
if (opts.output) {
|
|
23644
24016
|
for (const f of files) {
|
|
23645
|
-
const abs =
|
|
23646
|
-
await mkdir2(
|
|
24017
|
+
const abs = join46(opts.output, f.path);
|
|
24018
|
+
await mkdir2(dirname31(abs), { recursive: true });
|
|
23647
24019
|
await writeFile2(abs, f.contents);
|
|
23648
24020
|
}
|
|
23649
|
-
logInfo(`wrote ${files.length} file(s) from ${repo}:${
|
|
24021
|
+
logInfo(`wrote ${files.length} file(s) from ${repo}:${path50} (${ref}) \u2192 ${opts.output}`);
|
|
23650
24022
|
} else {
|
|
23651
24023
|
for (const f of files) {
|
|
23652
24024
|
if (files.length > 1) process.stdout.write(`
|
|
@@ -23671,10 +24043,10 @@ var init_get = __esm({
|
|
|
23671
24043
|
});
|
|
23672
24044
|
|
|
23673
24045
|
// packages/mesh-cli/src/commands/vcs/drafts.ts
|
|
23674
|
-
async function call(opts, repo,
|
|
24046
|
+
async function call(opts, repo, path50, method = "GET", body) {
|
|
23675
24047
|
const target = await resolveTarget2({ ...opts, repo });
|
|
23676
24048
|
const token = await resolveToken(opts);
|
|
23677
|
-
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${
|
|
24049
|
+
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${path50}`, method, body);
|
|
23678
24050
|
}
|
|
23679
24051
|
async function draftsListCommand(repo, opts) {
|
|
23680
24052
|
const data = await call(opts, repo, `/drafts${opts.all ? "?all=true" : ""}`);
|
|
@@ -23729,7 +24101,7 @@ var init_drafts = __esm({
|
|
|
23729
24101
|
|
|
23730
24102
|
// packages/mesh-cli/src/commands/vcs/propose.ts
|
|
23731
24103
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
23732
|
-
import { join as
|
|
24104
|
+
import { join as join47 } from "node:path";
|
|
23733
24105
|
function parseStatus(out) {
|
|
23734
24106
|
const tokens = out.split("\0");
|
|
23735
24107
|
const changes = [];
|
|
@@ -23762,13 +24134,13 @@ function parseStatus(out) {
|
|
|
23762
24134
|
}
|
|
23763
24135
|
return changes;
|
|
23764
24136
|
}
|
|
23765
|
-
async function writeOp(cwd,
|
|
23766
|
-
const buf = await readFile3(
|
|
24137
|
+
async function writeOp(cwd, path50) {
|
|
24138
|
+
const buf = await readFile3(join47(cwd, path50));
|
|
23767
24139
|
const asUtf8 = buf.toString("utf8");
|
|
23768
24140
|
if (Buffer.from(asUtf8, "utf8").equals(buf)) {
|
|
23769
|
-
return { op: "write", path:
|
|
24141
|
+
return { op: "write", path: path50, content: asUtf8 };
|
|
23770
24142
|
}
|
|
23771
|
-
return { op: "write", path:
|
|
24143
|
+
return { op: "write", path: path50, content: buf.toString("base64"), encoding: "base64" };
|
|
23772
24144
|
}
|
|
23773
24145
|
async function proposeCommand(opts) {
|
|
23774
24146
|
const cwd = process.cwd();
|
|
@@ -23812,8 +24184,8 @@ async function proposeCommand(opts) {
|
|
|
23812
24184
|
operations,
|
|
23813
24185
|
...opts.mergeParent ? { mergeParent: opts.mergeParent } : {}
|
|
23814
24186
|
};
|
|
23815
|
-
const
|
|
23816
|
-
const data = await vcsApi(target.baseUrl, token,
|
|
24187
|
+
const path50 = opts.revise ? `/v1/repos/${target.repo}/proposals/${opts.revise}/revisions` : `/v1/repos/${target.repo}/proposals`;
|
|
24188
|
+
const data = await vcsApi(target.baseUrl, token, path50, "POST", body);
|
|
23817
24189
|
console.log(
|
|
23818
24190
|
`proposal ${data.proposalId} @ ${data.sha.slice(0, 8)} \u2014 review: mesh vcs show ${target.repo} ${data.proposalId} --url ${target.baseUrl}`
|
|
23819
24191
|
);
|
|
@@ -23828,28 +24200,28 @@ var init_propose = __esm({
|
|
|
23828
24200
|
// packages/mesh-cli/src/commands/vcs/rm.ts
|
|
23829
24201
|
import { mkdtemp as mkdtemp2, rm as rmrf } from "node:fs/promises";
|
|
23830
24202
|
import { tmpdir as tmpdir10 } from "node:os";
|
|
23831
|
-
import { join as
|
|
24203
|
+
import { join as join48 } from "node:path";
|
|
23832
24204
|
function normalize2(p) {
|
|
23833
24205
|
return p.trim().replace(/^\.\//, "").replace(/\/+$/, "");
|
|
23834
24206
|
}
|
|
23835
24207
|
function expandPathsToDeletions(repoFiles, requested) {
|
|
23836
24208
|
const out = /* @__PURE__ */ new Set();
|
|
23837
24209
|
for (const raw of requested) {
|
|
23838
|
-
const
|
|
23839
|
-
if (
|
|
24210
|
+
const path50 = normalize2(raw);
|
|
24211
|
+
if (path50.startsWith("/") || path50.split("/").includes("..")) {
|
|
23840
24212
|
throw new Error(
|
|
23841
24213
|
`"${raw}" is not a repo-relative path \u2014 vcs paths never start with "/" or traverse with "..".`
|
|
23842
24214
|
);
|
|
23843
24215
|
}
|
|
23844
|
-
const exact = repoFiles.filter((f) => f ===
|
|
24216
|
+
const exact = repoFiles.filter((f) => f === path50);
|
|
23845
24217
|
if (exact.length > 0) {
|
|
23846
24218
|
for (const f of exact) out.add(f);
|
|
23847
24219
|
continue;
|
|
23848
24220
|
}
|
|
23849
|
-
const under = repoFiles.filter((f) => f.startsWith(`${
|
|
24221
|
+
const under = repoFiles.filter((f) => f.startsWith(`${path50}/`));
|
|
23850
24222
|
if (under.length === 0) {
|
|
23851
24223
|
throw new Error(
|
|
23852
|
-
`"${raw}" matched no files in the repo \u2014 nothing was proposed. Check the path with: mesh vcs get <repo> ${
|
|
24224
|
+
`"${raw}" matched no files in the repo \u2014 nothing was proposed. Check the path with: mesh vcs get <repo> ${path50}`
|
|
23853
24225
|
);
|
|
23854
24226
|
}
|
|
23855
24227
|
for (const f of under) out.add(f);
|
|
@@ -23860,7 +24232,7 @@ async function rmCommand(repo, paths, opts) {
|
|
|
23860
24232
|
const baseUrl = (opts.url ?? process.env.VCS_URL)?.replace(/\/$/, "");
|
|
23861
24233
|
if (!baseUrl) throw new Error("rm requires --url or VCS_URL");
|
|
23862
24234
|
const token = await resolveToken(opts);
|
|
23863
|
-
const dir = await mkdtemp2(
|
|
24235
|
+
const dir = await mkdtemp2(join48(tmpdir10(), "mesh-vcs-rm-"));
|
|
23864
24236
|
try {
|
|
23865
24237
|
const git = (args, cwd) => gitWithAuth(args, token, cwd);
|
|
23866
24238
|
await git([
|
|
@@ -23885,7 +24257,7 @@ async function rmCommand(repo, paths, opts) {
|
|
|
23885
24257
|
const body = {
|
|
23886
24258
|
baseCommit: head.trim(),
|
|
23887
24259
|
message: opts.message ?? `Delete ${doomed.length} file(s)`,
|
|
23888
|
-
operations: doomed.map((
|
|
24260
|
+
operations: doomed.map((path50) => ({ op: "delete", path: path50 }))
|
|
23889
24261
|
};
|
|
23890
24262
|
const data = await vcsApi(
|
|
23891
24263
|
baseUrl,
|
|
@@ -23911,10 +24283,10 @@ var init_rm = __esm({
|
|
|
23911
24283
|
});
|
|
23912
24284
|
|
|
23913
24285
|
// packages/mesh-cli/src/commands/vcs/review.ts
|
|
23914
|
-
async function call2(opts, repo,
|
|
24286
|
+
async function call2(opts, repo, path50, method = "GET", body) {
|
|
23915
24287
|
const target = await resolveTarget2({ ...opts, repo });
|
|
23916
24288
|
const token = await resolveToken(opts);
|
|
23917
|
-
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${
|
|
24289
|
+
return vcsApi(target.baseUrl, token, `/v1/repos/${repo}${path50}`, method, body);
|
|
23918
24290
|
}
|
|
23919
24291
|
async function proposalsCommand(repo, opts) {
|
|
23920
24292
|
console.log(JSON.stringify(await call2(opts, repo, "/proposals"), null, 2));
|
|
@@ -24061,8 +24433,8 @@ function computeHappyPath(nodes, edges) {
|
|
|
24061
24433
|
];
|
|
24062
24434
|
const visited = /* @__PURE__ */ new Set([startNode.id]);
|
|
24063
24435
|
while (queue.length > 0) {
|
|
24064
|
-
const { id, path:
|
|
24065
|
-
if (targetIds.has(id)) return
|
|
24436
|
+
const { id, path: path50 } = queue.shift();
|
|
24437
|
+
if (targetIds.has(id)) return path50;
|
|
24066
24438
|
const neighbors = adjacency.get(id) ?? [];
|
|
24067
24439
|
const hasMainEdge = neighbors.some((e) => e.isMainPath);
|
|
24068
24440
|
const candidates = hasMainEdge ? neighbors.filter((e) => e.isMainPath) : neighbors;
|
|
@@ -24082,7 +24454,7 @@ function computeHappyPath(nodes, edges) {
|
|
|
24082
24454
|
if (!allowExceptional && (neighbor.isExceptional || neighbor.isTimeout || failureEndIds.has(neighbor.to)))
|
|
24083
24455
|
continue;
|
|
24084
24456
|
visited.add(neighbor.to);
|
|
24085
|
-
queue.push({ id: neighbor.to, path: [...
|
|
24457
|
+
queue.push({ id: neighbor.to, path: [...path50, neighbor.to] });
|
|
24086
24458
|
}
|
|
24087
24459
|
}
|
|
24088
24460
|
return null;
|
|
@@ -24367,11 +24739,11 @@ function wrapIntoGroup(workflow, nodeIds, groupId, label, groupType) {
|
|
|
24367
24739
|
}
|
|
24368
24740
|
}
|
|
24369
24741
|
if (found) {
|
|
24370
|
-
const
|
|
24371
|
-
for (let c = found; c !== void 0; c = prev.get(c))
|
|
24372
|
-
for (let i = 0; i <
|
|
24742
|
+
const path50 = [];
|
|
24743
|
+
for (let c = found; c !== void 0; c = prev.get(c)) path50.unshift(c);
|
|
24744
|
+
for (let i = 0; i < path50.length - 1; i++) mainEdgeKeys.add(edgeKey(path50[i], path50[i + 1]));
|
|
24373
24745
|
mainEdgeKeys.add(edgeKey(found, successExit.id));
|
|
24374
|
-
mainBody =
|
|
24746
|
+
mainBody = path50;
|
|
24375
24747
|
mainTail = [successExit.id];
|
|
24376
24748
|
}
|
|
24377
24749
|
}
|
|
@@ -24907,11 +25279,11 @@ function buildProcessManifest(artifact, outcomeNodeIds) {
|
|
|
24907
25279
|
...pointOfNoReturnStage ? { pointOfNoReturnStageId: pointOfNoReturnStage.id } : {}
|
|
24908
25280
|
};
|
|
24909
25281
|
}
|
|
24910
|
-
function formatPath(
|
|
24911
|
-
return
|
|
25282
|
+
function formatPath(path50) {
|
|
25283
|
+
return path50.length > 0 ? z4.core.toDotPath(path50) : "(root)";
|
|
24912
25284
|
}
|
|
24913
25285
|
function issueToDiagnostic(issue) {
|
|
24914
|
-
const
|
|
25286
|
+
const path50 = formatPath(issue.path);
|
|
24915
25287
|
let code = "SCHEMA_INVALID";
|
|
24916
25288
|
if (issue.code === "custom") {
|
|
24917
25289
|
const paramCode = issue.params?.code;
|
|
@@ -24922,8 +25294,8 @@ function issueToDiagnostic(issue) {
|
|
|
24922
25294
|
return {
|
|
24923
25295
|
severity: "error",
|
|
24924
25296
|
code,
|
|
24925
|
-
message: `${
|
|
24926
|
-
path:
|
|
25297
|
+
message: `${path50}: ${issue.message}`,
|
|
25298
|
+
path: path50
|
|
24927
25299
|
};
|
|
24928
25300
|
}
|
|
24929
25301
|
function upgradeV1(artifact) {
|
|
@@ -25090,24 +25462,24 @@ var init_process_artifact = __esm({
|
|
|
25090
25462
|
});
|
|
25091
25463
|
}
|
|
25092
25464
|
const declaredSelectors = new Set(Object.keys(process2.selectors ?? {}));
|
|
25093
|
-
const checkActor = (actorId,
|
|
25465
|
+
const checkActor = (actorId, path50) => {
|
|
25094
25466
|
if (actorId === void 0) return;
|
|
25095
25467
|
if (!Object.prototype.hasOwnProperty.call(process2.actors, actorId)) {
|
|
25096
25468
|
ctx.addIssue({
|
|
25097
25469
|
code: "custom",
|
|
25098
|
-
path:
|
|
25099
|
-
message: `Actor "${actorId}" is referenced at ${z4.core.toDotPath(
|
|
25470
|
+
path: path50,
|
|
25471
|
+
message: `Actor "${actorId}" is referenced at ${z4.core.toDotPath(path50)} but not declared in process.actors. Declare the actor (label, and optionally category/selector) or fix the reference.`,
|
|
25100
25472
|
params: { code: "UNDECLARED_ACTOR" }
|
|
25101
25473
|
});
|
|
25102
25474
|
}
|
|
25103
25475
|
};
|
|
25104
|
-
const checkSelector = (selector,
|
|
25476
|
+
const checkSelector = (selector, path50) => {
|
|
25105
25477
|
if (selector === void 0) return;
|
|
25106
25478
|
if (!declaredSelectors.has(selector)) {
|
|
25107
25479
|
ctx.addIssue({
|
|
25108
25480
|
code: "custom",
|
|
25109
|
-
path:
|
|
25110
|
-
message: `Selector "${selector}" is referenced at ${z4.core.toDotPath(
|
|
25481
|
+
path: path50,
|
|
25482
|
+
message: `Selector "${selector}" is referenced at ${z4.core.toDotPath(path50)} but not declared in process.selectors. Declare the selector or fix the reference.`,
|
|
25111
25483
|
params: { code: "UNDECLARED_SELECTOR" }
|
|
25112
25484
|
});
|
|
25113
25485
|
}
|
|
@@ -25121,20 +25493,20 @@ var init_process_artifact = __esm({
|
|
|
25121
25493
|
outcome: "DUPLICATE_OUTCOME_ID"
|
|
25122
25494
|
};
|
|
25123
25495
|
const idFirstSeenAt = /* @__PURE__ */ new Map();
|
|
25124
|
-
const checkId = (id, kind,
|
|
25496
|
+
const checkId = (id, kind, path50) => {
|
|
25125
25497
|
const first = idFirstSeenAt.get(id);
|
|
25126
25498
|
if (first) {
|
|
25127
25499
|
const kindLabel = kind === first.kind ? kind : "process";
|
|
25128
25500
|
ctx.addIssue({
|
|
25129
25501
|
code: "custom",
|
|
25130
|
-
path:
|
|
25131
|
-
message: `Duplicate ${kindLabel} id "${id}": ${kind} at ${z4.core.toDotPath(
|
|
25502
|
+
path: path50,
|
|
25503
|
+
message: `Duplicate ${kindLabel} id "${id}": ${kind} at ${z4.core.toDotPath(path50)} collides with ${first.kind} at ${z4.core.toDotPath(first.path)}.`,
|
|
25132
25504
|
params: {
|
|
25133
25505
|
code: kind === first.kind ? SAME_KIND_CODE[kind] : "DUPLICATE_PROCESS_ID"
|
|
25134
25506
|
}
|
|
25135
25507
|
});
|
|
25136
25508
|
} else {
|
|
25137
|
-
idFirstSeenAt.set(id, { kind, path:
|
|
25509
|
+
idFirstSeenAt.set(id, { kind, path: path50 });
|
|
25138
25510
|
}
|
|
25139
25511
|
};
|
|
25140
25512
|
process2.stages.forEach((stage, stageIndex) => {
|
|
@@ -25181,13 +25553,13 @@ function lintProcess(artifact, inventory, predicateNames, options = {}) {
|
|
|
25181
25553
|
const internalCommands = process2.internalCommands ?? [];
|
|
25182
25554
|
const internalSet = new Set(internalCommands);
|
|
25183
25555
|
const boundCommandPaths = /* @__PURE__ */ new Map();
|
|
25184
|
-
const checkPredicate = (predicate,
|
|
25556
|
+
const checkPredicate = (predicate, path50) => {
|
|
25185
25557
|
if (!predicateSet.has(predicate)) {
|
|
25186
25558
|
diagnostics.push({
|
|
25187
25559
|
severity: "error",
|
|
25188
25560
|
code: "UNKNOWN_PREDICATE",
|
|
25189
|
-
message: `Predicate "${predicate}" referenced at ${
|
|
25190
|
-
path:
|
|
25561
|
+
message: `Predicate "${predicate}" referenced at ${path50} is not in the predicate registry.`,
|
|
25562
|
+
path: path50
|
|
25191
25563
|
});
|
|
25192
25564
|
}
|
|
25193
25565
|
};
|
|
@@ -25247,19 +25619,19 @@ function lintProcess(artifact, inventory, predicateNames, options = {}) {
|
|
|
25247
25619
|
process2.outcomes.forEach((outcome, outcomeIndex) => {
|
|
25248
25620
|
const whenPath = `process.outcomes[${outcomeIndex}].when`;
|
|
25249
25621
|
outcomeTriggers(outcome).forEach((trigger, triggerIndex) => {
|
|
25250
|
-
const
|
|
25622
|
+
const path50 = Array.isArray(outcome.when) ? `${whenPath}[${triggerIndex}]` : whenPath;
|
|
25251
25623
|
if (trigger.kind === "predicate") {
|
|
25252
|
-
checkPredicate(trigger.name, `${
|
|
25624
|
+
checkPredicate(trigger.name, `${path50}.predicate`);
|
|
25253
25625
|
} else if (trigger.kind === "command") {
|
|
25254
25626
|
if (!boundCommandPaths.has(trigger.name)) {
|
|
25255
|
-
boundCommandPaths.set(trigger.name, `${
|
|
25627
|
+
boundCommandPaths.set(trigger.name, `${path50}.command`);
|
|
25256
25628
|
}
|
|
25257
25629
|
if (!commandNames.has(trigger.name)) {
|
|
25258
25630
|
diagnostics.push({
|
|
25259
25631
|
severity: "error",
|
|
25260
25632
|
code: "BOUND_COMMAND_NOT_IN_INVENTORY",
|
|
25261
|
-
message: `Command "${trigger.name}" triggering outcome "${outcome.id}" (${
|
|
25262
|
-
path: `${
|
|
25633
|
+
message: `Command "${trigger.name}" triggering outcome "${outcome.id}" (${path50}.command) does not exist in the inventory.`,
|
|
25634
|
+
path: `${path50}.command`
|
|
25263
25635
|
});
|
|
25264
25636
|
}
|
|
25265
25637
|
}
|
|
@@ -25371,10 +25743,10 @@ var init_src4 = __esm({
|
|
|
25371
25743
|
});
|
|
25372
25744
|
|
|
25373
25745
|
// packages/mesh-cli/src/commands/workflow.ts
|
|
25374
|
-
import * as
|
|
25375
|
-
import * as
|
|
25746
|
+
import * as fs42 from "fs";
|
|
25747
|
+
import * as path49 from "path";
|
|
25376
25748
|
import { createRequire as createRequire2 } from "module";
|
|
25377
|
-
import { execFileSync as
|
|
25749
|
+
import { execFileSync as execFileSync34 } from "child_process";
|
|
25378
25750
|
function resolveExtractorPath() {
|
|
25379
25751
|
try {
|
|
25380
25752
|
const require2 = createRequire2(import.meta.url);
|
|
@@ -25388,7 +25760,7 @@ function runExtraction(targetPath, extractorPath, explicitProcessPath) {
|
|
|
25388
25760
|
let explicitProcessArtifact;
|
|
25389
25761
|
if (explicitProcessPath) {
|
|
25390
25762
|
try {
|
|
25391
|
-
explicitProcessArtifact = JSON.parse(
|
|
25763
|
+
explicitProcessArtifact = JSON.parse(fs42.readFileSync(explicitProcessPath, "utf-8"));
|
|
25392
25764
|
} catch (err) {
|
|
25393
25765
|
logError(
|
|
25394
25766
|
`Could not read/parse --process ${explicitProcessPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -25429,7 +25801,7 @@ for (const file of files) {
|
|
|
25429
25801
|
process.stdout.write(JSON.stringify(results));
|
|
25430
25802
|
`;
|
|
25431
25803
|
try {
|
|
25432
|
-
const result =
|
|
25804
|
+
const result = execFileSync34("npx", ["tsx", "--eval", script], {
|
|
25433
25805
|
encoding: "utf-8",
|
|
25434
25806
|
stdio: ["pipe", "pipe", "inherit"],
|
|
25435
25807
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -25471,7 +25843,7 @@ for (const file of files) {
|
|
|
25471
25843
|
process.stdout.write(JSON.stringify(results));
|
|
25472
25844
|
`;
|
|
25473
25845
|
try {
|
|
25474
|
-
const result =
|
|
25846
|
+
const result = execFileSync34("npx", ["tsx", "--eval", script], {
|
|
25475
25847
|
encoding: "utf-8",
|
|
25476
25848
|
stdio: ["pipe", "pipe", "inherit"],
|
|
25477
25849
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -25488,7 +25860,7 @@ function runLintExtraction(targetPath, extractorPath, explicitProcessPath) {
|
|
|
25488
25860
|
let explicitProcessArtifact;
|
|
25489
25861
|
if (explicitProcessPath) {
|
|
25490
25862
|
try {
|
|
25491
|
-
explicitProcessArtifact = JSON.parse(
|
|
25863
|
+
explicitProcessArtifact = JSON.parse(fs42.readFileSync(explicitProcessPath, "utf-8"));
|
|
25492
25864
|
} catch (err) {
|
|
25493
25865
|
logError(
|
|
25494
25866
|
`Could not read/parse --process ${explicitProcessPath}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -25526,7 +25898,7 @@ for (const file of files) {
|
|
|
25526
25898
|
process.stdout.write(JSON.stringify(results));
|
|
25527
25899
|
`;
|
|
25528
25900
|
try {
|
|
25529
|
-
const result =
|
|
25901
|
+
const result = execFileSync34("npx", ["tsx", "--eval", script], {
|
|
25530
25902
|
encoding: "utf-8",
|
|
25531
25903
|
stdio: ["pipe", "pipe", "inherit"],
|
|
25532
25904
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -25596,16 +25968,16 @@ function registerWorkflowCommands(program2) {
|
|
|
25596
25968
|
).action(
|
|
25597
25969
|
async (targetPath, opts) => {
|
|
25598
25970
|
try {
|
|
25599
|
-
const resolvedPath =
|
|
25600
|
-
if (!
|
|
25971
|
+
const resolvedPath = path49.resolve(targetPath);
|
|
25972
|
+
if (!fs42.existsSync(resolvedPath)) {
|
|
25601
25973
|
logError(`Path does not exist: ${resolvedPath}`);
|
|
25602
25974
|
process.exitCode = 1;
|
|
25603
25975
|
return;
|
|
25604
25976
|
}
|
|
25605
25977
|
let resolvedProcessPath;
|
|
25606
25978
|
if (opts.process) {
|
|
25607
|
-
resolvedProcessPath =
|
|
25608
|
-
if (!
|
|
25979
|
+
resolvedProcessPath = path49.resolve(opts.process);
|
|
25980
|
+
if (!fs42.existsSync(resolvedProcessPath)) {
|
|
25609
25981
|
logError(`--process path does not exist: ${resolvedProcessPath}`);
|
|
25610
25982
|
process.exitCode = 1;
|
|
25611
25983
|
return;
|
|
@@ -25654,8 +26026,8 @@ function registerWorkflowCommands(program2) {
|
|
|
25654
26026
|
"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."
|
|
25655
26027
|
).action(async (targetPath) => {
|
|
25656
26028
|
try {
|
|
25657
|
-
const resolvedPath =
|
|
25658
|
-
if (!
|
|
26029
|
+
const resolvedPath = path49.resolve(targetPath);
|
|
26030
|
+
if (!fs42.existsSync(resolvedPath)) {
|
|
25659
26031
|
logError(`Path does not exist: ${resolvedPath}`);
|
|
25660
26032
|
process.exitCode = 1;
|
|
25661
26033
|
return;
|
|
@@ -25701,16 +26073,16 @@ function registerWorkflowCommands(program2) {
|
|
|
25701
26073
|
"Comma-separated named-selector registry (enables UNKNOWN_SELECTOR checks)"
|
|
25702
26074
|
).action(async (targetPath, opts) => {
|
|
25703
26075
|
try {
|
|
25704
|
-
const resolvedPath =
|
|
25705
|
-
if (!
|
|
26076
|
+
const resolvedPath = path49.resolve(targetPath);
|
|
26077
|
+
if (!fs42.existsSync(resolvedPath)) {
|
|
25706
26078
|
logError(`Path does not exist: ${resolvedPath}`);
|
|
25707
26079
|
process.exitCode = 1;
|
|
25708
26080
|
return;
|
|
25709
26081
|
}
|
|
25710
26082
|
let resolvedProcessPath;
|
|
25711
26083
|
if (opts.process) {
|
|
25712
|
-
resolvedProcessPath =
|
|
25713
|
-
if (!
|
|
26084
|
+
resolvedProcessPath = path49.resolve(opts.process);
|
|
26085
|
+
if (!fs42.existsSync(resolvedProcessPath)) {
|
|
25714
26086
|
logError(`--process path does not exist: ${resolvedProcessPath}`);
|
|
25715
26087
|
process.exitCode = 1;
|
|
25716
26088
|
return;
|
|
@@ -25964,7 +26336,7 @@ var init_program = __esm({
|
|
|
25964
26336
|
init_vpn2();
|
|
25965
26337
|
init_workflow();
|
|
25966
26338
|
CLI_NAME = "mesh";
|
|
25967
|
-
CLI_DESCRIPTION = "
|
|
26339
|
+
CLI_DESCRIPTION = "Build, run and deploy apps on a Mesh platform";
|
|
25968
26340
|
}
|
|
25969
26341
|
});
|
|
25970
26342
|
|