@getvitops/create 0.6.0 → 0.8.0-alpha.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.
Files changed (35) hide show
  1. package/CHANGELOG.md +178 -5
  2. package/package.json +2 -2
  3. package/templates/emdash/.agents/skills/setup/SKILL.md +61 -0
  4. package/templates/emdash/.astro/types.d.ts +3 -0
  5. package/templates/emdash/.github/workflows/deploy-prod.yml +1 -1
  6. package/templates/emdash/AGENTS.md +19 -11
  7. package/templates/emdash/README.md +45 -42
  8. package/templates/emdash/SETUP.html +576 -0
  9. package/templates/emdash/_gitignore +3 -0
  10. package/templates/emdash/astro.config.mjs +33 -3
  11. package/templates/emdash/package.json +14 -9
  12. package/templates/emdash/seed/seed.json +1 -1
  13. package/templates/emdash/site.json +303 -0
  14. package/templates/emdash/src/layouts/Layout.astro +7 -1
  15. package/templates/emdash/src/pages/404.astro +5 -0
  16. package/templates/emdash/src/pages/[...slug].astro +7 -0
  17. package/templates/emdash/src/pages/index.astro +7 -0
  18. package/templates/emdash/vite.config.ts +19 -5
  19. package/templates/emdash/wrangler.jsonc +8 -3
  20. package/templates/static/.agents/skills/setup/SKILL.md +61 -0
  21. package/templates/static/.github/workflows/deploy-prod.yml +1 -1
  22. package/templates/static/AGENTS.md +14 -7
  23. package/templates/static/README.md +15 -20
  24. package/templates/static/SETUP.html +576 -0
  25. package/templates/static/_gitignore +3 -0
  26. package/templates/static/astro.config.mjs +5 -1
  27. package/templates/static/package.json +8 -6
  28. package/templates/static/site.json +228 -0
  29. package/templates/static/src/pages/index.astro +2 -2
  30. package/templates/static/wrangler.jsonc +10 -3
  31. package/templates/emdash/design-system.json +0 -148
  32. package/templates/emdash/scripts/init-github.mjs +0 -186
  33. package/templates/emdash/scripts/init-hosting.mjs +0 -150
  34. package/templates/static/scripts/init-github.mjs +0 -186
  35. package/templates/static/scripts/init-hosting.mjs +0 -62
@@ -7,25 +7,30 @@
7
7
  "dev": "astro dev",
8
8
  "build": "astro build",
9
9
  "preview": "astro preview",
10
- "deploy": "astro build && wrangler deploy",
11
- "deploy:dev": "astro build && node scripts/build-dev-wrangler.mjs && wrangler deploy --config dist/server/wrangler.dev.json",
12
- "init:github": "node scripts/init-github.mjs",
13
- "init:hosting": "node scripts/init-hosting.mjs",
10
+ "deploy": "vitops email check && astro build && emdash migrate --wrangler-config wrangler.jsonc && wrangler deploy",
11
+ "deploy:dev": "vitops email check && astro build && node scripts/build-dev-wrangler.mjs && emdash migrate --wrangler-config dist/server/wrangler.dev.json && wrangler deploy --config dist/server/wrangler.dev.json",
12
+ "init:github": "vitops setup repo",
13
+ "init:hosting": "vitops setup hosting",
14
+ "setup": "vitops setup all",
14
15
  "typecheck": "astro check",
15
- "build:css": "vitops generate -i design-system.json -f tailwind -o src/styles",
16
- "lint:design": "vitops lint -i design-system.json -f tailwind --strict",
16
+ "build:css": "vitops generate -i site.json -f tailwind -o src/styles",
17
+ "lint:design": "vitops lint -i site.json -f tailwind --strict",
18
+ "sop": "vitops generate -i site.json -f css -o .vitops/sop",
17
19
  "prepare": "vp config"
18
20
  },
