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.
- package/dist/cli.js +1776 -449
- package/package.json +1 -1
- package/templates/agents/cbp-security-agent.md +9 -1
- package/templates/agents/cbp-testing-qa-agent.md +23 -9
- package/templates/github-workflows/ci.yml +63 -0
- package/templates/github-workflows/publish.yml +8 -27
- package/templates/github-workflows/release-desktop.yml +215 -0
- package/templates/settings.project.base.json +7 -1
- package/templates/skills/cbp-checkpoint-check/SKILL.md +9 -1
- package/templates/skills/cbp-checkpoint-end/SKILL.md +5 -1
- package/templates/skills/cbp-round-check/SKILL.md +2 -0
- package/templates/skills/cbp-setup-cd/SKILL.md +291 -0
- package/templates/skills/cbp-setup-cd/reference/github-actions-cd.md +231 -0
- package/templates/skills/cbp-setup-ci/SKILL.md +175 -0
- package/templates/skills/cbp-setup-ci/reference/github-actions.md +100 -0
- package/templates/skills/cbp-ship/SKILL.md +21 -0
- package/templates/skills/cbp-standalone-task-testing/SKILL.md +11 -2
- package/templates/skills/cbp-task-testing/SKILL.md +2 -0
|
@@ -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`)
|