Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
180 commits
Select commit Hold shift + click to select a range
76ac752
refactor(stack): remove legacy stack runtimes
jgoux Aug 28, 2026
c97c47c
feat(stack): define the greenfield public model
jgoux Aug 28, 2026
dc29b59
test(stack): strengthen capability uniqueness contract
jgoux Aug 28, 2026
fb428ed
feat(stack): add identity and safe state paths
jgoux Aug 28, 2026
c73353a
fix(stack): harden identity metadata
jgoux Aug 28, 2026
06800c9
feat(stack): compile closed capability definitions
jgoux Aug 28, 2026
6f0a69a
fix(stack): align capability releases and plans
jgoux Aug 28, 2026
0b0d036
fix(stack): align persisted plan reuse
jgoux Aug 28, 2026
20117b3
test(stack): avoid shared compiler mutation
jgoux Aug 28, 2026
15cbf5e
feat(stack): persist state secrets and sticky ports
jgoux Aug 28, 2026
7bc6bfc
fix(stack): fence running port changes
jgoux Aug 28, 2026
f21f38e
feat(stack): add supervisor ownership and managed handles
jgoux Aug 28, 2026
4dc2a48
feat(stack): reconcile workloads and publish observability
jgoux Aug 28, 2026
c027dc3
feat(stack): prepare artifacts and run native workloads
jgoux Aug 28, 2026
a06b1ab
feat(stack): add gateway and lazy activation
jgoux Aug 29, 2026
bff21f0
feat(stack): serve live functions through edge runtime
jgoux Aug 29, 2026
9134496
fix(stack): preserve tcp tunnel drain
jgoux Aug 29, 2026
4272a9e
feat(stack): run strict container stacks
jgoux Aug 29, 2026
76d3b70
feat(stack): complete managed lifecycle and recovery
jgoux Aug 29, 2026
24ae2c7
feat(stack): expose facades and migrate the CLI
jgoux Aug 29, 2026
3239f28
fix(stack): harden facades and managed CLI flows
jgoux Aug 29, 2026
fb1e999
fix(stack): close facade and CLI review gaps
jgoux Aug 29, 2026
36b4416
fix(stack): accept default-disabled test capabilities
jgoux Aug 29, 2026
604bd87
feat(stack): define the exhaustive workload catalog
jgoux Aug 29, 2026
1d5d4e2
fix(stack): harden workload artifacts and runtime specs
jgoux Aug 29, 2026
1294916
fix(stack): complete workload execution contracts
jgoux Aug 29, 2026
06e549e
docs(stack): simplify gateway ownership
jgoux Aug 29, 2026
f1758bd
fix(stack): close remaining workload contract gaps
jgoux Aug 29, 2026
a821c71
fix(stack): provide edge runtime jwt material
jgoux Aug 29, 2026
e8bc961
feat(stack): unify ingress and private ports
jgoux Aug 29, 2026
f5db058
refactor(stack): remove obsolete port runtime option
jgoux Aug 29, 2026
9809f3c
feat(stack): complete private routing contracts
jgoux Aug 29, 2026
018a13f
fix(stack): unify local jwt signing material
jgoux Aug 29, 2026
865a956
fix(stack): complete gateway request transforms
jgoux Aug 29, 2026
d210c9d
fix(stack): generate valid managed api credentials
jgoux Aug 29, 2026
a8a76ae
feat(stack): add production runtime preparation
jgoux Aug 29, 2026
f5a2ab7
fix(stack): validate readiness request paths
jgoux Aug 29, 2026
cf6d68b
feat(stack): own the edge runtime functions bootstrap
jgoux Aug 29, 2026
ebfe454
fix(stack): harden managed credential generation
jgoux Aug 29, 2026
cf6e0fd
fix(stack): contain live functions discovery
jgoux Aug 29, 2026
ce94384
fix(stack): contain functions package discovery
jgoux Aug 29, 2026
ff7dd8e
fix(stack): provide functions api credentials
jgoux Aug 29, 2026
20bc523
feat(stack): own supervisor ingress lifecycle
jgoux Aug 29, 2026
97f199b
fix(stack): harden ingress ownership and port startup
jgoux Aug 29, 2026
45024fb
docs(stack): record ingress rewrite decisions
jgoux Aug 29, 2026
1d413fd
fix(stack): fence port materialization by generation
jgoux Aug 29, 2026
a6265c3
docs(stack): record port generation fencing
jgoux Aug 29, 2026
02e53fe
feat(stack): bootstrap database runtime settings
jgoux Aug 29, 2026
66e91f1
docs(stack): record database bootstrap completion
jgoux Aug 29, 2026
2d6d843
fix(stack): gate recovered database readiness
jgoux Aug 29, 2026
d86ea26
feat(stack): compose the production runtime
jgoux Aug 29, 2026
024dbba
fix(stack): clean production runtime files
jgoux Aug 29, 2026
02c9246
fix(stack): preserve runtime file cleanup failures
jgoux Aug 29, 2026
f832817
docs(stack): record production runtime composition
jgoux Aug 29, 2026
2db9d14
feat(stack): expose persisted stack credentials
jgoux Aug 29, 2026
21200b8
feat(stack): capture container workload logs
jgoux Aug 29, 2026
afc26d9
docs(stack): narrow the remaining rewrite scope
jgoux Aug 29, 2026
488ecdf
refactor(stack): remove deferred reset lifecycle
jgoux Aug 29, 2026
ee1c7d9
fix(stack): fence persisted stack credentials
jgoux Aug 29, 2026
5e38321
test(stack): align postgres preparation fixtures
jgoux Aug 29, 2026
4a11a30
fix(stack): align service runtime contracts
jgoux Aug 29, 2026
1c301d2
fix(stack): use qualified slim mirror images
jgoux Aug 29, 2026
9b62d33
feat(stack): prepare immutable runtime artifacts
jgoux Aug 29, 2026
4c274c4
feat(stack): share storage container data
jgoux Aug 29, 2026
6640872
docs(stack): record postgres 17 scope
jgoux Aug 29, 2026
a0c1276
feat(stack): run service startup migrations
jgoux Aug 29, 2026
ff02f41
feat(stack): resolve runtime owner inputs
jgoux Aug 29, 2026
81edf99
refactor(stack): require native process plans
jgoux Aug 29, 2026
a77c0e0
fix(stack): scope runtime input resolution
jgoux Aug 29, 2026
dd79736
docs(stack): record reviewed runtime milestones
jgoux Aug 29, 2026
12188c4
feat(stack): coordinate supervisor lifecycle ownership
jgoux Aug 31, 2026
783d5e9
fix(stack): close lifecycle ownership gaps
jgoux Aug 31, 2026
961f4a0
fix(stack): allow supervisor readiness startup time
jgoux Aug 31, 2026
335db22
fix(stack): preserve accepted terminal operations
jgoux Aug 31, 2026
4d75a97
fix(stack): complete terminal transport handoffs
jgoux Aug 31, 2026
bbea510
fix(stack): preserve RPC request defects
jgoux Aug 31, 2026
824421f
fix(stack): close lifecycle freshness windows
jgoux Aug 31, 2026
f498726
fix(stack): close completion witness race
jgoux Aug 31, 2026
d01a4c5
feat(stack): correct runtime input startup contracts
jgoux Aug 31, 2026
d899e73
fix(stack): harden runtime input ownership
jgoux Aug 31, 2026
c465dd2
test(stack): cover runtime owner scope teardown
jgoux Aug 31, 2026
fd77707
fix(stack): satisfy runtime input lint contract
jgoux Aug 31, 2026
501099d
feat(stack): wire runtime inputs and auth templates
jgoux Aug 31, 2026
ca8738c
fix(stack): tighten runtime input ownership
jgoux Aug 31, 2026
8229fe7
fix(stack): fence runtime input generations
jgoux Aug 31, 2026
d1ce5c0
test(stack): harden native runtime integration under load
jgoux Aug 31, 2026
eca151c
chore(stack): remove unused artifact source import
jgoux Aug 31, 2026
00fc547
chore(stack): prune unused declarations and configure knip
jgoux Aug 31, 2026
2632b1f
chore(stack): close private functions export surface
jgoux Aug 31, 2026
791c0e0
fix(cli): normalize stack config boundary
jgoux Aug 31, 2026
b10b2b8
fix(stack): normalize functions and embedded supervisor startup
jgoux Aug 31, 2026
20b3669
fix(stack): run service migrations before containers
jgoux Aug 31, 2026
cc35248
fix(stack): isolate container startup processes
jgoux Aug 31, 2026
50fef8d
test(stack): close container migration review
jgoux Aug 31, 2026
b668163
feat(stack): implement managed runtime parity
jgoux Sep 1, 2026
4d59850
chore(stack): ignore runtime development artifacts
jgoux Sep 1, 2026
c9854ce
docs(stack): record runtime completion evidence
jgoux Sep 1, 2026
2dab6e4
Merge remote-tracking branch 'origin/develop' into feat/stack-runtime…
jgoux Sep 1, 2026
7d379b2
refactor(stack): simplify workload catalog contracts
jgoux Sep 1, 2026
145bf55
fix(stack): disable native BEAM distribution
jgoux Sep 1, 2026
499cd6c
test(stack): cover native BEAM startup environment propagation
jgoux Sep 1, 2026
43f0c54
docs(stack): record BEAM correction checkpoint
jgoux Sep 1, 2026
d36cbfb
refactor(stack): reuse native readiness listener
jgoux Sep 1, 2026
aaffa24
docs(stack): record BEAM review convergence
jgoux Sep 1, 2026
02ec086
docs(stack): record artifact workflow evidence
jgoux Sep 1, 2026
1e90f3e
docs(stack): record exact BEAM rollout evidence
jgoux Sep 1, 2026
87d13f8
feat(stack): simplify managed runtime architecture
jgoux Sep 1, 2026
559fa3c
feat(stack): complete managed runtime rewrite
jgoux Sep 2, 2026
07198fa
Merge remote-tracking branch 'origin/develop' into feat/stack-runtime…
jgoux Sep 2, 2026
56bfb37
chore(stack): simplify observation handles
jgoux Sep 2, 2026
38f68cb
docs(stack): record observation simplification report
jgoux Sep 2, 2026
28b975e
chore(stack): untrack local task report
jgoux Sep 2, 2026
cf727f1
chore(stack): close log observation review gaps
jgoux Sep 3, 2026
c8d57f3
chore(stack): simplify lifecycle restart composition
jgoux Sep 3, 2026
d99eb60
test(stack): strengthen lifecycle simplification coverage
jgoux Sep 3, 2026
f8063af
test(stack): remove owner cleanup polling
jgoux Sep 3, 2026
13c9ae6
refactor(stack): make preparation caller-owned
jgoux Sep 3, 2026
a3fc2b8
test(stack): harden preparation boundaries
jgoux Sep 3, 2026
01462b5
refactor(stack): compare materialized definitions
jgoux Sep 3, 2026
40ec591
refactor(stack): launch workloads per session
jgoux Sep 3, 2026
4072423
fix(stack): make lifecycle cleanup attempt scoped
jgoux Sep 3, 2026
d17d668
fix(stack): simplify lifecycle fencing
jgoux Sep 3, 2026
267f669
fix(stack): unify activation cleanup attempts
jgoux Sep 3, 2026
e2929a5
test(stack): cover ingress rollback cleanup
jgoux Sep 3, 2026
0a253b0
test(stack): assert successor eager launch
jgoux Sep 3, 2026
35bc303
fix(stack): preserve ingress reservation identity
jgoux Sep 3, 2026
85b84ac
refactor(stack): prune stale public surface
jgoux Sep 3, 2026
9d7124a
refactor(stack): tighten lifecycle and observability surfaces
jgoux Sep 3, 2026
e855ba8
refactor(stack): consolidate runtime ownership
jgoux Sep 3, 2026
ad7ff8f
refactor(stack): simplify runtime and log construction
jgoux Sep 3, 2026
65e77f6
refactor(stack): remove runtime factory terminology
jgoux Sep 3, 2026
f20d126
chore(stack): preserve lifecycle and runtime error details
jgoux Sep 3, 2026
ffdad59
chore(stack): preserve runtime failures and lifecycle state
jgoux Sep 3, 2026
eb7b251
chore(stack): preserve follower failures and cold start state
jgoux Sep 3, 2026
62564c9
chore(stack): settle final lifecycle failure paths
jgoux Sep 3, 2026
81560c6
chore(stack): close final runtime review gaps
jgoux Sep 3, 2026
4bb2100
chore(stack): preserve typed log initialization causes
jgoux Sep 3, 2026
18c4493
test(stack): cover all-eager runtime startup
jgoux Sep 3, 2026
b7a212d
chore(stack): simplify structural runtime boundaries
jgoux Sep 3, 2026
47ac17e
docs(stack): clarify container engine selection defaults
jgoux Sep 3, 2026
c825848
test(stack): consolidate lifecycle coverage at EffectStack
jgoux Sep 3, 2026
b90ef61
test(stack): preserve supervisor log phase coverage
jgoux Sep 3, 2026
a26383e
refactor(stack): simplify artifact cache validation
jgoux Sep 3, 2026
bf5f1bf
refactor(stack): harden artifact cache probes
jgoux Sep 3, 2026
728c05d
chore(stack): apply final runtime cleanup fixes
jgoux Sep 3, 2026
84b3a7b
chore(stack): close final review gaps
jgoux Sep 3, 2026
509db7e
chore(stack): close final runtime cleanup gaps
jgoux Sep 3, 2026
82ed5ad
fix(stack): retry fresh host port binds
jgoux Sep 3, 2026
356360d
test(stack): coordinate concurrent test stacks
jgoux Sep 3, 2026
8e16252
chore(stack): satisfy effect dependency lint
jgoux Sep 3, 2026
9c67381
chore(stack): clarify automatic port retries
jgoux Sep 3, 2026
05941b7
test(stack): share managed state root with test helpers
jgoux Sep 4, 2026
277de03
fix(stack): preserve port intent and refresh stale artifacts
jgoux Sep 4, 2026
a7d4f60
fix(stack): harden lifecycle and observability
jgoux Sep 4, 2026
71d08c4
Merge remote-tracking branch 'origin/develop' into feat/stack-runtime…
jgoux Sep 4, 2026
c0ce848
chore(repo): resolve merged quality checks
jgoux Sep 4, 2026
5eb9122
test(stack): synchronize concurrent start assertion
jgoux Sep 4, 2026
e794073
fix(stack): harden runtime lifecycle boundaries
jgoux Sep 4, 2026
e94d804
Merge remote-tracking branch 'origin/develop' into feat/stack-runtime…
jgoux Sep 4, 2026
c143ec0
Merge remote-tracking branch 'origin/develop' into feat/stack-runtime…
jgoux Sep 4, 2026
102bb9c
fix(stack): restore coverage provider
jgoux Sep 4, 2026
6e364cf
test(stack): harden integration tests under CI load
jgoux Sep 4, 2026
2182c2f
fix(stack): close late listener connections
jgoux Sep 4, 2026
25aeaef
test(stack): await accepted listener connections
jgoux Sep 4, 2026
7c8fe2e
fix(stack): support Linux container callbacks
jgoux Sep 4, 2026
c5b5726
fix(stack): cancel abandoned lazy activation
jgoux Sep 4, 2026
a37872b
fix(stack): expose pooler input to containers
jgoux Sep 4, 2026
bee20fd
fix(stack): gracefully stop postgres after owner loss
jgoux Sep 4, 2026
0eefb58
Merge branch 'develop' of github.com:supabase/cli into feat/stack-run…
jgoux Sep 4, 2026
20e7e8c
fix(stack): preserve configured function paths
jgoux Sep 4, 2026
b7e5bc3
fix(cli): map function paths to container mounts
jgoux Sep 4, 2026
5ca7531
fix(stack): use a stable container functions root
jgoux Sep 4, 2026
db7ab4e
fix(stack): finalize runtime catalog and ownership
jgoux Sep 4, 2026
3bdf39f
refactor(stack): remove redundant runtime mechanisms
jgoux Sep 4, 2026
5868dd9
refactor(stack): scope input preparation to workload startup
jgoux Sep 5, 2026
d3ee71b
perf(stack): start independent workloads concurrently
jgoux Sep 5, 2026
27355b4
perf(stack): prefetch lazy artifacts with observable progress
jgoux Sep 5, 2026
3338a94
refactor(stack): delegate service preparation to runtime artifacts
jgoux Sep 5, 2026
c25f8da
chore(stack): remove obsolete preparation test import
jgoux Sep 5, 2026
1944456
fix(stack): allow cold native services to finish loading
jgoux Sep 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
45 changes: 34 additions & 11 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ jobs:
(github.event_name == 'merge_group' ||
inputs.force ||
github.event.pull_request.draft == false)
name: Run end-to-end tests (shard ${{ matrix.shard }}/3)
name: Run CLI end-to-end tests (shard ${{ matrix.shard }}/3)
runs-on: blacksmith-8vcpu-ubuntu-2404
strategy:
fail-fast: false
Expand Down Expand Up @@ -186,16 +186,39 @@ jobs:
run: pnpm exec turbo run supabase#build

