@getvitops/create 0.5.0 → 0.7.0
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/CHANGELOG.md +44 -5
- package/README.md +7 -0
- package/package.json +18 -2
- package/templates/emdash/.agents/skills/setup/SKILL.md +61 -0
- package/templates/emdash/.env +1 -0
- package/templates/emdash/.github/workflows/ci.yml +12 -0
- package/templates/emdash/.github/workflows/deploy-dev.yml +17 -19
- package/templates/emdash/.github/workflows/deploy-prod.yml +17 -21
- package/templates/emdash/.github/workflows/promote.yml +8 -36
- package/templates/emdash/.mcp.json +4 -0
- package/templates/emdash/.nvmrc +1 -0
- package/templates/emdash/AGENTS.md +23 -11
- package/templates/emdash/README.md +44 -42
- package/templates/emdash/SETUP.html +526 -0
- package/templates/emdash/_gitignore +3 -0
- package/templates/emdash/astro.config.mjs +7 -1
- package/templates/emdash/package.json +6 -4
- package/templates/emdash/seed/seed.json +1 -1
- package/templates/emdash/site.json +228 -0
- package/templates/emdash/src/assets/placeholder/wireframe-400x400.png +0 -0
- package/templates/emdash/src/assets/placeholder/wireframe-400x400.svg +1 -0
- package/templates/emdash/src/assets/placeholder/wireframe-400x600.png +0 -0
- package/templates/emdash/src/assets/placeholder/wireframe-400x600.svg +1 -0
- package/templates/emdash/src/assets/placeholder/wireframe-600x400.png +0 -0
- package/templates/emdash/src/assets/placeholder/wireframe-600x400.svg +1 -0
- package/templates/emdash/vite.config.ts +1 -1
- package/templates/emdash/wrangler.jsonc +8 -3
- package/templates/static/.agents/skills/setup/SKILL.md +61 -0
- package/templates/static/.env +1 -0
- package/templates/static/.github/workflows/ci.yml +12 -0
- package/templates/static/.github/workflows/deploy-dev.yml +33 -0
- package/templates/static/.github/workflows/deploy-prod.yml +29 -0
- package/templates/static/.github/workflows/promote.yml +16 -0
- package/templates/static/.nvmrc +1 -0
- package/templates/static/AGENTS.md +64 -0
- package/templates/static/README.md +80 -0
- package/templates/static/SETUP.html +526 -0
- package/templates/static/_gitignore +27 -0
- package/templates/static/astro.config.mjs +23 -0
- package/templates/{emdash → static}/design-system.json +1 -1
- package/templates/static/package.json +41 -0
- package/templates/static/scripts/dev-wrangler-config.mjs +28 -0
- package/templates/static/site.json +228 -0
- package/templates/static/src/assets/placeholder/wireframe-400x400.png +0 -0
- package/templates/static/src/assets/placeholder/wireframe-400x400.svg +1 -0
- package/templates/static/src/assets/placeholder/wireframe-400x600.png +0 -0
- package/templates/static/src/assets/placeholder/wireframe-400x600.svg +1 -0
- package/templates/static/src/assets/placeholder/wireframe-600x400.png +0 -0
- package/templates/static/src/assets/placeholder/wireframe-600x400.svg +1 -0
- package/templates/static/src/layouts/Layout.astro +26 -0
- package/templates/static/src/pages/404.astro +11 -0
- package/templates/static/src/pages/index.astro +13 -0
- package/templates/static/tsconfig.json +5 -0
- package/templates/static/wrangler.jsonc +22 -0
- package/templates/emdash/scripts/init-github.mjs +0 -102
- package/templates/emdash/scripts/init-hosting.mjs +0 -150
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Setup</title>
|
|
7
|
+
<!--
|
|
8
|
+
Opened straight from disk (file://) before anything is deployed, which is
|
|
9
|
+
when most of these steps happen — so it links a relative, pre-generated
|
|
10
|
+
stylesheet rather than the site's own build output. Run `pnpm run sop`
|
|
11
|
+
first (it's a one-line `vitops generate -f css` into .vitops/sop/); the
|
|
12
|
+
banner below explains this if the stylesheet 404s, and the markup stays
|
|
13
|
+
legible either way — every item here is a real checkbox in a real
|
|
14
|
+
<details>, readable and tickable with JS off.
|
|
15
|
+
|
|
16
|
+
This file is template DATA copied verbatim by `vp create`, not framework
|
|
17
|
+
code — see AGENTS.md's "Client onboarding" section for why it isn't a
|
|
18
|
+
<wc-*> element. Only class names from @getvitops/core's own vocabulary
|
|
19
|
+
are used here; if you need something this page can't express, that's a
|
|
20
|
+
missing framework pattern, not a reason to hand-write CSS.
|
|
21
|
+
-->
|
|
22
|
+
<link id="sop-stylesheet" rel="stylesheet" href=".vitops/sop/styles.css" />
|
|
23
|
+
<style>
|
|
24
|
+
/* Minimal fallback so the page is still legible before `pnpm run sop`
|
|
25
|
+
has run once — intentionally not framework CSS, since it only ever
|
|
26
|
+
applies in the narrow window before the real stylesheet exists. */
|
|
27
|
+
body {
|
|
28
|
+
font-family:
|
|
29
|
+
system-ui,
|
|
30
|
+
-apple-system,
|
|
31
|
+
'Segoe UI',
|
|
32
|
+
sans-serif;
|
|
33
|
+
max-width: 64rem;
|
|
34
|
+
margin-inline: auto;
|
|
35
|
+
padding: 2rem 1.5rem 6rem;
|
|
36
|
+
line-height: 1.5;
|
|
37
|
+
}
|
|
38
|
+
</style>
|
|
39
|
+
</head>
|
|
40
|
+
<body class="centered">
|
|
41
|
+
<div class="rhythm">
|
|
42
|
+
<header class="region rhythm">
|
|
43
|
+
<h1>Client onboarding checklist</h1>
|
|
44
|
+
<p id="no-stylesheet-notice" class="banner" hidden>
|
|
45
|
+
This page isn't styled yet — run <code>pnpm run sop</code> once (it generates
|
|
46
|
+
<code>.vitops/sop/styles.css</code>), then reload.
|
|
47
|
+
</p>
|
|
48
|
+
<p>
|
|
49
|
+
A local working document — it is never deployed, never committed to a build, and nothing
|
|
50
|
+
here is read by the site itself. Work top to bottom; each stage gates the next. Every
|
|
51
|
+
command is copy-pasteable as written. Progress is saved in this browser only
|
|
52
|
+
(<code>localStorage</code>), so it won't follow you to another machine.
|
|
53
|
+
</p>
|
|
54
|
+
<p>
|
|
55
|
+
<span class="badge" id="progress-badge">0 / 0 done</span>
|
|
56
|
+
</p>
|
|
57
|
+
</header>
|
|
58
|
+
|
|
59
|
+
<main class="rhythm">
|
|
60
|
+
<details class="details" open data-sop-stage="host">
|
|
61
|
+
<summary>1. Choose the host</summary>
|
|
62
|
+
<div class="rhythm">
|
|
63
|
+
<label class="custom-check">
|
|
64
|
+
<input type="checkbox" data-sop="host.decide" />
|
|
65
|
+
<span class="custom-check__box"
|
|
66
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
67
|
+
></span>
|
|
68
|
+
<span>
|
|
69
|
+
Decide the hosting target — <strong>Cloudflare Workers</strong> is the default and
|
|
70
|
+
what the shipped deploy workflows target. A <code>node</code> target exists for the
|
|
71
|
+
EmDash template (VPS / docker-compose / k8s) but needs manual setup — see that
|
|
72
|
+
template's README "Hosting" section — and the deploy workflows here are
|
|
73
|
+
Cloudflare-specific either way.
|
|
74
|
+
</span>
|
|
75
|
+
</label>
|
|
76
|
+
</div>
|
|
77
|
+
</details>
|
|
78
|
+
|
|
79
|
+
<details class="details" data-sop-stage="repo">
|
|
80
|
+
<summary>2. GitHub repo + branch policy</summary>
|
|
81
|
+
<div class="rhythm">
|
|
82
|
+
<p>
|
|
83
|
+
<code>dev</code> is the unprotected integration branch — push and merge to it
|
|
84
|
+
directly. <code>main</code> is production: protected, gated by a
|
|
85
|
+
<code>production</code> environment that pauses for an admin's approval, and reachable
|
|
86
|
+
only through the <code>promote</code> workflow (never a direct push).
|
|
87
|
+
</p>
|
|
88
|
+
<label class="custom-check">
|
|
89
|
+
<input type="checkbox" data-sop="repo.plan" />
|
|
90
|
+
<span class="custom-check__box"
|
|
91
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
92
|
+
></span>
|
|
93
|
+
<span> Preview it: <code>npx vitops setup repo --dry</code> </span>
|
|
94
|
+
</label>
|
|
95
|
+
<label class="custom-check">
|
|
96
|
+
<input type="checkbox" data-sop="repo.run" />
|
|
97
|
+
<span class="custom-check__box"
|
|
98
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
99
|
+
></span>
|
|
100
|
+
<span>
|
|
101
|
+
Run it: <code>npx vitops setup repo</code> — creates the GitHub repo, pushes
|
|
102
|
+
<code>main</code> + <code>dev</code>, makes <code>dev</code> default, and requests
|
|
103
|
+
branch protection + the <code>production</code>/<code>dev</code>
|
|
104
|
+
environments.
|
|
105
|
+
</span>
|
|
106
|
+
</label>
|
|
107
|
+
<label class="custom-check">
|
|
108
|
+
<input type="checkbox" data-sop="repo.verify" />
|
|
109
|
+
<span class="custom-check__box"
|
|
110
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
111
|
+
></span>
|
|
112
|
+
<span>
|
|
113
|
+
Verify by hand in GitHub → Settings → Branches / Environments. Branch protection and
|
|
114
|
+
environment reviewers need GitHub Pro/Team on a private repo — if the command
|
|
115
|
+
reported that as blocked, this is where you set it up manually.
|
|
116
|
+
</span>
|
|
117
|
+
</label>
|
|
118
|
+
</div>
|
|
119
|
+
</details>
|
|
120
|
+
|
|
121
|
+
<details class="details" data-sop-stage="hosting">
|
|
122
|
+
<summary>3. Hosting resources</summary>
|
|
123
|
+
<div class="rhythm">
|
|
124
|
+
<label class="custom-check">
|
|
125
|
+
<input type="checkbox" data-sop="hosting.plan" />
|
|
126
|
+
<span class="custom-check__box"
|
|
127
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
128
|
+
></span>
|
|
129
|
+
<span> Preview it: <code>npx vitops setup hosting --dry</code> </span>
|
|
130
|
+
</label>
|
|
131
|
+
<label class="custom-check">
|
|
132
|
+
<input type="checkbox" data-sop="hosting.run" />
|
|
133
|
+
<span class="custom-check__box"
|
|
134
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
135
|
+
></span>
|
|
136
|
+
<span>
|
|
137
|
+
Run it: <code>npx vitops setup hosting</code> — provisions the isolated dev D1
|
|
138
|
+
database + R2 bucket (EmDash template) and sets the <code>DEV_D1_ID</code> /
|
|
139
|
+
<code>CLOUDFLARE_ACCOUNT_ID</code> repo secrets. Requires
|
|
140
|
+
<code>npx wrangler login</code> first.
|
|
141
|
+
</span>
|
|
142
|
+
</label>
|
|
143
|
+
<label class="custom-check">
|
|
144
|
+
<input type="checkbox" data-sop="hosting.token" />
|
|
145
|
+
<span class="custom-check__box"
|
|
146
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
147
|
+
></span>
|
|
148
|
+
<span>
|
|
149
|
+
<strong>Create a Cloudflare API token by hand</strong> — no API can mint one:
|
|
150
|
+
<a
|
|
151
|
+
class="link"
|
|
152
|
+
href="https://dash.cloudflare.com/profile/api-tokens"
|
|
153
|
+
target="_blank"
|
|
154
|
+
rel="noopener"
|
|
155
|
+
>dash.cloudflare.com/profile/api-tokens</a
|
|
156
|
+
>
|
|
157
|
+
(Workers + D1 + R2 edit), then
|
|
158
|
+
<code>gh secret set CLOUDFLARE_API_TOKEN</code>. The first workflow runs fail until
|
|
159
|
+
this exists.
|
|
160
|
+
</span>
|
|
161
|
+
</label>
|
|
162
|
+
</div>
|
|
163
|
+
</details>
|
|
164
|
+
|
|
165
|
+
<details class="details" data-sop-stage="domain">
|
|
166
|
+
<summary>4. Domain strategy</summary>
|
|
167
|
+
<div class="rhythm">
|
|
168
|
+
<p>Two mutually exclusive tracks. Pick one — do not do both in the same deploy.</p>
|
|
169
|
+
|
|
170
|
+
<h3>4a. Go live on <code>*.workers.dev</code> (default, safe)</h3>
|
|
171
|
+
<p>
|
|
172
|
+
Leaves any existing live site untouched at its current domain. Do this first, always —
|
|
173
|
+
cutover is a separate, later step.
|
|
174
|
+
</p>
|
|
175
|
+
<label class="custom-check">
|
|
176
|
+
<input type="checkbox" data-sop="domain.workersdev.leave" />
|
|
177
|
+
<span class="custom-check__box"
|
|
178
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
179
|
+
></span>
|
|
180
|
+
<span>
|
|
181
|
+
Leave <code>workers_dev: true</code> and the <code>routes</code> block commented out
|
|
182
|
+
in <code>wrangler.jsonc</code> — this is the shipped default.
|
|
183
|
+
</span>
|
|
184
|
+
</label>
|
|
185
|
+
<label class="custom-check">
|
|
186
|
+
<input type="checkbox" data-sop="domain.workersdev.url" />
|
|
187
|
+
<span class="custom-check__box"
|
|
188
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
189
|
+
></span>
|
|
190
|
+
<span>
|
|
191
|
+
Deploy once (<code>pnpm deploy</code>), note the printed
|
|
192
|
+
<code>*.workers.dev</code> URL, and set
|
|
193
|
+
<code>site.environments.production.url</code> in <code>site.json</code> to it.
|
|
194
|
+
</span>
|
|
195
|
+
</label>
|
|
196
|
+
<label class="custom-check">
|
|
197
|
+
<input type="checkbox" data-sop="domain.workersdev.noindex" />
|
|
198
|
+
<span class="custom-check__box"
|
|
199
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
200
|
+
></span>
|
|
201
|
+
<span>
|
|
202
|
+
Set <code>site.environments.production.robots</code> to
|
|
203
|
+
<code>"noindex,nofollow"</code> — a workers.dev URL is indexable, and this is the
|
|
204
|
+
launch gate that stops search engines picking it up as a duplicate of the real site.
|
|
205
|
+
</span>
|
|
206
|
+
</label>
|
|
207
|
+
|
|
208
|
+
<h3>4b. Cut over to the custom domain</h3>
|
|
209
|
+
<p>
|
|
210
|
+
<strong>This step overwrites the zone's DNS record the moment you deploy</strong>
|
|
211
|
+
— it is the one irreversible-feeling moment in this whole checklist, and it takes an
|
|
212
|
+
existing live site down at that instant. Do it deliberately, not as part of a bigger
|
|
213
|
+
batch of changes. It is safe to complete stage 6 (Search Console / GCP / ads) before
|
|
214
|
+
this — <code>vitops search setup</code> only ever <em>creates</em> a verification TXT
|
|
215
|
+
record, it never touches the apex.
|
|
216
|
+
</p>
|
|
217
|
+
<label class="custom-check">
|
|
218
|
+
<input type="checkbox" data-sop="domain.cutover.ttl" />
|
|
219
|
+
<span class="custom-check__box"
|
|
220
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
221
|
+
></span>
|
|
222
|
+
<span> If replacing a live site, lower that site's DNS TTL well ahead of time. </span>
|
|
223
|
+
</label>
|
|
224
|
+
<label class="custom-check">
|
|
225
|
+
<input type="checkbox" data-sop="domain.cutover.plan" />
|
|
226
|
+
<span class="custom-check__box"
|
|
227
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
228
|
+
></span>
|
|
229
|
+
<span>
|
|
230
|
+
Preview it: <code>npx vitops setup domain --domain <apex> --dry</code> — this
|
|
231
|
+
only plans and checks; it never applies the cutover itself.
|
|
232
|
+
</span>
|
|
233
|
+
</label>
|
|
234
|
+
<label class="custom-check">
|
|
235
|
+
<input type="checkbox" data-sop="domain.cutover.uncomment" />
|
|
236
|
+
<span class="custom-check__box"
|
|
237
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
238
|
+
></span>
|
|
239
|
+
<span>
|
|
240
|
+
Uncomment the <code>routes</code> block in <code>wrangler.jsonc</code>, set your
|
|
241
|
+
apex, and deploy: <code>pnpm deploy</code>.
|
|
242
|
+
</span>
|
|
243
|
+
</label>
|
|
244
|
+
<label class="custom-check">
|
|
245
|
+
<input type="checkbox" data-sop="domain.cutover.config" />
|
|
246
|
+
<span class="custom-check__box"
|
|
247
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
248
|
+
></span>
|
|
249
|
+
<span>
|
|
250
|
+
Set <code>site.domains.canonical</code> and
|
|
251
|
+
<code>site.environments.production.url</code> to the custom domain, and flip
|
|
252
|
+
<code>environments.production.robots</code> back to <code>"index,follow"</code> (or
|
|
253
|
+
remove it).
|
|
254
|
+
</span>
|
|
255
|
+
</label>
|
|
256
|
+
<label class="custom-check">
|
|
257
|
+
<input type="checkbox" data-sop="domain.cutover.notify" />
|
|
258
|
+
<span class="custom-check__box"
|
|
259
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
260
|
+
></span>
|
|
261
|
+
<span>
|
|
262
|
+
Re-run <code>npx vitops robots</code> and <code>npx vitops search notify</code>.
|
|
263
|
+
</span>
|
|
264
|
+
</label>
|
|
265
|
+
</div>
|
|
266
|
+
</details>
|
|
267
|
+
|
|
268
|
+
<details class="details" data-sop-stage="config">
|
|
269
|
+
<summary>5. Configuration</summary>
|
|
270
|
+
<div class="rhythm">
|
|
271
|
+
<label class="custom-check">
|
|
272
|
+
<input type="checkbox" data-sop="config.fill" />
|
|
273
|
+
<span class="custom-check__box"
|
|
274
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
275
|
+
></span>
|
|
276
|
+
<span>
|
|
277
|
+
Fill in <code>site.json</code>: <code>organization</code> (name, address, contact),
|
|
278
|
+
<code>site.locales</code>, <code>site.environments</code>, <code>site.seo</code>,
|
|
279
|
+
<code>site.analytics</code>, <code>site.legal.*.enabled</code>,
|
|
280
|
+
<code>site.favicon</code>, <code>site.icons</code>.
|
|
281
|
+
</span>
|
|
282
|
+
</label>
|
|
283
|
+
<label class="custom-check">
|
|
284
|
+
<input type="checkbox" data-sop="config.validate" />
|
|
285
|
+
<span class="custom-check__box"
|
|
286
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
287
|
+
></span>
|
|
288
|
+
<span> Check it: <code>npx vitops validate site.json</code> </span>
|
|
289
|
+
</label>
|
|
290
|
+
</div>
|
|
291
|
+
</details>
|
|
292
|
+
|
|
293
|
+
<details class="details" data-sop-stage="connections">
|
|
294
|
+
<summary>6. Search Console / GCP / ads</summary>
|
|
295
|
+
<div class="rhythm">
|
|
296
|
+
<label class="custom-check">
|
|
297
|
+
<input type="checkbox" data-sop="connections.gcp" />
|
|
298
|
+
<span class="custom-check__box"
|
|
299
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
300
|
+
></span>
|
|
301
|
+
<span>
|
|
302
|
+
Set <code>site.google.project</code>, and the environment variables:
|
|
303
|
+
<code>VITOPS_GOOGLE_CLIENT_ID</code>, <code>VITOPS_GOOGLE_CLIENT_SECRET</code>,
|
|
304
|
+
<code>VITOPS_GOOGLE_REFRESH_TOKEN</code>, <code>CLOUDFLARE_API_TOKEN</code>.
|
|
305
|
+
</span>
|
|
306
|
+
</label>
|
|
307
|
+
<label class="custom-check">
|
|
308
|
+
<input type="checkbox" data-sop="connections.search" />
|
|
309
|
+
<span class="custom-check__box"
|
|
310
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
311
|
+
></span>
|
|
312
|
+
<span>
|
|
313
|
+
Preview then run: <code>npx vitops setup search --dry</code>, then
|
|
314
|
+
<code>npx vitops setup search</code>. This is a <strong>user OAuth</strong>
|
|
315
|
+
action, deliberately — verifying a site makes the caller an owner, and that should
|
|
316
|
+
be a person, not a deploy robot.
|
|
317
|
+
</span>
|
|
318
|
+
</label>
|
|
319
|
+
<label class="custom-check">
|
|
320
|
+
<input type="checkbox" data-sop="connections.ads" />
|
|
321
|
+
<span class="custom-check__box"
|
|
322
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
323
|
+
></span>
|
|
324
|
+
<span>
|
|
325
|
+
Preview then run: <code>npx vitops setup ads --dry</code>, then
|
|
326
|
+
<code>npx vitops setup ads</code>.
|
|
327
|
+
</span>
|
|
328
|
+
</label>
|
|
329
|
+
<label class="custom-check">
|
|
330
|
+
<input type="checkbox" data-sop="connections.manual" />
|
|
331
|
+
<span class="custom-check__box"
|
|
332
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
333
|
+
></span>
|
|
334
|
+
<span>
|
|
335
|
+
Two things are never automated, by design: adding a Search Console
|
|
336
|
+
<strong>Full User</strong> (via a Google Group), and clicking each platform's own
|
|
337
|
+
"Verify" button. Both are named in the command output when they apply.
|
|
338
|
+
</span>
|
|
339
|
+
</label>
|
|
340
|
+
</div>
|
|
341
|
+
</details>
|
|
342
|
+
|
|
343
|
+
<details class="details" data-sop-stage="legal">
|
|
344
|
+
<summary>7. Legal</summary>
|
|
345
|
+
<div class="rhythm">
|
|
346
|
+
<label class="custom-check">
|
|
347
|
+
<input type="checkbox" data-sop="legal.generate" />
|
|
348
|
+
<span class="custom-check__box"
|
|
349
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
350
|
+
></span>
|
|
351
|
+
<span>
|
|
352
|
+
Generate real documents from the filled-in config —
|
|
353
|
+
<code>npx vitops legal --format portable-text</code> (EmDash; paste into the admin)
|
|
354
|
+
or <code>npx vitops legal --format md</code> (static; commit the output). The seeded
|
|
355
|
+
<code>/terms</code> and <code>/privacy</code> pages are deliberately short,
|
|
356
|
+
obviously-unfinished placeholders.
|
|
357
|
+
</span>
|
|
358
|
+
</label>
|
|
359
|
+
<label class="custom-check">
|
|
360
|
+
<input type="checkbox" data-sop="legal.review" />
|
|
361
|
+
<span class="custom-check__box"
|
|
362
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
363
|
+
></span>
|
|
364
|
+
<span>
|
|
365
|
+
<strong>Have it reviewed before publishing.</strong> Every generated document opens
|
|
366
|
+
with a non-optional review banner — it is a starting point from your config, not
|
|
367
|
+
legal advice, and a plausible-looking policy shipped unread is the one failure mode
|
|
368
|
+
here with real consequences.
|
|
369
|
+
</span>
|
|
370
|
+
</label>
|
|
371
|
+
</div>
|
|
372
|
+
</details>
|
|
373
|
+
|
|
374
|
+
<details class="details" data-sop-stage="launch">
|
|
375
|
+
<summary>8. Launch gates</summary>
|
|
376
|
+
<div class="rhythm">
|
|
377
|
+
<label class="custom-check">
|
|
378
|
+
<input type="checkbox" data-sop="launch.robots" />
|
|
379
|
+
<span class="custom-check__box"
|
|
380
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
381
|
+
></span>
|
|
382
|
+
<span>
|
|
383
|
+
Robots directive matches the live origin's intent (blocked while on workers.dev,
|
|
384
|
+
open after cutover) — <code>npx vitops robots</code>.
|
|
385
|
+
</span>
|
|
386
|
+
</label>
|
|
387
|
+
<label class="custom-check">
|
|
388
|
+
<input type="checkbox" data-sop="launch.canonical" />
|
|
389
|
+
<span class="custom-check__box"
|
|
390
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
391
|
+
></span>
|
|
392
|
+
<span>
|
|
393
|
+
Canonical domain in <code>site.json</code> matches the actual live origin.
|
|
394
|
+
</span>
|
|
395
|
+
</label>
|
|
396
|
+
<label class="custom-check">
|
|
397
|
+
<input type="checkbox" data-sop="launch.favicon" />
|
|
398
|
+
<span class="custom-check__box"
|
|
399
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
400
|
+
></span>
|
|
401
|
+
<span> Favicon / PWA assets present and correct. </span>
|
|
402
|
+
</label>
|
|
403
|
+
<label class="custom-check">
|
|
404
|
+
<input type="checkbox" data-sop="launch.lint" />
|
|
405
|
+
<span class="custom-check__box"
|
|
406
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
407
|
+
></span>
|
|
408
|
+
<span>
|
|
409
|
+
<code>npx vitops lint --src</code> and <code>pnpm typecheck</code> both clean.
|
|
410
|
+
</span>
|
|
411
|
+
</label>
|
|
412
|
+
<label class="custom-check">
|
|
413
|
+
<input type="checkbox" data-sop="launch.approve" />
|
|
414
|
+
<span class="custom-check__box"
|
|
415
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
416
|
+
></span>
|
|
417
|
+
<span>
|
|
418
|
+
Prod deploy approved by an admin in the <code>production</code> GitHub Environment
|
|
419
|
+
gate.
|
|
420
|
+
</span>
|
|
421
|
+
</label>
|
|
422
|
+
<label class="custom-check">
|
|
423
|
+
<input type="checkbox" data-sop="launch.notify" />
|
|
424
|
+
<span class="custom-check__box"
|
|
425
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
426
|
+
></span>
|
|
427
|
+
<span> <code>npx vitops search notify</code> run once live. </span>
|
|
428
|
+
</label>
|
|
429
|
+
<label class="custom-check">
|
|
430
|
+
<input type="checkbox" data-sop="launch.check" />
|
|
431
|
+
<span class="custom-check__box"
|
|
432
|
+
><span class="custom-check__indicator custom-check__indicator--check"></span
|
|
433
|
+
></span>
|
|
434
|
+
<span>
|
|
435
|
+
A day or two later: <code>npx vitops search notify --check</code> confirms Google
|
|
436
|
+
actually indexed it.
|
|
437
|
+
</span>
|
|
438
|
+
</label>
|
|
439
|
+
</div>
|
|
440
|
+
</details>
|
|
441
|
+
</main>
|
|
442
|
+
|
|
443
|
+
<footer class="region rhythm">
|
|
444
|
+
<div class="card">
|
|
445
|
+
<p><strong>Working alongside an AI agent?</strong></p>
|
|
446
|
+
<p>
|
|
447
|
+
Point it at <code>.agents/skills/setup/</code> — it works this same list autonomously
|
|
448
|
+
and only stops at the steps marked above as requiring a person (the Cloudflare API
|
|
449
|
+
token, the domain cutover, and publishing any generated legal document).
|
|
450
|
+
</p>
|
|
451
|
+
</div>
|
|
452
|
+
</footer>
|
|
453
|
+
</div>
|
|
454
|
+
|
|
455
|
+
<script type="module">
|
|
456
|
+
// The whole persistence contract. An admin portal that wants this same
|
|
457
|
+
// checklist backed by shared/server storage defines
|
|
458
|
+
// `window.__vitopsSopStore` before this script runs; everything below is
|
|
459
|
+
// DOM wiring against whichever store is present. Do not add a second
|
|
460
|
+
// storage backend inline here — swap the store, not this file.
|
|
461
|
+
//
|
|
462
|
+
// { get(id): boolean, set(id, v): void|Promise<void>, all(): Record<string, boolean> }
|
|
463
|
+
function localStore(key) {
|
|
464
|
+
const read = () => {
|
|
465
|
+
try {
|
|
466
|
+
return JSON.parse(localStorage.getItem(key) ?? '{}');
|
|
467
|
+
} catch {
|
|
468
|
+
return {};
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
return {
|
|
472
|
+
get: (id) => Boolean(read()[id]),
|
|
473
|
+
set: (id, value) => {
|
|
474
|
+
const state = read();
|
|
475
|
+
state[id] = value;
|
|
476
|
+
localStorage.setItem(key, JSON.stringify(state));
|
|
477
|
+
},
|
|
478
|
+
all: () => read(),
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const store = window.__vitopsSopStore ?? localStore('vitops.sop.v1');
|
|
483
|
+
const checkboxes = Array.from(document.querySelectorAll('input[data-sop]'));
|
|
484
|
+
const badge = document.getElementById('progress-badge');
|
|
485
|
+
|
|
486
|
+
// A <link> still loading (network/disk latency) reports zero cssRules just
|
|
487
|
+
// like a 404'd one — the check has to wait for the sheet to settle rather
|
|
488
|
+
// than sampling it once at parse time, or a real stylesheet that simply
|
|
489
|
+
// hasn't finished loading yet reads as "not styled".
|
|
490
|
+
function checkStylesheet() {
|
|
491
|
+
const link = document.getElementById('sop-stylesheet');
|
|
492
|
+
try {
|
|
493
|
+
if (link.sheet && link.sheet.cssRules.length > 0) return;
|
|
494
|
+
} catch {
|
|
495
|
+
// A cross-origin or 404'd sheet throws on `.cssRules` under `file://` —
|
|
496
|
+
// that failure IS the signal the stylesheet isn't there yet.
|
|
497
|
+
}
|
|
498
|
+
document.getElementById('no-stylesheet-notice').hidden = false;
|
|
499
|
+
}
|
|
500
|
+
const sopLink = document.getElementById('sop-stylesheet');
|
|
501
|
+
if (sopLink.sheet) checkStylesheet();
|
|
502
|
+
else {
|
|
503
|
+
sopLink.addEventListener('load', checkStylesheet);
|
|
504
|
+
sopLink.addEventListener('error', checkStylesheet);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function updateBadge() {
|
|
508
|
+
const done = checkboxes.filter((c) => c.checked).length;
|
|
509
|
+
badge.textContent = `${done} / ${checkboxes.length} done`;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
const saved = store.all();
|
|
513
|
+
for (const box of checkboxes) {
|
|
514
|
+
box.checked = Boolean(saved[box.dataset.sop]);
|
|
515
|
+
}
|
|
516
|
+
updateBadge();
|
|
517
|
+
|
|
518
|
+
document.addEventListener('change', (event) => {
|
|
519
|
+
const box = event.target;
|
|
520
|
+
if (!(box instanceof HTMLInputElement) || !box.dataset.sop) return;
|
|
521
|
+
store.set(box.dataset.sop, box.checked);
|
|
522
|
+
updateBadge();
|
|
523
|
+
});
|
|
524
|
+
</script>
|
|
525
|
+
</body>
|
|
526
|
+
</html>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# build output
|
|
2
|
+
dist/
|
|
3
|
+
|
|
4
|
+
# dependencies
|
|
5
|
+
node_modules/
|
|
6
|
+
|
|
7
|
+
# generated types
|
|
8
|
+
.astro/
|
|
9
|
+
|
|
10
|
+
# wrangler local state
|
|
11
|
+
.wrangler/
|
|
12
|
+
.wrangler.dev.json
|
|
13
|
+
|
|
14
|
+
# generated by the vitops() integration on dev/build
|
|
15
|
+
src/styles/
|
|
16
|
+
public/vitops/
|
|
17
|
+
|
|
18
|
+
# generated by `pnpm run sop` — styles SETUP.html for a file:// open
|
|
19
|
+
.vitops/
|
|
20
|
+
|
|
21
|
+
# environment
|
|
22
|
+
.env
|
|
23
|
+
.env.*
|
|
24
|
+
!.env.example
|
|
25
|
+
|
|
26
|
+
# os / editor
|
|
27
|
+
.DS_Store
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import vitops from '@getvitops/astro';
|
|
3
|
+
import { defineConfig } from 'astro/config';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
// Pure static output — deploys as Workers Static Assets (see
|
|
7
|
+
// wrangler.jsonc), no adapter and no server runtime.
|
|
8
|
+
output: 'static',
|
|
9
|
+
integrations: [
|
|
10
|
+
vitops({
|
|
11
|
+
// site.json is the umbrella Config — organization + site facts plus the
|
|
12
|
+
// design system at designSystem.themes.default — so css.input points
|
|
13
|
+
// there instead of a bare design-system.json. legal/robots/search/ads/
|
|
14
|
+
// reviews all read the same file (see AGENTS.md's "Client onboarding").
|
|
15
|
+
css: {
|
|
16
|
+
input: 'site.json',
|
|
17
|
+
format: 'css',
|
|
18
|
+
out: 'src/styles',
|
|
19
|
+
},
|
|
20
|
+
webComponents: true,
|
|
21
|
+
}),
|
|
22
|
+
],
|
|
23
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "my-static-site",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "astro dev",
|
|
8
|
+
"build": "astro build",
|
|
9
|
+
"preview": "astro preview",
|
|
10
|
+
"deploy": "astro build && wrangler deploy",
|
|
11
|
+
"deploy:dev": "astro build && node scripts/dev-wrangler-config.mjs && wrangler deploy --config .wrangler.dev.json",
|
|
12
|
+
"init:github": "vitops setup repo",
|
|
13
|
+
"init:hosting": "vitops setup hosting --no-dev-resources",
|
|
14
|
+
"setup": "vitops setup repo && vitops setup hosting --no-dev-resources",
|
|
15
|
+
"typecheck": "astro check",
|
|
16
|
+
"build:css": "vitops generate -i site.json -f css -o src/styles",
|
|
17
|
+
"lint:design": "vitops lint -i site.json -f css --strict",
|
|
18
|
+
"sop": "vitops generate -i site.json -f css -o .vitops/sop",
|
|
19
|
+
"prepare": "vp config"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@getvitops/astro": "latest",
|
|
23
|
+
"astro": "^7.1.2"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@astrojs/check": "^0.9.7",
|
|
27
|
+
"@getvitops/cli": "latest",
|
|
28
|
+
"typescript": "^6.0.3",
|
|
29
|
+
"vite": "latest",
|
|
30
|
+
"vite-plus": "latest",
|
|
31
|
+
"wrangler": "^4.111.0"
|
|
32
|
+
},
|
|
33
|
+
"devEngines": {
|
|
34
|
+
"runtime": {
|
|
35
|
+
"name": "node",
|
|
36
|
+
"version": "24.18.0",
|
|
37
|
+
"onFail": "download"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"packageManager": "pnpm@11.17.0"
|
|
41
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Local counterpart to the rewrite the CI dev-deploy workflow does: no adapter
|
|
2
|
+
// regenerates this site's `wrangler.jsonc` (it's a pure static build — Workers
|
|
3
|
+
// Static Assets, no server config to merge), so the checked-in file already
|
|
4
|
+
// IS the deploy config. This just suffixes the worker name and any
|
|
5
|
+
// custom-domain route so a local `pnpm run deploy:dev` never touches the prod
|
|
6
|
+
// worker, writing the result to a gitignored file rather than editing
|
|
7
|
+
// wrangler.jsonc in place.
|
|
8
|
+
//
|
|
9
|
+
// pnpm run deploy:dev → astro build && node scripts/dev-wrangler-config.mjs
|
|
10
|
+
// && wrangler deploy --config .wrangler.dev.json
|
|
11
|
+
|
|
12
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
13
|
+
|
|
14
|
+
const SRC = 'wrangler.jsonc';
|
|
15
|
+
const OUT = '.wrangler.dev.json';
|
|
16
|
+
|
|
17
|
+
const raw = readFileSync(SRC, 'utf8')
|
|
18
|
+
.replace(/\/\/.*$/gm, '')
|
|
19
|
+
.replace(/,(\s*[}\]])/g, '$1');
|
|
20
|
+
const cfg = JSON.parse(raw);
|
|
21
|
+
|
|
22
|
+
cfg.name = `${cfg.name}-dev`;
|
|
23
|
+
cfg.routes = (cfg.routes ?? []).map((r) =>
|
|
24
|
+
r?.pattern ? { ...r, pattern: `dev.${r.pattern}` } : r,
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
writeFileSync(OUT, `${JSON.stringify(cfg, null, 2)}\n`);
|
|
28
|
+
console.log(`Wrote ${OUT}\n name: ${cfg.name}\n routes: ${JSON.stringify(cfg.routes)}`);
|