codebyplan 1.5.1 → 1.9.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/cli.js +4462 -748
- package/package.json +5 -1
- package/templates/.gitkeep +0 -0
- package/templates/README.md +20 -0
- package/templates/agents/cbp-cc-executor.md +213 -0
- package/templates/agents/cbp-database-agent.md +229 -0
- package/templates/agents/cbp-improve-claude.md +245 -0
- package/templates/agents/cbp-improve-round.md +284 -0
- package/templates/agents/cbp-mechanical-edits.md +111 -0
- package/templates/agents/cbp-research.md +282 -0
- package/templates/agents/cbp-round-executor.md +604 -0
- package/templates/agents/cbp-security-agent.md +134 -0
- package/templates/agents/cbp-task-check.md +213 -0
- package/templates/agents/cbp-task-planner.md +582 -0
- package/templates/agents/cbp-test-e2e-agent.md +363 -0
- package/templates/agents/cbp-testing-qa-agent.md +400 -0
- package/templates/context/mcp-docs.md +139 -0
- package/templates/hooks/README.md +236 -0
- package/templates/hooks/cbp-auto-test-hooks.sh +44 -0
- package/templates/hooks/cbp-lint-format-on-edit.sh +159 -0
- package/templates/hooks/cbp-maestro-yaml-validate.sh +100 -0
- package/templates/hooks/cbp-mcp-migration-guard.sh +32 -0
- package/templates/hooks/cbp-mcp-round-sync.sh +79 -0
- package/templates/hooks/cbp-mcp-worktree-inject.sh +76 -0
- package/templates/hooks/cbp-notify.sh +68 -0
- package/templates/hooks/cbp-plugin-dispatch.sh +29 -0
- package/templates/hooks/cbp-pre-commit-quality-gate.sh +204 -0
- package/templates/hooks/cbp-statusline.sh +347 -0
- package/templates/hooks/cbp-subagent-statusline.sh +182 -0
- package/templates/hooks/cbp-test-coverage-gate.sh +144 -0
- package/templates/hooks/cbp-test-hooks.sh +320 -0
- package/templates/hooks/hooks.json +85 -0
- package/templates/hooks/validate-context-usage.sh +59 -0
- package/templates/hooks/validate-git-commit.sh +78 -0
- package/templates/hooks/validate-git-stash-deny.sh +32 -0
- package/templates/hooks/validate-structure-lengths.sh +57 -0
- package/templates/hooks/validate-structure-lib.sh +104 -0
- package/templates/hooks/validate-structure-patterns.sh +54 -0
- package/templates/hooks/validate-structure-scope.sh +33 -0
- package/templates/hooks/validate-structure-smoke.sh +95 -0
- package/templates/hooks/validate-structure-templates.sh +34 -0
- package/templates/hooks/validate-structure.sh +69 -0
- package/templates/rules/.gitkeep +0 -0
- package/templates/rules/README.md +47 -0
- package/templates/rules/context-file-loading.md +52 -0
- package/templates/rules/scope-vocabulary.md +64 -0
- package/templates/rules/todo-backend.md +109 -0
- package/templates/settings.project.base.json +55 -0
- package/templates/settings.user.base.json +25 -0
- package/templates/skills/cbp-build-cc-agent/SKILL.md +139 -0
- package/templates/skills/cbp-build-cc-agent/examples/read-only-reviewer.md +32 -0
- package/templates/skills/cbp-build-cc-agent/examples/with-hooks.md +41 -0
- package/templates/skills/cbp-build-cc-agent/examples/with-skills-preload.md +25 -0
- package/templates/skills/cbp-build-cc-agent/reference/cbp-quality.md +153 -0
- package/templates/skills/cbp-build-cc-agent/reference/frontmatter-fields.md +37 -0
- package/templates/skills/cbp-build-cc-agent/reference/permission-modes.md +18 -0
- package/templates/skills/cbp-build-cc-agent/scripts/validate-agent.sh +67 -0
- package/templates/skills/cbp-build-cc-agent/templates/agent.md +66 -0
- package/templates/skills/cbp-build-cc-claude-file/SKILL.md +178 -0
- package/templates/skills/cbp-build-cc-claude-file/examples/minimal-project.md +33 -0
- package/templates/skills/cbp-build-cc-claude-file/examples/monorepo-with-imports.md +39 -0
- package/templates/skills/cbp-build-cc-claude-file/reference/imports.md +72 -0
- package/templates/skills/cbp-build-cc-claude-file/reference/what-belongs.md +39 -0
- package/templates/skills/cbp-build-cc-claude-file/templates/project-claude-md.md +48 -0
- package/templates/skills/cbp-build-cc-claude-file/templates/user-claude-md.md +22 -0
- package/templates/skills/cbp-build-cc-memory/SKILL.md +201 -0
- package/templates/skills/cbp-build-cc-memory/examples/feedback-memory.md +11 -0
- package/templates/skills/cbp-build-cc-memory/examples/project-memory.md +11 -0
- package/templates/skills/cbp-build-cc-memory/examples/reference-memory.md +13 -0
- package/templates/skills/cbp-build-cc-memory/examples/user-memory.md +14 -0
- package/templates/skills/cbp-build-cc-memory/reference/memory-types.md +59 -0
- package/templates/skills/cbp-build-cc-memory/reference/when-to-save.md +62 -0
- package/templates/skills/cbp-build-cc-memory/templates/MEMORY-index.md +4 -0
- package/templates/skills/cbp-build-cc-memory/templates/memory-entry.md +15 -0
- package/templates/skills/cbp-build-cc-mode/SKILL.md +99 -0
- package/templates/skills/cbp-build-cc-rule/SKILL.md +176 -0
- package/templates/skills/cbp-build-cc-rule/examples/global-rule.md +19 -0
- package/templates/skills/cbp-build-cc-rule/examples/scoped-rule.md +41 -0
- package/templates/skills/cbp-build-cc-rule/reference/paths-patterns.md +48 -0
- package/templates/skills/cbp-build-cc-rule/templates/rule.md +32 -0
- package/templates/skills/cbp-build-cc-settings/SKILL.md +220 -0
- package/templates/skills/cbp-build-cc-settings/examples/hooks-config.json +64 -0
- package/templates/skills/cbp-build-cc-settings/examples/permissions-config.json +34 -0
- package/templates/skills/cbp-build-cc-settings/examples/sandbox-config.json +42 -0
- package/templates/skills/cbp-build-cc-settings/reference/cbp-conventions.md +104 -0
- package/templates/skills/cbp-build-cc-settings/reference/permission-rules.md +61 -0
- package/templates/skills/cbp-build-cc-settings/reference/scope-precedence.md +73 -0
- package/templates/skills/cbp-build-cc-settings/reference/settings-fields.md +166 -0
- package/templates/skills/cbp-build-cc-settings/templates/settings.json +23 -0
- package/templates/skills/cbp-build-cc-settings/templates/settings.local.json +10 -0
- package/templates/skills/cbp-build-cc-skill/SKILL.md +154 -0
- package/templates/skills/cbp-build-cc-skill/examples/dynamic-context.md +31 -0
- package/templates/skills/cbp-build-cc-skill/examples/fork-skill.md +22 -0
- package/templates/skills/cbp-build-cc-skill/examples/knowledge-skill.md +25 -0
- package/templates/skills/cbp-build-cc-skill/examples/task-skill.md +29 -0
- package/templates/skills/cbp-build-cc-skill/reference/cbp-quality.md +157 -0
- package/templates/skills/cbp-build-cc-skill/reference/frontmatter-fields.md +35 -0
- package/templates/skills/cbp-build-cc-skill/reference/string-substitutions.md +60 -0
- package/templates/skills/cbp-build-cc-skill/scripts/validate-skill.sh +90 -0
- package/templates/skills/cbp-build-cc-skill/templates/skill.md +51 -0
- package/templates/skills/cbp-checkpoint-check/SKILL.md +156 -0
- package/templates/skills/cbp-checkpoint-complete/SKILL.md +109 -0
- package/templates/skills/cbp-checkpoint-create/SKILL.md +116 -0
- package/templates/skills/cbp-checkpoint-end/SKILL.md +241 -0
- package/templates/skills/cbp-checkpoint-plan/SKILL.md +137 -0
- package/templates/skills/cbp-checkpoint-plan/reference/alternative-comparison-template.md +54 -0
- package/templates/skills/cbp-checkpoint-plan/reference/dep-decision-rubric.md +50 -0
- package/templates/skills/cbp-checkpoint-plan/reference/e2e-discovery-probe.md +57 -0
- package/templates/skills/cbp-checkpoint-plan/reference/gap-analysis-playbook.md +47 -0
- package/templates/skills/cbp-checkpoint-start/SKILL.md +84 -0
- package/templates/skills/cbp-checkpoint-update/SKILL.md +115 -0
- package/templates/skills/cbp-frontend-a11y/SKILL.md +109 -0
- package/templates/skills/cbp-frontend-a11y/reference/aria-roles-states.md +130 -0
- package/templates/skills/cbp-frontend-a11y/reference/contrast-visual.md +122 -0
- package/templates/skills/cbp-frontend-a11y/reference/keyboard-patterns.md +154 -0
- package/templates/skills/cbp-frontend-a11y/reference/semantic-html.md +111 -0
- package/templates/skills/cbp-frontend-design/SKILL.md +145 -0
- package/templates/skills/cbp-frontend-design/reference/nextjs-scss.md +118 -0
- package/templates/skills/cbp-frontend-design/reference/rn-expo.md +101 -0
- package/templates/skills/cbp-frontend-design/reference/tauri-react.md +82 -0
- package/templates/skills/cbp-frontend-ui/SKILL.md +262 -0
- package/templates/skills/cbp-frontend-ui/reference/ui-label-maps.md +42 -0
- package/templates/skills/cbp-frontend-ui/reference/ui-layout-patterns.md +105 -0
- package/templates/skills/cbp-frontend-ui/reference/variant-defaults.md +149 -0
- package/templates/skills/cbp-frontend-ux/SKILL.md +181 -0
- package/templates/skills/cbp-git-branch-feat-create/SKILL.md +115 -0
- package/templates/skills/cbp-git-commit/SKILL.md +278 -0
- package/templates/skills/cbp-git-worktree-create/SKILL.md +226 -0
- package/templates/skills/cbp-git-worktree-remove/SKILL.md +145 -0
- package/templates/skills/cbp-merge-main/SKILL.md +228 -0
- package/templates/skills/cbp-round-check/SKILL.md +104 -0
- package/templates/skills/cbp-round-end/SKILL.md +183 -0
- package/templates/skills/cbp-round-end/reference/findings-presentation.md +44 -0
- package/templates/skills/cbp-round-end/reference/inline-fallback.md +35 -0
- package/templates/skills/cbp-round-execute/SKILL.md +211 -0
- package/templates/skills/cbp-round-execute/reference/inline-fallback.md +59 -0
- package/templates/skills/cbp-round-input/SKILL.md +165 -0
- package/templates/skills/cbp-round-start/SKILL.md +222 -0
- package/templates/skills/cbp-round-update/SKILL.md +163 -0
- package/templates/skills/cbp-session-end/SKILL.md +187 -0
- package/templates/skills/cbp-session-start/SKILL.md +155 -0
- package/templates/skills/cbp-ship/SKILL.md +332 -0
- package/templates/skills/cbp-ship/reference/changesets-overview.md +120 -0
- package/templates/skills/cbp-ship/reference/eas-cli-overview.md +60 -0
- package/templates/skills/cbp-ship/reference/gh-cli-overview.md +135 -0
- package/templates/skills/cbp-ship/reference/gh-cli-shipment-commands.md +283 -0
- package/templates/skills/cbp-ship/reference/npm-publish-monorepo.md +252 -0
- package/templates/skills/cbp-ship/reference/npm-publish-oidc-trusted.md +157 -0
- package/templates/skills/cbp-ship/reference/npm-publish-overview.md +171 -0
- package/templates/skills/cbp-ship/reference/preflight-checklist.md +88 -0
- package/templates/skills/cbp-ship/reference/railway-nestjs-deployment.md +169 -0
- package/templates/skills/cbp-ship/reference/railway-overview.md +120 -0
- package/templates/skills/cbp-ship/reference/railway-troubleshooting.md +168 -0
- package/templates/skills/cbp-ship/reference/release-please-overview.md +99 -0
- package/templates/skills/cbp-ship/reference/surface-expo-eas.md +155 -0
- package/templates/skills/cbp-ship/reference/surface-npm.md +180 -0
- package/templates/skills/cbp-ship/reference/surface-railway.md +152 -0
- package/templates/skills/cbp-ship/reference/surface-supabase.md +178 -0
- package/templates/skills/cbp-ship/reference/surface-tauri.md +138 -0
- package/templates/skills/cbp-ship/reference/surface-vercel.md +124 -0
- package/templates/skills/cbp-ship/reference/surface-vscode-ext.md +144 -0
- package/templates/skills/cbp-ship/reference/surfaces.md +60 -0
- package/templates/skills/cbp-ship/reference/testflight-automation.md +215 -0
- package/templates/skills/cbp-ship/reference/testflight-internal-vs-external.md +69 -0
- package/templates/skills/cbp-ship/reference/testflight-overview.md +98 -0
- package/templates/skills/cbp-ship/reference/versioning.md +116 -0
- package/templates/skills/cbp-ship/scripts/detect-surfaces.sh +217 -0
- package/templates/skills/cbp-ship/scripts/verify-expo-eas.sh +35 -0
- package/templates/skills/cbp-ship/scripts/verify-npm.sh +21 -0
- package/templates/skills/cbp-ship/scripts/verify-railway.sh +41 -0
- package/templates/skills/cbp-ship/scripts/verify-supabase.sh +19 -0
- package/templates/skills/cbp-ship/scripts/verify-tauri.sh +24 -0
- package/templates/skills/cbp-ship/scripts/verify-vercel.sh +32 -0
- package/templates/skills/cbp-ship/scripts/verify-vscode-ext.sh +25 -0
- package/templates/skills/cbp-ship/templates/eas.json +66 -0
- package/templates/skills/cbp-ship/templates/railway.toml +15 -0
- package/templates/skills/cbp-ship/templates/release-please-config.json +17 -0
- package/templates/skills/cbp-ship/templates/vercel.json +19 -0
- package/templates/skills/cbp-ship/templates/vscodeignore +21 -0
- package/templates/skills/cbp-ship/templates/workflow-changesets.yml +41 -0
- package/templates/skills/cbp-ship/templates/workflow-eas-submit.yml +53 -0
- package/templates/skills/cbp-ship/templates/workflow-npm-publish.yml +36 -0
- package/templates/skills/cbp-ship/templates/workflow-release-please.yml +21 -0
- package/templates/skills/cbp-ship/templates/workflow-tauri-release.yml +69 -0
- package/templates/skills/cbp-ship/templates/workflow-vsce-publish.yml +31 -0
- package/templates/skills/cbp-ship-configure/SKILL.md +296 -0
- package/templates/skills/cbp-ship-configure/reference/expo-mobile.md +204 -0
- package/templates/skills/cbp-ship-configure/reference/npm-package.md +165 -0
- package/templates/skills/cbp-ship-configure/reference/railway-backend.md +199 -0
- package/templates/skills/cbp-ship-configure/reference/supabase.md +200 -0
- package/templates/skills/cbp-ship-configure/reference/tauri-desktop.md +181 -0
- package/templates/skills/cbp-ship-configure/reference/vercel.md +117 -0
- package/templates/skills/cbp-ship-configure/reference/vscode-ext.md +155 -0
- package/templates/skills/cbp-ship-main/SKILL.md +65 -0
- package/templates/skills/cbp-supabase-branch-check/SKILL.md +337 -0
- package/templates/skills/cbp-supabase-branch-check/reference/dag-steps.md +29 -0
- package/templates/skills/cbp-supabase-migrate/SKILL.md +314 -0
- package/templates/skills/cbp-supabase-migrate/reference/advisor-triage.md +70 -0
- package/templates/skills/cbp-supabase-migrate/reference/cli-fallback.md +87 -0
- package/templates/skills/cbp-supabase-migrate/reference/preflight-dry-run.md +58 -0
- package/templates/skills/cbp-supabase-setup/SKILL.md +239 -0
- package/templates/skills/cbp-supabase-setup/reference/branching-setup.md +121 -0
- package/templates/skills/cbp-supabase-setup/reference/cli-fallback.md +109 -0
- package/templates/skills/cbp-task-check/SKILL.md +166 -0
- package/templates/skills/cbp-task-complete/SKILL.md +206 -0
- package/templates/skills/cbp-task-complete/reference/checkpoint-done-branching.md +48 -0
- package/templates/skills/cbp-task-complete/reference/next-step-heuristic.md +56 -0
- package/templates/skills/cbp-task-create/SKILL.md +167 -0
- package/templates/skills/cbp-task-start/SKILL.md +239 -0
- package/templates/skills/cbp-task-testing/SKILL.md +277 -0
- package/templates/skills/cbp-todo/SKILL.md +111 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Surface: railway-backend
|
|
2
|
+
|
|
3
|
+
Deploy a backend service (NestJS / Node / Bun / Python) to Railway.
|
|
4
|
+
|
|
5
|
+
Railway is the standard backend platform for the CBP family (per architectural decision 2026-04-29). Other Docker-friendly platforms (Fly, Render, Heroku) can be added as separate surfaces if needed — Railway is the default.
|
|
6
|
+
|
|
7
|
+
## Detection
|
|
8
|
+
|
|
9
|
+
Signals (any of):
|
|
10
|
+
|
|
11
|
+
- `railway.toml` or `railway.json` at app root
|
|
12
|
+
- `.railway/` directory at app root
|
|
13
|
+
- `Dockerfile` AND `package.json` with non-frontend deps (no `next`, no `react-native`) AND not under workspace `packages/`
|
|
14
|
+
|
|
15
|
+
## Configured indicators
|
|
16
|
+
|
|
17
|
+
`configured: true` requires:
|
|
18
|
+
|
|
19
|
+
1. `railway.toml` or `.railway/config.json` present with `project` ID
|
|
20
|
+
2. `railway` CLI installed (`railway --version` succeeds)
|
|
21
|
+
3. `railway whoami` returns a logged-in user
|
|
22
|
+
4. `.codebyplan/shipment.json` `.surfaces.railway-backend` block has `project_id` AND `service_id` AND `environment_id`
|
|
23
|
+
|
|
24
|
+
## Variants
|
|
25
|
+
|
|
26
|
+
| Variant | When |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `deploy` | Service code or Dockerfile changed since last shipment |
|
|
29
|
+
| `skip` | No backend changes |
|
|
30
|
+
|
|
31
|
+
Detection uses git diff: if any path under the service directory changed between the prior shipment SHA and the current ship SHA, mark `deploy`.
|
|
32
|
+
|
|
33
|
+
## STEPS — deploy variant
|
|
34
|
+
|
|
35
|
+
Railway has two deployment modes:
|
|
36
|
+
|
|
37
|
+
- **Auto-deploy on push** — preferred. Linked to a GH branch; pushes trigger deploys via webhook.
|
|
38
|
+
- **Manual `railway up`** — fallback when GH integration isn't desired.
|
|
39
|
+
|
|
40
|
+
Detection: `railway service --json | jq .repoConfig` — if non-null, it's auto-deploy. Otherwise manual.
|
|
41
|
+
|
|
42
|
+
### Auto-deploy mode
|
|
43
|
+
|
|
44
|
+
1. **Verify GH integration is healthy**:
|
|
45
|
+
```bash
|
|
46
|
+
railway service --json | jq -r .repoConfig.repoLink
|
|
47
|
+
# Should match the current repo
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
2. **Wait for the deploy webhook to fire** (up to 30s after PR merge):
|
|
51
|
+
```bash
|
|
52
|
+
timeout 60 bash -c "while ! railway logs --json 2>/dev/null | jq -e '.[0].timestamp > \"$(date -u -v-1M +%FT%T)\"'; do sleep 5; done"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
3. **Get the deployment ID**:
|
|
56
|
+
```bash
|
|
57
|
+
DEPLOY_ID=$(railway deployment list --json | jq -r '.[0].id')
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
4. **Wait for deployment SUCCESS state**:
|
|
61
|
+
```bash
|
|
62
|
+
timeout 600 bash -c "while [ \"\$(railway deployment status \"$DEPLOY_ID\" --json | jq -r .status)\" != \"SUCCESS\" ]; do
|
|
63
|
+
STATUS=\$(railway deployment status \"$DEPLOY_ID\" --json | jq -r .status)
|
|
64
|
+
[ \"\$STATUS\" = \"FAILED\" ] && exit 1
|
|
65
|
+
sleep 10
|
|
66
|
+
done"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
5. **Capture URL**:
|
|
70
|
+
```bash
|
|
71
|
+
URL=$(railway domain --json | jq -r '.[0].domain' | head -1)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Manual deploy mode
|
|
75
|
+
|
|
76
|
+
1. **Confirm with user**:
|
|
77
|
+
```
|
|
78
|
+
Railway is configured for manual deploy. Run: railway up
|
|
79
|
+
This builds locally + uploads + deploys (5-10 min).
|
|
80
|
+
A) Run `railway up` — start the deploy
|
|
81
|
+
B) Skip — deploy manually later
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
2. **Run the deploy**:
|
|
85
|
+
```bash
|
|
86
|
+
cd "$APP_PATH"
|
|
87
|
+
railway up --detach
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
3. **Steps 3-5 same as auto-deploy mode**.
|
|
91
|
+
|
|
92
|
+
## Verification
|
|
93
|
+
|
|
94
|
+
`scripts/verify-railway.sh`:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
DEPLOY_ID="$1"
|
|
98
|
+
URL="$2"
|
|
99
|
+
|
|
100
|
+
# Deployment status
|
|
101
|
+
STATUS=$(railway deployment status "$DEPLOY_ID" --json | jq -r .status)
|
|
102
|
+
[ "$STATUS" = "SUCCESS" ] || { echo "Deploy not successful: $STATUS"; exit 1; }
|
|
103
|
+
|
|
104
|
+
# Health endpoint (if configured)
|
|
105
|
+
if [ -n "$URL" ]; then
|
|
106
|
+
HEALTH=$(curl -sI -m 10 "https://$URL/health" 2>/dev/null | head -1 | awk '{print $2}')
|
|
107
|
+
[ "$HEALTH" = "200" ] || echo "WARN: /health returned $HEALTH (may not be implemented)"
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
echo "OK"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Common failures
|
|
114
|
+
|
|
115
|
+
| Symptom | Cause | Fix |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| Deploy fails at "Building" | Dockerfile build error | `railway logs --build` — usually missing system dep or wrong Node version |
|
|
118
|
+
| Deploy succeeds, app crashes on start | Missing env var | `railway variables` — compare to `.env.example` |
|
|
119
|
+
| Health endpoint times out | Service not listening on Railway's `$PORT` | Bind to `process.env.PORT` not hardcoded port |
|
|
120
|
+
| GH webhook not firing | Disconnect or branch filter mismatch | Railway dashboard → service → Settings → Source → reconnect |
|
|
121
|
+
| OOM during build | Large node_modules | Add `.dockerignore`; use multi-stage build |
|
|
122
|
+
|
|
123
|
+
## Rollback
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
railway redeploy <prior-deployment-id>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The orchestrator surfaces this when verification fails:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
Railway deployment FAILED.
|
|
133
|
+
Options:
|
|
134
|
+
A) Retry — sometimes transient
|
|
135
|
+
B) Rollback to deployment <prior-id> (last successful)
|
|
136
|
+
C) Investigate logs — railway logs --build / --runtime
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Multi-service projects
|
|
140
|
+
|
|
141
|
+
A Railway project can have multiple services (e.g., `api`, `worker`, `cron`). Each shipment surface is per-service. The detection emits one entry per service:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{ "id": "railway-backend", "instance": "apps/backend", "service_id": "svc_abc", ... }
|
|
145
|
+
{ "id": "railway-backend", "instance": "apps/worker", "service_id": "svc_def", ... }
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The orchestrator deploys each independently.
|
|
149
|
+
|
|
150
|
+
## Configure-once setup
|
|
151
|
+
|
|
152
|
+
See `${CLAUDE_PLUGIN_ROOT}/skills/ship-configure/reference/railway-backend.md` for first-time setup (railway login, project creation/link, env var sync, GH integration, custom domain, health endpoint config).
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Surface: supabase
|
|
2
|
+
|
|
3
|
+
Push pending database migrations to the linked Supabase project.
|
|
4
|
+
|
|
5
|
+
This is the most consequential shipment surface — schema mismatches break web/backend immediately. Migration push is **always interactive** with explicit user review of the diff before applying.
|
|
6
|
+
|
|
7
|
+
## Detection
|
|
8
|
+
|
|
9
|
+
Signals:
|
|
10
|
+
|
|
11
|
+
- `supabase/` directory with `config.toml`
|
|
12
|
+
- `supabase/migrations/*.sql` — count of files newer than `last_shipped_migration_version` in `.codebyplan/shipment.json` `.surfaces.supabase`
|
|
13
|
+
|
|
14
|
+
## Configured indicators
|
|
15
|
+
|
|
16
|
+
`configured: true` requires:
|
|
17
|
+
|
|
18
|
+
1. `supabase/config.toml` parseable with `project_id` field
|
|
19
|
+
2. `supabase` CLI installed (`supabase --version` succeeds)
|
|
20
|
+
3. `supabase projects list` succeeds (CLI authenticated)
|
|
21
|
+
4. `.codebyplan/shipment.json` `.surfaces.supabase` block has `project_ref`
|
|
22
|
+
|
|
23
|
+
Library docs via DocsByPlan MCP (`resolve_library_id('supabase')`).
|
|
24
|
+
|
|
25
|
+
## Variants
|
|
26
|
+
|
|
27
|
+
| Variant | When |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `push-migrations` | At least one migration file is newer than `last_shipped_migration_version` |
|
|
30
|
+
| `skip` | No new migrations |
|
|
31
|
+
|
|
32
|
+
## STEPS — push-migrations variant
|
|
33
|
+
|
|
34
|
+
This is **always interactive**. The orchestrator does NOT silently apply migrations even with confirmation up front, because the diff might surprise the user (auto-generated migrations sometimes include unintended changes).
|
|
35
|
+
|
|
36
|
+
1. **List pending migrations**:
|
|
37
|
+
```bash
|
|
38
|
+
PROJECT_REF=$(jq -r '.surfaces.supabase.project_ref' .codebyplan/shipment.json)
|
|
39
|
+
LAST_VERSION=$(jq -r '.surfaces.supabase.last_shipped_migration_version // ""' .codebyplan/shipment.json)
|
|
40
|
+
|
|
41
|
+
PENDING=$(ls supabase/migrations/*.sql | sort)
|
|
42
|
+
if [ -n "$LAST_VERSION" ]; then
|
|
43
|
+
PENDING=$(echo "$PENDING" | awk -v cutoff="$LAST_VERSION" '$0 > "supabase/migrations/" cutoff')
|
|
44
|
+
fi
|
|
45
|
+
echo "$PENDING"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
2. **Show user the migration list** + counts:
|
|
49
|
+
```
|
|
50
|
+
## Pending migrations (4)
|
|
51
|
+
|
|
52
|
+
- 0083_add_user_avatars.sql (12 lines)
|
|
53
|
+
- 0084_index_session_lookups.sql (4 lines)
|
|
54
|
+
- 0085_rls_share_links.sql (28 lines)
|
|
55
|
+
- 0086_view_active_users.sql (8 lines)
|
|
56
|
+
|
|
57
|
+
Press Enter to review each diff individually, or type 'all' to see them concatenated.
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
3. **Walk through each migration** via AskUserQuestion (one per file):
|
|
61
|
+
```
|
|
62
|
+
### 0083_add_user_avatars.sql
|
|
63
|
+
|
|
64
|
+
```sql
|
|
65
|
+
ALTER TABLE users ADD COLUMN avatar_url text;
|
|
66
|
+
CREATE INDEX users_avatar_url_idx ON users(avatar_url) WHERE avatar_url IS NOT NULL;
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Approve this migration?
|
|
70
|
+
A) Approve — include in push
|
|
71
|
+
B) Skip this one (manual review needed)
|
|
72
|
+
C) Abort — stop shipment, don't push anything
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The user reviews each file. If they pick C on any, halt — do NOT continue with subsequent surfaces.
|
|
76
|
+
|
|
77
|
+
4. **Generate diff against the live project** for safety:
|
|
78
|
+
```bash
|
|
79
|
+
supabase db diff --use-migra --schema public,auth
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
This compares local migrations to remote state. If the diff shows things NOT in the migrations (drift on the remote), HALT and surface to the user — remote drift means someone applied changes via the dashboard, and we shouldn't blindly push.
|
|
83
|
+
|
|
84
|
+
5. **Push approved migrations**:
|
|
85
|
+
```bash
|
|
86
|
+
supabase db push --include-all
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If push fails partway (e.g., migration 0084 errors), Supabase rolls back to the last successful migration. Surface the failure:
|
|
90
|
+
```
|
|
91
|
+
Migration push FAILED at 0084_index_session_lookups.sql
|
|
92
|
+
Reason: <error from supabase>
|
|
93
|
+
|
|
94
|
+
The migrations applied successfully:
|
|
95
|
+
✓ 0083_add_user_avatars.sql
|
|
96
|
+
|
|
97
|
+
The remaining migrations (0085, 0086) were NOT applied.
|
|
98
|
+
|
|
99
|
+
Options:
|
|
100
|
+
A) Fix migration 0084 in code, re-run /cbp-ship
|
|
101
|
+
B) Skip 0084 and proceed with 0085+0086 (use --include-files)
|
|
102
|
+
C) Abort — schema is partially-shipped; revert the applied migration manually if needed
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
6. **Regenerate TypeScript types** (if the project uses generated types):
|
|
106
|
+
```bash
|
|
107
|
+
if [ -f "supabase/functions/_shared/db.types.ts" ] || [ -f "packages/supabase/types.ts" ]; then
|
|
108
|
+
supabase gen types typescript --project-id "$PROJECT_REF" > "$TYPES_PATH"
|
|
109
|
+
# If diff exists, surface to user — types changes may need to be committed
|
|
110
|
+
if ! git diff --quiet "$TYPES_PATH"; then
|
|
111
|
+
echo "Types regenerated — diff present. Commit before completing checkpoint."
|
|
112
|
+
fi
|
|
113
|
+
fi
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
7. **Update the last-shipped marker**:
|
|
117
|
+
```bash
|
|
118
|
+
LAST_APPLIED=$(echo "$PENDING" | tail -1 | xargs basename)
|
|
119
|
+
jq --arg v "$LAST_APPLIED" '.surfaces.supabase.last_shipped_migration_version = $v' .codebyplan/shipment.json > .codebyplan/shipment.json.tmp
|
|
120
|
+
mv .codebyplan/shipment.json.tmp .codebyplan/shipment.json
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
8. **Result**:
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"status": "verified",
|
|
127
|
+
"migrations_applied": ["0083_...", "0084_...", "0085_...", "0086_..."],
|
|
128
|
+
"types_regenerated": true,
|
|
129
|
+
"project_ref": "abcdefgh"
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Verification
|
|
134
|
+
|
|
135
|
+
`scripts/verify-supabase.sh`:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
PROJECT_REF="$1"
|
|
139
|
+
EXPECTED_LAST="$2"
|
|
140
|
+
|
|
141
|
+
# All listed migrations are recorded in supabase_migrations table
|
|
142
|
+
APPLIED=$(supabase migration list --remote --linked 2>/dev/null | grep -F "$EXPECTED_LAST" | wc -l)
|
|
143
|
+
[ "$APPLIED" -gt 0 ] || { echo "Migration $EXPECTED_LAST not found on remote"; exit 1; }
|
|
144
|
+
|
|
145
|
+
# No drift
|
|
146
|
+
DRIFT=$(supabase db diff --use-migra 2>/dev/null | grep -v "^--" | grep -c .)
|
|
147
|
+
[ "$DRIFT" -eq 0 ] || { echo "WARN: $DRIFT lines of drift between local migrations and remote"; }
|
|
148
|
+
|
|
149
|
+
echo "OK"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Common failures
|
|
153
|
+
|
|
154
|
+
| Symptom | Cause | Fix |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| `db push` fails with permission error | Service role token missing scopes | `supabase login` again, ensure access token has full project access |
|
|
157
|
+
| Migration fails on `RAISE EXCEPTION` | Data assertion failure | Inspect data; usually means a NOT NULL constraint with existing NULLs |
|
|
158
|
+
| RLS policy fails to apply | References non-existent role | Migrations must be self-contained; check `supabase/seed.sql` for role creation |
|
|
159
|
+
| Drift detected | Someone applied changes via dashboard | Pull dashboard changes into a migration: `supabase db diff -f resolve_drift` |
|
|
160
|
+
| Types regen breaks compilation | New column not exposed via API | Add the table/column to `exposed_schemas` in `config.toml` |
|
|
161
|
+
|
|
162
|
+
## Rollback
|
|
163
|
+
|
|
164
|
+
There's no clean rollback for applied migrations. Two paths:
|
|
165
|
+
|
|
166
|
+
1. **Forward-only revert** — write a new migration that undoes the change, push it
|
|
167
|
+
2. **Point-in-time restore** — Supabase paid tier; via dashboard
|
|
168
|
+
|
|
169
|
+
The orchestrator surfaces #1 as the recommended path:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
Migration cannot be auto-rolled-back.
|
|
173
|
+
Recommended: write a new migration that reverses the schema change, then re-run /cbp-ship.
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Configure-once setup
|
|
177
|
+
|
|
178
|
+
See `${CLAUDE_PLUGIN_ROOT}/skills/ship-configure/reference/supabase.md` for first-time setup (supabase login, project link, types path config, optional auto-types-on-edit).
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Surface: tauri-desktop
|
|
2
|
+
|
|
3
|
+
Build, sign, notarize, and release a Tauri desktop app via GitHub Actions tag-trigger.
|
|
4
|
+
|
|
5
|
+
This surface file is the orchestrator's interface to the Tauri release pipeline — secrets, CI workflow, signing, notarization, and gotchas are all covered in the sections below.
|
|
6
|
+
|
|
7
|
+
## Detection
|
|
8
|
+
|
|
9
|
+
Signals:
|
|
10
|
+
|
|
11
|
+
- `src-tauri/tauri.conf.json` present
|
|
12
|
+
- `apps/desktop/src-tauri/` (monorepo) — instance is `apps/desktop`
|
|
13
|
+
|
|
14
|
+
## Configured indicators
|
|
15
|
+
|
|
16
|
+
`configured: true` requires:
|
|
17
|
+
|
|
18
|
+
1. `src-tauri/tauri.conf.json` parseable, with `productName` + `version`
|
|
19
|
+
2. `.github/workflows/release-desktop.yml` (or similar tag-trigger workflow) present
|
|
20
|
+
3. Required GitHub secrets set (per architecture doc — 9 secrets for the WBP setup)
|
|
21
|
+
4. `gh auth status` succeeds (CLI authenticated)
|
|
22
|
+
|
|
23
|
+
Probe: `gh secret list -R OWNER/REPO` and check that the 9 secret names from the architecture doc are present.
|
|
24
|
+
|
|
25
|
+
## Variants
|
|
26
|
+
|
|
27
|
+
| Variant | When |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `tag-and-release` | Version bump detected in `src-tauri/tauri.conf.json` `version` OR root `package.json` |
|
|
30
|
+
| `skip` | No version change since last shipment — desktop releases are tag-driven, not branch-driven |
|
|
31
|
+
|
|
32
|
+
## STEPS — tag-and-release variant
|
|
33
|
+
|
|
34
|
+
1. **Read version from tauri config**:
|
|
35
|
+
```bash
|
|
36
|
+
VERSION=$(jq -r .version "$APP_PATH/src-tauri/tauri.conf.json")
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
2. **Verify tag doesn't already exist**:
|
|
40
|
+
```bash
|
|
41
|
+
git fetch origin --tags
|
|
42
|
+
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
|
|
43
|
+
echo "Tag v$VERSION already exists — skip or bump version"; exit 1
|
|
44
|
+
fi
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
3. **Confirm with user** via AskUserQuestion:
|
|
48
|
+
```
|
|
49
|
+
Push tag v$VERSION? This triggers GH Actions build + sign + notarize + release.
|
|
50
|
+
The build takes ~15 min. You'll receive a GH Releases page when complete.
|
|
51
|
+
A) Push tag — start the release
|
|
52
|
+
B) Skip — bump version in another commit first
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
4. **Push the tag**:
|
|
56
|
+
```bash
|
|
57
|
+
git tag -a "v$VERSION" -m "Release v$VERSION"
|
|
58
|
+
git push origin "v$VERSION"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
5. **Get the workflow run** triggered by the tag:
|
|
62
|
+
```bash
|
|
63
|
+
sleep 5 # GH Actions registration lag
|
|
64
|
+
RUN_ID=$(gh run list --workflow=release-desktop.yml --limit 1 --json databaseId,headBranch,event \
|
|
65
|
+
| jq -r ".[] | select(.event == \"push\" and .headBranch == \"v$VERSION\") | .databaseId")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
6. **Watch the run** (15 min cap):
|
|
69
|
+
```bash
|
|
70
|
+
gh run watch "$RUN_ID" --exit-status
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
7. **Verify GH Release was created**:
|
|
74
|
+
```bash
|
|
75
|
+
gh release view "v$VERSION" --json assets,publishedAt | jq
|
|
76
|
+
```
|
|
77
|
+
Expect: 2 assets minimum (ARM .dmg + Intel .dmg) for macOS-only builds; more for Win/Linux if configured.
|
|
78
|
+
|
|
79
|
+
8. **Result**:
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"status": "verified",
|
|
83
|
+
"version": "v1.4.0",
|
|
84
|
+
"release_url": "https://github.com/OWNER/REPO/releases/tag/v1.4.0",
|
|
85
|
+
"assets": ["WorkByPlan_1.4.0_aarch64.dmg", "WorkByPlan_1.4.0_x64.dmg"],
|
|
86
|
+
"workflow_run_id": "1234567890"
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Verification
|
|
91
|
+
|
|
92
|
+
`scripts/verify-tauri.sh`:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
VERSION="$1"
|
|
96
|
+
|
|
97
|
+
# Tag exists locally + remote
|
|
98
|
+
git rev-parse "v$VERSION" >/dev/null 2>&1 || { echo "Tag missing"; exit 1; }
|
|
99
|
+
git ls-remote --tags origin "v$VERSION" | grep -q . || { echo "Tag not pushed"; exit 1; }
|
|
100
|
+
|
|
101
|
+
# GH Release published
|
|
102
|
+
PUBLISHED=$(gh release view "v$VERSION" --json publishedAt -q .publishedAt 2>/dev/null)
|
|
103
|
+
[ -n "$PUBLISHED" ] || { echo "Release not published"; exit 1; }
|
|
104
|
+
|
|
105
|
+
# At least one signed .dmg in assets
|
|
106
|
+
ASSETS=$(gh release view "v$VERSION" --json assets -q '.assets | length')
|
|
107
|
+
[ "$ASSETS" -ge 1 ] || { echo "No release assets"; exit 1; }
|
|
108
|
+
|
|
109
|
+
# Updater manifest (latest.json) updated — Tauri auto-update needs this
|
|
110
|
+
gh release view "v$VERSION" --json assets -q '.assets[].name' | grep -q "latest.json" \
|
|
111
|
+
|| echo "WARN: latest.json missing from release — auto-update may not work"
|
|
112
|
+
|
|
113
|
+
echo "OK"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Common failures
|
|
117
|
+
|
|
118
|
+
| Symptom | Cause | Fix |
|
|
119
|
+
|---|---|---|
|
|
120
|
+
| Workflow fails at "Notarize" step | Apple API key file path issue | See architecture doc § "Apple Notarization Key" — `.p8` content must be written to a file path, not passed as string |
|
|
121
|
+
| `latest.json` missing | Tauri updater config disabled in tauri.conf.json | Enable `tauri.bundle.updater` |
|
|
122
|
+
| ARM/Intel asset missing | matrix build for one arch failed | Check workflow logs; commonly Rust toolchain issue on the failed runner |
|
|
123
|
+
| "Invalid signing identity" | `APPLE_SIGNING_IDENTITY` secret has wrong format | Must be exact match: `Developer ID Application: Name (TEAMID)` |
|
|
124
|
+
| Public download URL broken | Vercel Blob upload step failed | Check `BLOB_READ_WRITE_TOKEN` secret + Vercel storage quota |
|
|
125
|
+
|
|
126
|
+
## Rollback
|
|
127
|
+
|
|
128
|
+
Tauri's auto-updater honors the most recent `latest.json` published. To rollback:
|
|
129
|
+
|
|
130
|
+
1. Delete the bad release: `gh release delete v$VERSION --yes`
|
|
131
|
+
2. Republish a prior tag: `gh release create v$PRIOR --notes "Republish after rollback" $PRIOR_ASSETS`
|
|
132
|
+
3. The auto-updater will roll users back at their next launch
|
|
133
|
+
|
|
134
|
+
The orchestrator surfaces this as an option when verification fails.
|
|
135
|
+
|
|
136
|
+
## Configure-once setup
|
|
137
|
+
|
|
138
|
+
See `${CLAUDE_PLUGIN_ROOT}/skills/ship-configure/reference/tauri-desktop.md` for first-time setup (Apple Developer cert, key generation, secrets upload, workflow scaffolding).
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Surface: vercel-web
|
|
2
|
+
|
|
3
|
+
Deploy a Next.js (or static) app to Vercel.
|
|
4
|
+
|
|
5
|
+
## Detection
|
|
6
|
+
|
|
7
|
+
Signals (any one is sufficient):
|
|
8
|
+
|
|
9
|
+
- `vercel.json` at app root
|
|
10
|
+
- `.vercel/project.json` at app root (links repo to Vercel project)
|
|
11
|
+
- App directory contains `next` in `package.json` dependencies AND no other surface signal claims it
|
|
12
|
+
|
|
13
|
+
A repo can have multiple `vercel-web` instances — one per app folder under `apps/*`.
|
|
14
|
+
|
|
15
|
+
## Configured indicators
|
|
16
|
+
|
|
17
|
+
`configured: true` requires:
|
|
18
|
+
|
|
19
|
+
1. `.vercel/project.json` present with `projectId` and `orgId`
|
|
20
|
+
2. Vercel CLI authenticated (`vercel whoami` succeeds)
|
|
21
|
+
3. `.codebyplan/shipment.json` `.surfaces.vercel-web.{instance}` block (optional but recommended)
|
|
22
|
+
|
|
23
|
+
If `.vercel/project.json` is missing → `configured: false`, reason "not linked to Vercel project — run /cbp-ship-configure".
|
|
24
|
+
|
|
25
|
+
## Variant: production
|
|
26
|
+
|
|
27
|
+
Default for shipping to PRODUCTION branch (per `branch_config.production`). Vercel auto-deploys on push to the linked production branch — this variant **observes** the auto-deploy, doesn't trigger it.
|
|
28
|
+
|
|
29
|
+
### STEPS — production variant
|
|
30
|
+
|
|
31
|
+
1. **Read project ID** from `.vercel/project.json`:
|
|
32
|
+
```bash
|
|
33
|
+
PROJECT_ID=$(jq -r .projectId .vercel/project.json)
|
|
34
|
+
ORG_ID=$(jq -r .orgId .vercel/project.json)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
2. **Get the deployment triggered by the merge commit**:
|
|
38
|
+
```bash
|
|
39
|
+
MERGE_SHA=$(git rev-parse HEAD)
|
|
40
|
+
DEPLOYMENT=$(vercel ls --json 2>/dev/null | jq -r ".[] | select(.meta.githubCommitSha == \"$MERGE_SHA\") | .uid" | head -1)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
If no deployment found within 60s, Vercel is slow — wait up to 5min:
|
|
44
|
+
```bash
|
|
45
|
+
timeout 300 bash -c "while ! vercel ls --json | jq -e '.[] | select(.meta.githubCommitSha == \"$MERGE_SHA\")' > /dev/null; do sleep 10; done"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
3. **Wait for READY state**:
|
|
49
|
+
```bash
|
|
50
|
+
vercel inspect "$DEPLOYMENT" --wait
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
4. **Capture URL + readyState**:
|
|
54
|
+
```bash
|
|
55
|
+
STATUS=$(vercel inspect "$DEPLOYMENT" --json | jq -r '.readyState')
|
|
56
|
+
URL=$(vercel inspect "$DEPLOYMENT" --json | jq -r '.alias[0] // .url')
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
5. **Result**: `{ status: STATUS, url: URL, deployment_id: DEPLOYMENT }` to orchestrator.
|
|
60
|
+
|
|
61
|
+
## Variant: manual-redeploy
|
|
62
|
+
|
|
63
|
+
For "the auto-deploy failed, force a redeploy" path. User triggers explicitly.
|
|
64
|
+
|
|
65
|
+
### STEPS — manual-redeploy variant
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
cd "$APP_PATH"
|
|
69
|
+
vercel --prod --yes
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Capture deployment ID from output, then run Steps 3–5 from production variant.
|
|
73
|
+
|
|
74
|
+
## Variant: preview
|
|
75
|
+
|
|
76
|
+
Vercel auto-creates a preview deployment per PR. The orchestrator typically does NOT need to trigger anything for staging shipments — but it CAN verify the preview deployment for the integration branch:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
INTEGRATION=$(jq -r .branch_config.integration .codebyplan/git.json)
|
|
80
|
+
INTEGRATION_SHA=$(git rev-parse "origin/$INTEGRATION")
|
|
81
|
+
vercel ls --json | jq ".[] | select(.meta.githubCommitSha == \"$INTEGRATION_SHA\" and .target == \"preview\")"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Verification
|
|
85
|
+
|
|
86
|
+
`scripts/verify-vercel.sh` does:
|
|
87
|
+
|
|
88
|
+
1. `vercel inspect "$DEPLOYMENT_ID" --json | jq -r .readyState` returns `READY`
|
|
89
|
+
2. `curl -sI "$URL" | head -1` returns `HTTP/2 200` (or 401 for password-protected previews — also success)
|
|
90
|
+
3. If `apps/{instance}/public/health.json` or `/api/health` exists, hit it: expect 200
|
|
91
|
+
|
|
92
|
+
Timeouts:
|
|
93
|
+
- Build: 5 min (Vercel Hobby is slower; allow 8 min)
|
|
94
|
+
- HTTP probe: 30s
|
|
95
|
+
|
|
96
|
+
## Common failures
|
|
97
|
+
|
|
98
|
+
| Symptom | Likely cause | Fix |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| `vercel ls` shows no deployment for the merge SHA | GitHub integration not connected, or push didn't trigger | Check Vercel dashboard → Settings → Git; reconnect if needed |
|
|
101
|
+
| Build fails with "Module not found" | Monorepo root not configured | In Vercel project settings: Build Command → `cd ../.. && pnpm turbo build --filter={instance}`, Root Directory → `apps/{instance}` |
|
|
102
|
+
| Preview URL 404s | Project paused or env var missing | Check Vercel logs for the deployment; common: missing `DATABASE_URL` |
|
|
103
|
+
| Build succeeds but page is blank | Production env vars missing | `vercel env ls production` — compare to `.env.example` |
|
|
104
|
+
|
|
105
|
+
## Rollback
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
vercel rollback # interactive: pick a prior deployment
|
|
109
|
+
vercel promote "$PRIOR_DEPLOYMENT" # promote a specific deployment to production
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The orchestrator surfaces this as an option when a verification fails:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
Vercel deployment failed verification.
|
|
116
|
+
Options:
|
|
117
|
+
A) Retry — the deploy may complete async
|
|
118
|
+
B) Rollback to prior production deployment
|
|
119
|
+
C) Investigate manually — show me the build logs
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Configure-once setup
|
|
123
|
+
|
|
124
|
+
See `${CLAUDE_PLUGIN_ROOT}/skills/ship-configure/reference/vercel.md` for first-time setup (vercel link, env var sync, GH integration verification).
|