19
21
  "dependencies": {
20
22
  "@astrojs/cloudflare": "^14.0.0",
21
23
  "@astrojs/react": "^6.0.0",
22
- "@emdash-cms/cloudflare": "^0.31.0",
24
+ "@emdash-cms/cloudflare": "^1.0.1",
23
25
  "@getvitops/astro": "latest",
26
+ "@getvitops/core": "latest",
24
27
  "@getvitops/emdash": "latest",
28
+ "@tailwindcss/vite": "^4.3.3",
25
29
  "astro": "^7.1.2",
26
- "emdash": "^0.31.0",
30
+ "emdash": "^1.0.1",
27
31
  "react": "^19.2.4",
28
- "react-dom": "^19.2.4"
32
+ "react-dom": "^19.2.4",
33
+ "tailwindcss": "^4.3.3"
29
34
  },
30
35
  "devDependencies": {
31
36
  "@astrojs/check": "^0.9.7",
@@ -97,7 +97,7 @@
97
97
  "_type": "vitops.details",
98
98
  "_key": "next-steps",
99
99
  "summary": "Next steps",
100
- "body": "Adjust design-system.json to your brand (colors, type, patterns), replace src/assets/logo.svg, then deploy with `pnpm deploy`.",
100
+ "body": "Adjust site.json (under designSystem.themes.default) to your brand (colors, type, patterns), replace src/assets/logo.svg, then deploy with `pnpm deploy`.",
101
101
  "open": false
102
102
  }
103
103
  ]
