prizmkit 1.1.49 → 1.1.53
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/bundled/VERSION.json +3 -3
- package/bundled/skills/_metadata.json +9 -1
- package/bundled/skills/prizmkit-deploy/SKILL.md +139 -167
- package/bundled/skills/prizmkit-deploy/references/ci-cd-workflows.md +115 -0
- package/bundled/skills/prizmkit-deploy/references/database-setup.md +46 -0
- package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +1 -0
- package/bundled/skills/prizmkit-deploy/references/deployment-modes.md +50 -0
- package/bundled/skills/prizmkit-deploy/references/direct-upload.md +26 -0
- package/bundled/skills/prizmkit-deploy/references/dns-setup.md +42 -0
- package/bundled/skills/prizmkit-deploy/references/firewall-setup.md +37 -0
- package/bundled/skills/prizmkit-deploy/references/live-validation-notes.md +21 -0
- package/bundled/skills/prizmkit-deploy/references/ssl-setup.md +56 -0
- package/bundled/skills/prizmkit-implement/SKILL.md +3 -0
- package/bundled/skills/prizmkit-test/SKILL.md +281 -0
- package/package.json +1 -1
- package/src/scaffold.js +5 -0
package/bundled/VERSION.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.1.
|
|
2
|
+
"version": "1.1.53",
|
|
3
3
|
"skills": {
|
|
4
4
|
"prizm-kit": {
|
|
5
5
|
"description": "Full-lifecycle dev toolkit. Covers spec-driven development, Prizm context docs, code quality, debugging, deployment, and knowledge management.",
|
|
@@ -64,6 +64,13 @@
|
|
|
64
64
|
"hasAssets": false,
|
|
65
65
|
"hasScripts": false
|
|
66
66
|
},
|
|
67
|
+
"prizmkit-test": {
|
|
68
|
+
"description": "Full-stack test generation and orchestration. Detects architecture, discovers/runs existing tests, analyzes coverage gaps, generates missing tests (unit/integration/E2E), outputs unified report.",
|
|
69
|
+
"tier": "1",
|
|
70
|
+
"category": "prizmkit-skill",
|
|
71
|
+
"hasAssets": false,
|
|
72
|
+
"hasScripts": false
|
|
73
|
+
},
|
|
67
74
|
"feature-workflow": {
|
|
68
75
|
"description": "One-stop entry point for feature development. Orchestrates feature-planner → feature-pipeline-launcher → background execution. Handles multi-feature batch development from a single request.",
|
|
69
76
|
"tier": "companion",
|
|
@@ -166,6 +173,7 @@
|
|
|
166
173
|
"prizmkit-committer",
|
|
167
174
|
"prizmkit-retrospective",
|
|
168
175
|
"prizmkit-deploy",
|
|
176
|
+
"prizmkit-test",
|
|
169
177
|
"feature-workflow",
|
|
170
178
|
"refactor-workflow",
|
|
171
179
|
"app-planner",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "prizmkit-deploy"
|
|
3
|
-
description: "Universal deployment gateway for any PrizmKit project. Discovers project type and target (SSH server, Vercel, Docker, etc.), then routes: full automation for SSH Linux with PM2 + Nginx + blue/green switching, guided setup for cloud platforms, or safe documentation fallback for unsupported targets. Also operates existing deployments: status, logs, restart, rollback, health checks, history.
|
|
3
|
+
description: "Universal deployment gateway for any PrizmKit project. Discovers project type and target (SSH server, Vercel, Docker, etc.), then routes: full automation for SSH Linux with PM2 + Nginx + blue/green switching, guided setup for cloud platforms, or safe documentation fallback for unsupported targets. Also operates existing deployments: status, logs, restart, rollback, health checks, history, validate. Use this skill whenever the user asks about deployment, hosting, going live, or server operations. Triggers on: 'deploy', 'ship it', 'take this live', 'deploy to Vercel', 'deploy to my server', 'check deploy status', 'view logs', 'restart app', 'rollback', 'how do I deploy this', any deployment or hosting question."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# PrizmKit Deploy — Universal Deployment Gateway
|
|
@@ -73,26 +73,12 @@ If headless mode and no target can be determined, exit with `NEEDS_INPUT` listin
|
|
|
73
73
|
|
|
74
74
|
Based on detected target, route the rest of the session:
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
Vercel / Netlify → §Cloud Platform Deployment Path (guided)
|
|
82
|
-
detect CLI tools, walk through deploy commands,
|
|
83
|
-
generate deploy.md with platform-specific steps
|
|
84
|
-
|
|
85
|
-
Docker → §Docker Deployment Path (guided)
|
|
86
|
-
detect Dockerfile/Compose, build image,
|
|
87
|
-
container lifecycle (run, stop, logs, restart)
|
|
88
|
-
|
|
89
|
-
Unsupported → §Unsupported Deployment Fallback
|
|
90
|
-
generate deploy.md with detected info,
|
|
91
|
-
record missing adapter gap,
|
|
92
|
-
provide manual deployment checklist
|
|
93
|
-
```
|
|
76
|
+
1. **SSH Linux server** → §SSH Deployment Path — full automation: bootstrap, configure, deploy, operate. First-version adapter: PM2 + Nginx + blue/green.
|
|
77
|
+
2. **Vercel / Netlify** → §Cloud Platform Deployment Path — guided: detect CLI tools, walk through deploy commands, generate deploy.md. Details in `references/cloud-platform-deploy.md`.
|
|
78
|
+
3. **Docker** → §Docker Deployment Path — guided: detect Dockerfile/Compose, build image, container lifecycle. Details in `references/docker-deploy.md`.
|
|
79
|
+
4. **Unsupported** → §Unsupported Deployment Fallback — generate deploy.md, record adapter gap, provide manual checklist.
|
|
94
80
|
|
|
95
|
-
|
|
81
|
+
Cloud and Docker paths follow the same discovery and documentation patterns but use platform CLIs instead of SSH + PM2.
|
|
96
82
|
|
|
97
83
|
**Compatibility check before routing to SSH**: The SSH adapter (PM2 + Nginx + blue/green) requires a Node.js project — verify `package.json` exists. Non-Node.js projects (Go, Rust, Python) targeting a Linux server route to Unsupported Fallback with a note: "Adapter gap: PM2 adapter requires Node.js."
|
|
98
84
|
|
|
@@ -101,18 +87,11 @@ The SSH path is fully documented in the sections below. Cloud and Docker paths f
|
|
|
101
87
|
When the deployment target or project type isn't covered by any adapter, don't fail silently. Instead:
|
|
102
88
|
|
|
103
89
|
1. **Detect what you can**: project language, framework, build/start commands, env vars, port usage, database dependencies.
|
|
104
|
-
2. **Generate `.prizmkit/deploy/deploy.md`**: human-readable deployment guide with
|
|
105
|
-
|
|
106
|
-
- Environment variables table (detected from code scan)
|
|
107
|
-
- Build and start instructions
|
|
108
|
-
- Health check suggestions
|
|
109
|
-
- Platform-specific tips if the target is partially recognized
|
|
110
|
-
3. **Record the adapter gap**: write a note in deploy.md and deploy-history identifying what's missing (e.g., "Adapter needed: Python/FastAPI on systemd", "Adapter needed: Go binary deployment").
|
|
90
|
+
2. **Generate `.prizmkit/deploy/deploy.md`**: human-readable deployment guide with prerequisites, environment variables table, build/start instructions, health check suggestions.
|
|
91
|
+
3. **Record the adapter gap**: write a note in deploy.md and deploy-history identifying what's missing (e.g., "Adapter needed: Python/FastAPI on systemd").
|
|
111
92
|
4. **Provide a manual checklist**: concrete steps the user can follow to deploy manually.
|
|
112
93
|
5. **Offer to generate CI/CD config**: if `.github/workflows/` exists or the user wants one, generate a basic deploy workflow.
|
|
113
94
|
|
|
114
|
-
This ensures every deployment request produces useful output, even when full automation isn't available yet.
|
|
115
|
-
|
|
116
95
|
## Mode Detection
|
|
117
96
|
|
|
118
97
|
Detect invocation mode from the user's initial message. The mode determines what you're allowed to do:
|
|
@@ -124,9 +103,9 @@ Detect invocation mode from the user's initial message. The mode determines what
|
|
|
124
103
|
- Production requires explicit user confirmation before execution.
|
|
125
104
|
|
|
126
105
|
**Headless mode** (invoked via `--headless` flag, pipeline, or script):
|
|
127
|
-
-
|
|
106
|
+
- Never wait for user input — unattended shells that time out on a prompt block pipelines silently without visible errors, so exit with clear status codes instead.
|
|
128
107
|
- May ONLY target `dev` or `test` environments.
|
|
129
|
-
- If `--env production` in headless mode: exit immediately with `ENVIRONMENT_DENIED — production deployment requires interactive mode
|
|
108
|
+
- If `--env production` in headless mode: exit immediately with `ENVIRONMENT_DENIED — production deployment requires interactive mode`, because production deploys must never happen without human oversight.
|
|
130
109
|
- If required info is missing, exit with `NEEDS_INPUT` and write pending questions to `.prizmkit/deploy/pending-input.json`.
|
|
131
110
|
- May only perform actions already authorized by `deploy.config.json`.
|
|
132
111
|
|
|
@@ -164,16 +143,34 @@ All artifacts live under `.prizmkit/deploy/`:
|
|
|
164
143
|
pending-input.json # pending questions for headless mode resume
|
|
165
144
|
deploy-history/
|
|
166
145
|
<deployment-id>.json # one per deploy/rollback/event
|
|
167
|
-
deploy-scripts/ # future —
|
|
146
|
+
deploy-scripts/ # future — PrizmKit-managed deploy scripts
|
|
168
147
|
secrets.enc.json # optional, encrypted local secrets
|
|
169
148
|
secrets.local.json # optional, plaintext secrets (must be gitignored)
|
|
170
149
|
```
|
|
171
150
|
|
|
172
|
-
|
|
151
|
+
Read `references/deploy-config-schema.md` when writing or validating `deploy.config.json`. Read `references/deploy-history-schema.md` when writing history records.
|
|
152
|
+
|
|
153
|
+
## SSH Deployment Path
|
|
154
|
+
|
|
155
|
+
The following sections define the SSH deployment adapter — the only fully-automated path. Route here when Discovery determines the target is a Linux server with SSH access.
|
|
156
|
+
|
|
157
|
+
### SSH: Deployment Mode Selection
|
|
173
158
|
|
|
174
|
-
|
|
159
|
+
After Discovery routes to SSH, **before** entering the configuration wizard, ask the user how they want to deploy.
|
|
175
160
|
|
|
176
|
-
|
|
161
|
+
**First question:**
|
|
162
|
+
> "你想怎么部署到服务器?"
|
|
163
|
+
> - **A. 直接上传(快速上手)** — 本地构建,传到服务器启动。适合第一次部署。
|
|
164
|
+
> - **B. CI/CD 自动部署(推荐)** — 配置 GitHub Actions,以后 `git push` 自动部署。
|
|
165
|
+
|
|
166
|
+
**If user chooses CI/CD, second question:**
|
|
167
|
+
> "CI/CD 有两种模式:"
|
|
168
|
+
> - **Push 模式** — GitHub Actions runner 编译,SCP 传到服务器。服务器压力小。
|
|
169
|
+
> - **Pull 模式** — 服务器自己拉代码编译。配置更简单但需 Deploy Key。
|
|
170
|
+
|
|
171
|
+
For detailed mode descriptions and the full Push/Pull comparison table, read `references/deployment-modes.md`.
|
|
172
|
+
|
|
173
|
+
**Config field:** `deployStrategy` in `deploy.config.json` — `"direct-upload"`, `"ci-cd-push"`, or `"ci-cd-pull"`. Existing configs without this field default to `"ci-cd-pull"` for backward compatibility.
|
|
177
174
|
|
|
178
175
|
### SSH: Server Model
|
|
179
176
|
|
|
@@ -181,7 +178,7 @@ Servers are generic SSH targets. A server is valid if it:
|
|
|
181
178
|
- Can be reached over SSH.
|
|
182
179
|
- Provides a Linux shell.
|
|
183
180
|
- Can install or has Node.js, npm, PM2, Nginx, Git.
|
|
184
|
-
- Can access the configured Git repository.
|
|
181
|
+
- Can access the configured Git repository (Pull mode only).
|
|
185
182
|
|
|
186
183
|
Server-side directory layout:
|
|
187
184
|
```
|
|
@@ -199,48 +196,46 @@ SSH roles: `bootstrapUser` (usually root, for initial setup) and `runtimeUser` (
|
|
|
199
196
|
|
|
200
197
|
### SSH: First-Run Configuration Wizard
|
|
201
198
|
|
|
202
|
-
When `.prizmkit/deploy/deploy.config.json` does not exist, enter configuration wizard.
|
|
199
|
+
When `.prizmkit/deploy/deploy.config.json` does not exist, enter configuration wizard. Flow: **deployment mode → collect → validate → confirm → persist**.
|
|
200
|
+
|
|
201
|
+
**Before any questions:** ask deployment mode (see §SSH: Deployment Mode Selection). This determines required steps:
|
|
202
|
+
|
|
203
|
+
| Step | Direct Upload | CI/CD Push | CI/CD Pull |
|
|
204
|
+
|------|:---:|:---:|:---:|
|
|
205
|
+
| SSH Server Discovery | Required | Required | Required |
|
|
206
|
+
| Repository Access | Skipped | Skipped | Required |
|
|
207
|
+
| Application Configuration | Required | Required | Required |
|
|
208
|
+
| Environment Variables | Required | Required | Required |
|
|
209
|
+
| Persist Configuration | Required | Required | Required |
|
|
203
210
|
|
|
204
211
|
#### Step 1: SSH Server Discovery
|
|
205
212
|
|
|
206
213
|
Ask for and validate:
|
|
207
214
|
- **Server host and port** (e.g., `43.161.221.171:22`)
|
|
208
|
-
- **Bootstrap user** (usually `root`) —
|
|
215
|
+
- **Bootstrap user** (usually `root`) — for initial package install and user creation
|
|
209
216
|
- **Runtime user** (recommend `deploy`) — app runs as this user, never root
|
|
210
217
|
- **Auth method** — SSH key path or agent
|
|
211
218
|
|
|
212
219
|
Validate immediately: `ssh <bootstrapUser>@<host> 'echo OK'`. If that fails, nothing else matters — stop and fix connectivity first.
|
|
213
220
|
|
|
214
|
-
#### Step 2: Repository Access
|
|
221
|
+
#### Step 2: Repository Access (CI/CD Pull mode only)
|
|
215
222
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
- **Auth strategy** — prefer read-only Deploy Key
|
|
223
|
+
Only needed when `deployStrategy` is `"ci-cd-pull"` — the server needs to `git pull` code. Skip for `"direct-upload"` (no Git on server) and `"ci-cd-push"` (GitHub Actions handles checkout).
|
|
224
|
+
|
|
225
|
+
Ask for: Git URL, branch, auth strategy (prefer read-only Deploy Key).
|
|
220
226
|
|
|
221
227
|
If using Deploy Key:
|
|
222
228
|
1. Generate ed25519 key on server: `sudo -u <runtimeUser> ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""`
|
|
223
|
-
2. Show
|
|
224
|
-
3. Wait for
|
|
229
|
+
2. Show public key to user: "Add this to GitHub Deploy Keys (read-only)"
|
|
230
|
+
3. Wait for confirmation, then verify: attempt a git clone as runtime user
|
|
225
231
|
|
|
226
232
|
#### Step 3: Application Configuration
|
|
227
233
|
|
|
228
|
-
For each app, collect:
|
|
229
|
-
- **id** — short name (e.g., `web`)
|
|
230
|
-
- **path** — relative path within repo
|
|
231
|
-
- **packageManager** — npm / yarn / pnpm
|
|
232
|
-
- **installCommand** — `npm ci` / `yarn install` etc.
|
|
233
|
-
- **buildCommand** — `npm run build` etc.
|
|
234
|
-
- **startCommand** — `npm run start` etc.
|
|
235
|
-
- **ports** — blue/green port pair (default 3101/3102)
|
|
236
|
-
- **healthChecks** — list of `{ name, url, expectedStatus[] }`
|
|
234
|
+
For each app, collect: id, path, packageManager, installCommand, buildCommand, startCommand, blue/green port pair (default 3101/3102), healthChecks.
|
|
237
235
|
|
|
238
236
|
#### Step 4: Environment Variables
|
|
239
237
|
|
|
240
|
-
|
|
241
|
-
- Ask user for each required value.
|
|
242
|
-
- Identify which are secrets (API keys, tokens) vs. non-secrets (URLs, anon keys).
|
|
243
|
-
- Ask about secret storage strategy (see Secrets Management below).
|
|
238
|
+
Scan source code for `process.env.<VAR>` references. Ask user for each required value. Identify secrets vs non-secrets. Ask about secret storage strategy (see §Secrets Management).
|
|
244
239
|
|
|
245
240
|
#### Step 5: Persist Configuration
|
|
246
241
|
|
|
@@ -248,7 +243,7 @@ Write `deploy.config.json` with all collected values and `validated: {}` stubs f
|
|
|
248
243
|
|
|
249
244
|
### SSH: Bootstrap Flow
|
|
250
245
|
|
|
251
|
-
Before first deployment, bootstrap the server. Present a plan
|
|
246
|
+
Before first deployment, bootstrap the server. Present a plan showing every privileged action before executing anything.
|
|
252
247
|
|
|
253
248
|
**Always-run preflight:**
|
|
254
249
|
```
|
|
@@ -256,18 +251,9 @@ locale-gen en_US.UTF-8 # fix locale warnings on bare Ubuntu
|
|
|
256
251
|
apt-get update -qq # refresh package list
|
|
257
252
|
```
|
|
258
253
|
|
|
259
|
-
**Check-and-install (idempotent):**
|
|
260
|
-
- **Node.js**: check `node --version`. If missing or too old, install via NodeSource. Use v22 LTS if v25 not available — that's fine for most projects.
|
|
261
|
-
- **npm**: verify separately from node (`which npm`). On minimal installs, npm may be a separate package.
|
|
262
|
-
- **PM2**: `npm install -g pm2` if missing.
|
|
263
|
-
- **Nginx**: `apt-get install -y nginx` if missing.
|
|
264
|
-
- **Git**: `apt-get install -y git` if missing.
|
|
254
|
+
**Check-and-install (idempotent):** Node.js, npm, PM2, Nginx, Git. Use v22 LTS if v25 not available.
|
|
265
255
|
|
|
266
|
-
**Detect port conflicts
|
|
267
|
-
```
|
|
268
|
-
ss -tlnp | grep :80 || true
|
|
269
|
-
```
|
|
270
|
-
If port 80/443 is occupied, report what's using it and ask how to resolve.
|
|
256
|
+
**Detect port conflicts:** `ss -tlnp | grep :80 || true`. If port 80/443 is occupied, report and ask how to resolve.
|
|
271
257
|
|
|
272
258
|
**User and directory setup:**
|
|
273
259
|
```
|
|
@@ -281,104 +267,119 @@ chown -R <runtimeUser>:<runtimeUser> /var/www/<project>
|
|
|
281
267
|
env PATH=$PATH:/usr/bin pm2 startup systemd -u <runtimeUser> --hp /home/<runtimeUser>
|
|
282
268
|
```
|
|
283
269
|
|
|
284
|
-
**Deploy key (
|
|
270
|
+
**Deploy key (Pull mode only):**
|
|
285
271
|
```
|
|
286
272
|
sudo -u <runtimeUser> ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
|
|
287
273
|
sudo -u <runtimeUser> ssh-keyscan -H github.com >> ~/.ssh/known_hosts
|
|
288
274
|
```
|
|
289
275
|
|
|
276
|
+
**Security baseline (firewall):** After core tools are installed, ask whether to configure ufw. If user agrees, read `references/firewall-setup.md` for the full interactive flow and rule templates.
|
|
277
|
+
|
|
278
|
+
**Database setup:** If Discovery detected database drivers, ask whether to install the database on the server. If user agrees, read `references/database-setup.md` for platform-specific setup commands and security notes.
|
|
279
|
+
|
|
290
280
|
After each bootstrap step, record the result. Bootstrap operations must be idempotent. Back up any existing config files before modifying them.
|
|
291
281
|
|
|
282
|
+
### SSH: Direct Upload Deployment
|
|
283
|
+
|
|
284
|
+
When `deployStrategy` is `"direct-upload"`, the AI builds locally and transfers artifacts to the server. No Git operations on the server. Full procedure in `references/direct-upload.md`.
|
|
285
|
+
|
|
286
|
+
### SSH: CI/CD Pipeline Configuration
|
|
287
|
+
|
|
288
|
+
When `deployStrategy` is `"ci-cd-push"` or `"ci-cd-pull"`, generate `.github/workflows/deploy.yml` with the appropriate workflow template. Both modes share the same trigger and secrets. Full YAML templates in `references/ci-cd-workflows.md`.
|
|
289
|
+
|
|
290
|
+
After generating the workflow, verify: the first `git push` to the configured branch will trigger the first deployment. Monitor the GitHub Actions run and report results.
|
|
291
|
+
|
|
292
|
+
### SSH: DNS Guidance
|
|
293
|
+
|
|
294
|
+
Before SSL, check if the user has a domain pointing to the server.
|
|
295
|
+
|
|
296
|
+
1. Ask: "你有没有域名要绑定到这个项目?" If no domain → skip DNS + SSL, note in deploy.md.
|
|
297
|
+
2. Check DNS: `dig +short <domain> A`. If resolved → proceed to SSL.
|
|
298
|
+
3. If not resolved: show the user DNS setup instructions. Full procedure in `references/dns-setup.md`.
|
|
299
|
+
|
|
300
|
+
### SSH: SSL/HTTPS Configuration
|
|
301
|
+
|
|
302
|
+
Once DNS is confirmed pointing to the server, configure HTTPS via Let's Encrypt.
|
|
303
|
+
|
|
304
|
+
1. Detect cloud vendor via metadata endpoints.
|
|
305
|
+
2. If cloud vendor detected, ask: Let's Encrypt (recommended) or cloud vendor certificate.
|
|
306
|
+
3. Install certbot and request certificate.
|
|
307
|
+
4. Verify auto-renewal with `certbot renew --dry-run`.
|
|
308
|
+
|
|
309
|
+
Full procedure in `references/ssl-setup.md`.
|
|
310
|
+
|
|
292
311
|
### SSH: Deployment Execution Flow
|
|
293
312
|
|
|
294
313
|
Pipeline runs in strict order. Each group must complete before the next begins. If any step before traffic switch fails, STOP — do not touch the live version.
|
|
295
314
|
|
|
315
|
+
**Pre-flight — Change Summary:** Show what will be deployed using `git log --oneline <last-deployed-commit>..HEAD`. If first deployment, show last 5 commits. If no new commits, warn "没有新的代码变更。确定要重新部署吗?"
|
|
316
|
+
|
|
296
317
|
**Group 1 — Pre-flight & Prepare:**
|
|
297
318
|
- Verify SSH, runtime user, tools, deploy key, port availability.
|
|
298
319
|
- Generate `releaseId`: `YYYYMMDD-<short-commit-sha>`. Create `releases/<releaseId>`.
|
|
299
320
|
- Determine target color: read `activeColor` from `shared/deploy-metadata.json` and use the opposite. If first deploy (no metadata, no `current` symlink), default to blue (port 3101).
|
|
300
321
|
|
|
301
322
|
**Group 2 — Fetch & Build:**
|
|
302
|
-
|
|
303
|
-
- `
|
|
304
|
-
-
|
|
305
|
-
-
|
|
323
|
+
|
|
324
|
+
- **CI/CD Pull mode** (server-side build): git clone → install → copy `.env.production` before build (NEXT_PUBLIC_* vars are baked at build time) → build. If build fails: STOP.
|
|
325
|
+
- **CI/CD Push mode** (runner-side build): extract tarball, skip install/build.
|
|
326
|
+
- **Direct-upload mode**: build was already done locally and SCP'd. Skip this group.
|
|
306
327
|
|
|
307
328
|
**Group 3 — Stage & Health Check:**
|
|
308
|
-
- Start new version on
|
|
329
|
+
- Start new version on inactive port via PM2: `pm2 start npm --name <project>-<app>-<color> -- run start -- -p <inactivePort>`.
|
|
309
330
|
- PM2 process naming: `<project>-<app>-<color>` (e.g., `prizm-ideas-web-green`).
|
|
310
|
-
- Wait 3-5 seconds, run health checks against new port. If any fails: STOP
|
|
331
|
+
- Wait 3-5 seconds, run health checks against new port. If any fails: STOP, do NOT switch traffic.
|
|
311
332
|
|
|
312
333
|
**Group 4 — Switch & Verify:**
|
|
313
334
|
- Update Nginx upstream to new port. Run `nginx -t` — abort on failure.
|
|
314
335
|
- `systemctl reload nginx`. Update `current` symlink to new release.
|
|
315
336
|
- Write `shared/deploy-metadata.json` with new `activeColor`, `activePort`, `lastReleaseId`.
|
|
316
|
-
- Run health checks against public endpoint. If any fails: rollback immediately
|
|
337
|
+
- Run health checks against public endpoint. If any fails: rollback immediately.
|
|
317
338
|
|
|
318
339
|
**Group 5 — Cleanup & Record:**
|
|
319
340
|
- Stop old PM2 process. Remove oldest releases beyond `releaseRetention` count. `pm2 save`.
|
|
320
|
-
- Write deploy-history JSON
|
|
321
|
-
|
|
341
|
+
- Write deploy-history JSON. Update `deploy.config.json` validation status.
|
|
342
|
+
|
|
343
|
+
**Post-deploy — Completion Summary:** Output a summary (project, URL, version, duration, health status) and append to deploy.md. If `deployStrategy` is `"direct-upload"`, offer CI/CD upgrade (see §SSH: Post-Deploy CI/CD Upgrade).
|
|
322
344
|
|
|
323
345
|
### SSH: Blue/Green PM2 + Nginx Strategy
|
|
324
346
|
|
|
325
|
-
|
|
326
|
-
-
|
|
327
|
-
-
|
|
347
|
+
- Blue: port 3101 (default), Green: port 3102 (default).
|
|
348
|
+
- Active color persisted in `/var/www/<project>/shared/deploy-metadata.json`.
|
|
349
|
+
- PM2 process naming: `<project>-<app>-<color>` (deterministic, never reuse old release IDs).
|
|
350
|
+
- Nginx config must include: `# PrizmKit Managed: <project> — DO NOT EDIT MANUALLY`.
|
|
351
|
+
- Before modifying any Nginx config lacking this marker, ask for user confirmation.
|
|
352
|
+
- Always `nginx -t` before `systemctl reload nginx`.
|
|
328
353
|
|
|
329
|
-
|
|
354
|
+
See `references/nginx-blue-green.md` for the full Nginx config template and traffic switch procedure.
|
|
330
355
|
|
|
331
|
-
|
|
356
|
+
### SSH: Rollback
|
|
332
357
|
|
|
333
|
-
|
|
334
|
-
```
|
|
335
|
-
# PrizmKit Managed: <project> — DO NOT EDIT MANUALLY
|
|
336
|
-
```
|
|
358
|
+
Two triggers: **automatic** (health check failure after traffic switch) and **manual** (`/prizmkit-deploy rollback --app <id> [--to <releaseId>]`).
|
|
337
359
|
|
|
338
|
-
|
|
360
|
+
Steps: identify target release → verify build exists → start PM2 on its port → update Nginx upstream → `nginx -t` → reload → health checks → write rollback event. Do NOT delete the failed release or its logs — preserve for debugging.
|
|
339
361
|
|
|
340
|
-
|
|
362
|
+
If no previous release exists, rollback is not possible — state this clearly.
|
|
341
363
|
|
|
342
|
-
### SSH:
|
|
364
|
+
### SSH: Operations Commands
|
|
343
365
|
|
|
344
|
-
|
|
345
|
-
1. **Automatic**: health check failure after traffic switch → roll back immediately.
|
|
346
|
-
2. **Manual**: `/prizmkit-deploy rollback --app <id> [--to <releaseId>]`
|
|
366
|
+
**status:** `pm2 list` as runtime user + active release, active color/port, last deploy timestamp.
|
|
347
367
|
|
|
348
|
-
|
|
349
|
-
1. Identify target release: `--to <releaseId>` or discover previous release from deploy history.
|
|
350
|
-
2. Verify target release directory exists and has a valid build.
|
|
351
|
-
3. Determine which port the target release used (from deploy history or release metadata).
|
|
352
|
-
4. Start the target PM2 process on its port (if not already running).
|
|
353
|
-
5. Update Nginx upstream to target port, run `nginx -t`, reload.
|
|
354
|
-
6. Run health checks against the restored version.
|
|
355
|
-
7. Write a rollback event to deploy history.
|
|
356
|
-
8. Do NOT delete the failed release or its logs — preserve for debugging.
|
|
368
|
+
**logs --app \<id\>:** `pm2 logs <process-name> --lines 100` as runtime user.
|
|
357
369
|
|
|
358
|
-
|
|
370
|
+
**restart --app \<id\>:** identify active PM2 process → `pm2 restart` → wait → health checks.
|
|
359
371
|
|
|
360
|
-
|
|
372
|
+
**health --app \<id\>:** run all configured health checks, report pass/fail for each.
|
|
361
373
|
|
|
362
|
-
|
|
363
|
-
SSH to server and run `pm2 list` as runtime user. Also show:
|
|
364
|
-
- Active release (from `current` symlink target)
|
|
365
|
-
- Active color/port (from `deploy-metadata.json`)
|
|
366
|
-
- Last deploy timestamp
|
|
374
|
+
**history:** list `.prizmkit/deploy/deploy-history/` events chronologically.
|
|
367
375
|
|
|
368
|
-
|
|
369
|
-
SSH to server and run `pm2 logs <process-name> --lines 100` as runtime user.
|
|
376
|
+
### SSH: Post-Deploy CI/CD Upgrade
|
|
370
377
|
|
|
371
|
-
|
|
372
|
-
1. Identify the active PM2 process for the app.
|
|
373
|
-
2. Run `pm2 restart <process-name>` as runtime user.
|
|
374
|
-
3. Wait for process to come online.
|
|
375
|
-
4. Run health checks to verify recovery.
|
|
378
|
+
After a successful direct-upload deployment, proactively offer CI/CD setup:
|
|
376
379
|
|
|
377
|
-
|
|
378
|
-
Run all configured health checks for the app against the public endpoint. Report pass/fail for each.
|
|
380
|
+
> "部署成功。要不要顺手帮你配置 CI/CD 自动部署?以后 `git push` 就自动上线。"
|
|
379
381
|
|
|
380
|
-
|
|
381
|
-
Read `.prizmkit/deploy/deploy-history/` directory, list events chronologically. Show event type, release ID, commit SHA, timestamp, status.
|
|
382
|
+
If user agrees, ask push vs pull, then configure accordingly. If Pull mode: set up deploy key. If Push mode: add GitHub Actions secrets. Generate `deploy.yml` from `references/ci-cd-workflows.md`, update `deployStrategy` in config, write upgrade event to history.
|
|
382
383
|
|
|
383
384
|
## Environment Policy
|
|
384
385
|
|
|
@@ -387,7 +388,7 @@ Read `.prizmkit/deploy/deploy-history/` directory, list events chronologically.
|
|
|
387
388
|
| Interactive | Allowed | Allowed | Allowed (requires confirmation) |
|
|
388
389
|
| Headless | Allowed | Allowed | **REJECTED** — exits with ENVIRONMENT_DENIED |
|
|
389
390
|
|
|
390
|
-
|
|
391
|
+
Headless must reject production because production deploys require human oversight — an unattended pipeline timing out mid-deploy can leave the site in a broken state with no one monitoring.
|
|
391
392
|
|
|
392
393
|
## Secrets Management
|
|
393
394
|
|
|
@@ -407,7 +408,7 @@ Deploy history records secret presence metadata only (e.g., `{"SUPABASE_SERVICE_
|
|
|
407
408
|
When deploying to a server that already has deployment assets:
|
|
408
409
|
|
|
409
410
|
1. Detect: existing `/var/www/<project>` directory, existing PM2 processes with similar names, Nginx config referencing the same domain/IP, port conflicts.
|
|
410
|
-
2. Report findings
|
|
411
|
+
2. Report findings and ask for takeover decision:
|
|
411
412
|
- **Take over and backup**: Back up existing config, then proceed.
|
|
412
413
|
- **Coexist**: Use different directory/ports/process names.
|
|
413
414
|
- **Manual resolve**: Stop and let the user handle it.
|
|
@@ -417,23 +418,15 @@ When deploying to a server that already has deployment assets:
|
|
|
417
418
|
|
|
418
419
|
- First Nginx config creation or update of a non-PrizmKit block requires user confirmation.
|
|
419
420
|
- Subsequent updates to PrizmKit-managed blocks (`# PrizmKit Managed:` marker) may proceed automatically.
|
|
420
|
-
-
|
|
421
|
-
- Always run `nginx -t` before reload.
|
|
422
|
-
- If a server block exists without the managed marker, ask before modifying.
|
|
421
|
+
- Always `nginx -t` before reload.
|
|
423
422
|
|
|
424
|
-
See `references/nginx-blue-green.md` for the full Nginx config template
|
|
423
|
+
See `references/nginx-blue-green.md` for the full Nginx config template.
|
|
425
424
|
|
|
426
425
|
### SSH: Bootstrap Safety Rules
|
|
427
426
|
|
|
428
|
-
Before executing privileged bootstrap work, generate an action plan listing:
|
|
429
|
-
- Packages to install/upgrade
|
|
430
|
-
- Users/groups to create/modify
|
|
431
|
-
- SSH keys to create
|
|
432
|
-
- Nginx config to create/modify
|
|
433
|
-
- Directories and permissions to change
|
|
434
|
-
- Services that may be restarted
|
|
427
|
+
Before executing privileged bootstrap work, generate an action plan listing: packages, users/groups, SSH keys, Nginx config, directories/permissions, services that may be restarted.
|
|
435
428
|
|
|
436
|
-
|
|
429
|
+
Rules:
|
|
437
430
|
- User gives one explicit approval for the entire bootstrap plan.
|
|
438
431
|
- If the plan changes during execution, pause and ask again.
|
|
439
432
|
- Bootstrap operations must be idempotent.
|
|
@@ -444,53 +437,32 @@ Execution rules:
|
|
|
444
437
|
### SSH: Multi-App Coordination
|
|
445
438
|
|
|
446
439
|
An all-app deploy creates one release group. Rules:
|
|
447
|
-
- Pre-traffic phases
|
|
448
|
-
- If any app fails before traffic switch, NO app switches traffic. Staged processes
|
|
449
|
-
- If any app fails after traffic switch, default: group rollback
|
|
440
|
+
- Pre-traffic phases must complete for ALL selected apps before ANY app switches traffic.
|
|
441
|
+
- If any app fails before traffic switch, NO app switches traffic. Staged processes stopped, live system unchanged.
|
|
442
|
+
- If any app fails after traffic switch, default: group rollback.
|
|
450
443
|
- Single-app deploys (`--app <id>`) do not affect unrelated apps.
|
|
451
444
|
|
|
452
445
|
## Validation
|
|
453
446
|
|
|
454
|
-
Validation is mandatory before production deploy. Check:
|
|
455
|
-
- SSH connectivity and user permissions
|
|
456
|
-
- Required tools present (node, npm, git, pm2, nginx)
|
|
457
|
-
- Repository reachability and branch existence
|
|
458
|
-
- Ports availability
|
|
459
|
-
- Required env vars present
|
|
460
|
-
- Nginx config syntax
|
|
461
|
-
- Health check routes accessible
|
|
447
|
+
Validation is mandatory before production deploy. Check: SSH connectivity, required tools (node, npm, git, pm2, nginx), repository reachability, port availability, required env vars, Nginx config syntax, health check routes accessible.
|
|
462
448
|
|
|
463
449
|
Persist validation in `deploy.config.json` under each section's `validated` field.
|
|
464
450
|
|
|
465
451
|
## Adapter Paths
|
|
466
452
|
|
|
467
|
-
After Discovery routes to a deployment target, read the corresponding reference
|
|
453
|
+
After Discovery routes to a deployment target, read the corresponding reference:
|
|
468
454
|
|
|
469
455
|
| Target | Reference | Mode |
|
|
470
456
|
|--------|-----------|------|
|
|
471
|
-
| SSH Linux server | SSH sections
|
|
457
|
+
| SSH Linux server | SSH sections in this file | Full automation |
|
|
472
458
|
| Vercel, Netlify, Fly.io | `references/cloud-platform-deploy.md` | Guided CLI |
|
|
473
459
|
| Docker / Docker Compose | `references/docker-deploy.md` | Guided build + run |
|
|
474
|
-
| Unrecognized target | Deployment Discovery Step 4 | Documented fallback |
|
|
475
|
-
|
|
476
|
-
The SSH path is documented inline below because it is the fully-automated adapter and the model needs its instructions in every SSH deployment session. Cloud and Docker paths are in references because they're loaded only when Discovery routes to them.
|
|
460
|
+
| Unrecognized target | §Deployment Discovery Step 4 | Documented fallback |
|
|
477
461
|
|
|
478
462
|
## Deploy History Record Schema
|
|
479
463
|
|
|
480
|
-
Each deployment, rollback, or significant event writes a record to `.prizmkit/deploy/deploy-history/<id>.json`.
|
|
481
|
-
|
|
482
|
-
Never record raw secret values in history — presence metadata only.
|
|
483
|
-
|
|
484
|
-
## Implementation Notes from Live Validation
|
|
464
|
+
Each deployment, rollback, or significant event writes a record to `.prizmkit/deploy/deploy-history/<id>.json`. Full schema in `references/deploy-history-schema.md`. Never record raw secret values in history — presence metadata only.
|
|
485
465
|
|
|
486
|
-
|
|
466
|
+
## Implementation Notes
|
|
487
467
|
|
|
488
|
-
|
|
489
|
-
2. **Verify npm separately from node.** Minimal Node installs may not bundle npm.
|
|
490
|
-
3. **Fix locale on bare Ubuntu.** Run `locale-gen en_US.UTF-8` early to avoid perl warnings in apt.
|
|
491
|
-
4. **Deploy key workflow is inherently interactive.** Generate key → wait for user to add to GitHub → verify. Headless mode cannot complete this.
|
|
492
|
-
5. **`pm2 startup` needs explicit PATH.** Always use `env PATH=$PATH:/usr/bin pm2 startup ...`.
|
|
493
|
-
6. **Persist deploy metadata on server.** Write `activeColor`, `activePort`, `lastReleaseId`, `lastDeployTimestamp` to `shared/deploy-metadata.json`.
|
|
494
|
-
7. **Detect first deployment.** If no `current` symlink and no PM2 process for the app, skip rollback safety checks and use blue (3101) as initial color.
|
|
495
|
-
8. **Build-time env vars.** Copy `.env.production` before `npm run build`, not after. `NEXT_PUBLIC_*` vars are baked at build time.
|
|
496
|
-
9. **Node.js version flexibility.** Default to v22 LTS if v25 is unavailable. Most frameworks tolerate a minor version diff.
|
|
468
|
+
Live validation findings from the first PrizmKit deployment are in `references/live-validation-notes.md`. Read when troubleshooting bootstrap or deploy issues — these cover port conflict detection, npm verification, locale fixes, deploy key interactivity, PM2 PATH handling, and build-time env var timing.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# CI/CD Workflow Templates
|
|
2
|
+
|
|
3
|
+
Read this file when `deployStrategy` is `ci-cd-push` or `ci-cd-pull`.
|
|
4
|
+
|
|
5
|
+
## Shared Configuration
|
|
6
|
+
|
|
7
|
+
**Secrets** (add to GitHub repository Settings → Secrets and variables → Actions):
|
|
8
|
+
- `SSH_HOST` — server IP/hostname
|
|
9
|
+
- `SSH_USER` — runtime user (e.g., `deploy`)
|
|
10
|
+
- `SSH_KEY` — SSH private key
|
|
11
|
+
- `SSH_PORT` — SSH port (default 22)
|
|
12
|
+
|
|
13
|
+
**Shared trigger:**
|
|
14
|
+
```yaml
|
|
15
|
+
on:
|
|
16
|
+
push:
|
|
17
|
+
branches: [<branch>]
|
|
18
|
+
paths-ignore:
|
|
19
|
+
- '.prizmkit/**'
|
|
20
|
+
- 'docs/**'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Push Mode Workflow (`ci-cd-push`)
|
|
26
|
+
|
|
27
|
+
Build happens on GitHub Actions runner. Only built artifacts are transferred to the server.
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
name: Deploy to Production (Push)
|
|
31
|
+
|
|
32
|
+
on:
|
|
33
|
+
push:
|
|
34
|
+
branches: [<branch>]
|
|
35
|
+
|
|
36
|
+
jobs:
|
|
37
|
+
deploy:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
|
|
42
|
+
- uses: actions/setup-node@v4
|
|
43
|
+
with:
|
|
44
|
+
node-version: 20
|
|
45
|
+
|
|
46
|
+
- name: Install & Build
|
|
47
|
+
run: |
|
|
48
|
+
npm ci
|
|
49
|
+
npm run build
|
|
50
|
+
|
|
51
|
+
- name: Package & Transfer
|
|
52
|
+
run: |
|
|
53
|
+
RELEASE_ID=$(date +%Y%m%d)-$(git rev-parse --short HEAD)
|
|
54
|
+
tar czf deploy-$RELEASE_ID.tar.gz \
|
|
55
|
+
<build-output-dir>/ node_modules/ package.json package-lock.json
|
|
56
|
+
scp -P ${{ secrets.SSH_PORT }} deploy-$RELEASE_ID.tar.gz \
|
|
57
|
+
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/var/www/<project>/releases/
|
|
58
|
+
|
|
59
|
+
- name: Deploy on Server
|
|
60
|
+
uses: appleboy/ssh-action@v1
|
|
61
|
+
with:
|
|
62
|
+
host: ${{ secrets.SSH_HOST }}
|
|
63
|
+
username: ${{ secrets.SSH_USER }}
|
|
64
|
+
key: ${{ secrets.SSH_KEY }}
|
|
65
|
+
port: ${{ secrets.SSH_PORT }}
|
|
66
|
+
script: |
|
|
67
|
+
cd /var/www/<project>
|
|
68
|
+
RELEASE_ID=$(date +%Y%m%d)-$(git rev-parse --short HEAD)
|
|
69
|
+
mkdir -p releases/$RELEASE_ID
|
|
70
|
+
tar xzf releases/deploy-$RELEASE_ID.tar.gz -C releases/$RELEASE_ID
|
|
71
|
+
rm releases/deploy-$RELEASE_ID.tar.gz
|
|
72
|
+
# PM2 start, health check, Nginx switch (same as manual flow)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Key difference from Pull:** the runner checks out code, installs, builds, and only transmits the result. The server doesn't need Git or build tools — just Node.js runtime and PM2.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Pull Mode Workflow (`ci-cd-pull`)
|
|
80
|
+
|
|
81
|
+
GitHub Actions runner only triggers the server. The server does all the work.
|
|
82
|
+
|
|
83
|
+
```yaml
|
|
84
|
+
name: Deploy to Production (Pull)
|
|
85
|
+
|
|
86
|
+
on:
|
|
87
|
+
push:
|
|
88
|
+
branches: [<branch>]
|
|
89
|
+
|
|
90
|
+
jobs:
|
|
91
|
+
deploy:
|
|
92
|
+
runs-on: ubuntu-latest
|
|
93
|
+
steps:
|
|
94
|
+
- name: Trigger Server Deploy
|
|
95
|
+
uses: appleboy/ssh-action@v1
|
|
96
|
+
with:
|
|
97
|
+
host: ${{ secrets.SSH_HOST }}
|
|
98
|
+
username: ${{ secrets.SSH_USER }}
|
|
99
|
+
key: ${{ secrets.SSH_KEY }}
|
|
100
|
+
port: ${{ secrets.SSH_PORT }}
|
|
101
|
+
script: |
|
|
102
|
+
cd /var/www/<project>
|
|
103
|
+
RELEASE_ID=$(date +%Y%m%d)-$(git rev-parse --short HEAD)
|
|
104
|
+
mkdir -p releases/$RELEASE_ID
|
|
105
|
+
git clone <repoUrl> --branch <branch> releases/$RELEASE_ID
|
|
106
|
+
cd releases/$RELEASE_ID
|
|
107
|
+
npm ci
|
|
108
|
+
cp ../shared/.env.production .
|
|
109
|
+
npm run build
|
|
110
|
+
# PM2 start, health check, Nginx switch
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Key difference from Push:** the workflow is simpler (one step: SSH + run script), but the server needs Git, full build toolchain, and must be able to reach the repo.
|
|
114
|
+
|
|
115
|
+
After generating the workflow, verify: the first `git push` to the configured branch will trigger the first deployment. Monitor the GitHub Actions run and report results.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Database Setup
|
|
2
|
+
|
|
3
|
+
Read this file when Discovery detected a database driver and the user wants AI-assisted database installation on the server.
|
|
4
|
+
|
|
5
|
+
## Entry condition
|
|
6
|
+
|
|
7
|
+
During Discovery Step 1 (Project Detection), database drivers were already scanned. If a driver was detected, ask after bootstrap tools are installed:
|
|
8
|
+
|
|
9
|
+
> "检测到项目使用了 <PostgreSQL/MySQL/Redis>,需要帮你在服务器上安装配置吗?"
|
|
10
|
+
> - **需要** → 继续数据库安装
|
|
11
|
+
> - **不需要** → 跳过,记录到 deploy.md,标注"数据库需用户自行配置"
|
|
12
|
+
|
|
13
|
+
## PostgreSQL setup
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
apt-get install -y postgresql postgresql-contrib
|
|
17
|
+
sudo -u postgres psql -c "CREATE DATABASE <project>;"
|
|
18
|
+
sudo -u postgres psql -c "CREATE USER <project> WITH PASSWORD '<random-password>';"
|
|
19
|
+
sudo -u postgres psql -c "GRANT ALL ON DATABASE <project> TO <project>;"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- Generate a secure random password (32 chars, alphanumeric + symbols).
|
|
23
|
+
- Write the connection string to `.prizmkit/deploy/secrets.local.json`: `DATABASE_URL=postgresql://<project>:<password>@localhost:5432/<project>`.
|
|
24
|
+
- In deploy.md, write: "PostgreSQL 已安装,连接信息已记录到 `.prizmkit/deploy/secrets.local.json`(不提交到 git)".
|
|
25
|
+
|
|
26
|
+
## MySQL setup (future)
|
|
27
|
+
|
|
28
|
+
Similar flow. Not implemented in first version — if project uses MySQL, direct user to documentation fallback.
|
|
29
|
+
|
|
30
|
+
## Redis setup
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
apt-get install -y redis-server
|
|
34
|
+
redis-cli CONFIG SET requirepass "<random-password>"
|
|
35
|
+
redis-cli CONFIG REWRITE
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- Bind to localhost only (modify `/etc/redis/redis.conf` if needed).
|
|
39
|
+
- Write `REDIS_URL=redis://:<password>@localhost:6379` to `.prizmkit/deploy/secrets.local.json`.
|
|
40
|
+
|
|
41
|
+
## Security notes
|
|
42
|
+
|
|
43
|
+
- Never write database passwords to deploy.md, because deploy.md may be committed to git and passwords would leak.
|
|
44
|
+
- Passwords stored in `.prizmkit/deploy/secrets.local.json` (gitignored).
|
|
45
|
+
- Default: database binds to localhost, no external access, because most indie projects only need local connections.
|
|
46
|
+
- Record a `"database-setup"` event in deploy history (presence metadata only, no passwords).
|
|
@@ -9,6 +9,7 @@ This file is the machine-readable deployment configuration. Always read it befor
|
|
|
9
9
|
"version": 1,
|
|
10
10
|
"project": "project-name",
|
|
11
11
|
"deploymentMode": "ssh",
|
|
12
|
+
"deployStrategy": "direct-upload|ci-cd-push|ci-cd-pull",
|
|
12
13
|
"defaults": { ... },
|
|
13
14
|
"environments": { ... },
|
|
14
15
|
"servers": [ ... ],
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Deployment Mode Details
|
|
2
|
+
|
|
3
|
+
Read this file when the user needs a detailed comparison of deployment modes during mode selection. SKILL.md contains the routing logic; this file has the full descriptions.
|
|
4
|
+
|
|
5
|
+
## Mode A — Direct Upload
|
|
6
|
+
|
|
7
|
+
1. Local build on the user's machine.
|
|
8
|
+
2. SCP built output + `node_modules` + `.env.production` to server.
|
|
9
|
+
3. PM2 start → health check → Nginx switch.
|
|
10
|
+
4. After success: offer to upgrade to CI/CD.
|
|
11
|
+
5. Bypasses: deploy key, git clone on server, server-side build.
|
|
12
|
+
|
|
13
|
+
Best for: first-time deployment, getting something live fast, low-spec servers.
|
|
14
|
+
|
|
15
|
+
## Mode B1 — CI/CD Push
|
|
16
|
+
|
|
17
|
+
1. Generate `.github/workflows/deploy.yml`: checkout → install → build → SCP tarball → SSH restart.
|
|
18
|
+
2. Add GitHub Secrets: `SSH_HOST`, `SSH_USER`, `SSH_KEY`, `SSH_PORT`.
|
|
19
|
+
3. First deploy triggered by push to configured branch.
|
|
20
|
+
4. Server only needs Node.js runtime + PM2 — no git, no build tools needed.
|
|
21
|
+
5. GitHub Actions runner handles the heavy lifting.
|
|
22
|
+
|
|
23
|
+
Best for: low-spec servers, heavy build processes, projects with large dependencies.
|
|
24
|
+
|
|
25
|
+
## Mode B2 — CI/CD Pull
|
|
26
|
+
|
|
27
|
+
1. Configure deploy key on server → add to GitHub.
|
|
28
|
+
2. Generate `.github/workflows/deploy.yml`: triggers SSH command on server.
|
|
29
|
+
3. Server-side deploy script: `git pull` → install → build → PM2 restart → health check.
|
|
30
|
+
4. Server needs full build toolchain (Node.js, npm, git).
|
|
31
|
+
5. Simpler workflow file, heavier server load.
|
|
32
|
+
|
|
33
|
+
Best for: simple setup, servers with sufficient CPU/RAM, projects where build is fast.
|
|
34
|
+
|
|
35
|
+
## Comparison
|
|
36
|
+
|
|
37
|
+
| 对比 | Push 模式 | Pull 模式 |
|
|
38
|
+
|------|----------|----------|
|
|
39
|
+
| 构建位置 | GitHub Actions runner | 服务器本地 |
|
|
40
|
+
| 服务器压力 | 低(只运行应用) | 高(编译+运行) |
|
|
41
|
+
| 配置复杂度 | 中(需 SCP 传产物) | 低(只需 SSH 触发脚本) |
|
|
42
|
+
| 适合场景 | 服务器配置低、编译重 | 部署简单优先、服务器性能充裕 |
|
|
43
|
+
| Deploy Key 需要 | 不需要 | 需要 |
|
|
44
|
+
| 产物传输 | SCP tarball | git pull(仅增量) |
|
|
45
|
+
|
|
46
|
+
## Common ground between all modes
|
|
47
|
+
|
|
48
|
+
- Same PM2 + Nginx blue/green strategy.
|
|
49
|
+
- Same health check and traffic switch procedure.
|
|
50
|
+
- Same ops commands (status/logs/restart/rollback).
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Direct Upload Deployment
|
|
2
|
+
|
|
3
|
+
Read this file when `deployStrategy` is `"direct-upload"`. The AI handles the build locally and transfers built artifacts to the server. No Git operations on the server.
|
|
4
|
+
|
|
5
|
+
## Build phase (local)
|
|
6
|
+
|
|
7
|
+
1. Run `<buildCommand>` locally (e.g., `npm run build`) in the project root.
|
|
8
|
+
2. Identify the build output directory: `.next/` for Next.js, `dist/` for Vite, `build/` for CRA.
|
|
9
|
+
3. Prepare a deployment tarball containing: build output + `node_modules/` + `package.json` + `package-lock.json` + any runtime config files.
|
|
10
|
+
|
|
11
|
+
## Transfer phase (SCP)
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
scp -P <port> deploy-<releaseId>.tar.gz <runtimeUser>@<host>:/var/www/<project>/releases/
|
|
15
|
+
ssh <runtimeUser>@<host> "cd /var/www/<project>/releases && mkdir <releaseId> && tar xzf deploy-<releaseId>.tar.gz -C <releaseId>"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Server-side setup
|
|
19
|
+
|
|
20
|
+
1. Copy `.env.production` from `shared/` into the release directory (or SCP it alongside the tarball if first deploy).
|
|
21
|
+
2. No `npm install` needed — `node_modules` was transferred directly.
|
|
22
|
+
3. Start PM2 on the inactive port. Health checks and traffic switch follow the standard flow (Groups 3-5 in SKILL.md).
|
|
23
|
+
|
|
24
|
+
## Why transfer node_modules
|
|
25
|
+
|
|
26
|
+
Direct upload is optimized for "fast first deploy." Re-running `npm ci` on a low-spec server can be slow. Transferring pre-built artifacts means the server only needs to run the app.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# DNS Setup Guidance
|
|
2
|
+
|
|
3
|
+
Read this file when the user has a domain for their project but DNS is not yet pointing to the server.
|
|
4
|
+
|
|
5
|
+
## Step 1 — Check DNS resolution
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
dig +short <domain> A
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
If it resolves to the server IP: DNS is already configured, proceed to SSL (`references/ssl-setup.md`).
|
|
12
|
+
If not: continue below.
|
|
13
|
+
|
|
14
|
+
## Step 2 — DNS setup guidance
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
域名 <example.com> 还未指向服务器 <服务器IP>。
|
|
18
|
+
|
|
19
|
+
请在 DNS 服务商(如阿里云、Cloudflare、Namecheap)添加以下记录:
|
|
20
|
+
|
|
21
|
+
Type: A
|
|
22
|
+
Name: @
|
|
23
|
+
Value: <服务器IP>
|
|
24
|
+
TTL: 600
|
|
25
|
+
|
|
26
|
+
如果要同时支持 www 子域名:
|
|
27
|
+
Type: A
|
|
28
|
+
Name: www
|
|
29
|
+
Value: <服务器IP>
|
|
30
|
+
|
|
31
|
+
配置完成后回复"好了",我继续检查并配 SSL 证书。
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Step 3 — Verify after user confirmation
|
|
35
|
+
|
|
36
|
+
- Re-run `dig +short <domain> A` to confirm resolution.
|
|
37
|
+
- If still not resolved: warn about DNS propagation delay (can take up to 48 hours, usually 5-30 minutes). Offer to wait or continue without SSL for now.
|
|
38
|
+
- Once confirmed: proceed to SSL (`references/ssl-setup.md`).
|
|
39
|
+
|
|
40
|
+
## Edge case — IP-only deployment
|
|
41
|
+
|
|
42
|
+
If user has no domain: skip DNS + SSL sections. Generate a note in deploy.md: "项目通过 IP 访问,未配置域名和 HTTPS。建议购买域名后运行 `/prizmkit-deploy setup-ssl`。"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Firewall Setup (UFW)
|
|
2
|
+
|
|
3
|
+
Read this file when the user wants AI-assisted firewall configuration during bootstrap.
|
|
4
|
+
|
|
5
|
+
## Flow
|
|
6
|
+
|
|
7
|
+
1. After core tools are installed, ask the user:
|
|
8
|
+
> "是否需要帮你配置防火墙(ufw)?只开放必要的端口,提高服务器安全性。"
|
|
9
|
+
|
|
10
|
+
2. If user declines: skip, record to deploy config.
|
|
11
|
+
|
|
12
|
+
3. If user agrees, ask which additional ports to open (beyond SSH/HTTP/HTTPS):
|
|
13
|
+
> "默认只开放 SSH(22)、HTTP(80)、HTTPS(443)。蓝绿部署预览端口(3101/3102)要不要也开放?如果需要其他端口(如数据库远程管理),可以一起列出来。"
|
|
14
|
+
|
|
15
|
+
4. Collect ports, then ask:
|
|
16
|
+
> "防火墙规则已整理好。是我直接上去改,还是你自己来?"
|
|
17
|
+
> - **A. 你帮我改** — AI 执行 ufw 命令
|
|
18
|
+
> - **B. 我自己改** — 输出规则清单,用户手工执行
|
|
19
|
+
|
|
20
|
+
## Planned rules (output before executing)
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
ufw default deny incoming
|
|
24
|
+
ufw default allow outgoing
|
|
25
|
+
ufw allow 22/tcp # SSH
|
|
26
|
+
ufw allow 80/tcp # HTTP
|
|
27
|
+
ufw allow 443/tcp # HTTPS
|
|
28
|
+
ufw allow 3101/tcp # blue preview (user-approved)
|
|
29
|
+
ufw allow 3102/tcp # green preview (user-approved)
|
|
30
|
+
ufw --force enable
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Rules for automatic execution
|
|
34
|
+
|
|
35
|
+
- Check `ufw status` first — if rules already exist, append only missing rules, don't overwrite.
|
|
36
|
+
- Never `ufw reset` unless explicitly asked, because it wipes custom rules the user may have configured manually.
|
|
37
|
+
- Record a `"security-baseline"` event in deploy history with the rule list, so future sessions can detect existing configuration.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Implementation Notes from Live Validation
|
|
2
|
+
|
|
3
|
+
These findings from the first PrizmKit deployment (PrizmIdeas) guide edge-case handling. Read when troubleshooting bootstrap or deploy issues.
|
|
4
|
+
|
|
5
|
+
1. **Detect port conflicts before installing Nginx.** Check what's on port 80/443 and ask before stopping anything, because overwriting an existing web server without confirmation can break unrelated services.
|
|
6
|
+
|
|
7
|
+
2. **Verify npm separately from node.** Minimal Node installs may not bundle npm. Run `which npm` after installing Node, because `node --version` succeeding doesn't guarantee npm is available.
|
|
8
|
+
|
|
9
|
+
3. **Fix locale on bare Ubuntu.** Run `locale-gen en_US.UTF-8` early to avoid perl warnings in apt. This is safe to run unconditionally even if locale is already configured.
|
|
10
|
+
|
|
11
|
+
4. **Deploy key workflow is inherently interactive.** Generate key → wait for user to add to GitHub → verify. Headless mode cannot complete this because it requires the user to paste the key into GitHub's UI.
|
|
12
|
+
|
|
13
|
+
5. **`pm2 startup` needs explicit PATH.** Always use `env PATH=$PATH:/usr/bin pm2 startup ...`, because the pm2 binary may not be on root's default PATH.
|
|
14
|
+
|
|
15
|
+
6. **Persist deploy metadata on server.** Write `activeColor`, `activePort`, `lastReleaseId`, `lastDeployTimestamp` to `shared/deploy-metadata.json`, because subsequent deploys and rollbacks depend on knowing the current active slot.
|
|
16
|
+
|
|
17
|
+
7. **Detect first deployment.** If no `current` symlink and no PM2 process for the app, skip rollback safety checks and use blue (3101) as initial color.
|
|
18
|
+
|
|
19
|
+
8. **Build-time env vars.** Copy `.env.production` before `npm run build`, not after. `NEXT_PUBLIC_*` vars are baked at build time and won't be picked up if the .env is added later.
|
|
20
|
+
|
|
21
|
+
9. **Node.js version flexibility.** Default to v22 LTS if v25 is unavailable. Most frameworks tolerate a minor version diff, and v22 has broader package compatibility.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# SSL/HTTPS Configuration (Let's Encrypt + Certbot)
|
|
2
|
+
|
|
3
|
+
Read this file when DNS is confirmed pointing to the server and SSL needs to be configured.
|
|
4
|
+
|
|
5
|
+
## Step 1 — Detect cloud vendor
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
# Try metadata endpoints to detect cloud vendor
|
|
9
|
+
curl -s --connect-timeout 2 http://100.100.100.200/latest/meta-data/ && echo "ALIBABA"
|
|
10
|
+
curl -s --connect-timeout 2 http://metadata.tencentyun.com/latest/meta-data/ && echo "TENCENT"
|
|
11
|
+
curl -s --connect-timeout 2 http://169.254.169.254/latest/meta-data/ && echo "AWS/GCP/AZURE"
|
|
12
|
+
```
|
|
13
|
+
Also check `/etc/hostname` for vendor patterns.
|
|
14
|
+
|
|
15
|
+
## Step 2 — Choose SSL strategy
|
|
16
|
+
|
|
17
|
+
- **Cloud vendor detected** → ask user:
|
|
18
|
+
> "检测到服务器运行在 <云厂商>。用哪种 SSL 方案?"
|
|
19
|
+
> - **A. Let's Encrypt 免费证书(推荐)** — 一行命令永久自动续期,最省心
|
|
20
|
+
> - **B. <云厂商> 自有证书** — 需手动下载配置,1年有效期需手动续期
|
|
21
|
+
>
|
|
22
|
+
> 选 A 我直接帮你搞定;选 B 你需要在云控制台下载证书后告诉我路径。
|
|
23
|
+
- **No cloud vendor / unknown** → use certbot directly, no choice needed.
|
|
24
|
+
|
|
25
|
+
## Step 3 — Certbot install & certificate request
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
# Install certbot (idempotent)
|
|
29
|
+
which certbot || apt-get install -y certbot python3-certbot-nginx
|
|
30
|
+
|
|
31
|
+
# Request certificate
|
|
32
|
+
certbot --nginx -d <domain> -d www.<domain> --non-interactive --agree-tos --email <user-email>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Collect from user before running:**
|
|
36
|
+
- Email address (Let's Encrypt expiry notifications)
|
|
37
|
+
- Confirm domain list (e.g., `example.com, www.example.com`)
|
|
38
|
+
|
|
39
|
+
## Step 4 — Verify auto-renewal
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
systemctl status certbot.timer
|
|
43
|
+
certbot renew --dry-run
|
|
44
|
+
```
|
|
45
|
+
If timer is inactive, enable it: `systemctl enable --now certbot.timer`.
|
|
46
|
+
|
|
47
|
+
## Step 5 — Record
|
|
48
|
+
|
|
49
|
+
- Write SSL configuration summary to deploy.md: certificate paths, auto-renewal status, expiry date.
|
|
50
|
+
- Record a `"ssl-setup"` event in deploy history.
|
|
51
|
+
|
|
52
|
+
## Edge cases
|
|
53
|
+
|
|
54
|
+
- **DNS not yet propagated** → certbot challenge fails. Tell user to wait and retry: `/prizmkit-deploy setup-ssl`.
|
|
55
|
+
- **Existing certificate found** → check expiry date (`certbot certificates`). If expiring within 30 days, warn. Otherwise skip.
|
|
56
|
+
- **Port 80/443 occupied by non-Nginx process** → report and ask how to resolve before proceeding.
|
|
@@ -40,6 +40,9 @@ For each unchecked task in plan.md, in order:
|
|
|
40
40
|
|
|
41
41
|
1. Read L1/L2 doc for the target file's module — check TRAPS and DECISIONS before modifying files
|
|
42
42
|
2. Apply TDD where applicable: write a failing test first, then implement until it passes. For UI components or configuration changes where unit tests don't apply, skip the test-first step.
|
|
43
|
+
- **Cover three paths for each function**: happy path (valid inputs producing expected behavior), edge cases (boundary values specific to the parameter type and domain — e.g., zero/min/max for numeric, empty collection, boundary index), and error conditions (inputs that should trigger error handling). Determine edge cases from the function's parameter types and domain logic, not from a fixed checklist. If a function has no edge or error paths, don't force them.
|
|
44
|
+
- **No redundant tests**: Check if a test for this behavior already exists before writing. Each test must verify a uniquely different code path — don't write multiple tests that exercise the same logic.
|
|
45
|
+
- **Test your own code only**: Don't test framework behavior, third-party library internals, or language built-ins. For library calls, test the integration point (correct parameters passed, return value correctly handled), not the library itself.
|
|
43
46
|
3. Mark task as `[x]` in `plan.md` immediately after completion — not batched at the end. Immediate marking means plan.md always reflects true progress, even if the session is interrupted.
|
|
44
47
|
4. **Parallel tasks**: If task has `[P]` marker, it can run in parallel with other `[P]` tasks in the same group. Sequential tasks stop on failure (later tasks may depend on this one). Parallel `[P]` tasks continue — report all failures at the end.
|
|
45
48
|
5. **Checkpoint tasks** (`CP:` prefix in plan.md): When a checkpoint task is reached, verify build passes and tests pass before continuing. Checkpoints catch integration errors early — skipping them means cascading failures in later phases.
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "prizmkit-test"
|
|
3
|
+
description: "Full-stack test generation and orchestration. Detects architecture, discovers/runs existing tests, analyzes coverage gaps, generates missing tests (unit/integration/E2E), outputs unified report. Use after completing development to verify quality before deploy. Trigger on: 'test', 'run tests', 'check quality', 'verify code', 'generate tests', 'test coverage', 'fill test gaps', 'quality check', '测试', '验证', '跑测试', '补测试'. (project)"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PrizmKit Test
|
|
7
|
+
|
|
8
|
+
A comprehensive test generation and orchestration skill. Discovers existing tests, runs them, compares coverage against spec acceptance criteria and module interfaces, generates missing tests at three levels (unit → integration → E2E), and produces a unified report.
|
|
9
|
+
|
|
10
|
+
### When to Use
|
|
11
|
+
- After completing one or more features/refactors/bugfixes
|
|
12
|
+
- As a quality gate before deploy
|
|
13
|
+
- Project has a test framework installed but zero tests written (first-time test generation)
|
|
14
|
+
- User says "test", "run tests", "verify", "check quality", "补测试"
|
|
15
|
+
|
|
16
|
+
### When NOT to Use
|
|
17
|
+
- Project has no test framework AND no code to test
|
|
18
|
+
- Trivial single-line config changes
|
|
19
|
+
|
|
20
|
+
## Precondition
|
|
21
|
+
|
|
22
|
+
| Required State | Check | If Missing |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| `.prizmkit/prizm-docs/root.prizm` exists | File exists | Run `/prizmkit-init` first |
|
|
25
|
+
| Test framework installed | Dependency in package.json or equivalent | Offer to skip or let user install one manually |
|
|
26
|
+
|
|
27
|
+
If `.prizmkit/prizm-docs/` exists but may be stale (no retrospective run after recent changes), warn user: "Prizm docs may be out of date. Gap analysis accuracy depends on current docs. Continue anyway?"
|
|
28
|
+
|
|
29
|
+
## Context Loading
|
|
30
|
+
|
|
31
|
+
Before execution, load context once:
|
|
32
|
+
|
|
33
|
+
1. **Architecture context**: Read `.prizmkit/prizm-docs/root.prizm` (L0 — project overview, module index, tech stack, conventions) and relevant L1 docs for modules in scope. If scope includes specific modules, also load relevant L2 docs for INTERFACES, DATA_FLOW, TRAPS, and DECISIONS.
|
|
34
|
+
2. **Project config**: Read `.prizmkit/config.json` (tech stack, AI CLI config).
|
|
35
|
+
3. **Dependencies**: Read `package.json` or equivalent to detect test framework and project type.
|
|
36
|
+
|
|
37
|
+
## Input
|
|
38
|
+
|
|
39
|
+
| Parameter | Required | Description |
|
|
40
|
+
|-----------|----------|-------------|
|
|
41
|
+
| `scope` | No | User selects interactively in Phase 1. In headless mode, defaults to full project. |
|
|
42
|
+
|
|
43
|
+
## Execution
|
|
44
|
+
|
|
45
|
+
### Phase 0: Architecture Detection
|
|
46
|
+
|
|
47
|
+
1. From context already loaded, classify project type:
|
|
48
|
+
|
|
49
|
+
| Signal | Classification |
|
|
50
|
+
|--------|---------------|
|
|
51
|
+
| react/vue/angular/next in deps, no backend framework | Frontend |
|
|
52
|
+
| express/fastify/django/flask in deps, no frontend framework | Backend |
|
|
53
|
+
| Both present | Fullstack |
|
|
54
|
+
| Neither clear | Ask user (headless: mark as "unknown", skip E2E) |
|
|
55
|
+
|
|
56
|
+
2. Detect test framework by scanning dependencies:
|
|
57
|
+
- Jest → `npx jest` or `npm test`
|
|
58
|
+
- Vitest → `npx vitest run`
|
|
59
|
+
- pytest → `python -m pytest`
|
|
60
|
+
- Go testing → `go test ./...`
|
|
61
|
+
- Multiple frameworks found → use the one with the most test files; list all in report
|
|
62
|
+
- Custom `npm test` script → use `npm test`
|
|
63
|
+
|
|
64
|
+
3. **Interactive mode**: Show "Detected: {type}, test framework: {name}. Correct?"
|
|
65
|
+
**Headless mode**: Auto-proceed with detected values, note assumptions in report.
|
|
66
|
+
|
|
67
|
+
### Phase 1: Scope Selection
|
|
68
|
+
|
|
69
|
+
**Interactive mode** — present three options:
|
|
70
|
+
|
|
71
|
+
1. **Full project** — all modules, all specs in `.prizmkit/specs/`
|
|
72
|
+
2. **Single module** — pick from L1 doc module names (e.g., "auth", "payment")
|
|
73
|
+
3. **Single feature** — pick from `.prizmkit/specs/###-*/` directories
|
|
74
|
+
|
|
75
|
+
**Headless mode** — default to full project. If `artifact_dir` or `scope` was passed by the caller, use that.
|
|
76
|
+
|
|
77
|
+
### Phase 2: Run Existing Tests
|
|
78
|
+
|
|
79
|
+
1. Find test directories matching common patterns: `tests/`, `__tests__/`, `*.test.*`, `*.spec.*`. If no test files exist at all, note this and skip to Phase 3 (all coverage is "missing").
|
|
80
|
+
|
|
81
|
+
2. Run the detected test command in scope. Capture:
|
|
82
|
+
- Pass/fail counts and failed test details
|
|
83
|
+
- Which test files exist (for gap analysis)
|
|
84
|
+
- Raw output (saved to report directory)
|
|
85
|
+
|
|
86
|
+
3. If existing tests fail: record failures but continue — this is coverage data. Do not attempt to fix pre-existing test failures (they predate this session).
|
|
87
|
+
|
|
88
|
+
### Phase 3: Coverage Gap Analysis
|
|
89
|
+
|
|
90
|
+
Staleness of `.prizmkit/prizm-docs/` was already checked during Context Loading (see Precondition). Gap analysis proceeds with the available data.
|
|
91
|
+
|
|
92
|
+
Compare what exists against what should exist, across three levels:
|
|
93
|
+
|
|
94
|
+
**Unit test gaps** — for each module in scope:
|
|
95
|
+
- Read the corresponding L2 `.prizm` doc INTERFACES section to get exported functions/classes. If no L2 doc exists for a module, analyze source files directly to identify exported functions/classes.
|
|
96
|
+
- Check if each has a corresponding test file (match project's test naming: `foo.test.ts`, `foo.spec.ts`, `test_foo.py`)
|
|
97
|
+
- Flag uncovered interfaces
|
|
98
|
+
|
|
99
|
+
**Integration test gaps** (skip if project has no API/DB layer — pure library/CLI tool):
|
|
100
|
+
- Read L1 doc DEPENDENCIES section for cross-module interactions
|
|
101
|
+
- Check if tests exist covering module boundaries, API endpoints, DB operations
|
|
102
|
+
- Flag missing integration coverage
|
|
103
|
+
|
|
104
|
+
**E2E test gaps** (skip if project has no UI):
|
|
105
|
+
- Collect acceptance criteria from all spec.md files in scope
|
|
106
|
+
- Check existing E2E test files against these criteria
|
|
107
|
+
- Flag uncovered criteria
|
|
108
|
+
|
|
109
|
+
### Phase 4: Generate Missing Tests
|
|
110
|
+
|
|
111
|
+
Generate tests in priority order: unit → integration → E2E. After each batch, run immediately.
|
|
112
|
+
|
|
113
|
+
When generated tests fail, distinguish two cases:
|
|
114
|
+
- **Test bug** (syntax error, wrong import, wrong mock, wrong framework API usage) → fix the test and re-run
|
|
115
|
+
- **Assertion failure** (test is valid but code returns unexpected result) → mark as "needs review" in report; do NOT modify production code. This is a potential bug discovered by the generated test.
|
|
116
|
+
|
|
117
|
+
If a test fails repeatedly after 2 fix attempts, skip it and mark as "unresolved" in the report.
|
|
118
|
+
|
|
119
|
+
**4a. Unit Tests (always applicable)**
|
|
120
|
+
|
|
121
|
+
For each uncovered interface:
|
|
122
|
+
- Read the source file to understand function signature and logic
|
|
123
|
+
- Generate test file matching project conventions (framework, naming, directory, import style, mock/fixture patterns)
|
|
124
|
+
- Common naming patterns to match:
|
|
125
|
+
- `src/foo.ts` → `src/__tests__/foo.test.ts` or `src/foo.spec.ts` or `tests/foo_test.py`
|
|
126
|
+
- Mirror the existing pattern; if no tests exist, use the framework's default convention
|
|
127
|
+
- Cover: happy path, edge cases (null/undefined/empty), error conditions, boundary values
|
|
128
|
+
- Do NOT test framework internals or third-party library behavior
|
|
129
|
+
- Run tests immediately after generating
|
|
130
|
+
|
|
131
|
+
**4b. Integration Tests**
|
|
132
|
+
|
|
133
|
+
For each module with dependencies:
|
|
134
|
+
- Generate tests for the module's primary interface exercising its real dependencies
|
|
135
|
+
- If API endpoints exist: request/response tests (valid input, invalid input, missing params, auth)
|
|
136
|
+
- If database operations exist: CRUD tests using the project's existing test database config
|
|
137
|
+
- Run tests immediately after generating
|
|
138
|
+
|
|
139
|
+
**4c. E2E Tests (conditional)**
|
|
140
|
+
|
|
141
|
+
Preconditions (ALL must be met):
|
|
142
|
+
- Playwright is available (`@playwright/test` or `playwright` in package.json dependencies, or `npx playwright --version` succeeds as fallback)
|
|
143
|
+
- Playwright browsers are installed (check `npx playwright install --dry-run 2>/dev/null` exits cleanly, or `node_modules/.cache/ms-playwright/` directory exists; if missing, warn in report and skip E2E)
|
|
144
|
+
- Project has a UI layer
|
|
145
|
+
- Project can be started (start/dev script in package.json)
|
|
146
|
+
- Acceptance criteria exist in spec.md files
|
|
147
|
+
|
|
148
|
+
If ALL met:
|
|
149
|
+
- **Before starting dev server**: detect whether it's already running: (1) check `package.json` scripts for port flags (`--port`, `-p`, `PORT=`), (2) fall back to framework defaults (3000 for React/Next/Express, 5173 for Vite, 8000 for Django, 5000 for Flask), (3) if still unknown, ask the user. Use the detected port in `lsof -i :<port>` to check. If running, tell user: "Dev server appears to be already running on port {N}. Use this running instance for E2E tests?" If user confirms, use existing instance. If user declines, skip E2E.
|
|
150
|
+
- Start the project dev server (only if not already running). Wait for it to be ready.
|
|
151
|
+
- For each uncovered acceptance criterion, generate a Playwright test script
|
|
152
|
+
- Run generated E2E tests, capture screenshots of failures
|
|
153
|
+
- **Only stop dev server if you started it.** Never stop a server that was already running.
|
|
154
|
+
|
|
155
|
+
If NOT met:
|
|
156
|
+
- Note what was skipped and why in the report
|
|
157
|
+
- If only the server wasn't startable: still generate E2E script files but mark as "not run — manual execution needed"
|
|
158
|
+
|
|
159
|
+
### Phase 5: Unified Report
|
|
160
|
+
|
|
161
|
+
Create `.prizmkit/test/{YYYY_MM_DD_HH_MM_SS}_testresult/` directory.
|
|
162
|
+
|
|
163
|
+
**test-report.md** format:
|
|
164
|
+
|
|
165
|
+
```markdown
|
|
166
|
+
# Test Report — {timestamp}
|
|
167
|
+
|
|
168
|
+
## Summary
|
|
169
|
+
- Scope: {full / module: name / feature: ###-name}
|
|
170
|
+
- Architecture: {frontend / backend / fullstack}
|
|
171
|
+
- Test framework: {name}
|
|
172
|
+
- Mode: {interactive / headless}
|
|
173
|
+
|
|
174
|
+
## Existing Tests
|
|
175
|
+
- Total: {N} | Passed: {N} | Failed: {N}
|
|
176
|
+
{failed test details or "All passing"}
|
|
177
|
+
{or "No existing tests found — generated first batch"}
|
|
178
|
+
|
|
179
|
+
## Coverage Gaps Found
|
|
180
|
+
| Module | Interface | Type | Status |
|
|
181
|
+
|--------|-----------|------|--------|
|
|
182
|
+
| ... | ... | unit/integration/e2e | covered / generated / needs-review / unresolved / skipped |
|
|
183
|
+
|
|
184
|
+
## Generated Tests
|
|
185
|
+
- Unit: {N} generated, {N} needs-review, {N} unresolved
|
|
186
|
+
- Integration: {N} generated, {N} needs-review, {N} unresolved
|
|
187
|
+
- E2E: {N} generated, {N} skipped ({reason})
|
|
188
|
+
|
|
189
|
+
## Final Status
|
|
190
|
+
- All tests passing: {yes / no}
|
|
191
|
+
- Needs human review: {list of tests marked needs-review}
|
|
192
|
+
{remaining failures if any}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Also save:
|
|
196
|
+
- `existing-test-output.txt` — raw output from Phase 2
|
|
197
|
+
- `generated-tests/` — copies of all generated test files
|
|
198
|
+
- `e2e-output/` — E2E logs and failure screenshots (if applicable)
|
|
199
|
+
|
|
200
|
+
## Output
|
|
201
|
+
|
|
202
|
+
- Test report: `.prizmkit/test/{timestamp}_testresult/test-report.md`
|
|
203
|
+
- Generated test files written to project test directories
|
|
204
|
+
- Existing test output, generated test copies, and E2E artifacts in the report directory
|
|
205
|
+
|
|
206
|
+
## Recovery
|
|
207
|
+
|
|
208
|
+
If the session is interrupted:
|
|
209
|
+
- Check `.prizmkit/test/` for the most recent report directory — it contains what was completed before interruption
|
|
210
|
+
- Re-run `/prizmkit-test` — it starts fresh, but Phase 2 will skip tests that already pass, and Phase 3 will re-evaluate gaps
|
|
211
|
+
|
|
212
|
+
## Examples
|
|
213
|
+
|
|
214
|
+
### Example 1: Full-Project Quality Check with Test Generation
|
|
215
|
+
|
|
216
|
+
**User**: `/prizmkit-test`
|
|
217
|
+
|
|
218
|
+
**Phase 0 — Architecture Detection**:
|
|
219
|
+
```
|
|
220
|
+
Detected: Fullstack (React + Express)
|
|
221
|
+
Test framework: Vitest (7 existing test files)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Phase 1 — Scope Selection** (user selects option 1):
|
|
225
|
+
```
|
|
226
|
+
Scope: Full project (all modules, all specs)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**Phase 2 — Existing Tests**: 7 test files found, 20 tests run, 18 passed, 2 pre-existing failures (recorded, not fixed).
|
|
230
|
+
|
|
231
|
+
**Phase 3 — Gap Analysis** (excerpt):
|
|
232
|
+
| Module | Interface | Type | Status |
|
|
233
|
+
|--------|-----------|------|--------|
|
|
234
|
+
| auth | login() | unit | missing |
|
|
235
|
+
| auth | register() | unit | missing |
|
|
236
|
+
| payment | processPayment() | unit | missing |
|
|
237
|
+
| payment | api/checkout | integration | missing |
|
|
238
|
+
| — | Checkout flow | e2e | missing |
|
|
239
|
+
|
|
240
|
+
**Phase 4**: Generated 5 unit tests (3 passing, 2 assertion failures marked "needs-review"), 1 integration test (passing), 1 E2E test (passing).
|
|
241
|
+
|
|
242
|
+
**Phase 5 — Report Summary**:
|
|
243
|
+
```
|
|
244
|
+
Generated: 5 unit (2 needs-review), 1 integration, 1 E2E
|
|
245
|
+
Report: .prizmkit/test/2026_05_23_14_30_00_testresult/test-report.md
|
|
246
|
+
Needs human review: processPayment (returns 400 for negative amounts, expected 422), refund (missing authorization header causes 500 instead of 401)
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Example 2: Single-Feature Targeted Test
|
|
250
|
+
|
|
251
|
+
**User**: `/prizmkit-test`
|
|
252
|
+
|
|
253
|
+
**Phase 0 — Architecture Detection**:
|
|
254
|
+
```
|
|
255
|
+
Detected: Backend (Express)
|
|
256
|
+
Test framework: Vitest
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Phase 1 — Scope Selection** (user selects option 3, then picks "042-payment-gateway"):
|
|
260
|
+
```
|
|
261
|
+
Scope: Single feature — 042-payment-gateway
|
|
262
|
+
Test files in scope: 2
|
|
263
|
+
|
|
264
|
+
**Phase 2 — Existing Tests**: 2 test files, 8 tests, all passing.
|
|
265
|
+
|
|
266
|
+
**Phase 3 — Gap Analysis** (excerpt):
|
|
267
|
+
| Module | Interface | Type | Status |
|
|
268
|
+
|--------|-----------|------|--------|
|
|
269
|
+
| payment | processPayment() | unit | missing |
|
|
270
|
+
| payment | refund() | unit | missing |
|
|
271
|
+
|
|
272
|
+
**Phase 4**: Generated 2 unit tests (both passing). No integration/E2E applicable for this scope.
|
|
273
|
+
|
|
274
|
+
**Phase 5 — Report Summary**:
|
|
275
|
+
```
|
|
276
|
+
Generated: 2 unit tests (all passing)
|
|
277
|
+
Report: .prizmkit/test/2026_05_23_15_00_00_testresult/test-report.md
|
|
278
|
+
All tests passing. Ready for commit.
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**HANDOFF:** Independent skill — no handoff. User may proceed to `/prizmkit-committer` if all tests pass, or fix issues manually if tests are marked "needs-review".
|
package/package.json
CHANGED
package/src/scaffold.js
CHANGED
|
@@ -769,6 +769,11 @@ export async function installPlaywrightCli(projectRoot, dryRun) {
|
|
|
769
769
|
try {
|
|
770
770
|
execSync('playwright-cli install --skills', { cwd: projectRoot, stdio: 'pipe', timeout: 60000 });
|
|
771
771
|
console.log(chalk.green(' ✓ playwright-cli skills installed'));
|
|
772
|
+
// playwright-cli creates an empty .playwright directory — remove it
|
|
773
|
+
const dotPlaywright = path.join(projectRoot, '.playwright');
|
|
774
|
+
if (fs.pathExistsSync(dotPlaywright)) {
|
|
775
|
+
fs.removeSync(dotPlaywright);
|
|
776
|
+
}
|
|
772
777
|
} catch (e) {
|
|
773
778
|
console.log(chalk.yellow(` ⚠ Skills install skipped: ${e.message}`));
|
|
774
779
|
console.log(chalk.yellow(' ⚠ Run manually: playwright-cli install --skills'));
|