@mesh-tech/mesh-cli 0.36.0 → 0.38.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.
Files changed (107) hide show
  1. package/assets/docs-preview.css +1599 -0
  2. package/dist/bin/mesh.auth-preflight-AQJ5TQES.js +48 -0
  3. package/dist/bin/mesh.auth-preflight-AQJ5TQES.js.map +6 -0
  4. package/dist/bin/mesh.capture-history-A4IAVVIR.js +38 -0
  5. package/dist/bin/mesh.capture-history-A4IAVVIR.js.map +6 -0
  6. package/dist/bin/mesh.chunk-2QIVBQX5.js +647 -0
  7. package/dist/bin/mesh.chunk-2QIVBQX5.js.map +6 -0
  8. package/dist/bin/mesh.chunk-2YRWJH5X.js +1747 -0
  9. package/dist/bin/mesh.chunk-2YRWJH5X.js.map +6 -0
  10. package/dist/bin/mesh.chunk-BF2SH6XT.js +303 -0
  11. package/dist/bin/mesh.chunk-BF2SH6XT.js.map +6 -0
  12. package/dist/bin/mesh.chunk-F4654EPX.js +383 -0
  13. package/dist/bin/mesh.chunk-F4654EPX.js.map +6 -0
  14. package/dist/bin/mesh.chunk-HPYZWPRM.js +1146 -0
  15. package/dist/bin/mesh.chunk-HPYZWPRM.js.map +6 -0
  16. package/dist/bin/mesh.chunk-I6NXLXGC.js +7715 -0
  17. package/dist/bin/mesh.chunk-I6NXLXGC.js.map +6 -0
  18. package/dist/bin/mesh.chunk-IQOBTL42.js +60 -0
  19. package/dist/bin/mesh.chunk-IQOBTL42.js.map +6 -0
  20. package/dist/bin/mesh.chunk-IU2IWH6O.js +835 -0
  21. package/dist/bin/mesh.chunk-IU2IWH6O.js.map +6 -0
  22. package/dist/bin/mesh.chunk-KN4BZOYH.js +187 -0
  23. package/dist/bin/mesh.chunk-KN4BZOYH.js.map +6 -0
  24. package/dist/bin/mesh.chunk-LMYPTJ2F.js +10092 -0
  25. package/dist/bin/mesh.chunk-LMYPTJ2F.js.map +6 -0
  26. package/dist/bin/mesh.chunk-MCBMHWXP.js +837 -0
  27. package/dist/bin/mesh.chunk-MCBMHWXP.js.map +6 -0
  28. package/dist/bin/mesh.chunk-OW5EMVG5.js +507 -0
  29. package/dist/bin/mesh.chunk-OW5EMVG5.js.map +6 -0
  30. package/dist/bin/mesh.chunk-TZAGJTKU.js +217 -0
  31. package/dist/bin/mesh.chunk-TZAGJTKU.js.map +6 -0
  32. package/dist/bin/mesh.chunk-WFFDF346.js +59 -0
  33. package/dist/bin/mesh.chunk-WFFDF346.js.map +6 -0
  34. package/dist/bin/mesh.cli-reference-H3TOPIET.js +158 -0
  35. package/dist/bin/mesh.cli-reference-H3TOPIET.js.map +6 -0
  36. package/dist/bin/mesh.convert-7N2H2SVK.js +274 -0
  37. package/dist/bin/mesh.convert-7N2H2SVK.js.map +6 -0
  38. package/dist/bin/mesh.create-app-NGXACFAU.js +39 -0
  39. package/dist/bin/mesh.create-app-NGXACFAU.js.map +6 -0
  40. package/dist/bin/mesh.dev-token-server-YP2VBP2S.js +61 -0
  41. package/dist/bin/mesh.dev-token-server-YP2VBP2S.js.map +6 -0
  42. package/dist/bin/mesh.js +20 -26418
  43. package/dist/bin/mesh.js.map +3 -3
  44. package/dist/bin/mesh.login-7SIAKFXJ.js +91 -0
  45. package/dist/bin/mesh.login-7SIAKFXJ.js.map +6 -0
  46. package/dist/bin/mesh.platform-setup-CJXE3BCP.js +37 -0
  47. package/dist/bin/mesh.platform-setup-CJXE3BCP.js.map +6 -0
  48. package/dist/bin/mesh.preview-RJGTCTY3.js +2410 -0
  49. package/dist/bin/mesh.preview-RJGTCTY3.js.map +6 -0
  50. package/dist/bin/mesh.program-BIDQBSSI.js +23 -0
  51. package/dist/bin/mesh.program-BIDQBSSI.js.map +6 -0
  52. package/dist/bin/mesh.registry-7P4MGXEK.js +47 -0
  53. package/dist/bin/mesh.registry-7P4MGXEK.js.map +6 -0
  54. package/dist/bin/mesh.registry-identity-JW4KO7N7.js +42 -0
  55. package/dist/bin/mesh.registry-identity-JW4KO7N7.js.map +6 -0
  56. package/dist/bin/mesh.skills-MNDSMBIE.js +23 -0
  57. package/dist/bin/mesh.skills-MNDSMBIE.js.map +6 -0
  58. package/dist/bin/mesh.src-5D5DFSLX.js +1302 -0
  59. package/dist/bin/mesh.src-5D5DFSLX.js.map +6 -0
  60. package/dist/bin/mesh.src-G7TJBLNJ.js +40 -0
  61. package/dist/bin/mesh.src-G7TJBLNJ.js.map +6 -0
  62. package/dist/bin/mesh.stack-EFTFAOCV.js +64 -0
  63. package/dist/bin/mesh.stack-EFTFAOCV.js.map +6 -0
  64. package/dist/bin/mesh.start-MPQFIEMH.js +454 -0
  65. package/dist/bin/mesh.start-MPQFIEMH.js.map +6 -0
  66. package/dist/bin/mesh.wizard-ZJE4S6PC.js +500 -0
  67. package/dist/bin/mesh.wizard-ZJE4S6PC.js.map +6 -0
  68. package/dist/build-info.json +2 -2
  69. package/dist/src/commands/app-check.d.ts +2 -1
  70. package/dist/src/commands/app-check.js +32 -0
  71. package/dist/src/commands/create-app.d.ts +0 -1
  72. package/dist/src/commands/create-app.js +0 -4
  73. package/dist/src/commands/dev.d.ts +6 -0
  74. package/dist/src/commands/dev.js +152 -3
  75. package/dist/src/commands/docs.js +33 -0
  76. package/dist/src/commands/local/act-as-local.d.ts +5 -0
  77. package/dist/src/commands/local/act-as-local.js +41 -0
  78. package/dist/src/commands/local/auth-provision.d.ts +1 -0
  79. package/dist/src/commands/local/auth-provision.js +1 -0
  80. package/dist/src/commands/local/index.js +4 -0
  81. package/dist/src/commands/local/local-api-key.d.ts +44 -0
  82. package/dist/src/commands/local/local-api-key.js +115 -0
  83. package/dist/src/commands/local/local-spicedb.d.ts +95 -0
  84. package/dist/src/commands/local/local-spicedb.js +304 -0
  85. package/dist/src/commands/local/publish-docs.d.ts +81 -0
  86. package/dist/src/commands/local/publish-docs.js +328 -0
  87. package/dist/src/commands/local/seed-zitadel.js +2 -0
  88. package/dist/src/commands/temporal.js +191 -61
  89. package/dist/src/commands/temporal.js.map +3 -3
  90. package/dist/src/docs/convert.d.ts +35 -0
  91. package/dist/src/docs/convert.js +276 -0
  92. package/dist/src/docs/preview-source.d.ts +13 -0
  93. package/dist/src/docs/preview-source.js +58 -0
  94. package/dist/src/docs/preview.d.ts +32 -0
  95. package/dist/src/docs/preview.js +279 -0
  96. package/dist/src/utils/scaffold-versions.d.ts +0 -1
  97. package/dist/src/utils/scaffold-versions.js +0 -1
  98. package/fragments/agents/AGENTS.md.hbs +27 -27
  99. package/fragments/base/README.md.hbs +5 -2
  100. package/fragments/base/index.ts.hbs +19 -33
  101. package/fragments/base/package.json.hbs +4 -2
  102. package/fragments/service/api/openapi.json.hbs +1 -1
  103. package/fragments/service/docs/docs.yaml.hbs +10 -0
  104. package/fragments/service/docs/pages/getting-started.md.hbs +6 -9
  105. package/package.json +19 -3
  106. package/skills/mesh/SKILL.md +2 -2
  107. package/stack/docker-compose.hub.yml +6 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mesh-tech/mesh-cli",