- name: Run end-to-end tests
run: pnpm exec turbo run test:e2e:run --only --concurrency=1 -- --shard=${{ matrix.shard }}/3
run: pnpm exec turbo run test:e2e:run --only --concurrency=1 --filter=supabase --filter=@supabase/cli-e2e -- --shard=${{ matrix.shard }}/3
env:
CLI_HARNESS_TARGET: ts-legacy
SUPABASE_GO_BINARY: ${{ github.workspace }}/apps/cli-go/supabase-go

# Summary job that gates branch protection. The matrix `test-e2e` job
# produces per-shard check names (`Run end-to-end tests (shard N/3)`), so
# this job preserves the original `Run end-to-end tests` check name that
# branch protection rules already require. It succeeds iff every shard
# succeeded (or skipped — `success()` is true for skipped jobs).
test-stack-e2e:
if: |
!startsWith(github.head_ref, 'release-notes/') &&
(github.event_name == 'merge_group' ||
inputs.force ||
github.event.pull_request.draft == false)
name: Run stack end-to-end tests (${{ matrix.runtime }})
runs-on: blacksmith-8vcpu-ubuntu-2404
strategy:
fail-fast: false
matrix:
runtime: [native, container]
steps:
- name: Checkout
uses: useblacksmith/checkout@6fd481652155169ed4d2f25ebaf97464f685175f # v1.0.0-beta

