create-contractor-site 2.1.1 → 2.2.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/README.md +144 -0
- package/bin/create-contractor-site.mjs +30 -2
- package/package.json +1 -1
- package/scripts/smoke-test.mjs +713 -5
- package/src/copy-template.mjs +1 -1
- package/src/prompts.mjs +360 -20
- package/src/replace-data.mjs +43 -4
package/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# create-contractor-site
|
|
2
|
+
|
|
3
|
+
Scaffold a client contractor website from the [website-multipages](https://github.com/glacayo/website-multipages) Astro template.
|
|
4
|
+
|
|
5
|
+
**Package version:** `2.2.0` · **Default template ref:** `v2.2.0` (`CREATE_CONTRACTOR_TEMPLATE_REF`)
|
|
6
|
+
|
|
7
|
+
The CLI validates the target, copies the template, replaces placeholder values in `src/data/*.json`, installs with **pnpm**, validates data, builds, and initializes git **only after** success.
|
|
8
|
+
|
|
9
|
+
## What's new in 2.2.0
|
|
10
|
+
|
|
11
|
+
- **`siteType`** — choose `one-page`, `multipage`, or `seo` (aliases accepted). Written to `site.json.site_type`. Default for new scaffolds: `multipage`.
|
|
12
|
+
- **Expanded intake** — payment methods, hours, free-estimate wording, years of experience, license, insurance, social links, and directories (interactive, `--yes` defaults, or `CREATE_CONTRACTOR_SITE_ANSWERS_JSON`).
|
|
13
|
+
- **Template clone default** — published fallback uses git ref **`v2.2.0`** unless you set `CREATE_CONTRACTOR_TEMPLATE_ROOT` or `CREATE_CONTRACTOR_TEMPLATE_REF`.
|
|
14
|
+
- After scaffold, treat `business.json` + `site.json` as authoritative identity; leftover demo trade content is expected seed material to rewrite.
|
|
15
|
+
|
|
16
|
+
Full release notes: repository root [`CHANGELOG.md`](../../CHANGELOG.md).
|
|
17
|
+
|
|
18
|
+
## Requirements
|
|
19
|
+
|
|
20
|
+
- **Node.js** 22+
|
|
21
|
+
- **pnpm** 11.1.2+
|
|
22
|
+
- **git**
|
|
23
|
+
|
|
24
|
+
## Quick start
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm create contractor-site my-client-site
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This downloads and runs `create-contractor-site` from npm. It is equivalent to the explicit `pnpm dlx` form below.
|
|
31
|
+
|
|
32
|
+
### Explicit command
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pnpm dlx create-contractor-site my-client-site
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Local / monorepo development
|
|
39
|
+
|
|
40
|
+
From a checkout of this repository:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
node ./packages/create-contractor-site/bin/create-contractor-site.mjs ../my-client-site
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
By default, the CLI prompts for client details. For a non-interactive smoke run, add `--yes`:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
node ./packages/create-contractor-site/bin/create-contractor-site.mjs --yes ../my-client-site
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Or use the published CLI while pointing it at a local template checkout:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
CREATE_CONTRACTOR_TEMPLATE_ROOT=/path/to/website-multipages \
|
|
56
|
+
pnpm dlx create-contractor-site my-client-site
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## What the CLI does
|
|
60
|
+
|
|
61
|
+
1. Checks that **pnpm** and **git** are available
|
|
62
|
+
2. Resolves the template source (see env vars below)
|
|
63
|
+
3. Validates the target directory and refuses targets equal to or inside the template root
|
|
64
|
+
4. Copies the template into the target directory (denylist excludes `node_modules`, `dist`, `.astro`, `.git`, `.codegraph`, `docs_trash`, `openspec`, `.atl`, `logs`, `*.log`, `.env*`, `package-lock.json`, and `packages/`)
|
|
65
|
+
5. Replaces **values only** in target `src/data/*.json` (schema/shape preserved)
|
|
66
|
+
6. Runs `pnpm install`
|
|
67
|
+
7. Runs `pnpm run validate:data`
|
|
68
|
+
8. Runs `pnpm run build`
|
|
69
|
+
9. Runs `git init` + initial commit **only after** validate and build succeed
|
|
70
|
+
|
|
71
|
+
If install, validate, or build fails, git init is skipped so a broken scaffold is never committed.
|
|
72
|
+
|
|
73
|
+
### After scaffold
|
|
74
|
+
|
|
75
|
+
In the generated client repo:
|
|
76
|
+
|
|
77
|
+
- Treat `src/data/business.json` and `src/data/site.json` as **authoritative client identity**
|
|
78
|
+
- Leftover masonry/hardscape services, blog posts, section copy, and demo assets are **expected seed content** — rewrite them for the real trade; do not treat them as a conflict
|
|
79
|
+
- Keep replacing **values/copy/assets only**; preserve JSON shape and `_instructions`
|
|
80
|
+
- Keep real client PII out of the shared template base (this repo)
|
|
81
|
+
|
|
82
|
+
See the template root `AGENTS.md`, `SKILL.md`, and `README.md` for the full agent/developer workflow. Finish client customization with `pnpm run validate:data` and `pnpm run build`.
|
|
83
|
+
|
|
84
|
+
## Environment variables
|
|
85
|
+
|
|
86
|
+
| Variable | Purpose |
|
|
87
|
+
|----------|---------|
|
|
88
|
+
| `CREATE_CONTRACTOR_SITE_ANSWERS_JSON` | JSON object with client answers for scripted/non-interactive scaffolds |
|
|
89
|
+
| `CREATE_CONTRACTOR_TEMPLATE_ROOT` | Path to a local template checkout (preferred for monorepo/dev) |
|
|
90
|
+
| `CREATE_CONTRACTOR_TEMPLATE_REPO` | Git URL for the published fallback clone (default: this template repo) |
|
|
91
|
+
| `CREATE_CONTRACTOR_TEMPLATE_REF` | Git branch/tag/ref to clone (default: `v2.2.0`) |
|
|
92
|
+
|
|
93
|
+
Template source precedence: `CREATE_CONTRACTOR_TEMPLATE_ROOT` → local monorepo discovery → temporary clone of repo @ ref.
|
|
94
|
+
|
|
95
|
+
### Scripted answers example
|
|
96
|
+
|
|
97
|
+
Trust, payment, hours, social, directory, and website-type fields may be omitted/blank — `buildAnswers` fills defaults. `--yes` omits them for the same parity (including `site_type: multipage`).
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
CREATE_CONTRACTOR_SITE_ANSWERS_JSON='{"businessName":"Acme Masonry","phone":"(757) 555-0199","email":"info@example.com","street":"123 Main St","city":"Virginia Beach","state":"VA","zip":"23451","serviceArea":"Virginia Beach, Norfolk, Chesapeake","primaryServices":["Masonry","Patios"]}' \
|
|
101
|
+
pnpm dlx create-contractor-site my-client-site
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Compact payment/hours/social/directories + website type:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
CREATE_CONTRACTOR_SITE_ANSWERS_JSON='{"businessName":"Acme Masonry","primaryServices":["Masonry"],"paymentMethods":"Cash, Credit Card","hoursWeekday":"8:00 AM - 5:00 PM","hoursSaturday":"Closed","hoursSunday":"Closed","social":"facebook=https://facebook.com/acme,instagram=https://instagram.com/acme","directories":"Google Business|https://g.co/acme,BBB|https://bbb.org/acme","siteType":"one-page"}' \
|
|
108
|
+
pnpm dlx create-contractor-site my-client-site
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
All answer paths (`CREATE_CONTRACTOR_SITE_ANSWERS_JSON`, `--yes`, interactive) go through `buildAnswers`:
|
|
112
|
+
|
|
113
|
+
| Field | JSON key | Blank / omitted |
|
|
114
|
+
|-------|----------|-----------------|
|
|
115
|
+
| Free-estimate wording | `freeEstimate` | `Free On-Site Estimate` |
|
|
116
|
+
| Years of experience | `yearsExperience` | `10+` |
|
|
117
|
+
| License | `license` | `Licensed & Insured` |
|
|
118
|
+
| Insurance | `insurance` | Fully insured with general liability and workers' compensation. |
|
|
119
|
+
| Founded year (optional) | `foundedYear` | `""` — key always written; never removed |
|
|
120
|
+
| Payment methods | `paymentMethods` (CSV string or `string[]`) | `Cash`, `Check`, `Credit Card`, `Financing Available` — never `[]` |
|
|
121
|
+
| Business hours | `hours` (`[{days,time}]` ×3) or compact `hoursWeekday` / `hoursSaturday` / `hoursSunday` | Mon–Fri `7:00 AM - 6:00 PM`, Sat `8:00 AM - 2:00 PM`, Sun `Closed` |
|
|
122
|
+
| Social links | `social` (object or `network=url` CSV) | `{}`; blank keys omitted (`facebook`…`x`) |
|
|
123
|
+
| Directories | `directories` (`[{name,url}]` or `Name\|url` CSV) | none → ≥1 placeholder + `enable_directories: false` (never `[]`) |
|
|
124
|
+
| Website type | `siteType` (`one-page` \| `multipage` \| `seo`; aliases like `one page` / `single-page` / `multi page` / `multi` accepted) | `multipage` — always written to `site.json.site_type` as a canonical value |
|
|
125
|
+
|
|
126
|
+
## pnpm only
|
|
127
|
+
|
|
128
|
+
This project and the scaffolded client sites use **pnpm only**.
|
|
129
|
+
|
|
130
|
+
- Do **not** use `npm install` or `npx` for project setup
|
|
131
|
+
- Package runners (`pnpm create`, `pnpm dlx`) may start the binary; install/build inside the scaffold always use pnpm
|
|
132
|
+
|
|
133
|
+
## Options
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
create-contractor-site [options] <target-dir>
|
|
137
|
+
|
|
138
|
+
-y, --yes Non-interactive mode with built-in sample answers
|
|
139
|
+
-h, --help Show help
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
ISC. See the [repository](https://github.com/glacayo/website-multipages) for full template documentation.
|
|
@@ -35,6 +35,7 @@ Environment:
|
|
|
35
35
|
CREATE_CONTRACTOR_SITE_ANSWERS_JSON
|
|
36
36
|
JSON object with at least businessName and primaryServices[].
|
|
37
37
|
When set, skips prompts (and overrides --yes sample answers).
|
|
38
|
+
All paths funnel through buildAnswers (trim + blank defaults).
|
|
38
39
|
|
|
39
40
|
CREATE_CONTRACTOR_TEMPLATE_ROOT
|
|
40
41
|
Absolute/relative path to a local template checkout (preferred for
|
|
@@ -45,7 +46,19 @@ Environment:
|
|
|
45
46
|
Default: https://github.com/glacayo/website-multipages.git
|
|
46
47
|
|
|
47
48
|
CREATE_CONTRACTOR_TEMPLATE_REF
|
|
48
|
-
Git branch/tag/ref to clone for the published fallback. Default: v2.
|
|
49
|
+
Git branch/tag/ref to clone for the published fallback. Default: v2.2.0
|
|
50
|
+
|
|
51
|
+
Answer defaults (buildAnswers; blank/whitespace → these; --yes omits trust/payment/hours/social/directories/siteType):
|
|
52
|
+
freeEstimate Free On-Site Estimate
|
|
53
|
+
yearsExperience 10+
|
|
54
|
+
license Licensed & Insured
|
|
55
|
+
insurance Fully insured with general liability and workers' compensation.
|
|
56
|
+
foundedYear "" (optional; key always written; skip/blank → empty string)
|
|
57
|
+
paymentMethods Cash, Check, Credit Card, Financing Available (CSV or string[]; blank/[] → defaults, never [])
|
|
58
|
+
hours 3-row [{days,time}] Mon–Fri / Sat / Sun (or compact hoursWeekday/hoursSaturday/hoursSunday)
|
|
59
|
+
social object or network=url CSV (facebook…x); blank keys omitted
|
|
60
|
+
directories [{name,url}] or Name|url CSV; none → ≥1 placeholder + enable_directories false (never [])
|
|
61
|
+
siteType multipage (one-page | multipage | seo; aliases like "one page"/"onepage" ok; invalid → multipage)
|
|
49
62
|
|
|
50
63
|
Answer precedence (highest first):
|
|
51
64
|
1. CREATE_CONTRACTOR_SITE_ANSWERS_JSON
|
|
@@ -120,6 +133,7 @@ async function resolveAnswers(nonInteractive) {
|
|
|
120
133
|
}
|
|
121
134
|
|
|
122
135
|
if (nonInteractive) {
|
|
136
|
+
// Omitted trust/payment/hours/social/directories/siteType → buildAnswers defaults (siteType multipage).
|
|
123
137
|
return buildAnswers({
|
|
124
138
|
businessName: 'Acme Masonry',
|
|
125
139
|
legalName: 'Acme Masonry LLC',
|
|
@@ -131,7 +145,6 @@ async function resolveAnswers(nonInteractive) {
|
|
|
131
145
|
state: 'VA',
|
|
132
146
|
zip: '23451',
|
|
133
147
|
serviceArea: 'Virginia Beach and Hampton Roads',
|
|
134
|
-
foundedYear: '2015',
|
|
135
148
|
primaryServices: ['Masonry', 'Patios', 'Retaining Walls'],
|
|
136
149
|
siteUrl: 'https://acmemasonry.example',
|
|
137
150
|
});
|
|
@@ -251,6 +264,21 @@ async function main() {
|
|
|
251
264
|
console.log('→ Replacing JSON values in src/data (shape preserved)…');
|
|
252
265
|
replaceTargetData(targetDir, answers);
|
|
253
266
|
|
|
267
|
+
const skipSetupForTests = process.env.CREATE_CONTRACTOR_SITE_SKIP_SETUP === '1';
|
|
268
|
+
if (skipSetupForTests && process.env.NODE_ENV !== 'test') {
|
|
269
|
+
throw new Error('CREATE_CONTRACTOR_SITE_SKIP_SETUP is test-only and requires NODE_ENV=test.');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (skipSetupForTests) {
|
|
273
|
+
console.log(`
|
|
274
|
+
✓ Data replace complete (setup skipped)
|
|
275
|
+
|
|
276
|
+
Path: ${targetDir}
|
|
277
|
+
CREATE_CONTRACTOR_SITE_SKIP_SETUP=1 — pnpm install/validate/build and git init were skipped.
|
|
278
|
+
`);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
254
282
|
stage = 'pnpm-setup';
|
|
255
283
|
runPnpmSetup(targetDir);
|
|
256
284
|
|