@@ -0,0 +1,303 @@
1
+ {
2
+ "$schema": "./node_modules/@getvitops/generator/config.schema.json",
3
+ "designSystem": {
4
+ "themes": {
5
+ "default": {
6
+ "$schema": "./node_modules/@getvitops/generator/schema.json",
7
+ "colors": {
8
+ "palette": {
9
+ "brand": {
10
+ "seed": "#2e9b73"
11
+ },
12
+ "ink": {
13
+ "seed": "#3f4a5c"
14
+ },
15
+ "sky": {
16
+ "seed": "#2f7bc0"
17
+ },
18
+ "sun": {
19
+ "seed": "#d08a1f"
20
+ },
21
+ "rose": {
22
+ "seed": "#c74a42"
23
+ }
24
+ },
25
+ "roles": {
26
+ "neutral": "ink",
27
+ "surface": "ink",
28
+ "ui-primary": "brand",
29
+ "brand-primary": "brand",
30
+ "info": "sky",
31
+ "success": "brand",
32
+ "warning": "sun",
33
+ "danger": "rose"
34
+ },
35
+ "utilities": ["bg", "text", "icon", "border"]
36
+ },
37
+ "shadows": {
38
+ "sm": "0 1px 2px rgb(0 0 0 / 0.08)",
39
+ "md": "0 4px 6px rgb(0 0 0 / 0.12)",
40
+ "lg": "0 10px 15px rgb(0 0 0 / 0.18)"
41
+ },
42
+ "fonts": {
43
+ "display": "system-ui, -apple-system, \"Segoe UI\", sans-serif",
44
+ "sans": "system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif",
45
+ "mono": "ui-monospace, \"SF Mono\", Menlo, monospace"
46
+ },
47
+ "typeScale": {
48
+ "base": "1rem",
49
+ "names": ["2xs", "xs", "s", "m", "l", "xl", "2xl", "3xl"],
50
+ "baseStep": 4,
51
+ "baseline": "m",
52
+ "ratio": 1.2,
53
+ "fluid": {
54
+ "minVw": "22.5rem",
55
+ "maxVw": "80rem",
56
+ "minRatio": 1.12
57
+ }
58
+ },
59
+ "spaceScale": {
60
+ "base": "1rem",
61
+ "names": ["2xs", "xs", "s", "m", "l", "xl", "2xl", "3xl"],
62
+ "baseStep": 4,
63
+ "baseline": "m",
64
+ "ratio": 1.25,
65
+ "fluid": {
66
+ "minVw": "22.5rem",
67
+ "maxVw": "80rem",
68
+ "minRatio": 1.2
69
+ }
70
+ },
71
+ "patterns": {
72
+ "defaults": {
73
+ "ds": "none",
74
+ "b": "1px solid var(--color-bg-surface-x-muted)",
75
+ "br": "0.375rem",
76
+ "p": "1rem",
77
+ "fs": "1rem"
78
+ },
79
+ "radii": {
80
+ "circle": "50%"
81
+ },
82
+ "groups": {
83
+ "control": {
84
+ "ds": "var(--ds-default)",
85
+ "b": "var(--b-default)",
86
+ "br": "var(--br-default)",
87
+ "p": "0.5em 1em",
88
+ "fs": "var(--fs-default)"
89
+ },
90
+ "panel": {
91
+ "ds": "var(--shadow-md)",
92
+ "b": "var(--b-default)",
93
+ "br": "0.5rem",
94
+ "p": "1rem",
95
+ "fs": "var(--fs-default)"
96
+ }
97
+ },
98
+ "z": {
99
+ "raised": 1,
100
+ "sticky": 100,
101
+ "overlay": 200,
102
+ "top": 1000
103
+ },
104
+ "items": {
105
+ "button": {
106
+ "group": "control",
107
+ "element": "button",
108
+ "default_role": "brand-primary",
109
+ "base": {
110
+ "padding": "0.6em 1.2em",
111
+ "border-radius": "var(--br-control, 0.25rem)",
112
+ "border": "none",
113
+ "font-weight": "600",
114
+ "color": "#fff",
115
+ "cursor": "pointer",
116
+ "box-shadow": "var(--shadow-sm)"
117
+ },
118
+ "states": {
119
+ "hover": {
120
+ "step": 1
121
+ },
122
+ "active": {
123
+ "scale": 0.97
124
+ },
125
+ "focus-visible": {
126
+ "ring": true
127
+ }
128
+ },
129
+ "roles": []
130
+ },
131
+ "card": {
132
+ "group": "panel",
133
+ "class": "card",
134
+ "base": {
135
+ "border-radius": "var(--br-card-group)",
136
+ "padding": "1.5rem",
137
+ "background": "var(--color-bg-surface-muted)",
138
+ "border": "var(--b-card-group)",
139
+ "box-shadow": "var(--ds-card-group)"
140
+ },
141
+ "states": {},
142
+ "roles": []
143
+ }
144
+ }
145
+ },
146
+ "typography": {
147
+ "families": {
148
+ "display": "var(--font-display)",
149
+ "sans": "var(--font-sans)",
150
+ "code": "var(--font-mono, ui-monospace, monospace)"
151
+ },
152
+ "roles": {
153
+ "display": {
154
+ "family": "display",
155
+ "size": "var(--text-3xl)",
156
+ "weight": 700,
157
+ "line-height": "1.05",
158
+ "tracking": "-0.03em"
159
+ },
160
+ "heading": {
161
+ "family": "display",
162
+ "size": "var(--text-xl)",
163
+ "weight": 600,
164
+ "line-height": "1.3"
165
+ },
166
+ "body": {
167
+ "family": "sans",
168
+ "size": "var(--text-m)",
169
+ "weight": 400,
170
+ "line-height": "1.55"
171
+ }
172
+ },
173
+ "headings": {
174
+ "h1": "display",
175
+ "h2": "heading",
176
+ "h3": "heading"
177
+ }
178
+ },
179
+ "animations": {
180
+ "effects": {
181
+ "fade-in": {
182
+ "kf": "composite",
183
+ "vars": {
184
+ "opacity-from": 0
185
+ }
186
+ },
187
+ "slide-up": {
188
+ "kf": "composite",
189
+ "vars": {
190
+ "translate-y-from": "var(--slide-distance, 2rem)"
191
+ }
192
+ }
193
+ },
194
+ "journeys": {
195
+ "base": {
196
+ "fade": {
197
+ "opacity-from": 0
198
+ },
199
+ "slide": {}
200
+ },
201
+ "compose": [["fade"], ["slide"], ["fade", "slide"]]
202
+ }
203
+ }
204
+ }
205
+ },
206
+ "defaultColorScheme": "light"
207
+ },
208
+ "organization": {
209
+ "name": "My EmDash Site"
210
+ },
211
+ "site": {
212
+ "defaultLocale": "en",
213
+ "locales": {
214
+ "en": {
215
+ "name": "English"
216
+ }
217
+ },
218
+ "environments": {
219
+ "production": {
220
+ "url": "https://my-emdash-site.example.com"
221
+ },
222
+ "dev": {
223
+ "url": "https://dev.my-emdash-site.example.com",
224
+ "robots": "noindex,nofollow"
225
+ }
226
+ },
227
+ "icons": {
228
+ "sprite": true,
229
+ "semantic": [
230
+ "menu",
231
+ "close",
232
+ "home",
233
+ "settings",
234
+ "search",
235
+ "add",
236
+ "remove",
237
+ "delete",
238
+ "edit",
239
+ "save",
240
+ "copy",
241
+ "paste",
242
+ "attach",
243
+ "upload",
244
+ "download",
245
+ "share",
246
+ "bookmark",
247
+ "favorite",
248
+ "star",
249
+ "login",
250
+ "logout",
251
+ "email",
252
+ "phone",
253
+ "location",
254
+ "globe",
255
+ "link",
256
+ "clock",
257
+ "calendar",
258
+ "schedule",
259
+ "person",
260
+ "group",
261
+ "file",
262
+ "folder",
263
+ "image",
264
+ "export",
265
+ "import",
266
+ "backup",
267
+ "compress",
268
+ "check",
269
+ "error",
270
+ "warning",
271
+ "info",
272
+ "help",
273
+ "cart",
274
+ "tag",
275
+ "receipt",
276
+ "leaf",
277
+ "tree",
278
+ "seedling",
279
+ "trowel",
280
+ "droplet",
281
+ "snowflake",
282
+ "sun",
283
+ "cloud",
284
+ "grid",
285
+ "list",
286
+ "filter",
287
+ "sort",
288
+ "fullscreen",
289
+ "collapse",
290
+ "building",
291
+ "video",
292
+ "lock",
293
+ "unlock",
294
+ "eye",
295
+ "print",
296
+ "code",
297
+ "palette",
298
+ "lightbulb",
299
+ "lightning"
300
+ ]
301
+ }
302
+ }
303
+ }
@@ -1,8 +1,10 @@
1
1
  ---