- name: Setup
uses: ./.github/actions/setup
with:
dependency-firewall-token: ${{ secrets.DF_FIREWALL_TOKEN }}

- name: Run stack end-to-end tests
run: pnpm --filter @supabase/stack test:e2e:run
env:
SUPABASE_STACK_E2E_RUNTIME: ${{ matrix.runtime }}

# Summary job that gates branch protection. It preserves the original check
# name and succeeds iff every CLI shard and stack runtime succeeded.
test-e2e-summary:
if: |
always() &&
Expand All @@ -204,13 +227,13 @@ jobs:
inputs.force ||
github.event.pull_request.draft == false)
name: Run end-to-end tests
needs: test-e2e
needs: [test-e2e, test-stack-e2e]
runs-on: ubuntu-latest
steps:
- name: Verify all shards succeeded
run: |
if [ "${{ needs.test-e2e.result }}" = "failure" ] || [ "${{ needs.test-e2e.result }}" = "cancelled" ]; then
echo "::error ::One or more e2e shards failed: ${{ needs.test-e2e.result }}"
if [ "${{ needs.test-e2e.result }}" = "failure" ] || [ "${{ needs.test-e2e.result }}" = "cancelled" ] || [ "${{ needs.test-stack-e2e.result }}" = "failure" ] || [ "${{ needs.test-stack-e2e.result }}" = "cancelled" ]; then
echo "::error ::One or more e2e jobs failed: cli=${{ needs.test-e2e.result }}, stack=${{ needs.test-stack-e2e.result }}"
exit 1
fi
echo "All e2e shards reported: ${{ needs.test-e2e.result }}"
echo "All e2e jobs reported: cli=${{ needs.test-e2e.result }}, stack=${{ needs.test-stack-e2e.result }}"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ coverage/
!.env.example
.claude/
.agents/.repos/effect-v3
.repos/slim-services/
.worktrees/
.supabase/
erl_crash.dump
# Stray `supabase` project dir created by running the CLI at the repo root
# (e.g. supabase/.temp/linked-project.json). This monorepo has no top-level
# Supabase project — real fixtures live under apps/cli-e2e/fixtures/.
Expand All @@ -23,6 +25,7 @@ packages/cli-*/bin/

