stack/packages/stack-cli
BilalG1 15faf709f3
stack-cli: explicit --cloud-project-id / --config-file across exec, config, project (#1422)
## Summary

Reworks the `stack` CLI surface so the cloud-vs-local choice is
**explicit at every invocation**, removing the global `--project-id` /
`STACK_PROJECT_ID` env var and the local-default `exec` behavior
introduced earlier in this branch.

### `stack exec`
- Removes `--cloud`, `STACK_EXEC_DEFAULT_TARGET`, and the implicit local
default. The CLI now requires **exactly one** of:
  - `--cloud-project-id <id>` — run against the Stack Auth cloud API
- `--config-file <path>` — run against the local emulator project mapped
to that absolute config-file path
- The `--config-file` branch resolves the project id by calling the
existing `GET /api/latest/internal/local-emulator/project` endpoint and
matching `absolute_file_path` client-side. No new backend endpoint
introduced.

### `stack config pull` / `stack config push`
- Both now take `--cloud-project-id <id>` per-command instead of the
global flag / `STACK_PROJECT_ID` env.
- `config pull --config-file` is **optional**: when omitted, the CLI
uses `./stack.config.ts` from the current directory. If neither flag nor
cwd file is present, it exits with a clear hint to pass `--config-file`
or `cd` into a directory containing `stack.config.ts`.

### `stack project list`
- Default (no flags) lists both **cloud and local emulator** projects.
Each entry carries a `target: "cloud" | "dev"` field (text format:
`<id>\t<displayName>\t[<target>]`).
- `--cloud` / `--dev` filter to a single source (mutually exclusive —
passing both errors).
- On the default code path, an unreachable local emulator emits a single
stderr warning (`warning: skipping dev projects — local emulator not
reachable …`) and the command still succeeds with cloud results. With
`--dev` explicit, the unreachable case hard-errors.

### `stack project create`
- Now requires `--cloud` to make the cloud-vs-local choice explicit.
There is no local alternative today; the flag exists to surface the
decision so a future local-project create doesn't silently change
behavior.

### Backend
- Bumps the `LIMIT` on `GET /api/latest/internal/local-emulator/project`
from 20 → 100 so `project list --dev` doesn't silently truncate.

### Refactors (from earlier in this branch, unchanged here)
- Local-emulator paths/ports/PCK polling live in
`packages/stack-cli/src/lib/emulator-paths.ts`.
- Shared local-emulator admin credentials live in
`packages/stack-shared/src/local-emulator.ts`.
- `resolveAuth` / `resolveLocalEmulatorAuth` take an explicit
`projectId: string` (no more `Flags` parameter).
- New `packages/stack-cli/src/lib/local-emulator-client.ts` encapsulates
the GET-and-match flow used by both `exec --config-file` and `project
list --dev`.

## Breaking changes

**Scripts that relied on any of the following must be updated:**

| Removed | Replacement |
| --- | --- |
| Global `--project-id <id>` flag | Per-command `--cloud-project-id
<id>` |
| `STACK_PROJECT_ID` env var | Per-command `--cloud-project-id <id>` |
| `stack exec --cloud` | `stack exec --cloud-project-id <id>` |
| `STACK_EXEC_DEFAULT_TARGET=cloud\|local` | `--cloud-project-id <id>`
or `--config-file <path>` |
| `stack exec` defaulting to local emulator | Explicit `--config-file
<path>` required |
| `stack project create` without a flag | `stack project create --cloud
…` required |

## Test plan
- [x] `pnpm lint` (stack-cli, backend, e2e) — clean
- [x] `pnpm --filter @stackframe/stack-cli typecheck` — clean
- [x] `pnpm --filter @stackframe/stack-cli exec vitest run` — **72/72
passing** (new unit tests: `parseExecTarget`,
`resolveConfigFilePathForPull`, `resolveProjectListSources`,
`formatProjectList`)
- [x] `pnpm test run apps/e2e/tests/general/cli.test.ts` — **73 passing,
4 skipped, 0 failing**. New e2e cases cover:
  - `exec` with neither flag → errors with "Specify a target"
  - `exec` with both flags → errors with "not both"
- `exec --config-file` with missing file / missing PCK / unreachable API
- `exec --config-file` happy path against a real local-emulator backend
(gated on `NEXT_PUBLIC_STACK_IS_LOCAL_EMULATOR=true`)
  - `config pull` cwd fallback to `./stack.config.ts`
- `config pull` with no `--config-file` and no cwd `stack.config.ts` →
errors with `Pass --config-file …`
  - `project list --cloud --dev` together → errors
- `project list` default with unreachable emulator → cloud results +
single stderr warning
  - `project create` without `--cloud` → errors
  - All previously-`--cloud` exec cases ported to `--cloud-project-id`
- [x] Manual smoke: `stack exec --help`, `stack project list --cloud
--dev`, `stack project create` all emit the expected friendly errors /
help text.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* CLI `exec`, `config`, and `project` commands now require explicit
targeting via `--cloud-project-id` (cloud) or `--config-file` (local
emulator).
* `project list` now supports `--cloud` and `--dev` flags to display
projects from both sources with target indicators.
* Enhanced environment variable validation for emulator service ports
with proper fallback handling.

* **Bug Fixes**
* `project list` now gracefully handles unreachable emulator with
warning fallback instead of failure.

* **Tests**
* Expanded test coverage for project targeting, config file resolution,
and emulator connectivity scenarios.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-14 17:20:40 -07:00
..
scripts local emulator security and features fixes (#1247) 2026-04-14 15:36:24 -07:00
src stack-cli: explicit --cloud-project-id / --config-file across exec, config, project (#1422) 2026-05-14 17:20:40 -07:00
.eslintrc.cjs Stack CLI (#1227) 2026-03-09 13:24:15 -07:00
package.json chore: update package versions 2026-05-11 10:10:47 -07:00
tsconfig.json Stack CLI (#1227) 2026-03-09 13:24:15 -07:00
tsdown.config.ts stack-cli: cloud/local init flow, auto-create on empty projects, post-setup next-steps (#1383) 2026-05-08 10:47:49 -07:00
vitest.config.ts Fast-start local emulator via RAM snapshot + live secret rotation (#1340) 2026-04-20 14:24:49 -07:00