@friedbotstudio/create-baseline 0.2.0 → 0.2.1

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 (28) hide show
  1. package/obj/template/.claude/skills/audit-baseline/audit.sh +11 -5
  2. package/obj/template/.claude/skills/google-analytics/SKILL.md +129 -0
  3. package/obj/template/.claude/skills/google-analytics/references/audiences.md +389 -0
  4. package/obj/template/.claude/skills/google-analytics/references/bigquery.md +470 -0
  5. package/obj/template/.claude/skills/google-analytics/references/custom-dimensions.md +355 -0
  6. package/obj/template/.claude/skills/google-analytics/references/custom-events.md +383 -0
  7. package/obj/template/.claude/skills/google-analytics/references/data-management.md +416 -0
  8. package/obj/template/.claude/skills/google-analytics/references/debugview.md +364 -0
  9. package/obj/template/.claude/skills/google-analytics/references/events-fundamentals.md +398 -0
  10. package/obj/template/.claude/skills/google-analytics/references/gtag.md +502 -0
  11. package/obj/template/.claude/skills/google-analytics/references/gtm-integration.md +483 -0
  12. package/obj/template/.claude/skills/google-analytics/references/measurement-protocol.md +519 -0
  13. package/obj/template/.claude/skills/google-analytics/references/privacy.md +441 -0
  14. package/obj/template/.claude/skills/google-analytics/references/recommended-events.md +464 -0
  15. package/obj/template/.claude/skills/google-analytics/references/reporting.md +397 -0
  16. package/obj/template/.claude/skills/google-analytics/references/setup.md +344 -0
  17. package/obj/template/.claude/skills/google-analytics/references/user-tracking.md +417 -0
  18. package/obj/template/.claude/skills/optimize-seo/SKILL.md +313 -0
  19. package/obj/template/.claude/skills/optimize-seo/scripts/pagespeed.mjs +197 -0
  20. package/obj/template/.claude/skills/pagespeed-insights/LICENSE.md +37 -0
  21. package/obj/template/.claude/skills/pagespeed-insights/SKILL.md +446 -0
  22. package/obj/template/.claude/skills/pagespeed-insights/reference.md +50 -0
  23. package/obj/template/CLAUDE.md +3 -3
  24. package/obj/template/docs/init/seed.md +2 -2
  25. package/obj/template/manifest.json +26 -5
  26. package/package.json +1 -1
  27. package/src/CLAUDE.template.md +3 -3
  28. package/src/seed.template.md +2 -2