# Turbo
.turbo/
apps/cli/.supabase/

# Transient render dir created by packages/api/scripts/generated-output-sync.unit.test.ts
packages/api/.generated-output-sync-*/
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
[submodule ".repos/cheffect"]
path = .repos/cheffect
url = https://github.com/tim-smart/cheffect.git
[submodule ".repos/process-compose"]
path = .repos/process-compose
url = https://github.com/F1bonacc1/process-compose.git
[submodule ".repos/t3code"]
path = .repos/t3code
url = https://github.com/pingdotgg/t3code.git
Expand Down
2 changes: 0 additions & 2 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
".repos",
"apps/cli-go",
"apps/cli-e2e/fixtures",
"packages/stack",
"packages/process-compose",
"**/testdata",
"**/dist",
"**/coverage",
Expand Down
1 change: 0 additions & 1 deletion .repos/process-compose
Submodule process-compose deleted from a4038d
5 changes: 2 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ Bun monorepo with workspaces under `apps/` and `packages/`.
- `apps/docs` — internal Next.js docs site
- `packages/api` — typed Supabase Management API client
- `packages/config` — config schema and generated types
- `packages/process-compose` — process orchestration library
- `packages/stack` — programmatic local Supabase stack runtime
- `packages/cli-*` — platform-specific published CLI binary wrappers

