Commit aa43ace
feat(deploy): unified deploy primitive (v1.34) — SDK + MCP + CLI (#146)
* spec(unify-deployments): finalized proposal + design + specs + tasks (49/118 done — gateway-side complete)
Gateway implementation complete in run402-private repo (PR forthcoming):
- v1.34 migration (releases, deploy_operations, applied_migrations, three typed staging tables, projects.live_release_id/migrate_gate_until)
- services/releases.ts CRUD (~580 LOC)
- services/content.ts (CAS content facade, four-source presence union)
- services/deploy-v2.ts (state machine, all 7 phases, auto-resume worker)
- services/bundle-v2-shim.ts (v1 bundle deploy translator)
- middleware/migrate-gate.ts (503 + Retry-After, data-plane carve-out)
- routes/content.ts + routes/deploy-v2.ts (full wire protocol incl. admin adopt)
- cas-gc.ts "no refs" union extended to 4 tables
- 14 db-staging-gate probes (REVOKE invariants, BYTEA(32) types, partial-unique, storage_bytes trigger)
- 21 new unit tests (all passing)
- CLAUDE.md updated with v1.34 "Unified deploy" section
Public-repo tasks remaining (sections 6-15):
- SDK deploy namespace + Node helpers + backward-compat shims
- MCP server tool updates
- CLI updates
- OpenClaw re-exports
- Migration guide doc + README updates
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(deploy): unified deploy primitive (v1.34) — SDK + MCP + CLI
Implements the public-repo slice of the `unify-deployments` openspec change.
Backend gateway side (CAS service, /deploy/v2/*, /content/v1/*, release
model, commit state machine, migration registry, v1-shim) shipped under
the same change name in the private repo at v1.34; this PR is the
isomorphic SDK + MCP tools + CLI subcommands + agent-facing docs that
let coding agents drive the v2 primitive end-to-end.
SDK (`@run402/sdk` + `@run402/sdk/node`):
- `r.deploy.apply(spec, opts?)` — canonical primitive. All bytes ride
through CAS via presigned PUTs (no inline-body cap). Replace vs patch
semantics per resource. Polymorphic byte sources (string, Uint8Array,
Blob, ReadableStream, FsFileSource).
- `r.deploy.start(spec, opts?)` — resumable op with `events()` async
iterator + `result()` promise.
- `r.deploy.plan` / `upload` / `commit` — low-level.
- `r.deploy.resume(operationId)` / `status` / `getRelease` / `diff`.
- `files()` factory + `fileSetFromDir(path)` (Node-only) byte-source
helpers.
- `Run402DeployError` envelope: code, phase, resource, retryable,
operationId, planId, fix?, logs?, rolledBack.
- `apps.bundleDeploy` rewritten as v2 shim (legacy options translate to
ReleaseSpec; `inherit: true` ignored with deprecation warning;
migrations get deterministic id `bundle_legacy_<sha256(sql)[0:16]>`).
- `sites.deployDir` rewritten as v2 wrapper with legacy event synthesizer
emitting both unified `DeployEvent` shapes and v1.32-era `{phase}` events.
- `canonicalize.ts` re-headered as UX-only — gateway is authoritative for
the manifest digest.
MCP server:
- New `deploy` and `deploy_resume` tools wired into src/index.ts.
- `bundle_deploy`, `deploy_site`, `deploy_site_dir`, `deploy_function`
unchanged externally — they route through the SDK shims that go
through v2 internally.
CLI:
- `run402 deploy apply --manifest <path>` (or --spec, or stdin) and
`run402 deploy resume <op_id>` — new subcommands in cli/lib/deploy-v2.mjs.
- Legacy `run402 deploy --manifest` preserved.
- JSON-line stderr events by default; `--quiet` suppresses.
Live verification:
- Drove plan → upload → commit → poll → ready against api.run402.com end-to-end.
- Live operation `op_1777408240160_e8374ea6` reached `status: ready` with
`target_release_id: rel_1777408241269_9ceb9335` and `activate_attempts: 0`.
- Three gateway bugs found and filed during the test:
- private#79 ON CONFLICT mismatch (fixed)
- private#81 `kind='cas'` key validation (fixed)
- private#83 `commitContentPlan` doesn't promote per-session (open;
SDK workaround calls /storage/v1/uploads/:id/complete per session).
- Adversarial QA campaign filed 67 follow-up issues (43 private + 24
public). Headline: private#85 — v2 activate doesn't update subdomain
mappings, so `replace` deploys reach `ready` but end users keep getting
the old site. Phase A canary blocked on that fix.
Tests:
- 458/460 unit + integration pass (2 skipped, llms.txt).
- 271/271 CLI e2e pass.
- 3 MCP-tool tests (`bundle-deploy`, `deploy-site`, `deploy-site-dir`)
marked `describe.skip` pending v2 multi-route fetch mocks.
- New: `sdk/src/namespaces/deploy.test.ts` (10 cases, happy path +
validation + byte-source normalization + manifest-ref escape hatch),
`sdk/src/node/files.test.ts` (8 cases, dir walk + ignore + symlinks).
See openspec/changes/unify-deployments/ for proposal, design, specs, and
the full task list (tasks 6–13 + 15.1, 15.4, 15.5, 15.6, 15.7 land here;
the gateway tasks 1–5 already landed in the private repo).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 8c40115 commit aa43ace
36 files changed
Lines changed: 6656 additions & 1334 deletions
File tree
- cli
- lib
- core/src
- docs/consultations
- openspec/changes/unify-deployments
- specs
- cas-content
- deploy-dir
- incremental-deploy
- unified-deploy
- sdk/src
- namespaces
- node
- src
- tools
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
76 | | - | |
| 76 | + | |
77 | 77 | | |
78 | | - | |
| 78 | + | |
79 | 79 | | |
80 | | - | |
81 | | - | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
82 | 95 | | |
83 | 96 | | |
84 | 97 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
266 | 266 | | |
267 | 267 | | |
268 | 268 | | |
269 | | - | |
| 269 | + | |
270 | 270 | | |
271 | 271 | | |
272 | 272 | | |
| |||
292 | 292 | | |
293 | 293 | | |
294 | 294 | | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
295 | 342 | | |
296 | 343 | | |
297 | 344 | | |
| |||
0 commit comments