2
2
  import VitopsHead from '@getvitops/astro/Head.astro';
3
+ import { resolveOrganizationName } from '@getvitops/astro/routes';
3
4
  import { getMenu, getSiteSettings } from 'emdash';
4
5
  import { createPublicPageContext } from 'emdash/page';
5
6
  import { EmDashHead } from 'emdash/ui';
7
+ import config from '../../site.json' with { type: 'json' };
6
8
  // Design-system CSS, layout-scoped (vitops css.inject: false): only pages
7
9
  // rendered through this layout get it — keeps it out of /_emdash/admin, while
8
10
  // EmDash previews (rendered through this layout) keep it.
@@ -19,7 +21,11 @@ interface Props {
19
21
 
20
22
  const { title, description, image } = Astro.props;
21
23
  const settings = await getSiteSettings();
22
- const siteTitle = settings?.title || 'My EmDash Site';
24
+ // getSiteSettings().title is the editable, client-facing display name (set in
25
+ // the EmDash admin) — it wins whenever it's set. resolveOrganizationName(config)
26
+ // is the fallback rather than a second hardcoded string, so a fresh scaffold
27
+ // shows organization.name (from site.json) before anyone's touched the admin.
28
+ const siteTitle = settings?.title || resolveOrganizationName(config) || 'My EmDash Site';
23
29
  const fullTitle = title ? `${title} — ${siteTitle}` : siteTitle;
24
30
  const siteDescription = settings?.tagline || 'An EmDash website with the Vitops design system';
25
31
 
@@ -1,5 +1,10 @@
1
1
  ---
2
2
  import Layout from '../layouts/Layout.astro';
3
+
4
+ // No per-request data — safe to prerender per AGENTS.md's "Prerender by
5
+ // default" rule. [...slug].astro reaches this via Astro.rewrite('/404'),
6
+ // which resolves a prerendered destination the same as a server-rendered one.
7
+ export const prerender = true;
3
8
  ---
4
9
 
5
10
  <Layout title="Page not found">
@@ -4,6 +4,13 @@ import { PortableText } from 'emdash/ui';
4
4
  import Layout from '../layouts/Layout.astro';
5
5
 
6
6
  // Catch-all: any entry in the `pages` collection renders at its slug.
7
+ //
8
+ // Deliberately NOT prerendered, unlike AGENTS.md's general "prerender by
9
+ // default" rule — see index.astro's comment for why: a live EmDash publish
10
+ // should reach visitors without a redeploy. A page that's known ahead of
11
+ // time and doesn't need that (rarely edited, or fine to lag a build) can
12
+ // move to its own prerendered route with `getStaticPaths()` over the
13
+ // `pages` collection instead of relying on this catch-all.
7
14
  const { slug } = Astro.params;
8
15
  const { entry: page } = slug ? await getEmDashEntry('pages', slug) : { entry: null };
9
16
 
@@ -6,6 +6,13 @@ import Layout from '../layouts/Layout.astro';
6
6
  // The seeded home page (seed/seed.json → pages/home). Edit it in the admin;
7
7
  // the Vitops blocks from @getvitops/emdash render automatically — EmDash
8
8
  // merges the plugin's block components into <PortableText>.
9
+ //
10
+ // Deliberately NOT prerendered, unlike AGENTS.md's general "prerender by
11
+ // default" rule: this is the one route where the tradeoff that rule names
12
+ // (prerendered = fast, but reflects the database as of the last build) is
13
+ // unacceptable — the whole point of editing in EmDash is that a publish
14
+ // shows up without a redeploy. Add `getStaticPaths()` + `prerender = true`
15
+ // here only if this site's home page genuinely doesn't need that.
9
16
  const { entry: page } = await getEmDashEntry('pages', 'home');
10
17
  ---
11
18
 
@@ -8,16 +8,30 @@ export default defineConfig({
8
8
  // `subgrid` is the drift this catches, and it is only ever cheap to fix at the
9
9
  // moment it is written. `vitops lint` takes the staged paths as positionals.
10
10
  'src/**/*.{astro,html,ts,tsx,jsx,vue,svelte,css}':
11
- 'vitops lint -i design-system.json -f tailwind --strict',
11
+ 'vitops lint -i site.json -f tailwind --strict',
12
12
  },
13
13
  fmt: {
14
+ // Explicit, matching the monorepo root's style: unlike `lint`, a nested
15
+ // `fmt` config genuinely takes effect independently here rather than
16
+ // being root-only, so leaving these unset let this file (and anything
17
+ // else oxfmt formats under this directory, e.g. SETUP.html's embedded
18
+ // `<script>`) drift to a different default quote style each time
19
+ // `vp check --fix` ran, breaking `templates.test.ts`'s byte-identical
20
+ // mirror assertion.
21
+ semi: true,
22
+ singleQuote: true,
14
23
  ignorePatterns: ['dist/**', 'node_modules/**', 'src/styles/**', 'public/vitops/**'],
15
24
  },
16
25
  lint: {
17
26
  ignorePatterns: ['dist/**', 'node_modules/**', 'src/styles/**', 'public/vitops/**'],
18
- options: {
19
- typeAware: true,
20
- typeCheck: true,
21
- },
27
+ // `options.typeAware`/`typeCheck` commented out, not deleted: vite-plus 1.0
28
+ // only honours those at the root config, and while this file sits nested
29
+ // inside the getvitops/design-system monorepo (which has its own root
30
+ // vite.config.ts), setting them here is a hard error — "typeAware is only
31
+ // supported in the root config" — rather than the silent no-op it was
32
+ // pre-1.0. Once `vp create @getvitops:emdash` scaffolds this file out into
33
+ // its own project, it *becomes* that project's root config, and
34
+ // uncommenting this is the right move there.
35
+ // options: { typeAware: true, typeCheck: true },
22
36
  },
23
37
  });