3
- "version": "0.36.0",
3
+ "version": "0.38.0",
4
4
  "description": "CLI for Mesh platform development utilities",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -42,11 +42,13 @@
42
42
  },
43
43
  "devDependencies": {
44
44
  "@mesh-tech/agent-contracts": "0.2.0",
45
- "@mesh-tech/tsconfig": "2.37.0",
45
+ "@mesh-tech/tsconfig": "2.39.0",
46
46
  "@mesh-tech/workflow-viz": "0.3.1",
47
47
  "@tanstack/intent": "^0.3.6",
48
48
  "@types/node": "^20.0.0",
49
- "tsx": "^4.20.4"
49
+ "@types/react": "^19.1.8",
50
+ "@types/react-dom": "^19.1.6",
51
+ "tailwindcss": "^4.2.2"
50
52
  },
51
53
  "dependencies": {
52
54
  "@aws-sdk/client-route-53": "^3.700.0",
@@ -61,9 +63,23 @@
61
63
  "chalk": "^5.3.0",
62
64
  "commander": "^12.1.0",
63
65
  "handlebars": "^4.7.8",
66
+ "react": "^19.2.0",
67
+ "react-dom": "^19.2.0",
68
+ "react-markdown": "^10.1.0",
69
+ "rehype-highlight": "^7.0.2",
70
+ "remark-gfm": "^4.0.1",
71
+ "tsx": "^4.20.4",
64
72
  "yaml": "^2.8.1",
65
73
  "zod": "^4.2.1"
66
74
  },
