codebyplan 1.13.52 → 1.13.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.
@@ -0,0 +1,291 @@
1
+ ---
2
+ scope: org-shared
3
+ name: cbp-setup-cd
4
+ description: Detect configured CD surfaces, write/update .codebyplan/cd.json via `codebyplan cd init`, scaffold publish.yml and release-desktop.yml GitHub Actions workflows, and walk through environment/approval/OIDC setup. Interactive, idempotent.
5
+ argument-hint: "[--force]"
6
+ effort: xhigh
7
+ allowed-tools: Read, Write, Edit, Bash(cat *), Bash(jq *), Bash(test *), Bash(ls *), Bash(diff *), Bash(codebyplan cd *), Bash(npx codebyplan cd *), AskUserQuestion
8
+ ---
9
+
10
+ # CD Setup
11
+
12
+ Configure `.codebyplan/cd.json`, scaffold `.github/workflows/publish.yml` and
13
+ `.github/workflows/release-desktop.yml`, and record the credential env-var names needed
14
+ at deploy time. Invoke at any time. Already-configured surfaces are preserved unless
15
+ `--force` is passed.
16
+
17
+ Pass `--force` to re-detect all surfaces and overwrite existing workflow files.
18
+
19
+ ## Arguments
20
+
21
+ Inspect `$ARGUMENTS` for `--force`. If present, set `force_mode = true`.
22
+ Absent: idempotent mode — existing surface keys in `.codebyplan/cd.json` are preserved;
23
+ workflow files are not overwritten unless `--force`.
24
+
25
+ ## Step 1 — Detect configured surfaces + read current state
26
+
27
+ Read detection signals and existing config:
28
+
29
+ ```bash
30
+ cat .codebyplan/shipment.json 2>/dev/null || echo '{}'
31
+ cat .codebyplan/cd.json 2>/dev/null || echo '{}'
32
+ ```
33
+
34
+ **Surface detection signals** (derive from `shipment.json` + filesystem):
35
+
36
+ | Surface | Signal |
37
+ |---------|--------|
38
+ | `npm` | `packages/*/package.json` with `publishConfig.access` set |
39
+ | `tauri` | `apps/*/src-tauri/tauri.conf.json` present |
40
+ | `vscode` | `apps/*/package.json` with `contributes` block |
41
+ | `expo` | `apps/*/eas.json` present |
42
+ | `vercel` | `.vercel/project.json` or `vercel.json` in any app |
43
+ | `railway` | `apps/*/railway.toml` or `apps/*/Dockerfile` present |
44
+
45
+ **Idempotency**: a surface already in `.codebyplan/cd.json` is "configured". A newly
46
+ detected surface not yet in the file is "new". A surface in the file but no longer
47
+ detected is "stale".
48
+
49
+ Display a detection table:
50
+
51
+ ```
52
+ Surface | Detected | Configured | Workflow file
53
+ --------- | -------- | ---------- | ----------------------------------------
54
+ npm | yes | yes | .github/workflows/publish.yml (present)
55
+ tauri | yes | yes | .github/workflows/release-desktop.yml (present)
56
+ vscode | no | no | —
57
+ expo | no | no | —
58
+ ```
59
+
60
+ ## Step 2 — Confirm surfaces to manage
61
+
62
+ AskUserQuestion (multi-select):
63
+
64
+ ```
65
+ Detected CD surfaces:
66
+ <table from Step 1>
67
+
68
+ Which surfaces should be managed by cd.json?
69
+ Already-configured surfaces are pre-checked. Deselect to remove from cd.json.
70
+
71
+ Select all that apply:
72
+ A) npm — publish.yml (GitHub Actions + OIDC)
73
+ B) tauri — release-desktop.yml (cross-platform Tauri build + signing)
74
+ C) vscode — VS Code marketplace publish (undetected — add eas.json to enable)
75
+ D) expo — EAS build + store submit (undetected)
76
+ E) vercel — Vercel production deploy (managed by Vercel GitHub integration)
77
+ F) railway — Railway deploy hook (managed by Railway GitHub integration)
78
+ ```
79
+
80
+ In `--force` mode: re-ask even for already-configured surfaces.
81
+ Otherwise: surfaces already in `cd.json` are preserved without re-asking.
82
+
83
+ If an expected surface is MISSING from detection: add the detection signal (e.g.
84
+ `publishConfig.access` in package.json, or `src-tauri/tauri.conf.json`) and re-run.
85
+ To DROP a surface: deselect it here and re-run with `--force` to remove its key from
86
+ `cd.json`, or edit `.codebyplan/cd.json` directly.
87
+
88
+ ## Step 3 — Collect credential env-var names (per surface)
89
+
90
+ For each confirmed surface, collect only the env-var NAMES (never the values). Skip if
91
+ `--force` is absent AND `credentials.env_var_names[]` is already non-empty in `cd.json`.
92
+
93
+ Per-surface default name sets (accept defaults or override):
94
+
95
+ | Surface | Default env-var names |
96
+ | ------- | --------------------- |
97
+ | `npm` (OIDC) | *(none — OIDC handles auth; record `[]`)* |
98
+ | `npm` (token) | `NPM_TOKEN` |
99
+ | `tauri` | `TAURI_SIGNING_PRIVATE_KEY`, `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`, `APPLE_CERTIFICATE`, `APPLE_CERTIFICATE_PASSWORD`, `APPLE_SIGNING_IDENTITY`, `APPLE_API_ISSUER`, `APPLE_API_KEY`, `APPLE_API_KEY_CONTENT`, `WINDOWS_CERTIFICATE`, `WINDOWS_CERTIFICATE_PASSWORD` |
100
+ | `vscode` | `VSCE_PAT` |
101
+ | `expo` | `EXPO_TOKEN` |
102
+
103
+ Full var descriptions: [reference/github-actions-cd.md](reference/github-actions-cd.md) § Per-Surface Credential Var-Name Reference.
104
+
105
+ Record collected names into `credentials.env_var_names[]`. Never write secret values.
106
+
107
+ ## Step 4 — Collect environment + approval config (per surface)
108
+
109
+ For each confirmed surface, ask about GitHub Environments and approval gates. Skip if
110
+ already configured in `cd.json` and `--force` is absent.
111
+
112
+ AskUserQuestion per surface:
113
+
114
+ ```
115
+ GitHub Environment config for [surface]:
116
+
117
+ 1. Deploy environment name (leave blank for none — e.g. "production"):
118
+ Environment: ___
119
+
120
+ 2. Require manual approval before deploy?
121
+ A) No — auto-deploy on push (recommended for npm OIDC / Tauri tag)
122
+ B) Yes — require a reviewer to approve the workflow run
123
+
124
+ 3. OIDC auth (exchange GitHub OIDC token for deploy credential)?
125
+ A) Yes — recommended for npm (no long-lived token; requires Trusted Publisher config on npmjs.com)
126
+ B) No — use a long-lived token from repository secrets
127
+ ```
128
+
129
+ Record as `environment`, `approval_required`, and `oidc_auth` on the surface block.
130
+
131
+ ## Step 5 — Write .codebyplan/cd.json
132
+
133
+ Run `codebyplan cd init` to write the config:
134
+
135
+ ```bash
136
+ npx codebyplan cd init [--force]
137
+ ```
138
+
139
+ The CLI writes `cd.json` from the collected surface data. If the CLI is unavailable (not
140
+ yet on PATH), write the file directly via jq:
141
+
142
+ ```bash
143
+ jq -n \
144
+ --argjson surfaces "$SURFACES_JSON" \
145
+ --argjson workflow "$WORKFLOW_JSON" \
146
+ '{surfaces: $surfaces, workflow: $workflow}' \
147
+ > .codebyplan/cd.json
148
+ ```
149
+
150
+ Confirm by reading back the result:
151
+
152
+ ```bash
153
+ cat .codebyplan/cd.json
154
+ ```
155
+
156
+ Per-surface shape: `{ trigger, path_filter, approval_required, oidc_auth, version_gate,
157
+ credentials: { env_var_names[] } }`. Credentials are env-var NAMES only — never values.
158
+ Schema: `packages/codebyplan-package/src/lib/types.ts` (`CdConfig`).
159
+
160
+ ## Step 6 — Scaffold workflow files (diff-guarded)
161
+
162
+ Preview each workflow before writing:
163
+
164
+ ```bash
165
+ npx codebyplan cd scaffold-workflow --dry-run
166
+ ```
167
+
168
+ For each workflow file that already exists, show a diff and ask before overwriting (unless
169
+ `--force` is set):
170
+
171
+ ```bash
172
+ diff .github/workflows/publish.yml <(npx codebyplan cd scaffold-workflow --workflow publish --dry-run)
173
+ ```
174
+
175
+ AskUserQuestion (only when file exists and `--force` is absent):
176
+
177
+ ```
178
+ .github/workflows/publish.yml already exists.
179
+ Diff (existing → new):
180
+ <diff output>
181
+
182
+ Overwrite?
183
+ A) Yes — adopt the scaffolded workflow (recommended — picks up latest template)
184
+ B) No — keep existing workflow unchanged
185
+ ```
186
+
187
+ Then write:
188
+
189
+ ```bash
190
+ npx codebyplan cd scaffold-workflow [--force]
191
+ ```
192
+
193
+ If the CLI errors (missing bin, not yet released), write from the canonical templates at
194
+ `packages/codebyplan-package/templates/github-workflows/`:
195
+
196
+ ```bash
197
+ cp packages/codebyplan-package/templates/github-workflows/publish.yml \
198
+ .github/workflows/publish.yml
199
+ cp packages/codebyplan-package/templates/github-workflows/release-desktop.yml \
200
+ .github/workflows/release-desktop.yml
201
+ ```
202
+
203
+ Only copy templates relevant to the confirmed surface set (npm → publish.yml;
204
+ tauri → release-desktop.yml).
205
+
206
+ After writing, update `cd.json` to record `workflow.workflows_scaffolded: true` and the
207
+ current timestamp:
208
+
209
+ ```bash
210
+ jq '.workflow.workflows_scaffolded = true | .workflow.scaffolded_at = "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'"' \
211
+ .codebyplan/cd.json > .codebyplan/cd.json.tmp \
212
+ && mv .codebyplan/cd.json.tmp .codebyplan/cd.json
213
+ ```
214
+
215
+ ## Step 7 — OIDC Trusted Publishing verification (npm surface)
216
+
217
+ If the npm surface uses `oidc_auth: true`, walk the user through verifying the npmjs.com
218
+ Trusted Publisher registration:
219
+
220
+ ```
221
+ npm OIDC Trusted Publishing setup
222
+
223
+ Verify these settings on npmjs.com → package → Settings → Trusted Publishers:
224
+
225
+ Publisher type : GitHub Actions
226
+ Repository owner: <github-org>
227
+ Repository name : <repo-slug>
228
+ Workflow filename: publish.yml
229
+ Environment : (blank, unless you set a GitHub Environment above)
230
+
231
+ If the Trusted Publisher is NOT configured, publish.yml will fail with E401.
232
+ Configure it at: https://www.npmjs.com/package/<package-name>/access
233
+
234
+ Configured? (Y/n)
235
+ ```
236
+
237
+ If `n`: print the npmjs.com configuration URL and pause — the user must complete this
238
+ before the first publish will succeed. Record the gap in `cd.json` as
239
+ `workflow.npm_oidc_publisher_verified: false`.
240
+
241
+ On `Y`: record `workflow.npm_oidc_publisher_verified: true`.
242
+
243
+ Skip this step when `oidc_auth: false` for the npm surface.
244
+
245
+ ## Step 8 — Verify and report
246
+
247
+ Re-read the config and confirm workflow files exist:
248
+
249
+ ```bash
250
+ cat .codebyplan/cd.json
251
+ test -f .github/workflows/publish.yml && echo "publish.yml present" || echo "publish.yml MISSING"
252
+ test -f .github/workflows/release-desktop.yml && echo "release-desktop.yml present" || echo "release-desktop.yml MISSING"
253
+ ```
254
+
255
+ Emit a summary:
256
+
257
+ ```
258
+ CD Setup — Complete
259
+
260
+ Surface | trigger | path_filter | approval | oidc | version_gate | workflow
261
+ ------- | ------------- | -------------------------------- | -------- | ----- | ------------ | --------
262
+ npm | push-to-main | packages/codebyplan-package/** | no | yes | yes | publish.yml (present)
263
+ tauri | push-to-main | apps/desktop/** | no | no | yes | release-desktop.yml (present)
264
+
265
+ cd.json: .codebyplan/cd.json (written)
266
+
267
+ Next:
268
+ 1. Add the credential env vars to GitHub repository secrets (Settings → Secrets and variables → Actions).
269
+ 2. For npm OIDC: verify the Trusted Publisher on npmjs.com (Step 7 above).
270
+ 3. Push a version bump to main to verify the publish.yml gate fires.
271
+ 4. See reference/github-actions-cd.md for workflow anatomy and troubleshooting.
272
+ ```
273
+
274
+ ## Key Rules
275
+
276
+ - Credentials are NEVER written to `cd.json` or this skill — var names only
277
+ - Idempotent — re-running without `--force` preserves existing surface keys and workflow
278
+ files; it never clobbers a customized workflow
279
+ - Diff-guarded — existing workflow files are shown as a diff before overwriting
280
+ - Repos without `cd.json` fall back to the existing surface-detection path in `/cbp-ship`
281
+ — this skill writes the config that informs `/cbp-ship` Step 3 variant selection
282
+ - This skill is org-shared; its template twin at
283
+ `packages/codebyplan-package/templates/skills/cbp-setup-cd/SKILL.md` must stay
284
+ byte-identical (GATE-6)
285
+
286
+ ## Additional resources
287
+
288
+ - Workflow anatomy + OIDC + drift-guard: [reference/github-actions-cd.md](reference/github-actions-cd.md)
289
+ - CD config schema: `packages/codebyplan-package/src/lib/types.ts` (`CdConfig`)
290
+ - CD CLI commands: `packages/codebyplan-package/src/cli/cd.ts`
291
+ - Surface detection signals: `packages/codebyplan-package/src/lib/cd-init.ts` (`detectSurfaces`, `normaliseSurfaceKey`)
@@ -0,0 +1,231 @@
1
+ # GitHub Actions CD Reference
2
+
3
+ Workflow anatomy, OIDC setup, drift-guard guidance, and per-surface credential
4
+ var-name lists for the `codebyplan cd` scaffold.
5
+
6
+ ## Overview
7
+
8
+ GitHub Actions CD runs on every push to main (path-filtered per surface). The
9
+ `codebyplan cd scaffold-workflow` command writes `.github/workflows/publish.yml`
10
+ (npm surface) and `.github/workflows/release-desktop.yml` (Tauri surface) from
11
+ bundled canonical templates.
12
+
13
+ Workflow triggers:
14
+
15
+ ```yaml
16
+ # publish.yml (npm surface)
17
+ on:
18
+ push:
19
+ branches: [main, 'feat/**']
20
+ paths: ['packages/<package>/**']
21
+ workflow_dispatch:
22
+ inputs:
23
+ dry_run: { type: boolean, default: false }
24
+
25
+ # release-desktop.yml (Tauri surface)
26
+ on:
27
+ push:
28
+ branches: [main]
29
+ paths: ['apps/desktop/**']
30
+ workflow_dispatch: {}
31
+ ```
32
+
33
+ ## publish.yml Structure (npm surface)
34
+
35
+ Key sections of the scaffolded npm workflow:
36
+
37
+ | Section | What it does |
38
+ | ------- | ------------ |
39
+ | `check-version` job | Reads `package.json` version, compares against npm registry, sets `should_publish` output |
40
+ | `publish-codebyplan` job | Builds the package, upgrades npm for OIDC, publishes via `npm publish --access public --tag <dist_tag>` |
41
+ | `tag-and-release` job | Creates a `v<version>` git tag and GitHub release (idempotent) |
42
+ | `id-token: write` permission | Required for OIDC Trusted Publishing — no long-lived `NPM_TOKEN` needed |
43
+
44
+ The `check-version` job enforces several guards:
45
+
46
+ - **main push + stable version**: compares committed version against npm registry; publishes only when version is strictly greater.
47
+ - **main push + prerelease version**: skipped — prerelease versions on main require `workflow_dispatch` or a `feat/**` branch.
48
+ - **feat/** push + stable version**: skipped — feat branches require a prerelease version (e.g. `1.2.0-beta.1`).
49
+ - **feat/** push + prerelease version**: publishes only if the exact version is not already on npm (exact-version guard).
50
+ - **workflow_dispatch**: always publishes (recovery / forced re-publish path).
51
+
52
+ Scaffold only this workflow:
53
+
54
+ ```bash
55
+ npx codebyplan cd scaffold-workflow --workflow publish
56
+ ```
57
+
58
+ Path filters are baked into the workflow templates (they are not a CLI flag) — edit
59
+ the generated `.github/workflows/publish.yml` `paths:` block directly if your package
60
+ lives elsewhere.
61
+
62
+ ## release-desktop.yml Structure (Tauri surface)
63
+
64
+ Key sections of the scaffolded Tauri workflow:
65
+
66
+ | Section | What it does |
67
+ | ------- | ------------ |
68
+ | `check-version` job | Reads `apps/desktop/src-tauri/tauri.conf.json` version, checks whether `desktop-v<version>` tag exists |
69
+ | `build` job (matrix) | Builds macOS (arm64 + x86_64) and Windows (x86_64) using `tauri-apps/tauri-action` |
70
+ | `notify` job | Downloads `latest.json` from the GitHub release, posts release metadata to the CodeByPlan API |
71
+ | `contents: write` permission | Required to create tags and GitHub releases |
72
+
73
+ The build matrix:
74
+
75
+ | Platform | Target | Label |
76
+ | -------- | ------ | ----- |
77
+ | `macos-latest` | `aarch64-apple-darwin` | macOS (Apple Silicon) |
78
+ | `macos-latest` | `x86_64-apple-darwin` | macOS (Intel) |
79
+ | `windows-latest` | `x86_64-pc-windows-msvc` | Windows (x86_64) |
80
+
81
+ Windows leg is skipped when `WINDOWS_CERTIFICATE` secret is absent — lets macOS-only
82
+ notarized releases ship while the Windows EV cert is being procured.
83
+
84
+ ## OIDC Setup for npm Publish
85
+
86
+ npm Trusted Publishing (OIDC) eliminates long-lived `NPM_TOKEN` secrets. GitHub exchanges
87
+ a short-lived OIDC token for a publish credential at workflow runtime.
88
+
89
+ **Requirements:**
90
+
91
+ 1. npm >= 11.5.1 (the workflow upgrades npm before publishing — no manual action needed).
92
+ 2. A Trusted Publisher entry on npmjs.com configured for this repo + workflow.
93
+ 3. `id-token: write` permission on the publish job (already in the scaffolded template).
94
+ 4. No `registry-url:` on `actions/setup-node` — that would inject `_authToken` into
95
+ `.npmrc`, shadowing the OIDC exchange and causing `E404`.
96
+
97
+ **Configuring the Trusted Publisher on npmjs.com:**
98
+
99
+ 1. Go to `https://www.npmjs.com/package/<package-name>/access`.
100
+ 2. Under **Trusted Publishers**, click **Add a publisher**.
101
+ 3. Fill in:
102
+ - Publisher type: `GitHub Actions`
103
+ - Repository owner: `<github-org>`
104
+ - Repository name: `<repo-slug>`
105
+ - Workflow filename: `publish.yml`
106
+ - Environment: (blank unless a GitHub Environment is used)
107
+ 4. Save.
108
+
109
+ After the first successful publish, no further action is needed unless the workflow
110
+ filename or repo changes.
111
+
112
+ **Prerelease dist-tag routing:**
113
+
114
+ The workflow computes the dist-tag from the version string:
115
+
116
+ | Version | dist-tag |
117
+ | ------- | -------- |
118
+ | `1.2.3` | `latest` |
119
+ | `1.2.3-beta.1` | `beta` |
120
+ | `1.2.3-rc.1` | `rc` |
121
+
122
+ Consumers install the stable channel with `npm install <pkg>` and the prerelease channel
123
+ with `npm install <pkg>@beta`.
124
+
125
+ ## Drift Guard
126
+
127
+ Both workflow files may be adopted from the canonical templates via:
128
+
129
+ ```bash
130
+ npx codebyplan cd scaffold-workflow [--force]
131
+ ```
132
+
133
+ Without `--force`, the skill shows a diff of the existing file vs the template before
134
+ overwriting. **Never silently overwrite a customized workflow** — always diff first and
135
+ confirm.
136
+
137
+ Drift from the canonical template accumulates when:
138
+
139
+ - The repo patches a workflow inline (e.g. changes `node-version`).
140
+ - A new version of the template ships in `codebyplan` but the repo has not re-run
141
+ `/cbp-setup-cd`.
142
+
143
+ Recommended practice: re-run `/cbp-setup-cd` after each `codebyplan` version bump that
144
+ mentions workflow changes in its changelog; review the diff before accepting.
145
+
146
+ ## Per-Surface Credential Var-Name Reference
147
+
148
+ Credential ENV VAR NAMES only — never the values. Set these as GitHub repository secrets
149
+ at Settings → Secrets and variables → Actions.
150
+
151
+ ### npm surface (OIDC — no long-lived token required)
152
+
153
+ When `oidc_auth: true` (recommended):
154
+
155
+ | Var name | Purpose |
156
+ | -------- | ------- |
157
+ | *(none required)* | OIDC handles auth via Trusted Publisher; no secret needed |
158
+
159
+ When `oidc_auth: false` (fallback):
160
+
161
+ | Var name | Purpose |
162
+ | -------- | ------- |
163
+ | `NPM_TOKEN` | Long-lived npm automation token (scoped to the package) |
164
+
165
+ ### tauri surface
166
+
167
+ | Var name | Required | Purpose |
168
+ | -------- | -------- | ------- |
169
+ | `TAURI_SIGNING_PRIVATE_KEY` | Yes | Updater artifact signing (all platforms) |
170
+ | `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` | Yes | Passphrase for the signing key |
171
+ | `APPLE_CERTIFICATE` | macOS only | Base64-encoded `.p12` developer certificate |
172
+ | `APPLE_CERTIFICATE_PASSWORD` | macOS only | Password for the `.p12` certificate |
173
+ | `APPLE_SIGNING_IDENTITY` | macOS only | Certificate common name (`Developer ID Application: …`) |
174
+ | `APPLE_API_ISSUER` | macOS only | App Store Connect API issuer UUID |
175
+ | `APPLE_API_KEY` | macOS only | App Store Connect API key ID |
176
+ | `APPLE_API_KEY_CONTENT` | macOS only | Contents of the `.p8` API key file (for notarization) |
177
+ | `WINDOWS_CERTIFICATE` | Windows only | Base64-encoded EV certificate (`.pfx`) |
178
+ | `WINDOWS_CERTIFICATE_PASSWORD` | Windows only | Password for the `.pfx` certificate |
179
+ | `CODEBYPLAN_API_KEY` | notify job | API key for posting release metadata to the CodeByPlan API |
180
+
181
+ The Windows leg is skipped automatically when `WINDOWS_CERTIFICATE` is absent — macOS
182
+ notarized releases can ship independently while the Windows EV cert is being procured.
183
+
184
+ ### vscode surface
185
+
186
+ | Var name | Required | Purpose |
187
+ | -------- | -------- | ------- |
188
+ | `VSCE_PAT` | Yes | VS Code Marketplace Personal Access Token |
189
+
190
+ ### expo surface
191
+
192
+ | Var name | Required | Purpose |
193
+ | -------- | -------- | ------- |
194
+ | `EXPO_TOKEN` | Yes | EAS build + submit token |
195
+
196
+ ## Troubleshooting
197
+
198
+ **publish.yml fails with `E401 Unauthorized`** — npm Trusted Publishing is not configured
199
+ on npmjs.com. Follow the OIDC Setup section above. Common mistake: the workflow filename in
200
+ the Trusted Publisher entry does not match the actual workflow filename (e.g. `release.yml`
201
+ vs `publish.yml`).
202
+
203
+ **publish.yml fails on `check if publish needed`** — GitHub Actions billing block or
204
+ spending-limit hit. Read the run annotations in the GitHub Actions UI, fix billing, run
205
+ `gh run rerun --failed <run-id>`, then merge manually if needed.
206
+
207
+ **release-desktop.yml: macOS build fails with `code signing error`** — the Apple
208
+ certificate in `APPLE_CERTIFICATE` secret is expired or the `APPLE_SIGNING_IDENTITY`
209
+ does not match the certificate's common name exactly. Verify with `security find-identity
210
+ -p codesigning -v` on a local Mac.
211
+
212
+ **release-desktop.yml: Windows leg skipped unexpectedly** — the `WINDOWS_CERTIFICATE`
213
+ secret may be empty or set to a blank string. An empty (but present) secret evaluates to
214
+ `''`, which the `env.HAS_WINDOWS_CERT` check treats as absent. Verify the secret value in
215
+ Settings → Secrets.
216
+
217
+ **Version already published on npm, workflow skips** — expected behavior for the stable
218
+ channel on main. If a re-publish is needed, use `workflow_dispatch` with `dry_run: false`.
219
+
220
+ **release-desktop.yml: tag already exists** — the `check-version` job detects the tag and
221
+ sets `should_release=false`. To re-release the same version, delete the `desktop-v<x>` tag
222
+ and re-run the workflow.
223
+
224
+ ## Provider Roadmap
225
+
226
+ Additional CD provider reference docs are planned:
227
+
228
+ - `reference/gitlab-cd.md` — GitLab CI/CD release pipelines
229
+ - `reference/circleci-cd.md` — CircleCI release orbs
230
+
231
+ These will follow the same structure as this document when authored.
@@ -0,0 +1,175 @@
1
+ ---
2
+ scope: org-shared
3
+ name: cbp-setup-ci
4
+ description: Detect CI platforms, write/update .codebyplan/ci.json, scaffold the GitHub Actions CI workflow, and enforce the required CI status check on the main branch. Interactive, idempotent.
5
+ argument-hint: "[--force]"
6
+ effort: xhigh
7
+ allowed-tools: Read, Write, Edit, Bash(cat *), Bash(jq *), Bash(test *), Bash(ls *), Bash(codebyplan ci *), Bash(npx codebyplan ci *), Bash(gh api *), Bash(gh auth *), AskUserQuestion
8
+ ---
9
+
10
+ # CI Setup
11
+
12
+ Configure `.codebyplan/ci.json`, scaffold `.github/workflows/ci.yml`, and register the
13
+ required GitHub status check so every PR runs a uniform CI gate.
14
+
15
+ Invoke at any time. Already-configured platforms are preserved unless `--force` is passed.
16
+ Pass `--force` to re-detect all platforms and overwrite existing platform keys.
17
+
18
+ ## Arguments
19
+
20
+ Inspect `$ARGUMENTS` for `--force`. If present, set `force_mode = true`.
21
+ Absent: idempotent mode — existing platform keys in `.codebyplan/ci.json` are preserved;
22
+ `ci.yml` is not overwritten unless `--force`.
23
+
24
+ ## Step 1 — Detect platforms + read current state
25
+
26
+ Run detection and read the existing config:
27
+
28
+ ```bash
29
+ npx codebyplan ci init --dry-run --json
30
+ cat .codebyplan/ci.json 2>/dev/null || echo '{}'
31
+ ```
32
+
33
+ The first command lists detected platform slugs without writing any files. The second reads
34
+ the current config for the idempotency check.
35
+
36
+ Display a detection table:
37
+
38
+ ```
39
+ Platform | Detected | Configured | Status
40
+ --------- | -------- | ---------- | ------
41
+ next_js | yes | yes | configured
42
+ package | yes | no | new
43
+ nestjs | no | no | absent
44
+ tauri | no | no | absent
45
+ vscode | no | no | absent
46
+ expo | no | no | absent
47
+ ```
48
+
49
+ Also show workflow + required-check state if `.codebyplan/ci.json` exists:
50
+
51
+ ```bash
52
+ jq '.workflow // {}' .codebyplan/ci.json 2>/dev/null
53
+ ```
54
+
55
+ ## Step 2 — Confirm the detected set
56
+
57
+ `codebyplan ci init` writes ci.json from signal-based auto-detection (next.config /
58
+ `@nestjs/core` / tauri.conf.json / `@types/vscode` / expo / a `packages/` dir) — it does NOT
59
+ accept an explicit platform list. So this step CONFIRMS the detected set; it is not a free
60
+ selector (a deselected platform cannot be withheld from `ci init`, and an undetected one
61
+ cannot be added through it).
62
+
63
+ AskUserQuestion (single choice):
64
+
65
+ ```
66
+ Detected platforms: <list from Step 1>.
67
+ These (merged with any already in .codebyplan/ci.json) will be written. Proceed?
68
+
69
+ A) Proceed — write the detected platforms (recommended)
70
+ B) Cancel — stop without writing
71
+ ```
72
+
73
+ If an expected platform is MISSING: add its detection signal (e.g. a `next.config.ts`, or
74
+ `@nestjs/core` in package.json) and re-run — detection is signal-based, not free-form.
75
+ To DROP a platform: remove its signal and re-run with `--force`, or edit `.codebyplan/ci.json`
76
+ directly. Without `--force`, existing platform keys are always preserved.
77
+
78
+ ## Step 3 — Write .codebyplan/ci.json
79
+
80
+ Run `codebyplan ci init` to write the detected platforms:
81
+
82
+ ```bash
83
+ npx codebyplan ci init [--force]
84
+ ```
85
+
86
+ The CLI deep-merges newly confirmed platforms into the existing config; existing keys are
87
+ left unchanged without `--force`. Confirm by reading back the result:
88
+
89
+ ```bash
90
+ npx codebyplan ci init --dry-run --json
91
+ ```
92
+
93
+ ## Step 4 — Scaffold GitHub Actions workflow
94
+
95
+ Preview, then write `.github/workflows/ci.yml`:
96
+
97
+ ```bash
98
+ npx codebyplan ci scaffold-workflow --dry-run
99
+ ```
100
+
101
+ If the workflow already exists and `--force` is not set, confirm with the user before
102
+ writing. Then write:
103
+
104
+ ```bash
105
+ npx codebyplan ci scaffold-workflow [--force] [--pnpm-version 10] [--node-version 22]
106
+ ```
107
+
108
+ The scaffolded workflow installs pnpm + Node, caches the pnpm store, installs deps with
109
+ `pnpm install --frozen-lockfile`, and runs full-repo checks under a single job named
110
+ **Lint + typecheck + test + build**.
111
+
112
+ If the CLI errors (network, missing bin), print the manual workflow template from
113
+ `reference/github-actions.md` and continue — workflow authoring is non-fatal.
114
+
115
+ ## Step 5 — Enforce required status check
116
+
117
+ Register the GitHub required status check on the main branch:
118
+
119
+ ```bash
120
+ npx codebyplan ci enforce-check [--branch main] [--check-name "Lint + typecheck + test + build"]
121
+ ```
122
+
123
+ Behaviour:
124
+ - `workflow.required_check_enforced: true` already in `ci.json` — skip and report.
125
+ - `gh auth` not configured or API call fails with a permissions error — print the manual
126
+ fallback and point to `reference/github-actions.md` § Manual Setup.
127
+ - On success: the CLI writes `workflow.required_check_enforced: true` to `ci.json`.
128
+
129
+ **Name-match rule**: `--check-name` MUST equal `jobs.<job-id>.name` in `ci.yml` exactly.
130
+ A mismatch leaves the required check permanently pending. The default
131
+ `"Lint + typecheck + test + build"` matches the scaffolded template.
132
+
133
+ ## Step 6 — Verify and report
134
+
135
+ Re-read the config and confirm the workflow file exists:
136
+
137
+ ```bash
138
+ cat .codebyplan/ci.json
139
+ test -f .github/workflows/ci.yml && echo "ci.yml present" || echo "ci.yml MISSING"
140
+ jq '.workflow' .codebyplan/ci.json
141
+ ```
142
+
143
+ Emit a summary:
144
+
145
+ ```
146
+ CI Setup — Complete
147
+
148
+ Platform | unit_test | typecheck | build | lint | e2e
149
+ --------- | --------------- | -------------------- | ---------------- | ----------- | ---------
150
+ next_js | pnpm turbo test | pnpm turbo typecheck | pnpm turbo build | eslint.json | e2e.json
151
+ package | pnpm turbo test | pnpm turbo typecheck | pnpm turbo build | eslint.json | e2e.json
152
+
153
+ Workflow: .github/workflows/ci.yml (present)
154
+ Req check: Lint + typecheck + test + build (enforced: yes)
155
+
156
+ Next: push a branch and open a PR to verify the CI gate fires.
157
+ ```
158
+
159
+ ## Key Rules
160
+
161
+ - Idempotent — re-running without `--force` preserves all existing platform keys and the
162
+ workflow file; it never clobbers a customized `ci.yml`
163
+ - The required-check name MUST match `jobs.<job-id>.name` in `ci.yml` exactly — a mismatch
164
+ leaves the required check permanently pending
165
+ - Repos without `ci.json` fall back via `codebyplan ci resolve <category>` — this skill
166
+ writes the config that resolve reads
167
+ - This skill is org-shared; its template twin at
168
+ `packages/codebyplan-package/templates/skills/cbp-setup-ci/SKILL.md` must stay
169
+ byte-identical (GATE-6)
170
+
171
+ ## Additional resources
172
+
173
+ - GitHub Actions workflow anatomy + required-check setup: [reference/github-actions.md](reference/github-actions.md)
174
+ - CI config schema: `packages/codebyplan-package/src/lib/types.ts` (`CiConfig`)
175
+ - Platform detection signals: `packages/codebyplan-package/src/lib/ci-init.ts` (`detectPlatforms`)