@@ -4,11 +4,16 @@
4
4
  "main": "./src/worker.ts",
5
5
  "compatibility_date": "2026-02-24",
6
6
  "compatibility_flags": ["nodejs_compat"],
7
+ // Explicit rather than relying on wrangler's default: this is the fact that
8
+ // lets a first deploy go live at <name>.<account>.workers.dev without
9
+ // touching any existing site's DNS — see SETUP.html's "Domain strategy"
10
+ // stage and site.json's environments.production.url.
7
11
  "workers_dev": true,
8
12
  // Custom domain: uncomment and set your apex. Cloudflare provisions the DNS
9
- // record + TLS cert on deploy (the zone must already exist in the account).
10
- // The dev deploy (scripts/build-dev-wrangler.mjs) automatically serves the
11
- // dev worker from dev.<domain> when this is set.
13
+ // record + TLS cert on deploy (the zone must already exist in the account) —
14
+ // and OVERWRITES it, the moment an existing live site at that domain goes
15
+ // dark. The dev deploy (scripts/build-dev-wrangler.mjs) automatically serves
16
+ // the dev worker from dev.<domain> when this is set.
12
17
  // "routes": [{ "pattern": "example.com", "custom_domain": true }],
13
18
  // No database_id / bucket ids needed up front: wrangler provisions the D1
