@rashidee/co2 1.3.17 → 1.3.19
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/index.js +75 -26
- package/package.json +1 -1
- package/plugin/.claude-plugin/marketplace.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/skills/util-gencicdscript/SKILL.md +18 -23
- package/plugin/skills/util-gencicdscript/references/cicd-app-template.md +176 -141
- package/plugin/skills/util-plancicd/SKILL.md +319 -312
- package/static/assets/{abnfDiagram-VRR7QNED-kjS3baPt.js → abnfDiagram-VRR7QNED-cQAiKjYG.js} +1 -1
- package/static/assets/{arc-CXd0xnDj.js → arc-C4ZlEQ3S.js} +1 -1
- package/static/assets/{architectureDiagram-ZJ3FMSHR-5QfnAz_Q.js → architectureDiagram-ZJ3FMSHR-C_31NGnA.js} +1 -1
- package/static/assets/{blockDiagram-677ZJIJ3-ByICFNDb.js → blockDiagram-677ZJIJ3-DDQQ2PAJ.js} +1 -1
- package/static/assets/{c4Diagram-LMCZKHZV-C5a0Ubby.js → c4Diagram-LMCZKHZV-BPbCZxQJ.js} +1 -1
- package/static/assets/channel-CufY_jLp.js +1 -0
- package/static/assets/{chunk-2Q5K7J3B-UucADWxr.js → chunk-2Q5K7J3B-B3LoONkc.js} +1 -1
- package/static/assets/{chunk-32BRIVSS-WAe17d3N.js → chunk-32BRIVSS-Buim75a9.js} +1 -1
- package/static/assets/{chunk-5VM5RSS4-BQBMOb0f.js → chunk-5VM5RSS4-BjHqxxbw.js} +1 -1
- package/static/assets/{chunk-EX3LRPZG-BzaET0n4.js → chunk-EX3LRPZG-Dn0_qUTW.js} +1 -1
- package/static/assets/{chunk-JWPE2WC7-D_tBvbZg.js → chunk-JWPE2WC7-DpYEF0BV.js} +1 -1
- package/static/assets/{chunk-MOJQB5TN-CsYb9JBc.js → chunk-MOJQB5TN-CbNDWijQ.js} +1 -1
- package/static/assets/{chunk-RYQCIY6F-D5xRlnc7.js → chunk-RYQCIY6F-DOhXYkGG.js} +1 -1
- package/static/assets/{chunk-V7JOEXUC-y0cEgq6c.js → chunk-V7JOEXUC-CfASUuSJ.js} +1 -1
- package/static/assets/{chunk-VR4S4FIN-CSXJHPXT.js → chunk-VR4S4FIN-vgVNnFtp.js} +1 -1
- package/static/assets/{chunk-XXDRQBXY-QFNFGLYZ.js → chunk-XXDRQBXY-CVjoYUTB.js} +1 -1
- package/static/assets/classDiagram-OUVF2IWQ-CVQD_QZa.js +1 -0
- package/static/assets/classDiagram-v2-EOCWNBFH-CVQD_QZa.js +1 -0
- package/static/assets/{cose-bilkent-JH36ORCC-ValIntpZ.js → cose-bilkent-JH36ORCC-EqjuuBpY.js} +1 -1
- package/static/assets/{cynefin-VYW2F7L2-BgHVKyAR.js → cynefin-VYW2F7L2-DioyO_Cm.js} +1 -1
- package/static/assets/{cynefinDiagram-TSTJHNR4-LIZzpkLM.js → cynefinDiagram-TSTJHNR4-CuPa5A8w.js} +1 -1
- package/static/assets/{dagre-VKFMJZFB-DY9b36A5.js → dagre-VKFMJZFB-MIf1Dtbk.js} +1 -1
- package/static/assets/{diagram-FQU43EPY-aeuYUUxe.js → diagram-FQU43EPY-5OBJqg6R.js} +1 -1
- package/static/assets/{diagram-G47NLZAW-BWwcYYCF.js → diagram-G47NLZAW-B2ZGPKp3.js} +1 -1
- package/static/assets/{diagram-NH7WQ7WH-BObFlRPR.js → diagram-NH7WQ7WH-B5YEN-B-.js} +1 -1
- package/static/assets/{diagram-OA4YK3LP-BUnc8m1-.js → diagram-OA4YK3LP-BXg_CQ2m.js} +1 -1
- package/static/assets/{diagram-WEI45ONY-DsNxBIuJ.js → diagram-WEI45ONY-DVbqehF6.js} +1 -1
- package/static/assets/{ebnfDiagram-CCIWWBDH-DDL2Id1r.js → ebnfDiagram-CCIWWBDH-hmnXWJuZ.js} +1 -1
- package/static/assets/{erDiagram-Q63AITRT-DZZcG2QU.js → erDiagram-Q63AITRT-CLYATrvi.js} +1 -1
- package/static/assets/{flowDiagram-23GEKE2U-C6GvkBFb.js → flowDiagram-23GEKE2U-cs1YvuVH.js} +1 -1
- package/static/assets/{ganttDiagram-NO4QXBWP-C7ydCTnF.js → ganttDiagram-NO4QXBWP-CH5rfioY.js} +1 -1
- package/static/assets/{gitGraphDiagram-IHSO6WYX-C60P6bwf.js → gitGraphDiagram-IHSO6WYX-DjAOB5L7.js} +1 -1
- package/static/assets/{index-CfGMfAGO.js → index-B4Y8oBUt.js} +4 -4
- package/static/assets/{infoDiagram-FWYZ7A6U-CnH7Q2nX.js → infoDiagram-FWYZ7A6U-De2-PVxo.js} +1 -1
- package/static/assets/{ishikawaDiagram-FXEZZL3T-BNEvOQYX.js → ishikawaDiagram-FXEZZL3T-CDikxFR6.js} +1 -1
- package/static/assets/{journeyDiagram-5HDEW3XC-BOwGZTfX.js → journeyDiagram-5HDEW3XC-Bo6isp1w.js} +1 -1
- package/static/assets/{kanban-definition-HUTT4EX6-BEfHVl-l.js → kanban-definition-HUTT4EX6-jM1azdC7.js} +1 -1
- package/static/assets/{linear-BOHPNxBi.js → linear-CUk0_yzf.js} +1 -1
- package/static/assets/{mindmap-definition-LN4V7U3C-B84wfT_w.js → mindmap-definition-LN4V7U3C-l-cgg6PS.js} +1 -1
- package/static/assets/{pegDiagram-2B236MQR-BgEa7yRL.js → pegDiagram-2B236MQR-B-8nGU3G.js} +1 -1
- package/static/assets/{pieDiagram-ENE6RG2P-DgA9LQlc.js → pieDiagram-ENE6RG2P-Di1V86Ag.js} +1 -1
- package/static/assets/{quadrantDiagram-ABIIQ3AL-C5K_r0Mx.js → quadrantDiagram-ABIIQ3AL-BknVxapP.js} +1 -1
- package/static/assets/{railroadDiagram-RFXS5EU6-Ckh_mLXW.js → railroadDiagram-RFXS5EU6-D7Vohrlg.js} +1 -1
- package/static/assets/{requirementDiagram-TGXJPOKE-CtII7Obm.js → requirementDiagram-TGXJPOKE-BlFXj6Li.js} +1 -1
- package/static/assets/{sankeyDiagram-HTMAVEWB-DdkySwbL.js → sankeyDiagram-HTMAVEWB-Ck_A1wxA.js} +1 -1
- package/static/assets/{sequenceDiagram-DBY2YBRQ-DEIBg3kY.js → sequenceDiagram-DBY2YBRQ-D4mu07Ol.js} +1 -1
- package/static/assets/{sizeCapture-X5ZJPWSS-D2MM9f6M.js → sizeCapture-X5ZJPWSS-BwempBoZ.js} +1 -1
- package/static/assets/{stateDiagram-2N3HPSRC-DHmJsAte.js → stateDiagram-2N3HPSRC-DSh1YMwZ.js} +1 -1
- package/static/assets/stateDiagram-v2-6OUMAXLB-DrMkFhr2.js +1 -0
- package/static/assets/{swimlanes-5IMT3BWC-BBPvUQvZ.js → swimlanes-5IMT3BWC-4EE1KLA5.js} +2 -2
- package/static/assets/swimlanesDiagram-G3AALYLV-DoZQ3XaY.js +8 -0
- package/static/assets/{timeline-definition-FHXFAJF6-CG_Q0YTD.js → timeline-definition-FHXFAJF6-DVZepywq.js} +1 -1
- package/static/assets/{vennDiagram-L72KCM5P-DlFSe4is.js → vennDiagram-L72KCM5P-YqnYvNJT.js} +1 -1
- package/static/assets/{wardleyDiagram-EHGQE667-BTlvtp2f.js → wardleyDiagram-EHGQE667-Dc6PvPZE.js} +1 -1
- package/static/assets/{xychartDiagram-FW5EYKEG-Bm14zLxj.js → xychartDiagram-FW5EYKEG-DLbY5Kg1.js} +1 -1
- package/static/index.html +1 -1
- package/static/assets/channel-CrYjYK1f.js +0 -1
- package/static/assets/classDiagram-OUVF2IWQ-DoLCCqXD.js +0 -1
- package/static/assets/classDiagram-v2-EOCWNBFH-DoLCCqXD.js +0 -1
- package/static/assets/stateDiagram-v2-6OUMAXLB-B6sumoG6.js +0 -1
- package/static/assets/swimlanesDiagram-G3AALYLV-DH2ts1oT.js +0 -8
|
@@ -1,312 +1,319 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: util-plancicd
|
|
3
|
-
model: claude-opus-4-8
|
|
4
|
-
effort: high
|
|
5
|
-
description: >
|
|
6
|
-
Infer a local-deployment plan for every custom application of a CO2 project and write it to
|
|
7
|
-
cicd/CICD_PLAN.md for human review in Compound Context Studio. Reads the project's
|
|
8
|
-
ENVIRONMENT.md and DEVTOOL.md, CLAUDE.md (# Custom Applications, # Port Allocation) and each
|
|
9
|
-
application's context/specification/SPECIFICATION.md, then decides per application: deployment
|
|
10
|
-
method (container vs bare process), build command (e.g. Spring Boot jar vs Docker image),
|
|
11
|
-
start command, stop mechanism, deploy method + command (none / web-server copy / docker run /
|
|
12
|
-
kubectl apply — only when the environment calls for one), port and health-check URL, plus a
|
|
13
|
-
port for the generated CI/CD app itself. When Docker AND a docker repo/registry are both
|
|
14
|
-
configured (DEVTOOL.md + ENVIRONMENT.md), it additionally plans the docker-image build path:
|
|
15
|
-
per-application image names under the repo, Build commands extended with
|
|
16
|
-
`docker build -t <image>:
|
|
17
|
-
CI/CD app
|
|
18
|
-
`## Dockerfiles` section for any dockerized application lacking one (materialized before
|
|
19
|
-
Build, never overwriting an existing file). It also infers each application's RUNTIME CONFIG — the
|
|
20
|
-
config files its start command reads (e.g. `.env`), deciding per file whether the values come
|
|
21
|
-
from ENVIRONMENT.md or from an existing `.env` / `.env-*` file already in the app folder, listing
|
|
22
|
-
the required keys and, for ENVIRONMENT.md-sourced files, the resolved content — so the generated
|
|
23
|
-
CI/CD app can complete the config before start (guaranteeing the app comes up) and show it in a
|
|
24
|
-
per-application Config modal for troubleshooting. It also enumerates the project's supporting
|
|
25
|
-
infrastructure (3rd-party services from CLAUDE.md's `# Supporting 3rd Party Applications` and
|
|
26
|
-
ENVIRONMENT.md — host, port and optional console URL) into an `## Infrastructure` section so
|
|
27
|
-
the generated CI/CD app can surface a status-only Infrastructure page. The plan carries a
|
|
28
|
-
top-level
|
|
29
|
-
`**Status**: IN PROGRESS` header flipped to `COMPLETED` when done — the studio's watcher reads
|
|
30
|
-
it. This skill NEVER generates the CI/CD app (that is util-gencicdscript, which runs only
|
|
31
|
-
after the studio stamps an **Approved**: line into the plan). Trigger on keywords: "plan
|
|
32
|
-
cicd", "plan deployment", "cicd plan", "infer deployment", "deployment plan", "plan ci/cd".
|
|
33
|
-
Accepts one MANDATORY argument: the project-relative path of the plan-request markdown the
|
|
34
|
-
studio generated (e.g., /util-plancicd execution/cicd-plan-3-1753000000000.md).
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
# Util Plan CI/CD
|
|
38
|
-
|
|
39
|
-
## Inputs
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
/util-plancicd <path-to-plan-request-md>
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
| Argument | Required | Description |
|
|
46
|
-
|---|---|---|
|
|
47
|
-
| path | yes | Project-relative path of the studio-generated plan-request markdown under `execution/` |
|
|
48
|
-
|
|
49
|
-
If the argument is missing or the file does not exist, STOP and tell the user to click
|
|
50
|
-
**Plan deployment** in the studio's CI/CD screen first.
|
|
51
|
-
|
|
52
|
-
### Auto-Resolved Paths
|
|
53
|
-
|
|
54
|
-
| Logical file | Path |
|
|
55
|
-
|---|---|
|
|
56
|
-
| Plan request | `<argument>` |
|
|
57
|
-
| Environment | `ENVIRONMENT.md` (project root) |
|
|
58
|
-
| Dev tools | `DEVTOOL.md` (project root) |
|
|
59
|
-
| Project context | `CLAUDE.md` (project root; `source/CLAUDE.md` fallback) |
|
|
60
|
-
| App specification | `<app_folder>/context/specification/SPECIFICATION.md` |
|
|
61
|
-
| App config files | `<app_folder>/.env`, `<app_folder>/.env-*` (and stack-conventional config files) |
|
|
62
|
-
| Infrastructure | `CLAUDE.md` `# Supporting 3rd Party Applications` + `ENVIRONMENT.md` |
|
|
63
|
-
| Output plan | `cicd/CICD_PLAN.md` |
|
|
64
|
-
|
|
65
|
-
## Phase 1 — Gather
|
|
66
|
-
|
|
67
|
-
1. Read the plan-request markdown; its `## Applications` list is the authoritative application set.
|
|
68
|
-
2. Read `ENVIRONMENT.md` (registries, credentials, external services) and `DEVTOOL.md`
|
|
69
|
-
(installed tools + paths: node/pnpm/docker/kubectl/python versions).
|
|
70
|
-
2a. **Docker facts**: record whether Docker is installed (DEVTOOL.md) AND whether
|
|
71
|
-
ENVIRONMENT.md names a **docker repo/registry** — a registry URL or namespace the images
|
|
72
|
-
are tagged for (e.g. `registry.example.com/team`, a Docker Hub org, an ECR/GCR path).
|
|
73
|
-
The docker-image build path (below) activates ONLY when BOTH are present; Docker without
|
|
74
|
-
a configured repo keeps today's behavior (no image builds).
|
|
75
|
-
3. Read `CLAUDE.md`: `# Custom Applications` (folder names, Depends on), `# Port Allocation`
|
|
76
|
-
(per-application ports), and `# Supporting 3rd Party Applications` (the infrastructure the
|
|
77
|
-
applications depend on — databases, caches, object storage, SSO, mail, message brokers, etc.).
|
|
78
|
-
4. For each application, read its SPECIFICATION.md tech-stack section if present; otherwise
|
|
79
|
-
infer the stack from build files (`package.json` → node, `pom.xml` → spring-boot,
|
|
80
|
-
`composer.json` → laravel).
|
|
81
|
-
4a. For each application, discover its RUNTIME CONFIG files: list any existing `.env` / `.env-*`
|
|
82
|
-
in the application folder AND the stack-conventional config the start command reads (node/
|
|
83
|
-
laravel → `.env`; Spring Boot → `application.properties` / `application-<profile>.yml` or a
|
|
84
|
-
`.env` when the app loads one). Read the content of each existing file (values may be reused).
|
|
85
|
-
Cross-reference ENVIRONMENT.md for the per-application config values (DB/cache/broker hosts and
|
|
86
|
-
ports, external-service URLs, credentials, secrets, the app's own PORT) and the Infrastructure
|
|
87
|
-
list from step 5 for the hosts/ports the app must point at.
|
|
88
|
-
5. Build the **infrastructure list**: one entry per supporting 3rd-party service the project
|
|
89
|
-
declares. For each, resolve `host` (default `127.0.0.1`), `port` and — when it exposes a web
|
|
90
|
-
console/UI — a `url`, cross-referencing ENVIRONMENT.md for the actual host/port/endpoint. A
|
|
91
|
-
service with no host:port to probe (or a purely external SaaS with no local endpoint) is
|
|
92
|
-
omitted. If the project declares no supporting 3rd-party services, the infrastructure list is
|
|
93
|
-
empty and the plan's `## Infrastructure` section is written empty.
|
|
94
|
-
|
|
95
|
-
## Phase 2 — Decide (per application)
|
|
96
|
-
|
|
97
|
-
- **Working directory (CRITICAL)**: the generated CI/CD app executes every command with the
|
|
98
|
-
**application folder** (`<project>/<folder>`) as its working directory — NEVER the project
|
|
99
|
-
root. All paths inside build/start/stop/deploy commands must therefore be relative to the
|
|
100
|
-
application folder (`mvn -q package`, `java -jar target\app.jar`) — never prefixed with the
|
|
101
|
-
application folder itself (`skolafund_middleware\target\...` is WRONG).
|
|
102
|
-
- **Method**: `container` only when Docker appears in DEVTOOL.md AND the stack has a sensible
|
|
103
|
-
container path; otherwise `process` (bare local process — the default for a dev VM).
|
|
104
|
-
- **Build command
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
`
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
`
|
|
118
|
-
`
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
- **
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
>
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
1
|
+
---
|
|
2
|
+
name: util-plancicd
|
|
3
|
+
model: claude-opus-4-8
|
|
4
|
+
effort: high
|
|
5
|
+
description: >
|
|
6
|
+
Infer a local-deployment plan for every custom application of a CO2 project and write it to
|
|
7
|
+
cicd/CICD_PLAN.md for human review in Compound Context Studio. Reads the project's
|
|
8
|
+
ENVIRONMENT.md and DEVTOOL.md, CLAUDE.md (# Custom Applications, # Port Allocation) and each
|
|
9
|
+
application's context/specification/SPECIFICATION.md, then decides per application: deployment
|
|
10
|
+
method (container vs bare process), build command (e.g. Spring Boot jar vs Docker image),
|
|
11
|
+
start command, stop mechanism, deploy method + command (none / web-server copy / docker run /
|
|
12
|
+
kubectl apply — only when the environment calls for one), port and health-check URL, plus a
|
|
13
|
+
port for the generated CI/CD app itself. When Docker AND a docker repo/registry are both
|
|
14
|
+
configured (DEVTOOL.md + ENVIRONMENT.md), it additionally plans the docker-image build path:
|
|
15
|
+
per-application image names under the repo, Build commands extended with
|
|
16
|
+
`docker build --no-cache -t <image>:latest` (clean image build, no version token — the generated
|
|
17
|
+
CI/CD app runs commands verbatim on the current working tree), and a managed Dockerfile authored into the plan's
|
|
18
|
+
`## Dockerfiles` section for any dockerized application lacking one (materialized before
|
|
19
|
+
Build, never overwriting an existing file). It also infers each application's RUNTIME CONFIG — the
|
|
20
|
+
config files its start command reads (e.g. `.env`), deciding per file whether the values come
|
|
21
|
+
from ENVIRONMENT.md or from an existing `.env` / `.env-*` file already in the app folder, listing
|
|
22
|
+
the required keys and, for ENVIRONMENT.md-sourced files, the resolved content — so the generated
|
|
23
|
+
CI/CD app can complete the config before start (guaranteeing the app comes up) and show it in a
|
|
24
|
+
per-application Config modal for troubleshooting. It also enumerates the project's supporting
|
|
25
|
+
infrastructure (3rd-party services from CLAUDE.md's `# Supporting 3rd Party Applications` and
|
|
26
|
+
ENVIRONMENT.md — host, port and optional console URL) into an `## Infrastructure` section so
|
|
27
|
+
the generated CI/CD app can surface a status-only Infrastructure page. The plan carries a
|
|
28
|
+
top-level
|
|
29
|
+
`**Status**: IN PROGRESS` header flipped to `COMPLETED` when done — the studio's watcher reads
|
|
30
|
+
it. This skill NEVER generates the CI/CD app (that is util-gencicdscript, which runs only
|
|
31
|
+
after the studio stamps an **Approved**: line into the plan). Trigger on keywords: "plan
|
|
32
|
+
cicd", "plan deployment", "cicd plan", "infer deployment", "deployment plan", "plan ci/cd".
|
|
33
|
+
Accepts one MANDATORY argument: the project-relative path of the plan-request markdown the
|
|
34
|
+
studio generated (e.g., /util-plancicd execution/cicd-plan-3-1753000000000.md).
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
# Util Plan CI/CD
|
|
38
|
+
|
|
39
|
+
## Inputs
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
/util-plancicd <path-to-plan-request-md>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| Argument | Required | Description |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| path | yes | Project-relative path of the studio-generated plan-request markdown under `execution/` |
|
|
48
|
+
|
|
49
|
+
If the argument is missing or the file does not exist, STOP and tell the user to click
|
|
50
|
+
**Plan deployment** in the studio's CI/CD screen first.
|
|
51
|
+
|
|
52
|
+
### Auto-Resolved Paths
|
|
53
|
+
|
|
54
|
+
| Logical file | Path |
|
|
55
|
+
|---|---|
|
|
56
|
+
| Plan request | `<argument>` |
|
|
57
|
+
| Environment | `ENVIRONMENT.md` (project root) |
|
|
58
|
+
| Dev tools | `DEVTOOL.md` (project root) |
|
|
59
|
+
| Project context | `CLAUDE.md` (project root; `source/CLAUDE.md` fallback) |
|
|
60
|
+
| App specification | `<app_folder>/context/specification/SPECIFICATION.md` |
|
|
61
|
+
| App config files | `<app_folder>/.env`, `<app_folder>/.env-*` (and stack-conventional config files) |
|
|
62
|
+
| Infrastructure | `CLAUDE.md` `# Supporting 3rd Party Applications` + `ENVIRONMENT.md` |
|
|
63
|
+
| Output plan | `cicd/CICD_PLAN.md` |
|
|
64
|
+
|
|
65
|
+
## Phase 1 — Gather
|
|
66
|
+
|
|
67
|
+
1. Read the plan-request markdown; its `## Applications` list is the authoritative application set.
|
|
68
|
+
2. Read `ENVIRONMENT.md` (registries, credentials, external services) and `DEVTOOL.md`
|
|
69
|
+
(installed tools + paths: node/pnpm/docker/kubectl/python versions).
|
|
70
|
+
2a. **Docker facts**: record whether Docker is installed (DEVTOOL.md) AND whether
|
|
71
|
+
ENVIRONMENT.md names a **docker repo/registry** — a registry URL or namespace the images
|
|
72
|
+
are tagged for (e.g. `registry.example.com/team`, a Docker Hub org, an ECR/GCR path).
|
|
73
|
+
The docker-image build path (below) activates ONLY when BOTH are present; Docker without
|
|
74
|
+
a configured repo keeps today's behavior (no image builds).
|
|
75
|
+
3. Read `CLAUDE.md`: `# Custom Applications` (folder names, Depends on), `# Port Allocation`
|
|
76
|
+
(per-application ports), and `# Supporting 3rd Party Applications` (the infrastructure the
|
|
77
|
+
applications depend on — databases, caches, object storage, SSO, mail, message brokers, etc.).
|
|
78
|
+
4. For each application, read its SPECIFICATION.md tech-stack section if present; otherwise
|
|
79
|
+
infer the stack from build files (`package.json` → node, `pom.xml` → spring-boot,
|
|
80
|
+
`composer.json` → laravel).
|
|
81
|
+
4a. For each application, discover its RUNTIME CONFIG files: list any existing `.env` / `.env-*`
|
|
82
|
+
in the application folder AND the stack-conventional config the start command reads (node/
|
|
83
|
+
laravel → `.env`; Spring Boot → `application.properties` / `application-<profile>.yml` or a
|
|
84
|
+
`.env` when the app loads one). Read the content of each existing file (values may be reused).
|
|
85
|
+
Cross-reference ENVIRONMENT.md for the per-application config values (DB/cache/broker hosts and
|
|
86
|
+
ports, external-service URLs, credentials, secrets, the app's own PORT) and the Infrastructure
|
|
87
|
+
list from step 5 for the hosts/ports the app must point at.
|
|
88
|
+
5. Build the **infrastructure list**: one entry per supporting 3rd-party service the project
|
|
89
|
+
declares. For each, resolve `host` (default `127.0.0.1`), `port` and — when it exposes a web
|
|
90
|
+
console/UI — a `url`, cross-referencing ENVIRONMENT.md for the actual host/port/endpoint. A
|
|
91
|
+
service with no host:port to probe (or a purely external SaaS with no local endpoint) is
|
|
92
|
+
omitted. If the project declares no supporting 3rd-party services, the infrastructure list is
|
|
93
|
+
empty and the plan's `## Infrastructure` section is written empty.
|
|
94
|
+
|
|
95
|
+
## Phase 2 — Decide (per application)
|
|
96
|
+
|
|
97
|
+
- **Working directory (CRITICAL)**: the generated CI/CD app executes every command with the
|
|
98
|
+
**application folder** (`<project>/<folder>`) as its working directory — NEVER the project
|
|
99
|
+
root. All paths inside build/start/stop/deploy commands must therefore be relative to the
|
|
100
|
+
application folder (`mvn -q package`, `java -jar target\app.jar`) — never prefixed with the
|
|
101
|
+
application folder itself (`skolafund_middleware\target\...` is WRONG).
|
|
102
|
+
- **Method**: `container` only when Docker appears in DEVTOOL.md AND the stack has a sensible
|
|
103
|
+
container path; otherwise `process` (bare local process — the default for a dev VM).
|
|
104
|
+
- **Build command (ALWAYS a CLEAN build)**: the Build button must produce a from-scratch build so
|
|
105
|
+
no stale artifact from a previous run can ever be started or shipped — use the stack's CLEAN
|
|
106
|
+
lifecycle, never an incremental one:
|
|
107
|
+
- Maven → `mvn -q clean package` (never bare `package` — it reuses stale compiled classes in `target/`).
|
|
108
|
+
- Gradle → `./gradlew clean bootJar` (or `clean build`).
|
|
109
|
+
- Node (pnpm/npm/yarn) → wipe the build output the Start command runs from, THEN install and build:
|
|
110
|
+
`rm -rf <outdir> && pnpm install && pnpm build`, where `<outdir>` is the directory the Start
|
|
111
|
+
artifact lives in (`dist`, `build`, `.next`, `.output`, …). Keep the explicit wipe even when the
|
|
112
|
+
bundler normally empties its own outDir — it is the guarantee against a stale artifact.
|
|
113
|
+
- Laravel/PHP with a front-end build → `rm -rf public/build && composer install && npm ci && npm run build`;
|
|
114
|
+
plain PHP with no build step → `composer install`.
|
|
115
|
+
Use tool paths from DEVTOOL.md when the tool is not on PATH.
|
|
116
|
+
- **Start command**: the stack's production-ish local start (e.g. `node dist/index.js`,
|
|
117
|
+
`java -jar target/<artifact>.jar`, `php artisan serve --port <port>`); `docker build`/
|
|
118
|
+
`docker run` pair when method=container. For jar-based stacks, resolve the EXACT artifact
|
|
119
|
+
filename — read the pom/gradle build config: a Maven `<finalName>` means
|
|
120
|
+
`target/<finalName>.jar` with NO version suffix (Spring Boot repackage keeps that name and
|
|
121
|
+
leaves a `.jar.original` beside it — never reference the `.original`). Never guess
|
|
122
|
+
`<app>-<version>.jar` and never use a `target/*.jar` glob (shell-dependent, breaks on
|
|
123
|
+
Windows cmd).
|
|
124
|
+
- **Stop**: `process-kill` for bare processes; `docker stop <name>` for containers.
|
|
125
|
+
- **Deploy** (method + command): only when ENVIRONMENT.md/DEVTOOL.md show a deployment target —
|
|
126
|
+
`kubernetes` (`kubectl apply -f <app>/k8s/` when kubectl + a cluster/kubeconfig appear),
|
|
127
|
+
`docker` (`docker run`/`docker compose up -d` when the image is the deliverable),
|
|
128
|
+
`web-server` (copy the built artifact into the configured web/app server, e.g. nginx html
|
|
129
|
+
root or Tomcat webapps, when one is configured). Default **`none`** — a bare local process
|
|
130
|
+
needs no deploy step beyond Start; never invent a target the config does not name.
|
|
131
|
+
- **Docker image** (only when Gather 2a found Docker + a docker repo — otherwise skip this
|
|
132
|
+
bullet entirely):
|
|
133
|
+
- **Image name**: `<repo>/<app_folder>` — the application folder name, lowercased, with
|
|
134
|
+
any character docker rejects replaced by `-` (keep a leading `<number>_` prefix as-is;
|
|
135
|
+
e.g. `registry.example.com/team/skolafund_web`).
|
|
136
|
+
- **Build**: append the image build to the app build —
|
|
137
|
+
`<app build> && docker build --no-cache -t <image>:latest .` — `--no-cache` keeps the image a
|
|
138
|
+
clean build too, so no stale layer survives. Commands carry NO `{VERSION}` token or
|
|
139
|
+
any other placeholder — the generated CI/CD app runs them verbatim; only the current
|
|
140
|
+
working tree is ever built and images are always tagged `latest`.
|
|
141
|
+
Build never pushes — pushing belongs to a `docker` Deploy method.
|
|
142
|
+
- **Container start/deploy**: when method=container, reference `<image>:latest` in the
|
|
143
|
+
start/deploy commands too, so the freshly built tag is what runs.
|
|
144
|
+
- **Dockerfile**: if the application folder already has a `Dockerfile`, use it as-is
|
|
145
|
+
(`existing`). Otherwise author a stack-appropriate Dockerfile (node / spring-boot /
|
|
146
|
+
laravel — same stack detection as depgen-k8s) into the plan's `## Dockerfiles` section
|
|
147
|
+
(`managed`); the generated CI/CD app materializes it before Build only when the file is
|
|
148
|
+
still missing on disk.
|
|
149
|
+
- **Port**: from `# Port Allocation`; if absent, assign sequentially from 3000 avoiding
|
|
150
|
+
collisions with the studio (3001) and the CI/CD app port.
|
|
151
|
+
- **Health / running-detection**: the endpoint the generated CI/CD app uses to tell whether the
|
|
152
|
+
application is already running. Detection is a **raw TCP connect to the app's port on loopback**
|
|
153
|
+
— the generated app probes BOTH IPv4 (`127.0.0.1`) and IPv6 (`::1`) loopback, plus the host
|
|
154
|
+
named in this Health value — so it does not matter which family the framework binds. This
|
|
155
|
+
matters because dev servers differ: Spring Boot binds `127.0.0.1`, but **Vite / Next preview
|
|
156
|
+
servers bind IPv6 `::1` (localhost) only** and are invisible to an IPv4-only probe. Therefore
|
|
157
|
+
set the Health host to **`localhost`** (not `127.0.0.1`) for any Node/Vite/Next dev-server app
|
|
158
|
+
so the detection host set includes the interface it actually binds; use `127.0.0.1` for JVM
|
|
159
|
+
apps. Value form: `http://localhost:<port>/` or a documented health path from the spec (the
|
|
160
|
+
path is informational — detection keys on the port, not the path).
|
|
161
|
+
- **CI/CD app port**: 5000 unless taken in `# Port Allocation`; record it in the plan.
|
|
162
|
+
|
|
163
|
+
### Application config (per application)
|
|
164
|
+
|
|
165
|
+
Decide the runtime config the application needs so it STARTS SUCCESSFULLY, and where each value
|
|
166
|
+
comes from. For every config file the start command reads (`path`, relative to the application
|
|
167
|
+
folder):
|
|
168
|
+
|
|
169
|
+
- **source** — classify each file:
|
|
170
|
+
- `env-file` — an existing `.env` / `.env-*` in the app folder already holds the runtime values;
|
|
171
|
+
use it as-is on disk (do NOT re-materialize it). Set `managed: no`, no resolved content.
|
|
172
|
+
- `environment` — there is no complete runtime file; resolve the required values from
|
|
173
|
+
ENVIRONMENT.md (and the Infrastructure hosts/ports) and record the fully-resolved file content.
|
|
174
|
+
Set `managed: yes` so the CI/CD app writes it before Build/Start when missing.
|
|
175
|
+
- `derived` — the runtime file is chosen/combined from existing material (e.g. copy the target
|
|
176
|
+
env's `.env-<env>` to the canonical `.env` the start command reads, or merge an existing
|
|
177
|
+
`.env-*` with ENVIRONMENT.md values). Set `managed: yes` and record the resolved content.
|
|
178
|
+
- **required keys** — enumerate every key the app must have to boot: its own PORT, datastore/cache/
|
|
179
|
+
broker connection strings, external-service URLs, credentials/secrets. Cross-check them against
|
|
180
|
+
ENVIRONMENT.md and the Infrastructure list.
|
|
181
|
+
- **completeness (the point of this)** — every required key MUST be satisfiable from ENVIRONMENT.md
|
|
182
|
+
or an existing env file. If a required key cannot be resolved, still emit the config entry but
|
|
183
|
+
call out the unresolved key in that application's Rationale as a GAP (so the human fixes
|
|
184
|
+
ENVIRONMENT.md before approving) — never silently drop it.
|
|
185
|
+
- **managed content** — for a `managed: yes` file, write the resolved body verbatim into the plan
|
|
186
|
+
as a fenced block (`path=<file>`). Values (including credentials) are emitted verbatim under the
|
|
187
|
+
dev-environment plaintext rule; they must never appear in the Rationale narrative.
|
|
188
|
+
|
|
189
|
+
Only list files the app actually reads at runtime — do not invent config files. An app that needs
|
|
190
|
+
no config file gets an empty config list.
|
|
191
|
+
|
|
192
|
+
### Infrastructure (status-only)
|
|
193
|
+
|
|
194
|
+
Supporting 3rd-party services are **not** built/started/deployed by the CI/CD app — they are
|
|
195
|
+
surfaced status-only. For each service resolved in Gather step 5, decide:
|
|
196
|
+
|
|
197
|
+
- **id**: a stable kebab-case key unique within the plan (e.g. `postgres-main`, `keycloak`).
|
|
198
|
+
- **name**: display name (e.g. `PostgreSQL (skf_main)`, `Keycloak`).
|
|
199
|
+
- **host** / **port**: the address the CI/CD app TCP-probes for reachability; default host
|
|
200
|
+
`127.0.0.1`. Use the values ENVIRONMENT.md documents.
|
|
201
|
+
- **url**: the web console/UI opened in a new tab, when the service has one (Keycloak admin,
|
|
202
|
+
MinIO console, Mailcatcher inbox); `-` for headless services (PostgreSQL, Redis).
|
|
203
|
+
- **description**: a short blurb (e.g. `Shared app database`, `S3-compatible object storage`).
|
|
204
|
+
|
|
205
|
+
Never emit credentials into the infrastructure entries — status and links only.
|
|
206
|
+
|
|
207
|
+
## Phase 3 — Write the plan
|
|
208
|
+
|
|
209
|
+
Create `cicd/` if missing and write `cicd/CICD_PLAN.md` (shown here in a 4-backtick fence so the
|
|
210
|
+
inner ```env config block renders — the plan file itself uses a normal 3-backtick env fence):
|
|
211
|
+
|
|
212
|
+
````markdown
|
|
213
|
+
# CI/CD Deployment Plan — <Project Name>
|
|
214
|
+
|
|
215
|
+
**Generated**: <ISO date>
|
|
216
|
+
**Status**: IN PROGRESS
|
|
217
|
+
|
|
218
|
+
## CI/CD App
|
|
219
|
+
|
|
220
|
+
- **Port**: <port>
|
|
221
|
+
- **Folder**: cicd/app
|
|
222
|
+
|
|
223
|
+
## Deployment Decisions
|
|
224
|
+
|
|
225
|
+
| Application | Folder | Method | Port | Build | Start | Stop | Deploy Method | Deploy | Health |
|
|
226
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
227
|
+
| <name> | <folder> | process|container | <port> | `<cmd>` | `<cmd>` | process-kill|docker stop | none|web-server|docker|kubernetes | `<cmd or ->` | <url> |
|
|
228
|
+
|
|
229
|
+
> **Running-detection**: the generated CI/CD app determines "is it running?" by a TCP connect to
|
|
230
|
+
> each application's **Port** on both IPv4 (`127.0.0.1`) and IPv6 (`::1`) loopback plus the
|
|
231
|
+
> **Health** host — so an app is detected whichever family it binds. Use a `localhost` Health host
|
|
232
|
+
> for Node/Vite/Next apps (they bind IPv6 `::1`) and `127.0.0.1` for JVM apps.
|
|
233
|
+
|
|
234
|
+
## Docker
|
|
235
|
+
|
|
236
|
+
Written only from Gather 2a. When Docker or a docker repo is absent, write the section as:
|
|
237
|
+
`_Not dockerized — Docker and/or a docker repo are not configured in DEVTOOL.md/ENVIRONMENT.md._`
|
|
238
|
+
|
|
239
|
+
**Registry**: <repo, e.g. `registry.example.com/team`>
|
|
240
|
+
|
|
241
|
+
| Application | Image | Dockerfile |
|
|
242
|
+
|---|---|---|
|
|
243
|
+
| <name> | `<repo>/<app_folder>` | existing \| managed |
|
|
244
|
+
|
|
245
|
+
## Dockerfiles
|
|
246
|
+
|
|
247
|
+
One fenced block per `managed` Dockerfile (omit the section body — `_All Dockerfiles exist._`
|
|
248
|
+
— when every dockerized app already has one; `_Not dockerized._` when the Docker section is
|
|
249
|
+
inactive). The generated CI/CD app writes each body to `<app_folder>/Dockerfile` before Build
|
|
250
|
+
only when the file is missing on disk — an existing Dockerfile is never overwritten.
|
|
251
|
+
|
|
252
|
+
```dockerfile path=<app_folder>/Dockerfile
|
|
253
|
+
FROM node:22-slim
|
|
254
|
+
WORKDIR /app
|
|
255
|
+
COPY package*.json ./
|
|
256
|
+
RUN npm ci --omit=dev
|
|
257
|
+
COPY . .
|
|
258
|
+
EXPOSE <port>
|
|
259
|
+
CMD ["node", "dist/index.js"]
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Application Configs
|
|
263
|
+
|
|
264
|
+
The runtime config each application needs to START SUCCESSFULLY. The generated CI/CD app writes any
|
|
265
|
+
`managed=yes` file into the application folder before Build/Start when it is missing, and shows
|
|
266
|
+
every file (source, status, required keys, live content) in the per-application Config modal for
|
|
267
|
+
troubleshooting. One table per application; `Path` is relative to the application folder.
|
|
268
|
+
|
|
269
|
+
### <App Name> (<folder>)
|
|
270
|
+
|
|
271
|
+
| Path | Source | Managed | Required Keys |
|
|
272
|
+
|---|---|---|---|
|
|
273
|
+
| .env | environment | yes | DATABASE_URL, REDIS_HOST, PORT |
|
|
274
|
+
| .env-uat | env-file | no | DATABASE_URL, REDIS_HOST |
|
|
275
|
+
|
|
276
|
+
For each `Managed=yes` row, follow it with the resolved file body (verbatim — credentials allowed
|
|
277
|
+
under the dev-plaintext rule):
|
|
278
|
+
|
|
279
|
+
```env path=.env
|
|
280
|
+
DATABASE_URL=postgres://app:app@127.0.0.1:5432/appdb
|
|
281
|
+
REDIS_HOST=127.0.0.1
|
|
282
|
+
PORT=3000
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Omit the fenced block for `env-file` rows (the file is used as-is on disk). If an application needs
|
|
286
|
+
no config file, write `_No runtime config files._` under its heading.
|
|
287
|
+
|
|
288
|
+
## Infrastructure
|
|
289
|
+
|
|
290
|
+
Supporting 3rd-party services shown status-only (TCP reachability) on the CI/CD app's
|
|
291
|
+
Infrastructure page. Leave the table body empty when the project declares no supporting services.
|
|
292
|
+
|
|
293
|
+
| Id | Service | Host | Port | Console URL | Description |
|
|
294
|
+
|---|---|---|---|---|---|
|
|
295
|
+
| <id> | <name> | <host> | <port> | `<url or ->` | <blurb> |
|
|
296
|
+
|
|
297
|
+
## Rationale
|
|
298
|
+
|
|
299
|
+
- <per-application: why this method/commands, citing ENVIRONMENT.md/DEVTOOL.md evidence>
|
|
300
|
+
````
|
|
301
|
+
|
|
302
|
+
Then flip `**Status**: IN PROGRESS` to `**Status**: COMPLETED`. The studio watcher advances
|
|
303
|
+
only on COMPLETED.
|
|
304
|
+
|
|
305
|
+
## STOP — Hand Back to the Human
|
|
306
|
+
|
|
307
|
+
Print a one-paragraph summary and STOP. Never invoke util-gencicdscript or any other skill —
|
|
308
|
+
the human reviews and approves the plan in the studio's CI/CD screen first.
|
|
309
|
+
|
|
310
|
+
## Important Rules
|
|
311
|
+
|
|
312
|
+
- Every Build command is a CLEAN build — clean lifecycle (`mvn clean`, `gradlew clean`), a wiped
|
|
313
|
+
output dir before a Node/asset build, and `docker build --no-cache` — never an incremental build
|
|
314
|
+
that could start or ship a stale artifact.
|
|
315
|
+
- Never write the CI/CD app; never modify PRD.md/CLAUDE.md/BUG.md.
|
|
316
|
+
- Never delete an existing `**Approved**:` line if re-planning over a previous plan — overwrite
|
|
317
|
+
the whole file WITHOUT any Approved line (a re-plan always requires fresh approval).
|
|
318
|
+
- Credentials from ENVIRONMENT.md may be referenced in commands verbatim (dev-environment
|
|
319
|
+
plaintext rule) but never echoed into the Rationale narrative.
|