75
+ "peerDependencies": {
76
+ "mermaid": "^11.12.2"
77
+ },
78
+ "peerDependenciesMeta": {
79
+ "mermaid": {
80
+ "optional": true
81
+ }
82
+ },
67
83
  "optionalDependencies": {
68
84
  "@aws-sdk/client-s3": "^3.864.0",
69
85
  "@temporalio/client": "^1.17.0",
@@ -179,10 +179,10 @@ Top-level commands (each `register*` is wired in `src/program.ts`, which `bin/me
179
179
  | `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` |
180
180
  | `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-<api-port>`, so several local Hubs coexist once each is given an API port of its own (both ports default the same in every worktree). | `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` (or `MESH_HUB_DEV_API_PORT`, default 3002; also names the tmux session), `--platform-dir <dir>` (or `MESH_PLATFORM_DIR`), `--print-env`, `--kill` |
181
181
  | `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/`) |
182
- | `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` |
182
+ | `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`), an API surface publishes its docs as a native docs source rather than a docs site (`DOCS_SITE_DEPRECATED` — advisory: a `docs` block that builds a site, with no `docs.config`, deploys for one more minor release; the finding names the `mesh docs convert` command filled from the block), 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` |
183
183
  | `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` |
184
184
  | `mesh skills` | `sync` | Agent-skill distribution (D1/D2): installs the base building-with-Mesh skills into the repo's `.claude/skills/` — this one as `mesh/` (`/mesh`) — and the `@mesh-tech/*` package skills as `mesh-<pkg>[-<domain>]/` (`-core` dropped: `mesh-authn`, `mesh-app-kit-apps`); every copy's `name:` is its directory, and managed copies left under older names (`mesh-core/`, `mesh-<pkg>-core/`) are removed 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>` |
185
- | `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 |
185
+ | `mesh docs` | `build`, `portal`, `cli-reference`, `preview`, `convert` | `preview <dir>` renders one app's **native docs source** (`docs.yaml` + Markdown guides + the OpenAPI reference) as the Hub's Docs tab shows it, with no Hub or platform, using the deploy's own builder — every problem the deploy would refuse is printed and on the page (`--check` exits 1 on any; `-o` writes the bundle a local Hub reads; `-s` names the spec `docs.spec` points at). `convert` writes a starter `docs.yaml` from an ApiSurface's deprecated site-shaped `docs` block (`--spec` required, `--pages`, `--landing`, `--title`, `--out`): one `Guides` nav group in front-matter `order`/`sidebar_position` else filename order; `--fix-pages` moves each page's leading `# Title` into front-matter `title` and copies an outside landing file to `pages/index.md` (`.mdx` is reported, never converted); replaces nothing without `--force`; prints every remaining problem and the `docs: { spec, config }` edit, exit 1 while problems remain. `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 |
186
186
  | `mesh stack` | `init`, `status`, `rm <name>` | `init` in an **app** creates a personal app stack `dev-{github-user}`, copying base-stack config, setting `mesh:deploy: false`, inheriting KMS secrets provider; `--worktree` appends the git-worktree token (`dev-{user}-{token}`) so concurrent worktrees deploy to **distinct** stacks (SSM paths, Temporal namespace, Nexus endpoint all derive from the stack name → one discriminator isolates all three; no-op on the primary checkout). `init --platform` in a platform repo's **`platform/`** creates a **personal platform** `{tenant}-{github-user}-dev` — its own Zitadel, Hub, Temporal and tenant envs on the base stack's core (`mesh:coreEnv`, `mesh:clusterOwner false`, registry/VPN singletons off, deploy on); `--parent-zone` gives it its own DNS zone. `status` is the read-only drift check: for each platform this directory deploys (or an app deploys to), pinned vs deployed (the `core` and `platform` SSM registrations) vs latest `@mesh-tech/infra-components` / `@mesh-tech/hub`, plus this CLI vs the latest `@mesh-tech/mesh-cli`, with the upgrade steps when anything is behind. `rm <name>` removes a personal stack (backend state + local config), credentialed. `init`/`rm` assume the deployer role — no raw `pulumi` / manual creds needed. | `init`: `--from <stack>`, `--name <stack>`, `--worktree`, `--adopt`, `--platform`, `--parent-zone <zone>`; `status`: `--stack`, `--profile`, `--region`, `--json`, `--check` (exit 1 when behind); `rm`: `--yes` |
187
187
  | `mesh tenant` | `add <name>`, `list` | Register/inspect app tenants on a platform stack. Run from the **platform layer** of a tenant platform repo (e.g. `mesh-sandbox/platform`). `add` inserts the tenant under `mesh:tenants` in `Pulumi.<stack>.yaml` via a comment-preserving YAML round-trip (untouched lines don't reformat), refuses a tenant that is already declared (an existing entry may carry fields a re-add would drop), derives the `{name}-{env}` subdomain from the stack name (echoed in the success line), and guards against running on the core layer or an app dir; it then prints the deploy + verify sequence — `mesh deploy up` is what makes the registration live. `list` prints what the stack config declares, so "is it registered?" is answerable without opening YAML (warns when the project doesn't look like a platform layer, so an empty result isn't mistaken for "no tenants"). | `add`: `--display-name <name>`, `--subdomain <sub>`, `--zitadel-org-id <id>`, `--stack <stack>`, `--json`; `list`: `--stack <stack>`, `--json` |
188
188
  | `mesh tunnel [group]` | `external <name>` | SSM port-forward to platform services. Groups: `dev` (temporal+db), `temporal`. **`external <name>`** tunnels to a *registered* `ExternalService`: host/port are read from its credential secret (`mesh/{app-tenant}/{app-stage}/external/{name}`) — the same values deployed apps resolve at runtime — so anything the bastion can reach is tunnelable with no per-service CLI entry and no bastion services-map change. `-t/-e` are **optional inside an app directory** — they fall back to the same Pulumi/SST context detection `mesh dev` uses, which fails closed elsewhere, so pass `-t` outside an app dir (`-t` alone is enough; `-e` alone is not). `-e` names a platform env, not a stack, so it no longer doubles as the stage hint: the credential axis `external` keys on stays the app's real stack name. And `AWS_REGION`/`AWS_PROFILE` default from the nearest Pulumi config + the `{tenant}-{env}` profile convention (region falls back to the effective profile's own `region` — the `[default]` profile when none was resolved — before the platform default us-east-2). | root: `-t/--tenant`, `-e/--env`, `-l/--list`, `-s/--services <csv\|group>`, `--db-port`, `--temporal-ui-port`, `--temporal-frontend-port`; `external`: `-p/--port` (default: the remote port), `-k/--key <key>` (multi-instance `credentials.keyedBy` externals), `--app-tenant`/`--app-stage` (credential axis; default to `-t`/`-e`) |
@@ -77,6 +77,12 @@ services:
77
77
  PUBLIC_API_URL: http://localhost:4568
78
78
  AGENT_API_URL: http://hub-api:3002
79
79
  MESH_LOCAL: "1"
80
+ # The UI reads the API registry (SSM) and the published specs and docs
81
+ # sources (S3) itself — from the local fabric, like hub-api above.
82
+ AWS_ENDPOINT_URL: http://ministack:4566
83
+ AWS_REGION: us-east-2
84
+ AWS_ACCESS_KEY_ID: test
85
+ AWS_SECRET_ACCESS_KEY: test
80
86
  depends_on:
81
87
  - hub-api
82
88
  networks: