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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "frameworkVersion": "1.1.49",
3
- "bundledAt": "2026-05-21T14:22:00.608Z",
4
- "bundledFrom": "a8dea99"
2
+ "frameworkVersion": "1.1.53",
3
+ "bundledAt": "2026-05-24T05:20:15.152Z",
4
+ "bundledFrom": "156de40"
5
5
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.49",
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. Trigger on: 'deploy', 'deploy my app', 'help me deploy', 'ship it', 'take this live', 'deploy to Vercel', 'deploy to my server', 'how do I deploy this', any deployment or hosting question."
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
- SSH Linux server → §SSH Deployment Path (full automation)
78
- bootstrap, configure, deploy, operate
79
- First-version: PM2 + Nginx + blue/green
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
- The SSH path is fully documented in the sections below. Cloud and Docker paths follow the same discovery and documentation patterns but use platform CLIs instead of SSH + PM2.
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
- - Prerequisites (tools, accounts, versions)
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
- - Must never wait for user input or prompt — unattended shells timing out on a prompt blocks pipelines silently.
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 — currently unused, place for PrizmKit-managed deploy scripts and templates
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
- The full `deploy.config.json` schema is documented in `references/deploy-config-schema.md`. Read it when writing or validating config.
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
- ## SSH Deployment Path (Full Automation)
159
+ After Discovery routes to SSH, **before** entering the configuration wizard, ask the user how they want to deploy.
175
160
 
176
- The following sections — Server Model through Multi-App Coordination — define the SSH deployment adapter. This is the only fully-automated path in the first version. Route here when Discovery determines the target is a Linux server with SSH access.
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. The flow is: **collect → validate → confirm → persist**.
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`) — used for initial package install and user creation
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
- Ask for and validate:
217
- - **Git URL** (e.g., `git@github.com:owner/repo.git`)
218
- - **Branch** (e.g., `master`)
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 the public key to the user with explicit instruction: "Add this to GitHub Deploy Keys (read-only)"
224
- 3. Wait for user confirmation, then verify: attempt a git clone as runtime user
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
- - Scan source code for `process.env.<VAR>` references.
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 to the user showing every privileged action before executing anything.
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 before starting Nginx:**
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 (if strategy is 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
- - `git clone <repoUrl> --branch <branch> releases/<releaseId>` as runtime user.
303
- - `cd releases/<releaseId> && <installCommand>` as runtime user.
304
- - Copy `.env.production` from `shared/` into release dir BEFORE build `NEXT_PUBLIC_*` vars are baked at build time.
305
- - Run `<buildCommand>`. If build fails: STOP.
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 the inactive port via PM2: `pm2 start npm --name <project>-<app>-<color> -- run start -- -p <inactivePort>`.
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. Do NOT switch traffic. Record failure.
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 (switch Nginx back, restart old PM2).
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 to `.prizmkit/deploy/deploy-history/<releaseId>.json` (schema: `references/deploy-history-schema.md`).
321
- - Update `deploy.config.json` with new validation status.
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
- The active color (blue or green) maps to a port:
326
- - Blue: port 3101 (default)
327
- - Green: port 3102 (default)
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
- Active color is persisted in `/var/www/<project>/shared/deploy-metadata.json`. If metadata is missing, rediscover from Nginx `proxy_pass` directive or from running PM2 processes.
354
+ See `references/nginx-blue-green.md` for the full Nginx config template and traffic switch procedure.
330
355
 
331
- PM2 process naming: `<project>-<app>-<color>` (deterministic, never reuse old release IDs in names).
356
+ ### SSH: Rollback
332
357
 
333
- Nginx config must include the PrizmKit managed marker:
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
- Before modifying any Nginx config that lacks this marker, ask for user confirmation.
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
- Always `nginx -t` before `systemctl reload nginx`. If syntax check fails, abort.
362
+ If no previous release exists, rollback is not possible state this clearly.
341
363
 
342
- ### SSH: Rollback
364
+ ### SSH: Operations Commands
343
365
 
344
- Two rollback triggers:
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
- Rollback steps:
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
- If no previous release exists (first deployment), rollback is not possible state this clearly.
370
+ **restart --app \<id\>:** identify active PM2 process `pm2 restart` wait health checks.
359
371
 
360
- ### SSH: Operations Commands
372
+ **health --app \<id\>:** run all configured health checks, report pass/fail for each.
361
373
 
362
- #### status
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
- #### logs --app <id>
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
- #### restart --app <id>
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
- #### health --app <id>
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
- #### history
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
- This is non-negotiable. Even if config allows it, headless must reject production.
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 to the user and ask for takeover decision:
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
- - Managed marker format: `# PrizmKit Managed: <project> — DO NOT EDIT MANUALLY`
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, traffic switch procedure, and active port rediscovery technique.
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
- Execution rules:
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 (fetch, install, build, stage) must complete for ALL selected apps before ANY app switches traffic.
448
- - If any app fails before traffic switch, NO app switches traffic. Staged processes are stopped, live system unchanged.
449
- - If any app fails after traffic switch, default: group rollback (all apps in the release group roll back).
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 file for execution details:
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 below (Server Model through Multi-App) | Full automation |
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`. The full schema is in `references/deploy-history-schema.md` read it when writing history records.
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
- These findings from PrizmIdeas first deployment should guide your behavior:
466
+ ## Implementation Notes
487
467
 
488
- 1. **Detect port conflicts before installing Nginx.** Check what's on port 80/443 and ask before stopping anything.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prizmkit",
3
- "version": "1.1.49",
3
+ "version": "1.1.53",
4
4
  "description": "Create a new PrizmKit-powered project with clean initialization — no framework dev files, just what you need.",
5
5
  "type": "module",
6
6
  "bin": {
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'));