## Package Structure

Use `packages/process-compose` as the reference for internal TypeScript/Bun workspaces such as `apps/cli`, `packages/api`, `packages/config`, `packages/process-compose`, and `packages/stack`.
Use the existing internal TypeScript/Bun workspaces as references for package structure and scripts.

These workspaces should generally follow this structure:

Expand All @@ -29,7 +28,7 @@ These workspaces should generally follow this structure:
- Standard scripts: `test`, `types:check`
- Standard devDependencies: `@tsconfig/bun`, `@types/bun`, `typescript`

Generic linting (`oxlint`), formatting (`oxfmt`), and unused-code analysis (`knip`) are repo-wide, not per-package: the tools are root devDependencies configured by `.oxlintrc.json`, `.oxfmtrc.json`, and `knip.json` at the repo root (knip's config maps each workspace under its `workspaces` key). Effect-specific linting is incrementally scoped to `packages/stack` and `packages/process-compose` through `.oxlintrc.effect.json`; run it with the root `lint:effect:check` or `lint:effect:fix` scripts. The root `check:all`/`fix:all` scripts are the sole repo-wide quality entrypoints and use Turbo to orchestrate the root-owned generic `lint:*`/`fmt:*`/`knip:*` scripts and package `types:check` targets; `fix:all` runs the Effect lint fix after those generic fixes complete. Package-local work can run `pnpm types:check` and the package's test scripts; `pnpm exec oxlint`, `pnpm exec oxfmt`, and `pnpm exec knip-bun` from the repo root also work directly.
Generic linting (`oxlint`), formatting (`oxfmt`), and unused-code analysis (`knip`) are repo-wide, not per-package: the tools are root devDependencies configured by `.oxlintrc.json`, `.oxfmtrc.json`, and `knip.json` at the repo root (knip's config maps each workspace under its `workspaces` key). Effect-specific linting is scoped to `packages/stack` through `.oxlintrc.effect.json`; run it with the root `lint:effect:check` or `lint:effect:fix` scripts. The root `check:all`/`fix:all` scripts are the sole repo-wide quality entrypoints and use Turbo to orchestrate the root-owned generic `lint:*`/`fmt:*`/`knip:*` scripts and package `types:check` targets; `fix:all` runs the Effect lint fix after those generic fixes complete. Package-local work can run `pnpm types:check` and the package's test scripts; `pnpm exec oxlint`, `pnpm exec oxfmt`, and `pnpm exec knip-bun` from the repo root also work directly.

Expected exceptions:

Expand Down
4 changes: 1 addition & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ That pulls `.repos/effect/`, which is the local source of truth for Effect v4 AP
|-- packages/
| |-- api/ # Typed Supabase Management API client
| |-- config/ # Supabase config schema and generated types
| |-- process-compose/ # Effect-based process orchestration library
| |-- stack/ # Programmatic local Supabase stack runtime
| `-- cli-*/ # Platform-specific CLI binary packages
|-- tools/ # Repository tooling (release scripts, etc.)
Expand All @@ -115,7 +114,6 @@ That pulls `.repos/effect/`, which is the local source of truth for Effect v4 AP
| `packages/api` | Auto-generated TypeScript client for the Supabase Management API. |
| `packages/cli-test-helpers` | CLI test harness library — `createHarness`/`exec` API for spawning TS Legacy and TS Next CLI subprocesses in tests. |
| `packages/config` | JSON Schema and generated TypeScript types for Supabase configuration. |
| `packages/process-compose` | TypeScript/Bun port of `process-compose` used for multi-service orchestration. |
| `packages/stack` | Programmatic local Supabase stack used by the CLI and other tooling. |
| `packages/cli-darwin-arm64` | Published native CLI binary wrapper for macOS arm64. |
| `packages/cli-darwin-x64` | Published native CLI binary wrapper for macOS x64. |
Expand All @@ -140,7 +138,7 @@ pnpm run fix:all # run all fixers across every project

### Standard package scripts

Standard TypeScript workspaces (`apps/cli-e2e`, `apps/cli`, `packages/api`, `packages/cli-test-helpers`, `packages/config`, `packages/process-compose`, `packages/stack`) declare their package scripts explicitly. Test suites vary by package: unit tests are standard, while integration and e2e tests exist only where applicable.
Standard TypeScript workspaces (`apps/cli-e2e`, `apps/cli`, `packages/api`, `packages/cli-test-helpers`, `packages/config`, `packages/stack`) declare their package scripts explicitly. Test suites vary by package: unit tests are standard, while integration and e2e tests exist only where applicable.

| Script | What it does |
| ------------------ | -------------------------------------- |
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ export class LegacyThingMissingError extends Data.TaggedError("LegacyThingMissin
- **An instance-dependent getter must stay valid when its fields are absent** — the drift guard evaluates it against a field-less probe.
- **A plain `Error` subclass (no `_tag`) also declares its fingerprint identifier**: `static readonly [ErrorActionabilityFingerprintId] = "<ExportName>"`, matching the export name exactly. Tagged errors skip this — their fingerprint comes from the tag. The static identifier is what keeps `error:` fingerprints stable in minified release builds, where `constructor.name` is renamed.

**Errors defined outside `apps/cli/src`** (`@supabase/stack`, `@supabase/config`, `@supabase/process-compose`, `@supabase/api`, `effect`) cannot carry a declaration. Add a structural adapter keyed by `_tag` to `externalActionabilityByTag` in that same module, branching on the producer's typed fields.
**Errors defined outside `apps/cli/src`** (`@supabase/stack`, `@supabase/config`, `@supabase/api`, `effect`) cannot carry a declaration. Add a structural adapter keyed by `_tag` to `externalActionabilityByTag` in that same module, branching on the producer's typed fields.

`error-actionability-coverage.unit.test.ts` enforces this. It scans every `TaggedError("Tag")`, every `*Error("Tag")` factory, and every `class X extends Error` under `apps/cli/src`, and fails when a class is unexported, has no own declaration, or is untagged without its matching static fingerprint identifier. A failure there is the guard working: classify the new error rather than loosening the guard, because `unknown` in production telemetry must mean a genuinely unforeseen failure, not one nobody categorized.

Expand Down
75 changes: 75 additions & 0 deletions apps/cli/scripts/build-binary.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { spawn } from "node:child_process";
import { once } from "node:events";
import { NATIVE_PROCESS_DISPATCH_SENTINEL } from "@supabase/stack/internal/supervisor";

const fixturePath = fileURLToPath(
new URL("../tests/fixtures/compiled-libpg-query.ts", import.meta.url),
);
const versionFixturePath = fileURLToPath(
new URL("../tests/fixtures/compiled-cli-version.ts", import.meta.url),
);
const nativeDispatchFixturePath = fileURLToPath(
new URL("../tests/fixtures/compiled-native-dispatch.ts", import.meta.url),
);
const temporaryDirectories: string[] = [];

afterEach(async () => {
Expand Down Expand Up @@ -95,4 +101,73 @@ describe("compiled binary assets", () => {
expect(probeExitCode, stderr).toBe(0);
expect(stdout.trim()).toBe("7.8.9-beta.1");
}, 20_000);

test("dispatches the embedded native launcher from a compiled binary", async () => {
const directory = await mkdtemp(path.join(tmpdir(), "supabase-compiled-native-"));
temporaryDirectories.push(directory);
const executable = path.join(directory, "native-dispatch-probe");
const reap = async (child: ReturnType<typeof spawn> | undefined): Promise<void> => {
if (child === undefined || child.exitCode !== null || child.signalCode !== null) return;
await new Promise<void>((resolve) => {
const done = () => {
child.off("exit", done);
child.off("error", done);
resolve();
};
child.once("exit", done);
child.once("error", done);
child.kill("SIGKILL");
});
};

let build: ReturnType<typeof spawn> | undefined;
let child: ReturnType<typeof spawn> | undefined;
let buildStderr: Promise<string> | undefined;
let stdout: Promise<string> | undefined;
let stderr: Promise<string> | undefined;
try {
build = spawn(
"bun",
["build", nativeDispatchFixturePath, "--compile", `--outfile=${executable}`],
{ stdio: ["ignore", "pipe", "pipe"] },
);
buildStderr = new Response(build.stderr!).text();
const [buildExitCode] = (await once(build, "exit")) as [number | null, NodeJS.Signals | null];
expect(buildExitCode, await buildStderr).toBe(0);

child = spawn(executable, [NATIVE_PROCESS_DISPATCH_SENTINEL], {
cwd: directory,
env: {},
stdio: ["ignore", "pipe", "pipe", "pipe", "pipe"],
});
stdout = new Response(child.stdout!).text();
stderr = new Response(child.stderr!).text();
const payload = JSON.stringify({
executable: process.execPath,
args: ["-e", "process.stdout.write('native launcher dispatch ok\\n')"],
});
const payloadFd = child.stdio[4];
if (
payloadFd == null ||
typeof payloadFd === "number" ||
!("end" in payloadFd) ||
typeof payloadFd.end !== "function"
) {
throw new Error("compiled native dispatch probe did not expose payload fd");
}
payloadFd.end(payload);
const [exitCode] = (await once(child, "exit")) as [number | null, NodeJS.Signals | null];

expect(exitCode, await stderr).toBe(0);
expect((await stdout).trim()).toBe("native launcher dispatch ok");
} finally {
await reap(child);
await reap(build);
await Promise.all([
buildStderr?.catch(() => ""),
stdout?.catch(() => ""),
stderr?.catch(() => ""),
]);
}
}, 30_000);
});
4 changes: 1 addition & 3 deletions apps/cli/src/legacy/commands/config/pull/pull.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ const config = {

export type LegacyConfigPullFlags = CliCommand.Command.Config.Infer<typeof config>;

// Exported so integration tests can drive the exact wiring
// `Command.withHandler` uses below (same precedent as `legacyConfigDiffHandler`).
export const legacyConfigPullHandler = (flags: LegacyConfigPullFlags) =>
const legacyConfigPullHandler = (flags: LegacyConfigPullFlags) =>
legacyConfigPull(flags).pipe(
// `--project-ref` accepts branch names here (CLI-2167 vocabulary), so its
// value is only safe to log verbatim when it is actually ref-shaped — a
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/src/legacy/commands/config/pull/pull.format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const LEGACY_CONFIG_PULL_PAYLOAD_VERSION = 1;
* change `legacyPlanConfigPull` planned to write still ends up unwritten when
* the run is a dry run or the user declined.
*/
export type LegacyConfigPullChangeSkipReason = LegacyConfigPullSkipReason | "declined" | "dry_run";
type LegacyConfigPullChangeSkipReason = LegacyConfigPullSkipReason | "declined" | "dry_run";

/**
* The run's actual outcome, known only after the confirmation prompt (or
Expand Down
6 changes: 3 additions & 3 deletions apps/cli/src/legacy/commands/config/pull/pull.plan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,20 @@ export type LegacyConfigPullSkipReason =
| "unwritable"
| "would_invalidate";

export interface LegacyConfigPullSkip {
interface LegacyConfigPullSkip {
readonly change: ConfigChange;
readonly reason: LegacyConfigPullSkipReason;
}

export interface LegacyConfigPullPlannedWrite {
interface LegacyConfigPullPlannedWrite {
readonly change: ConfigChange;
/** `change.path`, prefixed with `["remotes", label]` when the destination
* is a `[remotes.*]` block — the exact path `applyConfigEdits` edits. */
readonly documentPath: ReadonlyArray<string>;
readonly value: ConfigEditValue;
}

export type LegacyConfigPullWarningKind =
type LegacyConfigPullWarningKind =
| "dual_scope"
| "duplicates_root"
| "array_drift"
Expand Down
8 changes: 4 additions & 4 deletions apps/cli/src/legacy/commands/config/pull/pull.scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ import { legacySanitizeInlineName } from "../../../shared/legacy-http-errors.ts"
* 5. Otherwise: the config root.
*/

export interface LegacyConfigPullDestinationRoot {
interface LegacyConfigPullDestinationRoot {
readonly kind: "root";
}

export interface LegacyConfigPullDestinationRemote {
interface LegacyConfigPullDestinationRemote {
readonly kind: "remote";
/**
* The `[remotes.<label>]` block's name — sanitized (control-char
Expand All @@ -62,7 +62,7 @@ export type LegacyConfigPullDestination =
| LegacyConfigPullDestinationRoot
| LegacyConfigPullDestinationRemote;

export interface LegacyConfigPullScopeOk {
interface LegacyConfigPullScopeOk {
readonly ok: true;
readonly destination: LegacyConfigPullDestination;
}
Expand Down Expand Up @@ -111,7 +111,7 @@ export interface LegacyConfigPullScopeLabelCollision {
* itself would never select for a read; rewriting the block's `project_id`
* would erase the user's env-var indirection).
*/
export interface LegacyConfigPullScopeEnvProjectId {
interface LegacyConfigPullScopeEnvProjectId {
readonly ok: false;
readonly reason: "env_project_id";
readonly label: string;
Expand Down
4 changes: 2 additions & 2 deletions apps/cli/src/legacy/commands/config/push/push.format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export interface LegacyPushUnencodable {
}

/** A template/notification body this encoder sent that has no registry row of its own. */
export interface LegacyPushExtra {
interface LegacyPushExtra {
readonly path: ReadonlyArray<string>;
readonly label: "content";
}
Expand Down Expand Up @@ -306,7 +306,7 @@ export function legacyPushNotes(input: LegacyPushNotesInput): string {
return lines.length === 0 ? "" : `${lines.join("\n")}\n`;
}

export interface LegacyPushPayloadServiceResult {
interface LegacyPushPayloadServiceResult {
readonly service: string;
readonly status: string;
readonly changes: ReadonlyArray<ReadonlyArray<string>>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { LegacyPgDeltaRemovalSummary } from "../../shared/legacy-pgdelta-en
/** Extensions that legacy pg-delta treated as part of its implicit Supabase baseline. */
const LEGACY_IMPLICIT_EXTENSIONS = ["pg_net", "pgcrypto", "uuid-ossp"] as const;

export type LegacyDeclarativeImplicitExtension = (typeof LEGACY_IMPLICIT_EXTENSIONS)[number];
type LegacyDeclarativeImplicitExtension = (typeof LEGACY_IMPLICIT_EXTENSIONS)[number];

export interface LegacyDeclarativeLoadDiagnostic {
readonly code: string;
Expand Down Expand Up @@ -294,7 +294,7 @@ function schemaArguments(schema: ReadonlyArray<string>, platform: LegacyShellPla
.join("");
}

export const legacyFormatDeclarativeSyncCommand = (
const legacyFormatDeclarativeSyncCommand = (
schema: ReadonlyArray<string>,
platform: LegacyShellPlatform,
): string =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { legacyWalkSqlFiles } from "../../../../shared/legacy-glob.ts";
/** The default declarative directory before it moved to `supabase/schemas`. */
const FORMER_DEFAULT_SEGMENTS = ["supabase", "database"] as const;

export const legacyFormerDeclarativeDefaultWarning = (
const legacyFormerDeclarativeDefaultWarning = (
formerDirRel: string,
defaultDirRel: string,
): string =>
Expand Down
Loading
Loading