14
19
  // database and R2 bucket on the first `pnpm deploy` if they don't exist.
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: setup
3
+ description: Work the client-onboarding checklist (SETUP.html) autonomously — GitHub repo + branch policy, hosting resources, Search Console/GCP/ads connections. Use when the user asks to set up, onboard, or provision this project (e.g. "run setup", "onboard this site", "get this ready to deploy"). Never run this as a side effect of unrelated work, and never on your own initiative without the user asking.
4
+ ---
5
+
6
+ # Setup (client onboarding)
7
+
8
+ `SETUP.html` is the canonical checklist — this skill adds only sequencing,
9
+ gates, and where to stop. It does not restate the steps; read `SETUP.html`
10
+ (or `npx vitops setup --help`) for what each stage actually does and why.
11
+
12
+ ## Steps
13
+
14
+ 1. **Preview the whole sequence first.**
15
+
16
+ ```bash
17
+ npx vitops setup all --dry
18
+ ```
19
+
20
+ Read the plan before doing anything. It names every step it would take and
21
+ why any step is blocked — a missing credential, a field not yet in
22
+ `site.json`, GitHub Pro/Team gating branch protection.
23
+
24
+ 2. **Run it.**
25
+
26
+ ```bash
27
+ npx vitops setup all
28
+ ```
29
+
30
+ Re-run `npx vitops setup --check` after each leg rather than retrying on
31
+ your own judgment — a step already done resolves to a no-op skip, so a
32
+ second run is safe, and `--check` tells you exactly what still needs doing
33
+ instead of you guessing from output.
34
+
35
+ 3. **Tick `SETUP.html` boxes only for what you actually completed.** Never
36
+ check a box for a step marked below as human-only, even if you did
37
+ everything up to it — the human still has to act.
38
+
39
+ ## Hard stops — ask the human, do not attempt
40
+
41
+ - **The Cloudflare API token.** No API can create one; there is no command to
42
+ run. Tell the user to create it at
43
+ <https://dash.cloudflare.com/profile/api-tokens> (Workers + D1 + R2 edit)
44
+ and run `gh secret set CLOUDFLARE_API_TOKEN`, then continue.
45
+ - **The domain cutover** (`vitops setup domain`, stage 4b in `SETUP.html`).
46
+ Uncommenting the custom-domain route and deploying overwrites the zone's DNS
47
+ record at that instant — it takes an existing live site down. `setup domain`
48
+ only ever plans and checks this; it never applies it, and neither should
49
+ you. Report the plan and hand the actual cutover to the user.
50
+ - **Publishing any generated legal document.** `vitops legal` renders a
51
+ starting point from the config, not a reviewed policy. Generate it, tell the
52
+ user it needs review, and stop — do not paste it into the admin or commit it
53
+ yourself.
54
+
55
+ ## If something is blocked
56
+
57
+ `vitops setup --check` names the field or credential and where to get it —
58
+ report that verbatim rather than guessing at a fix. A step reported as
59
+ "blocked" is not a failure to retry; it is waiting on one of the hard stops
60
+ above, or on a `site.json` field the user still needs to fill in (stage 5,
61
+ Configuration).
@@ -1,7 +1,7 @@
1
1
  # Deploys `main` to production.
