@mesh-tech/mesh-cli 0.30.0 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/mesh.js +7 -7
- package/dist/bin/mesh.js.map +1 -1
- package/dist/build-info.json +2 -2
- package/dist/src/commands/app-check.js +4 -4
- package/fragments/agents/AGENTS.md.hbs +8 -4
- package/fragments/base/index.ts.hbs +14 -10
- package/package.json +2 -2
- package/skills/core/SKILL.md +1 -1
- package/templates/api-auth/api/src/schema.ts.hbs +4 -0
package/dist/build-info.json
CHANGED
|
@@ -108,9 +108,9 @@ export const APP_CHECK_RULES = {
|
|
|
108
108
|
},
|
|
109
109
|
DOCS_SITE_PUBLIC: {
|
|
110
110
|
gate: "0.3",
|
|
111
|
-
title: "Docs site
|
|
111
|
+
title: "Docs site published through the Hub docs door",
|
|
112
112
|
severity: "advisory",
|
|
113
|
-
remediation: "
|
|
113
|
+
remediation: "publish the site through the Hub docs door — declare the API as a mesh.apps.AppApiSurface whose docs block builds this same site (docs: { spec, pages }), declare its readers' role on the ZitadelAppIdentity and grant it from the Hub's Access tab; then drop the hostname (docs.ingress on an API surface, where docs.auth, docs.basePath and docs.hubDoor do nothing either; the ingress with its auth and authentication on a mesh.apps.ApiDocs). The public shape keeps deploying until you do",
|
|
114
114
|
scope: "app",
|
|
115
115
|
},
|
|
116
116
|
DOCS_AUDIENCE_IMPLICIT: {
|
|
@@ -509,7 +509,7 @@ export function docsSiteFindings(text) {
|
|
|
509
509
|
findings.push({
|
|
510
510
|
code: "DOCS_SITE_PUBLIC",
|
|
511
511
|
line: decl.line,
|
|
512
|
-
why: `mesh.apps.${decl.ctor} declares a docs site with ${named} —
|
|
512
|
+
why: `mesh.apps.${decl.ctor} declares a docs site with ${named} — deprecated: the Hub docs door is the path this site is published on, and it is already built for it (no hostname, no sign-in and no door switch of its own), so the primitive ignores ${retired.length > 1 ? "them" : "it"}`,
|
|
513
513
|
});
|
|
514
514
|
}
|
|
515
515
|
const kindStated = decl.ctor === "AppApiSurface" || decl.ctor === "VendorApiSurface" || args.has("kind");
|
|
@@ -545,7 +545,7 @@ export function docsSiteFindings(text) {
|
|
|
545
545
|
findings.push({
|
|
546
546
|
code: "DOCS_SITE_PUBLIC",
|
|
547
547
|
line: decl.line,
|
|
548
|
-
why: `mesh.apps.ApiDocs is published on an ingress —
|
|
548
|
+
why: `mesh.apps.ApiDocs is published on an ingress — deprecated: the Hub docs door is the path a docs site is published on, and it opens for the API surface that declares the site. The hostname still deploys, with a preview warning, as the compatibility path`,
|
|
549
549
|
});
|
|
550
550
|
}
|
|
551
551
|
return findings;
|
|
@@ -20,10 +20,14 @@ Every mesh app follows 5 steps in `index.ts`:
|
|
|
20
20
|
|
|
21
21
|
`api/openapi.json` is the API's OpenAPI document and `docs/pages/` holds its
|
|
22
22
|
guides; `index.ts` declares a `mesh.apps.ApiDocs` site from both, reachable
|
|
23
|
-
under `mesh dev`.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
under `mesh dev`. **The Hub docs door is the path a docs site is published
|
|
24
|
+
on**: declare the API as a `mesh.apps.AppApiSurface` whose `docs` block builds
|
|
25
|
+
the site, and the Hub serves it through that door to the readers the app's
|
|
26
|
+
`docs` role admits. Giving the site a hostname of its own instead — `ingress`,
|
|
27
|
+
with the `auth` proxy and the in-page `authentication` sign-in — is the
|
|
28
|
+
deprecated public shape: it still deploys, as the compatibility path for the
|
|
29
|
+
sites that are public today, and warns at every `pulumi preview`. Nothing here
|
|
30
|
+
writes one, and a new app has no reason to. A site declared on a
|
|
27
31
|
`mesh.apps.VendorApiSurface` (a third-party core's raw reference) is read
|
|
28
32
|
through the same door by holders of the Hub's `vendor-docs` add-on only —
|
|
29
33
|
never by a partner — and declaring `audience: { roles: [] }` on one fails
|
|
@@ -107,16 +107,20 @@ const worker = new mesh.apps.TemporalWorker("worker", {
|
|
|
107
107
|
// Docs — the API's reference site, built by the platform from the spec and
|
|
108
108
|
// the guides in docs/pages/ (this README is its landing page — `landingPage`
|
|
109
109
|
// names another file, or `false` — and every guide is listed after it, in
|
|
110
|
-
// path order).
|
|
111
|
-
// is reachable under `mesh dev`, and
|
|
112
|
-
// the
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
//
|
|
116
|
-
// it
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
110
|
+
// path order). The Hub docs door is the path a docs site is published on:
|
|
111
|
+
// here the site is reachable under `mesh dev`, and to publish it you declare
|
|
112
|
+
// the API as a `mesh.apps.AppApiSurface` whose `docs` block builds this same
|
|
113
|
+
// site (`docs: { spec, pages }`) — the Hub then serves it through that door.
|
|
114
|
+
// A site given a hostname of its own instead (`ingress`, with the `auth`
|
|
115
|
+
// proxy and the in-page `authentication` sign-in) is the deprecated public
|
|
116
|
+
// shape: it still deploys, for the sites that are public today, and warns at
|
|
117
|
+
// every preview. This declaration names none of it, and a new app needs
|
|
118
|
+
// none. The site's readers hold this app's `docs` project role: declare the
|
|
119
|
+
// role on the ZitadelAppIdentity and grant it from Access → People; that same
|
|
120
|
+
// role is what the Hub reads when a partner holding the Hub's `docs:<tenant>`
|
|
121
|
+
// role opens this app's Docs tab, and the app then appears in their Apps list.
|
|
122
|
+
// `mesh app check` flags a docs site put on an ingress instead
|
|
123
|
+
// (`DOCS_SITE_PUBLIC`). Declaring `actAs: true`
|
|
120
124
|
// on that same surface opens the Hub's act-as playground: an operator picks
|
|
121
125
|
// one of this app's API keys on the Docs tab and the Hub executes the request
|
|
122
126
|
// against the deployed API as that key, over the cluster network, with a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mesh-tech/mesh-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"description": "CLI for Mesh platform development utilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@mesh-tech/agent-contracts": "0.2.0",
|
|
45
|
-
"@mesh-tech/tsconfig": "2.
|
|
45
|
+
"@mesh-tech/tsconfig": "2.23.0",
|
|
46
46
|
"@mesh-tech/workflow-viz": "0.3.0",
|
|
47
47
|
"@tanstack/intent": "^0.3.6",
|
|
48
48
|
"@types/node": "^20.0.0",
|
package/skills/core/SKILL.md
CHANGED
|
@@ -97,7 +97,7 @@ Top-level commands (each `register*` is wired in `src/program.ts`, which `bin/me
|
|
|
97
97
|
| `mesh start` / `mesh stop` / `mesh status` | — | Full-local Mesh platform via docker compose (project `mesh-local`, assets ship in the CLI package): Postgres, Temporal (+UI), Zitadel, SpiceDB, ministack (local AWS fabric: SSM/Secrets/S3 registry; also seeds a general-purpose `mesh-local-data` bucket with sample data — see `docs/guides/local-dagster.md`), memcached, OpenSearch, a **local mailbox** (Mailpit — SMTP :1025 wired into Zitadel, inbox at http://localhost:8025, so user-activation and password-reset mail is testable locally instead of vanishing), **and the hosted observability backends** (OTel collector + Loki + Tempo + Prometheus — the Hub's logs/traces/metrics views run unchanged). Seeds tenant `local`/env `dev` on first boot and reconciles every Zitadel-provisioned app tenant into the registry. **No AWS creds, VPN, or Pulumi state needed — Docker only.** The **Hub is included by default** — three overlay services, `hub-api` + `hub-ui` + `hub-auth` (an oauth2-proxy; it is what binds the front-door port and proxies to `hub-ui`, so front-door 401s/redirect loops are in ITS logs, not `hub-api`'s) — the front door at http://localhost:9000 — `MESH_HUB_PORT=<port>` publishes it elsewhere when 9000 is taken; export it for `mesh status` too (images build once from the published @mesh-tech/hub tarball; needs `mesh registry login` the first time; `--no-hub` opts out). Auth contract: `--with-hub` refreshes to the latest published hub after preflighting the CodeArtifact token — with an expired/missing token it falls back to the already-built local images (warn + fixing command), or fails fast naming `mesh registry login --profile mesh-dev` when none exist; the default (no-flag) path with an expired/missing token starts hub-less and names the same fix. `--hub-from-source` sidesteps the registry entirely — it builds the Hub images from THIS checkout's `apps/hub`, which is the only way to run an unpublished Hub change in the containerized stack. `--with-idps` adds two mock identity providers (SAML + OIDC) and federates the local Zitadel with BOTH, which is how enterprise SSO gets exercised without a cloud tenant — the two-provider shape is deliberate, since the instance login policy carries a LIST of IdPs and the failure worth catching is a second federation evicting the first (`docs/guides/local-federation.md`). Its two host ports (4569 SAML, 5556 OIDC — 5556 is Dex's own default) join the start-up port preflight only when the flag is passed, and `mesh status` lists both mocks once they are running. Non-TTY runs (CI, agents, piped output) get an `[HH:MM:SS]` prefix on every step line plus a heartbeat during long fetches/builds — `MESH_LOG_TIMESTAMPS=1/0` forces the prefix on/off (default: on when stderr is not a TTY). | `start`: `--no-seed`, `--no-hub`, `--with-hub`, `--hub-from-source`, `--with-idps`, `--takeover`, `--skip-port-check`; `stop`: `--destroy` (drops volumes/seeds), `--force`; `status`: `--json` |
|
|
98
98
|
| `mesh hub` | `dev` | One-command local Hub over a running dev-local stack. Launches the CURRENT-CODE Hub (apps/hub api+ui from a mesh-platform checkout) pointed at an existing `mesh dev` session — auto-assembles `HUB_TENANT`/`HUB_SCOPE_ENV`/`HUB_SCOPE_TENANTS` (session platform context), `TEMPORAL_ADDRESS` (session tunnel), `AWS_*` (session scratch profile), `DEV_USER_*`+`DEV_USER_TOKEN_URL` (session dev identity; starts its own token-server if the session predates it, so tokens stay fresh past ~1h). Refuses to launch with an empty tenant scope (which the Hub renders as silently blank). Runs in tmux session `mesh-hub-dev`. | `dev`: `--session <name>`, `--tenants <csv>`, `--port` (or `MESH_HUB_DEV_PORT`, default 9000; the containerized `mesh start` Hub uses the separate `MESH_HUB_PORT`), `--api-port <3002>`, `--platform-dir <dir>` (or `MESH_PLATFORM_DIR`), `--print-env`, `--kill` |
|
|
99
99
|
| `mesh create-app` | — | Scaffold a tenant app. Composable mode (primitives) or legacy template mode. Interactive when TTY + missing flags. Run at the root of an **empty** `{tenant}-mesh-apps` git clone (a `.git` with no `package.json`/`apps/`/`tenants/` and no enclosing pnpm workspace), it first generates the repo-level shape — `pnpm-workspace.yaml` over `apps/*`, private root `package.json`, scoped-registry `.npmrc`, base `tsconfig.json`, `.gitignore`, `README.md`, `apps/` — then scaffolds the app. Never overwrites an existing file. | `--tenant`, `--name`, `--primitives <csv>` (`service,database,temporal,bucket`), `--template <workflow\|api-auth\|api-role-gating\|external-service>`, `--test` (writes to `tests/tenants/`) |
|
|
100
|
-
| `mesh app` | `check [apps...]` | Checks tenant apps against the **Mesh app contract** (`@mesh-tech/app-kit#apps` → `references/app-contract.md`): a UI is its own Service (`UI_IN_API`, `NO_UI_SERVICE`), the app registers with the Hub (`NO_REGISTER`), sign-in goes through the platform proxy (`CUSTOM_SESSION_AUTH`), logs go through `@mesh-tech/logger` (`NON_PLATFORM_LOGGER`), and people/roles/keys are surfaced through the Hub (`NO_AUTHZ_POINTER`, `METADATA_UNPUBLISHED`, `IAC_GRANTS`, `PASSWORD_STORE`, `EMAIL_ALLOWLIST`, `USERS_TABLE`), and a docs site is
|
|
100
|
+
| `mesh app` | `check [apps...]` | Checks tenant apps against the **Mesh app contract** (`@mesh-tech/app-kit#apps` → `references/app-contract.md`): a UI is its own Service (`UI_IN_API`, `NO_UI_SERVICE`), the app registers with the Hub (`NO_REGISTER`), sign-in goes through the platform proxy (`CUSTOM_SESSION_AUTH`), logs go through `@mesh-tech/logger` (`NON_PLATFORM_LOGGER`), and people/roles/keys are surfaced through the Hub (`NO_AUTHZ_POINTER`, `METADATA_UNPUBLISHED`, `IAC_GRANTS`, `PASSWORD_STORE`, `EMAIL_ALLOWLIST`, `USERS_TABLE`), and a docs site is published through the Hub docs door rather than on a hostname of its own, with its readers stated and grantable (`DOCS_SITE_PUBLIC` — advisory: the public hostname is the deprecated compatibility path and keeps deploying, so the finding names the door instead — `DOCS_AUDIENCE_IMPLICIT`, `DOCS_AUDIENCE_UNGRANTABLE`, `DOCS_VENDOR_AUDIENCE_PARTNER` — a vendor surface's reference is never partner-readable); a tenant-local auth lib is advisory (`LOCAL_AUTH_LIB`), as is a pointer that names its own Zitadel project instead of binding the env with `zitadelAppProjectId` (`POINTER_PROJECT_OVERRIDE`). Gate 0.6 additionally resolves the Pulumi program's imports against the installed tree (`UNRESOLVABLE_IMPORT`) — an optional peer nothing declares installs silently and `skipLibCheck` hides it, so the break otherwise waits for `mesh deploy`; with no `node_modules` the gate reports itself not checked rather than met. One check per code on the `mesh dev doctor` engine; exit 1 on any BLOCK. The SAME gate `mesh create-app` runs after scaffolding, tenant CI runs beside `mesh skills sync --check`, and the platform reviewer runs on a PR. Default: every `apps/*` with a Pulumi program. | `[apps...]` (repo-relative dirs), `--root <dir>`, `--json`, `--verbose` |
|
|
101
101
|
| `mesh init` | (bare = wizard), `app-tenant`, `platform <tenant>` | **Bare `mesh init` is the guided setup wizard**: tenant (pre-filled from `mesh.json` / Pulumi `mesh:tenant`), **where the tenant runs — local-only, a deployed platform, or NOTHING YET (scaffold one; §1c)**, registry access (in-process `mesh registry login`; a 403 marks the step ✘ and the wizard continues), platform sign-in on the deployed branch only, repo bootstrap (empty clone, or an empty non-git folder the wizard offers to `git init`) or shape check, skills sync; writes `mesh.json` (`{tenant, platform}`) so `create-app` / `mesh dev` default `--tenant`; flags `--tenant --local\|--platform <env>\|--new-platform [env] --device --profile --skip-repo --yes --json`, plus the scaffold's own under `--new-platform` (`--region --domain --state-bucket --create-state-bucket/--no-create-state-bucket --dir`); exit 1 if any step failed, 130 on Ctrl-C. `platform <tenant>` **prompts** on a TTY for env/region/profile/state bucket (defaults on each) and for `--domain`, which has **no** default because a placeholder scaffolds an unvalidatable zone; it offers to create the Pulumi state bucket (versioned) and prints the deploy sequence including the manual NS delegation. `app-tenant` is the repo doctor (A1–A3): read-only check pipeline — CLI auth, registry access, public npm not hijacked, platform reachable (Hub API), app-tenant registration, deployer role, repo shape, agent skills — each failure names the exact `mesh` fix. **Registry access** is a live probe of the CodeArtifact token, not a grep of `~/.npmrc`: an expired token `fail`s (it used to `pass`), an unreachable registry `warn`s (a network fault is not an auth fault). **Public npm not hijacked** fails when `~/.npmrc` carries an unscoped `registry=<codeartifact>` line, which makes CodeArtifact your default registry — one `mesh registry login` fixes both. Exit 0 iff all pass; re-run any time. `--fix` applies developer-scope fixes (registry token, skills sync); operator actions stay remediations — and `--profile <p>` is the SSO profile `--fix` logs into CodeArtifact with, echoed back in the `fix:` command each check prints so the advertised command is the one that runs. | `app-tenant`: `--tenant <name>`, `--context <ctx>` (default `local`), `--hub-url <url>`, `--fix`, `--profile <sso>`, `--json` |
|
|
102
102
|
| `mesh skills` | `sync` | Agent-skill distribution (D1/D2): installs the base building-with-Mesh skills into the repo's `.claude/skills/mesh-*/` (managed-marker files) and wires TanStack-Intent discovery for the pattern skills shipping inside `@mesh-tech/*` packages (`.intent/hooks/` gate + `.claude/settings.json` SessionStart hook + AGENTS.md fence — the PR #2356 mechanism, vendored). Idempotent; runs automatically after `mesh create-app`. | `sync`: `--check` (CI/doctor: exit 1 when missing/stale), `--root <path>` |
|
|
103
103
|
| `mesh docs` | `build`, `portal`, `cli-reference` | `build` builds/validates an **app's** OpenAPI specs from `docs/docs.config.json` (file copy or SymXchange generation). `start`/`stop`/`list` are the simple front door: `start` serves the docs on loopback — DETACHED in a tmux session named `mesh-docs` by default (prints the bare URL once live; `stop` kills the session; `--foreground` or any non-TTY runs in the foreground) — serving the working tree in a mesh-platform checkout, or the published `@mesh-tech/docs` artifact fetched from the role-gated CodeArtifact registry anywhere else (docs version == the @mesh-tech/* baseline it describes; `-v` pins, default latest; cached under `~/.cache/mesh/docs/`). `list` shows the published docs versions. `portal` assembles the **Mesh developer portal** (docs.meshtech.io) from every `docs.json`-opted-in doc root in the repo — a directory publishes its markdown iff it holds a `docs.json`; route/title/order/nav derive from the tree and each file, so adding a doc is adding one file — then hands the assembled tree to Zudoku (`apps/docs/`): default runs `zudoku build`, `--serve` runs `zudoku dev`, `--assemble-only`/`-o` stop after assembly. Links between published files are rewritten to routes; links to unpublished repo files become blob links. Reserved directory names (`plans/`, `designs/`, `incidents/`, … the frozen list in `src/docs/schema.ts`) are excluded at any depth. `cli-reference` regenerates `docs/portal/generated/cli-reference.md` from THIS command tree, so it can't document a flag the binary lacks. `portal --check` is the CI gate (`pnpm check:docs-portal`): docs.json schema validation, reserved-segment fail-close, broken links, and CLI-reference staleness; `--diff-base <ref>` prints the publish-set diff for PR job summaries. Hidden commands and `--version` are excluded from the reference. | `build`: `-c/--config <path>` (default `docs/docs.config.json`); `portal`: `-o/--out <dir>`, `--assemble-only`, `--serve`, `-p/--port <n>` (default `3000`), `--check`, `--print-manifest`, `--diff-base <ref>`, `--manifest-out <path>`; `cli-reference`: `-o/--out <path>`, `--check`; `start`: `-v/--version <v>` (default: latest), `-p/--port <n>` (default `4400`; `0` is foreground-only), `--dev` (foreground HMR), `--foreground`; `stop`: no flags; `list`: no flags |
|
|
@@ -19,6 +19,10 @@ export const schema = defineSchema({
|
|
|
19
19
|
namespace: "{{name}}",
|
|
20
20
|
version: "1.0.0",
|
|
21
21
|
subjects: {
|
|
22
|
+
// `identity` marks `user` as a caller type: a request resolves into it
|
|
23
|
+
// (`resolveSubject` in src/index.ts), so the compiled `ops_*` relations
|
|
24
|
+
// admit it and the Hub can assign a person a role under it. A subject
|
|
25
|
+
// declared without `identity` is grant-handle vocabulary only.
|
|
22
26
|
user: { coarseRoles: ["user"], identity: { claim: "sub" } },
|
|
23
27
|
},
|
|
24
28
|
resources: {
|