@@ -0,0 +1,313 @@
1
+ ---
2
+ name: optimize-seo
3
+ description: "SEO + performance optimization orchestrator for the Friedbot Studio website. Drives a repeatable measure → diagnose → scope → fix → verify → commit loop. Use when performance scores drop, a PageSpeed audit surfaces issues, or before major traffic events. Trigger on: 'optimize the site', 'run a perf audit', 'fix pagespeed issues', 'improve core web vitals', 'check site performance'."
4
+ metadata:
5
+ version: 1.0.0
6
+ disable-model-invocation: true
7
+ ---
8
+
9
+ # Optimize SEO — Performance & Accessibility Workflow
10
+
11
+ You are the SEO and performance optimization orchestrator. Your job is to take the site from a baseline measurement through diagnosis, targeted fixes, and verification — with repeatability and no guesswork.
12
+
13
+ This is the **parallel orchestrator to `/orchestrate`**. Where `/orchestrate` delivers new features (requirements → design → copy → build), `/optimize-seo` improves existing features (measure → diagnose → fix → verify).
14
+
15
+ ## Workflow Pipeline
16
+
17
+ ```
18
+ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
19
+ │ 1. MEASURE │───▶│ 2. DIAGNOSE │───▶│ 3. SCOPE │
20
+ │ PageSpeed │ │ Root causes │ │ Fix plan │
21
+ └─────────────┘ └─────────────┘ └─────────────┘
22
+
23
+ ┌─────────────┐ ┌─────────────┐ ┌──────▼──────┐
24
+ │ 6. COMMIT │◀───│ 5. VERIFY │◀───│ 4. FIX │
25
+ │ Ship it │ │ Re-measure │ │ Apply fixes │
26
+ └─────────────┘ └─────────────┘ └─────────────┘
27
+ ```
28
+
29
+ **Never skip phases.** Never fix before diagnosing. Never ship without re-measuring.
30
+
31
+ ---
32
+
33
+ ## Task-Based Execution (mandatory)
34
+
35
+ At the start of every optimization cycle, create ALL tasks upfront using TaskCreate. Execute them strictly in order. Do not start a task until the previous one is marked complete.
36
+
37
+ ### Task List Template
38
+
39
+ Create these tasks when starting a new cycle (replace `[scope]` with e.g. `home-page`, `site-wide`):
40
+
41
+ ```
42
+ 1. [Measure] Create progress tracker at docs/progress/optimize-[scope].md
43
+ 2. [Measure] Run pagespeed.mjs for mobile + desktop, capture baseline scores
44
+ 3. [Measure] Run Playwright MCP to capture baseline screenshots (desktop 1280, tablet 768, mobile 375)
45
+ 4. [Diagnose] Invoke /pagespeed-insights to interpret the report and identify root causes
46
+ 5. [Diagnose] Invoke /nextjs-performance for framework-specific optimizations
47
+ 6. [Diagnose] Invoke /web-design-guidelines for accessibility audits
48
+ 7. [Diagnose] Cross-reference diagnosis against the codebase (Grep, Read) to confirm root causes
49
+ 8. [Scope] Draft fix plan in the progress tracker — batched by impact, with acceptance criteria
50
+ 9. [Scope] Get user approval on scope and batch order
51
+ 10. [Fix] Execute fix batches in order — each batch pauses at a visual verification gate
52
+ 11. [Verify] Re-run pagespeed.mjs for mobile + desktop, diff against baseline
53
+ 12. [Verify] Re-run Playwright screenshots, compare against baseline — no visual regressions
54
+ 13. [Verify] Invoke /simplify-code on all changed files
55
+ 14. [Verify] Present before/after report to user, confirm acceptance criteria met
56
+ 15. [Commit] Invoke /plan-commits
57
+ 16. [Commit] Finalize progress tracker — mark all phases Done with completion dates
58
+ 17. [Commit] Execute commits — REQUIRES USER APPROVAL (destructive action)
59
+ ```
60
+
61
+ ### Execution Rules
62
+
63
+ - **Mark each task complete immediately** after finishing it. Do not batch completions.
64
+ - **Do not skip tasks.** If a task is not applicable (e.g., no visual changes = skip screenshot diff), mark it complete with a note explaining why.
65
+ - **Task 1 creates the progress tracker**: Write `docs/progress/optimize-[scope].md` with all phases set to Pending. Update Measure to In Progress immediately.
66
+ - **Task 10 (Fix) is a parent task**: During scope (Task 8), break the fix plan into batches. For each batch, add child tasks dynamically via TaskCreate. Each batch must visually verify via Playwright before moving on.
67
+ - **Task 9 is a gate**: Present the scope document to the user and pause. Do not proceed until user approves the fix plan.
68
+ - **Task 14 is a gate**: Present the before/after report. Do not commit unless targets are met.
69
+ - **Task 17 MUST get explicit user approval** via AskUserQuestion before executing. This is destructive (git commits).
70
+
71
+ ---
72
+
73
+ ## Phase Details
74
+
75
+ ### Phase 1: MEASURE
76
+ **Tasks**: 1-3
77
+
78
+ **Goal**: Establish a factual baseline. No guessing what's slow — measure it.
79
+
80
+ **Actions**:
81
+
82
+ 1. Create the progress tracker file at `docs/progress/optimize-[scope].md` using the template in the Progress Tracking section. Set Measure to In Progress.
83
+ 2. Run `node .claude/skills/optimize-seo/scripts/pagespeed.mjs --url=https://friedbotstudio.com --output=/tmp/psi-baseline.json`. Capture scores and failing audits for both mobile and desktop strategies.
84
+ 3. Use **Playwright MCP** to capture screenshots at desktop (1280px), tablet (768px), and mobile (375px) widths. Save to `/tmp/screenshots-baseline/`.
85
+
86
+ **Required inputs**:
87
+ - `G_PAGESPEED_KEY` in `.env.local` (API key for PageSpeed Insights)
88
+ - Deployed live URL (default: `https://friedbotstudio.com`)
89
+
90
+ **Output**: Baseline scores + screenshots recorded in the progress tracker
91
+
92
+ ---
93
+
94
+ ### Phase 2: DIAGNOSE
95
+ **Tasks**: 4-7
96
+
97
+ **Goal**: Understand the root cause of every failing audit. Not the symptom — the cause.
98
+
99
+ **Actions**:
100
+
101
+ 1. **(Task 4)** Invoke `/pagespeed-insights` — let the skill interpret the Lighthouse report, surface the most impactful issues, and explain what each audit measures.
102
+ 2. **(Task 5)** Invoke `/nextjs-performance` — for any Next.js-specific findings (LCP, image optimization, RSC boundaries, bundle splitting, caching). This skill knows framework-level fixes.
103
+ 3. **(Task 6)** Invoke `/web-design-guidelines` — for accessibility-related failures (contrast, heading hierarchy, focus states, ARIA).
104
+ 4. **(Task 7)** Ground every diagnosis in code. Use Grep and Read to trace each failing audit to a specific file or pattern. Document file paths + line numbers in the progress tracker. If you cannot point to code, you do not have a root cause — keep investigating.
105
+
106
+ **Sub-skills invoked (mandatory):**
107
+
108
+ | Skill | Role |
109
+ | ------------------------ | -------------------------------------------------- |
110
+ | `/pagespeed-insights` | Interpret Lighthouse audits, prioritize fixes |
111
+ | `/nextjs-performance` | Next.js / React / Tailwind perf patterns |
112
+ | `/web-design-guidelines` | Accessibility and UX best practices |
113
+
114
+ **Output**: Root-cause map — for each failing audit, a concrete file/pattern reference
115
+
116
+ ---
117
+
118
+ ### Phase 3: SCOPE
119
+ **Tasks**: 8-9
120
+
121
+ **Goal**: A written, approved fix plan before any code changes.
122
+
123
+ **Actions**:
124
+
125
+ 1. **(Task 8)** Draft the fix plan in the progress tracker. Structure:
126
+ - Baseline scores
127
+ - Target scores (explicit numbers)
128
+ - Findings and root causes (with file references from Phase 2)
129
+ - Fix plan, batched by impact (biggest wins first)
130
+ - Acceptance criteria
131
+ - Risks and mitigations
132
+ - Out of scope
133
+ 2. **(Task 9)** Present the scope document to the user. Pause for approval. Do not proceed to fixes until user confirms batch order and acceptance criteria.
134
+
135
+ **Gate (Task 9)**: User approves the scope document before any code changes.
136
+
137
+ ---
138
+
139
+ ### Phase 4: FIX
140
+ **Tasks**: 10 (with dynamic child tasks)
141
+
142
+ **Goal**: Execute fixes in batches. Each batch is independently verifiable.
143
+
144
+ **Actions**:
145
+
146
+ 1. For each batch in the approved scope:
147
+ - Create child tasks via TaskCreate for the specific fixes in the batch
148
+ - Execute the fixes in order
149
+ - Use **Context7 MCP** for any library API lookups (do not rely on memory)
150
+ - Use `/code-structure` for all component changes (enforced by PostToolUse hook)
151
+ - After the batch, take a Playwright screenshot of affected pages at desktop + mobile
152
+ - Compare against baseline screenshots — no visual regressions allowed
153
+ 2. Mark each batch complete before starting the next.
154
+
155
+ **Sub-skills invoked (mandatory):**
156
+
157
+ | Skill | Role |
158
+ | --------------------------- | --------------------------------------- |
159
+ | `/nextjs-performance` | Applied during every fix for guidance |
160
+ | `/code-structure` | Enforced on every TSX/JSX edit (hook) |
161
+ | `/tailwind-design-system` | For any design token changes |
162
+
163
+ **Tools invoked (mandatory):**
164
+
165
+ | Tool | Role |
166
+ | ------------------ | --------------------------------- |
167
+ | **Context7 MCP** | Live library documentation lookup |
168
+ | **Playwright MCP** | Visual verification per batch |
169
+
170
+ **Output**: Implemented fixes, visual parity confirmed per batch
171
+
172
+ ---
173
+
174
+ ### Phase 5: VERIFY
175
+ **Tasks**: 11-14
176
+
177
+ **Goal**: Prove the fixes worked. No wishful thinking — measure.
178
+
179
+ **Actions**:
180
+
181
+ 1. **(Task 11)** Re-run `pagespeed.mjs` with `--baseline=/tmp/psi-baseline.json` to get a diff. Save to `/tmp/psi-after.json`.
182
+ 2. **(Task 12)** Re-run Playwright screenshots at 3 widths. Compare against `/tmp/screenshots-baseline/`. Flag any unexpected visual changes.
183
+ 3. **(Task 13)** Invoke `/simplify-code` on all changed files. Fix any High/Medium confidence issues before committing.
184
+ 4. **(Task 14)** Present a before/after report:
185
+ - Scores table: baseline vs after, per category, per strategy
186
+ - Specific audits that improved (and by how much)
187
+ - Any audits that regressed (must be zero)
188
+ - Visual verification: pass/fail
189
+ - Code quality: pass/fail
190
+ - Acceptance criteria met: yes/no
191
+ 5. If acceptance criteria are NOT met, loop back to Phase 4 (Fix) with a new batch. Do not commit under-delivered work.
192
+
193
+ **Sub-skills invoked (mandatory):**
194
+
195
+ | Skill | Role |
196
+ | ----------------- | --------------------------- |
197
+ | `/simplify-code` | Code quality + refactoring |
198
+
199
+ **Gate (Task 14)**: Acceptance criteria must be met before commit.
200
+
201
+ ---
202
+
203
+ ### Phase 6: COMMIT
204
+ **Tasks**: 15-17
205
+
206
+ **Goal**: Clean, conventional commits and a finalized progress tracker.
207
+
208
+ **Actions**:
209
+
210
+ 1. **(Task 15)** Invoke `/plan-commits` — audit `.gitignore`, group changes into logical commits, run pre-commit checks.
211
+ 2. **(Task 16)** Finalize the progress tracker — mark all phases Done with completion dates, attach the before/after report.
212
+ 3. **(Task 17)** Execute commits. **REQUIRES EXPLICIT USER APPROVAL.** Use AskUserQuestion to confirm before staging any files.
213
+
214
+ **Gate (Task 17)**: User explicitly approves before commits are executed.
215
+
216
+ ---
217
+
218
+ ## How to Use This Skill
219
+
220
+ ### Starting a new optimization cycle
221
+
222
+ ```
223
+ User: /optimize-seo the home page
224
+ ```
225
+
226
+ The skill will:
227
+
228
+ 1. Create the progress tracker at `docs/progress/optimize-home-page.md`
229
+ 2. Create all 17 tasks upfront
230
+ 3. Execute tasks in order, pausing at gates for approval
231
+
232
+ ### Resuming work
233
+
234
+ ```
235
+ User: /optimize-seo — where are we on the home page optimization?
236
+ ```
237
+
238
+ Check the task list for current status. Also check `docs/progress/optimize-[scope].md`.
239
+
240
+ ### Running a scheduled audit (no fixes)
241
+
242
+ ```
243
+ User: /optimize-seo audit only
244
+ ```
245
+
246
+ Run phases 1-2 only. Produce a baseline + diagnosis report. Stop before Scope.
247
+
248
+ ---
249
+
250
+ ## Progress Tracking
251
+
252
+ For each optimization cycle, maintain a progress file at `docs/progress/optimize-[scope].md`:
253
+
254
+ ```markdown
255
+ # Performance Optimization — [Scope] — Progress
256
+
257
+ | Phase | Status | Date | Notes |
258
+ | -------- | ----------- | ---------- | ---------------- |
259
+ | Measure | Done | YYYY-MM-DD | Baseline captured |
260
+ | Diagnose | In Progress | — | — |
261
+ | Scope | Pending | — | — |
262
+ | Fix | Pending | — | — |
263
+ | Verify | Pending | — | — |
264
+ | Commit | Pending | — | — |
265
+
266
+ ## Baseline Scores
267
+
268
+ | Category | Mobile | Desktop |
269
+ | -------------- | ------ | ------- |
270
+ | Performance | XX | XX |
271
+ | Accessibility | XX | XX |
272
+ | Best Practices | XX | XX |
273
+ | SEO | XX | XX |
274
+
275
+ ## Target Scores
276
+ ...
277
+
278
+ ## Findings & Root Causes
279
+ ...
280
+
281
+ ## Fix Plan
282
+ ...
283
+
284
+ ## Acceptance Criteria
285
+ ...
286
+
287
+ ## Before/After (populated at Verify phase)
288
+ ...
289
+ ```
290
+
291
+ **Task 1 creates this file.** Task 16 finalizes it. Update phase statuses as you enter each phase.
292
+
293
+ ---
294
+
295
+ ## Rules
296
+
297
+ 1. **Never fix without diagnosing** — guesswork burns time and introduces risk
298
+ 2. **Every root cause must cite a file and/or line** — if you can't point to code, you don't have a root cause
299
+ 3. **Every batch must visually verify** — perf wins that break the layout are regressions, not improvements
300
+ 4. **Never commit without a before/after diff** — prove the fix worked
301
+ 5. **Pause at gates** — scope approval (Task 9), verify report (Task 14), commit approval (Task 17)
302
+ 6. **One scope at a time** — full site vs page-specific vs single-component. Don't mix.
303
+ 7. **Sub-skill invocation is mandatory** — `/pagespeed-insights`, `/nextjs-performance`, `/web-design-guidelines`, `/simplify-code`, `/plan-commits` all have required invocation points
304
+ 8. **Use Context7 MCP for library API lookups during Fix** — do not rely on training data for Next.js, React, Tailwind APIs
305
+ 9. **Progress tracker is mandatory** — Task 1 creates it, Task 16 finalizes it before commits are executed
306
+
307
+ ---
308
+
309
+ ## Integration with `/orchestrate`
310
+
311
+ If a perf issue is discovered while delivering a new page, finish the `/orchestrate` cycle first. Run `/optimize-seo` as a separate follow-up cycle. Do not interleave.
312
+
313
+ If the same fix will ship alongside a new feature, scope it inside the `/orchestrate` Build phase, document it in the new page's progress tracker, and skip `/optimize-seo` for that cycle.
@@ -0,0 +1,197 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * PageSpeed Insights audit helper.
4
+ *
5
+ * Wraps the PageSpeed Insights API for repeatable baseline + diff audits.
6
+ * Reads G_PAGESPEED_KEY from .env.local at the project root.
7
+ *
8
+ * Usage:
9
+ * node pagespeed.mjs --url=https://friedbotstudio.com
10
+ * node pagespeed.mjs --url=https://friedbotstudio.com --output=/tmp/psi.json
11
+ * node pagespeed.mjs --url=https://friedbotstudio.com --baseline=/tmp/psi-baseline.json
12
+ *
13
+ * Flags:
14
+ * --url Target URL to audit (required)
15
+ * --strategy "mobile" | "desktop" | "both" (default: "both")
16
+ * --output Write raw results to this JSON file
17
+ * --baseline Compare against a previous --output file, print a diff table
18
+ * --silent Suppress human-readable output (still writes --output if set)
19
+ */
20
+
21
+ import { readFileSync, writeFileSync, existsSync } from "node:fs";
22
+ import { resolve, dirname } from "node:path";
23
+ import { fileURLToPath } from "node:url";
24
+
25
+ const __filename = fileURLToPath(import.meta.url);
26
+ const __dirname = dirname(__filename);
27
+
28
+ // ---------- argv parsing ----------
29
+
30
+ const args = Object.fromEntries(
31
+ process.argv.slice(2).map((a) => {
32
+ const [k, v] = a.replace(/^--/, "").split("=");
33
+ return [k, v ?? true];
34
+ })
35
+ );
36
+
37
+ if (!args.url) {
38
+ console.error("Error: --url is required");
39
+ console.error("Usage: node pagespeed.mjs --url=https://example.com [--strategy=mobile|desktop|both] [--output=file] [--baseline=file]");
40
+ process.exit(1);
41
+ }
42
+
43
+ const strategy = args.strategy || "both";
44
+ const strategies = strategy === "both" ? ["mobile", "desktop"] : [strategy];
45
+
46
+ // ---------- env loading ----------
47
+
48
+ function loadEnvKey() {
49
+ if (process.env.G_PAGESPEED_KEY) return process.env.G_PAGESPEED_KEY;
50
+ // Walk up looking for .env.local
51
+ let dir = __dirname;
52
+ for (let i = 0; i < 6; i++) {
53
+ const candidate = resolve(dir, ".env.local");
54
+ if (existsSync(candidate)) {
55
+ const content = readFileSync(candidate, "utf8");
56
+ const match = content.match(/^G_PAGESPEED_KEY\s*=\s*(.+)$/m);
57
+ if (match) return match[1].trim();
58
+ }
59
+ dir = resolve(dir, "..");
60
+ }
61
+ return null;
62
+ }
63
+
64
+ const apiKey = loadEnvKey();
65
+ if (!apiKey) {
66
+ console.error("Error: G_PAGESPEED_KEY not found in environment or .env.local");
67
+ process.exit(1);
68
+ }
69
+
70
+ // ---------- API call ----------
71
+
72
+ async function runAudit(url, strategy) {
73
+ const params = new URLSearchParams({
74
+ url,
75
+ strategy,
76
+ key: apiKey,
77
+ });
78
+ ["PERFORMANCE", "ACCESSIBILITY", "BEST_PRACTICES", "SEO"].forEach((c) =>
79
+ params.append("category", c)
80
+ );
81
+
82
+ const endpoint = `https://www.googleapis.com/pagespeedonline/v5/runPagespeed?${params}`;
83
+ const res = await fetch(endpoint);
84
+ if (!res.ok) {
85
+ const text = await res.text();
86
+ throw new Error(`PageSpeed API ${res.status}: ${text}`);
87
+ }
88
+ return res.json();
89
+ }
90
+
91
+ function extractSummary(raw) {
92
+ const categories = raw.lighthouseResult?.categories ?? {};
93
+ const audits = raw.lighthouseResult?.audits ?? {};
94
+
95
+ const scores = {};
96
+ for (const [id, cat] of Object.entries(categories)) {
97
+ scores[id] = Math.round((cat.score ?? 0) * 100);
98
+ }
99
+
100
+ const failures = [];
101
+ for (const audit of Object.values(audits)) {
102
+ if (
103
+ audit.score !== null &&
104
+ audit.score < 1 &&
105
+ !["informative", "notApplicable", "manual"].includes(audit.scoreDisplayMode)
106
+ ) {
107
+ failures.push({
108
+ id: audit.id,
109
+ title: audit.title,
110
+ score: audit.score,
111
+ severity: audit.score === 0 ? "FAIL" : "WARN",
112
+ displayValue: audit.displayValue ?? null,
113
+ });
114
+ }
115
+ }
116
+
117
+ // Sort failures: FAIL first, then by score ascending
118
+ failures.sort((a, b) => {
119
+ if (a.severity !== b.severity) return a.severity === "FAIL" ? -1 : 1;
120
+ return a.score - b.score;
121
+ });
122
+
123
+ return { scores, failures };
124
+ }
125
+
126
+ // ---------- reporting ----------
127
+
128
+ function printSummary(results) {
129
+ for (const [strategy, summary] of Object.entries(results)) {
130
+ console.log(`\n=== ${strategy.toUpperCase()} ===`);
131
+ console.log("Scores:");
132
+ for (const [cat, score] of Object.entries(summary.scores)) {
133
+ console.log(` ${cat.padEnd(16)} ${score}`);
134
+ }
135
+ if (summary.failures.length) {
136
+ console.log("\nFailing audits:");
137
+ for (const f of summary.failures) {
138
+ const display = f.displayValue ? ` — ${f.displayValue}` : "";
139
+ console.log(` [${f.severity}] ${f.title}${display}`);
140
+ }
141
+ }
142
+ }
143
+ }
144
+
145
+ function printDiff(baseline, current) {
146
+ console.log("\n=== DIFF (baseline → current) ===");
147
+ for (const strategy of Object.keys(current)) {
148
+ console.log(`\n${strategy.toUpperCase()}:`);
149
+ const base = baseline[strategy]?.scores ?? {};
150
+ const curr = current[strategy].scores;
151
+ for (const cat of Object.keys(curr)) {
152
+ const b = base[cat] ?? "—";
153
+ const c = curr[cat];
154
+ const delta = typeof b === "number" ? c - b : null;
155
+ const arrow = delta === null ? "" : delta > 0 ? ` ▲ +${delta}` : delta < 0 ? ` ▼ ${delta}` : " =";
156
+ console.log(` ${cat.padEnd(16)} ${String(b).padEnd(4)} → ${String(c).padEnd(4)}${arrow}`);
157
+ }
158
+
159
+ const baseFailures = new Set((baseline[strategy]?.failures ?? []).map((f) => f.id));
160
+ const currFailures = new Set(current[strategy].failures.map((f) => f.id));
161
+ const resolved = [...baseFailures].filter((id) => !currFailures.has(id));
162
+ const regressed = [...currFailures].filter((id) => !baseFailures.has(id));
163
+ if (resolved.length) {
164
+ console.log(` Resolved: ${resolved.length}`);
165
+ for (const id of resolved) console.log(` ✓ ${id}`);
166
+ }
167
+ if (regressed.length) {
168
+ console.log(` Regressed: ${regressed.length}`);
169
+ for (const id of regressed) console.log(` ✗ ${id}`);
170
+ }
171
+ }
172
+ }
173
+
174
+ // ---------- main ----------
175
+
176
+ const results = {};
177
+ for (const s of strategies) {
178
+ if (!args.silent) console.error(`Running ${s} audit for ${args.url}...`);
179
+ const raw = await runAudit(args.url, s);
180
+ results[s] = extractSummary(raw);
181
+ }
182
+
183
+ if (!args.silent) printSummary(results);
184
+
185
+ if (args.output) {
186
+ writeFileSync(args.output, JSON.stringify(results, null, 2));
187
+ if (!args.silent) console.log(`\nWrote results to ${args.output}`);
188
+ }
189
+
190
+ if (args.baseline) {
191
+ if (!existsSync(args.baseline)) {
192
+ console.error(`Baseline file not found: ${args.baseline}`);
193
+ process.exit(1);
194
+ }
195
+ const baseline = JSON.parse(readFileSync(args.baseline, "utf8"));
196
+ printDiff(baseline, results);
197
+ }
@@ -0,0 +1,37 @@
1
+ # License
2
+
3
+ ## Skill License - Free Use
4
+
5
+ This skill (the documentation, structure, and implementation) was created by **Ender Puentes <Endev/>** and is provided for **free and open use**. You are free to:
6
+
7
+ - ✅ **Use** this skill in any project, personal or commercial
8
+ - ✅ **Modify** the skill to fit your needs
9
+ - ✅ **Distribute** the skill to others
10
+ - ✅ **Share** modified versions of the skill
11
+ - ✅ **Include** this skill in your own skill collections
12
+
13
+ **No restrictions apply** - this skill is available for unrestricted use. Attribution is appreciated but not required.
14
+
15
+ **Note**: This skill documents and references the PageSpeed Insights guidelines and Core Web Vitals specifications, but the skill itself is an independent work created for team use.
16
+
17
+ ---
18
+
19
+ ## PageSpeed Insights Documentation
20
+
21
+ This skill documents the [PageSpeed Insights documentation](https://developers.google.com/speed/docs/insights/v5/about?hl=es-419), which is a separate work created by Google.
22
+
23
+ **The PageSpeed Insights documentation is NOT owned by the skill author.** The documentation has its own license:
24
+
25
+ **Creative Commons Attribution 4.0 International (CC BY 4.0)**
26
+
27
+ For information about the PageSpeed Insights documentation license, visit: https://creativecommons.org/licenses/by/4.0/
28
+
29
+ **Documentation Source**: https://developers.google.com/speed/docs/insights/v5/about?hl=es-419
30
+
31
+ This skill simply documents and references the official PageSpeed Insights guidelines for educational and practical use. The skill author claims no ownership or rights over the PageSpeed Insights documentation itself.
32
+
33
+ ## Skill Author
34
+
35
+ This skill was created by **Ender Puentes <Endev/>** - https://enderpuentes.com
36
+
37
+ The skill itself (as a documentation/implementation work) is released for free and unrestricted use. While attribution is appreciated, it is not required for using, modifying, or distributing this skill.