2
2
  # `main` should be branch-protected — it then only advances via the Promote
3
3
  # workflow (promote.yml), so a push here always represents promoted code. The
4
- # `production` GitHub Environment (set up by `scripts/init-github.mjs`) has
4
+ # `production` GitHub Environment (set up by `vitops setup repo`) has
5
5
  # required reviewers restricted to admins, so this PAUSES for approval before
6
6
  # deploying.
7
7
  #
@@ -3,10 +3,13 @@ as Cloudflare Workers static assets (no server runtime, no database).
3
3
 
4
4
  ## Ground rules
5
5
 
6
- - `design-system.json` is the single source of truth for the design system
7
- (colors, type, spacing, patterns, animations). Never edit `src/styles/` by
8
- hand — it is generated from the JSON by the `vitops()` integration on every
9
- dev/build and is gitignored.
6
+ - `site.json` is the single source of truth — organization + site facts, and
7
+ the design system (colors, type, spacing, patterns, animations) under
8
+ `designSystem.themes.default`. Never edit `src/styles/` by hand — it is
9
+ generated from `site.json` by the `vitops()` integration on every dev/build
10
+ and is gitignored. (There is no separate `design-system.json`: a scaffolded
11
+ config can't merely reference a sibling file, so the token set lives inside
12
+ `site.json`.)
10
13
  - `src/assets/placeholder/` holds neutral wireframe stand-ins (square,
11
14
  portrait, landscape; SVG + PNG) for layout work before real imagery
12
15
  exists. Delete the directory once real assets land.
@@ -29,6 +32,10 @@ as Cloudflare Workers static assets (no server runtime, no database).
29
32
  (cookies, headers, query params) at render time. If a page genuinely needs
30
33
  that, it needs an adapter and a different template — this one stays pure
31
34
  static on purpose.
35
+ - **`SETUP.html` is the client-onboarding checklist.** When working it via the
36
+ `.agents/skills/setup/` skill, tick a box only for a step you actually
37
+ completed — never on the operator's behalf for a step marked human-only
38
+ (the Cloudflare API token, the domain cutover, publishing legal documents).
32
39
 
33
40
  ## Branch model
34
41
 
@@ -44,7 +51,7 @@ as Cloudflare Workers static assets (no server runtime, no database).
44
51
 
45
52
  - `pnpm dev` — local dev
46
53
  - `pnpm typecheck` — `astro check`
47
- - `pnpm run build:css` — regenerate the framework CSS from `design-system.json`
54
+ - `pnpm run build:css` — regenerate the framework CSS from `site.json`
48
55
  - `pnpm deploy` — build + `wrangler deploy` to prod
49
56
  - `pnpm run deploy:dev` — build + deploy the isolated dev worker
50
57
  - `pnpm run init:github` — one-time: create + push the GitHub repo (main +
@@ -52,6 +59,6 @@ as Cloudflare Workers static assets (no server runtime, no database).
52
59
  the user asks to set up GitHub.
53
60
  - `pnpm run init:hosting` — one-time: read the Cloudflare account id and set
54
61
  it as a repo secret. Only run when the user asks for it.
55
- - `npx vitops validate design-system.json` — schema-check the design config
56
- - `npx vitops lint -i design-system.json -f css` — find framework classes in
62
+ - `npx vitops validate site.json` — schema-check the site config
63
+ - `npx vitops lint -i site.json -f css` — find framework classes in
57
64
  source that resolve to nothing under this format
@@ -10,8 +10,9 @@ Scaffolded from `vp create @getvitops:static`.
10
10
 
11
11
  - **Astro** (`output: 'static'`) on **Cloudflare Workers Static Assets** — no
12
12
  adapter, no database, no server runtime
13
- - **`@getvitops/astro`** — generates the design-system CSS from
14
- `design-system.json` and serves the web-component runtime
13
+ - **`@getvitops/astro`** — generates the design-system CSS from `site.json`
14
+ (design tokens live at `designSystem.themes.default`) and serves the
15
+ web-component runtime
15
16
 
16
17
  `src/assets/placeholder/` ships neutral wireframe images for layout work
17
18
  before real imagery exists — delete once real assets land.
@@ -51,24 +52,18 @@ The repo ships a two-environment flow modeled on branch = environment:
51
52
  with auto-merge enabled. With required reviews on `main`, a human approves
52
53
  the PR; merging deploys prod (after the admin approval above).
53
54
 
54
- One-time setup:
55
-
56
- 1. `pnpm run init:github` — creates a GitHub repo named after this project
57
- (via the `gh` CLI; `-- --public` for a public repo), commits if needed,
58
- pushes `main` + `dev`, makes `dev` the default branch, protects `main`
59
- (PR + review + the `ci` check required), and creates a `production`
60
- environment gated on your admin collaborators. Idempotent; `-- --dry-run`
61
- previews. (Branch protection and environment reviewers need GitHub
62
- Pro/Team on a private repo — the script prints the manual equivalent if
63
- your plan doesn't support them.)
64
- 2. `pnpm run init:hosting` — reads your Cloudflare account id (after
65
- `npx wrangler login`) and sets the `CLOUDFLARE_ACCOUNT_ID` repo secret.
66
- Idempotent; `-- --dry-run` previews.
67
- 3. Create a Cloudflare API token (Workers edit —
68
- <https://dash.cloudflare.com/profile/api-tokens>; tokens can't be created
69
- via CLI) and `gh secret set CLOUDFLARE_API_TOKEN`. Optionally
70
- `PROMOTE_TOKEN` (a PAT allowed to bypass protection) for hands-off
71
- promotion. The first workflow runs fail until the secrets exist.
55
+ One-time setup — work through the checklist:
56
+
57
+ ```bash
58
+ pnpm run sop && open SETUP.html # or: xdg-open SETUP.html
59
+ ```
60
+
61
+ It covers host choice, GitHub + branch policy, hosting resources, going live
62
+ safely on `*.workers.dev` before any custom-domain cutover, configuration,
63
+ Search Console/GCP/ads connections, legal documents, and launch gates — one
64
+ command per step. An AI agent can work the same list autonomously via
65
+ `.agents/skills/setup/`; it stops at the steps that genuinely need a human
66
+ (the Cloudflare API token, the domain cutover, publishing legal documents).
72
67
 
73
68
  `pnpm run deploy:dev` reproduces the dev deploy locally: it writes a
74
69
  gitignored `.wrangler.dev.json` with the worker renamed and any custom-domain