climaybe 3.4.7 → 3.5.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/README.md +82 -31
  2. package/bin/version.txt +1 -1
  3. package/package.json +3 -3
  4. package/src/commands/add-cursor-skill.js +11 -12
  5. package/src/commands/add-store.js +15 -0
  6. package/src/commands/app-init.js +8 -12
  7. package/src/commands/create-entrypoints.js +13 -3
  8. package/src/commands/ensure-branches.js +11 -0
  9. package/src/commands/init.js +114 -17
  10. package/src/commands/update-workflows.js +3 -2
  11. package/src/cursor/rules/00-rule-index.mdc +2 -1
  12. package/src/cursor/rules/cursor-rule-template.mdc +8 -7
  13. package/src/cursor/rules/figma-design-system.mdc +8 -8
  14. package/src/cursor/rules/global-rules-reference.mdc +2 -1
  15. package/src/cursor/rules/performance-guide.mdc +436 -0
  16. package/src/cursor/rules/snippets.mdc +1 -1
  17. package/src/cursor/skills/accessibility-pass/SKILL.md +2 -2
  18. package/src/cursor/skills/changelog-release/SKILL.md +2 -2
  19. package/src/cursor/skills/commit-in-groups/SKILL.md +2 -2
  20. package/src/cursor/skills/linear-create-task/SKILL.md +1 -1
  21. package/src/cursor/skills/liquid-doc-comments/SKILL.md +2 -2
  22. package/src/cursor/skills/locale-translation-prep/SKILL.md +2 -2
  23. package/src/cursor/skills/schema-section-change/SKILL.md +3 -3
  24. package/src/cursor/skills/section-from-spec/SKILL.md +6 -6
  25. package/src/cursor/skills/theme-check-fix/SKILL.md +4 -4
  26. package/src/index.js +3 -3
  27. package/src/lib/branch-protection.js +205 -0
  28. package/src/lib/config.js +11 -1
  29. package/src/lib/cursor-bundle.js +150 -12
  30. package/src/lib/git.js +12 -0
  31. package/src/lib/prompts.js +98 -4
  32. package/src/lib/theme-dev-kit.js +4 -0
  33. package/src/workflows/build/build-pipeline.yml +14 -0
  34. package/src/workflows/multi/pr-to-live.yml +1 -1
  35. package/src/workflows/preview/reusable-comment-on-pr.yml +6 -3
@@ -5,21 +5,26 @@ import {
5
5
  promptStoreLoop,
6
6
  promptPreviewWorkflows,
7
7
  promptBuildWorkflows,
8
+ promptLighthouseWorkflows,
8
9
  promptDevKit,
9
10
  promptVSCodeDevTasks,
10
11
  promptProjectName,
11
12
  promptCommitlint,
13
+ promptBranchProtection,
12
14
  promptCursorSkills,
15
+ promptAiEditors,
13
16
  promptConfigureCISecrets,
17
+ promptNoRemoteAction,
18
+ promptOwnerRepo,
14
19
  promptUpdateExistingSecrets,
15
20
  promptSecretValue,
16
21
  } from '../lib/prompts.js';
17
22
  import { readConfig, writeConfig, getProjectType, readPkg } from '../lib/config.js';
18
- import { ensureGitRepo, ensureInitialCommit, ensureStagingBranch, createStoreBranches, getSuggestedTagForRelease } from '../lib/git.js';
23
+ import { ensureGitRepo, ensureInitialCommit, ensureStagingBranch, createStoreBranches, getSuggestedTagForRelease, addOriginRemote } from '../lib/git.js';
19
24
  import { scaffoldWorkflows } from '../lib/workflows.js';
20
25
  import { createStoreDirectories } from '../lib/store-sync.js';
21
26
  import { scaffoldCommitlint } from '../lib/commit-tooling.js';
22
- import { scaffoldCursorBundle } from '../lib/cursor-bundle.js';
27
+ import { scaffoldAiConfig, logAiConfigResult } from '../lib/cursor-bundle.js';
23
28
  import { getMissingBuildWorkflowRequirements, ensureBuildWorkflowDefaults } from '../lib/build-workflows.js';
24
29
  import { getDevKitExistingFiles, scaffoldThemeDevKit } from '../lib/theme-dev-kit.js';
25
30
  import {
@@ -36,6 +41,7 @@ import {
36
41
  setSecret,
37
42
  setGitLabVariable,
38
43
  } from '../lib/github-secrets.js';
44
+ import { logBranchProtectionResult, syncBranchProtection } from '../lib/branch-protection.js';
39
45
 
40
46
  function installThemeDependencies(cwd = process.cwd()) {
41
47
  try {
@@ -48,23 +54,72 @@ function installThemeDependencies(cwd = process.cwd()) {
48
54
  }
49
55
  }
50
56
 
57
+ const DOCS_BASE = 'https://github.com/electricmaybe/climaybe#';
58
+
59
+ /**
60
+ * Print a short description (and optional docs link) as a preamble to the next prompt.
61
+ * A leading blank line detaches it from the previous answer, and there is no leading
62
+ * glyph, so the text reads as an intro to the question that follows — not a trailing
63
+ * note on the question above it.
64
+ * @param {string} text - one sentence, what the answer is for / what it should look like
65
+ * @param {string} [anchor] - README heading anchor (e.g. 'theme-dev-kit')
66
+ */
67
+ function hint(text, anchor) {
68
+ console.log('');
69
+ console.log(pc.dim(text));
70
+ if (anchor) console.log(pc.cyan(` ${DOCS_BASE}${anchor}`));
71
+ }
72
+
51
73
  /**
52
74
  * Run the full init flow: prompts, config write, git, branches, workflows.
53
75
  * Used by both init (when not already inited or user confirms reinit) and reinit.
54
76
  */
55
77
  async function runInitFlow() {
56
78
  const hasPackageJson = !!readPkg();
57
- const projectName = !hasPackageJson ? await promptProjectName() : undefined;
79
+ let projectName;
80
+ if (!hasPackageJson) {
81
+ hint("Used only when this repo has no package.json yet — the repo/folder name is usually fine.");
82
+ projectName = await promptProjectName();
83
+ }
58
84
 
59
85
  // 1. Collect stores from user
86
+ hint('Enter a Shopify subdomain (e.g. voldt-staging) or full domain; add 2+ stores for multi-store mode.');
60
87
  const stores = await promptStoreLoop();
61
88
  const mode = stores.length > 1 ? 'multi' : 'single';
89
+
90
+ hint('CI that publishes a preview theme per PR and cleans it up on close.', 'preview-and-cleanup-workflows');
62
91
  const enablePreviewWorkflows = await promptPreviewWorkflows();
92
+
93
+ hint('CI that bundles _scripts JS and compiles Tailwind on push. Yes if the theme uses _scripts/_styles.', 'build-and-lighthouse-workflows');
63
94
  const enableBuildWorkflows = await promptBuildWorkflows();
95
+
96
+ let enableLighthouseWorkflows = false;
97
+ if (enableBuildWorkflows) {
98
+ hint('Runs Lighthouse performance + a11y budgets on the staging branch (inside the build pipeline).', 'build-and-lighthouse-workflows');
99
+ enableLighthouseWorkflows = await promptLighthouseWorkflows();
100
+ }
101
+
102
+ hint('Local config + ignore defaults for theme work (Theme Check, Prettier, Lighthouse, gitignore).', 'theme-dev-kit');
64
103
  const enableDevKit = await promptDevKit();
65
- const enableVSCodeTasks = enableDevKit ? await promptVSCodeDevTasks() : false;
104
+ let enableVSCodeTasks = false;
105
+ if (enableDevKit) {
106
+ hint('Adds a VS Code task that runs `climaybe serve`. Only useful if you use VS Code.');
107
+ enableVSCodeTasks = await promptVSCodeDevTasks();
108
+ }
109
+
110
+ hint('Checks commit messages locally so they follow conventional commits (feat:, fix:, …).');
66
111
  const enableCommitlint = await promptCommitlint();
112
+
113
+ hint('Requires PRs on production branches (main, or each live-<alias>). Skips cleanly without GitHub/gh.', 'branch-protection');
114
+ const enableBranchProtection = await promptBranchProtection();
115
+
116
+ hint('Electric Maybe rules/skills/subagents installed to a single .config/ai/ source of truth.', 'ai-ruleset');
67
117
  const enableCursorSkills = await promptCursorSkills();
118
+ let aiEditors = [];
119
+ if (enableCursorSkills) {
120
+ hint('Pick the editors to bridge to .config/ai/ — only the ones you select get a bridge file.', 'ai-ruleset');
121
+ aiEditors = await promptAiEditors();
122
+ }
68
123
 
69
124
  console.log(pc.dim(`\n Mode: ${mode}-store (${stores.length} store(s))`));
70
125
 
@@ -102,11 +157,13 @@ async function runInitFlow() {
102
157
  default_store: stores[0].domain,
103
158
  preview_workflows: enablePreviewWorkflows,
104
159
  build_workflows: enableBuildWorkflows,
160
+ lighthouse_workflows: enableBuildWorkflows ? enableLighthouseWorkflows : undefined,
105
161
  build_entrypoints_ready: enableBuildWorkflows ? missingBuildFiles?.length === 0 : undefined,
106
162
  dev_kit: enableDevKit,
107
163
  vscode_tasks: enableVSCodeTasks,
108
164
  commitlint: enableCommitlint,
109
165
  cursor_skills: enableCursorSkills,
166
+ ai_editors: enableCursorSkills ? aiEditors : undefined,
110
167
  stores: {},
111
168
  };
112
169
 
@@ -134,13 +191,31 @@ async function runInitFlow() {
134
191
  }
135
192
  }
136
193
 
194
+ if (enableBranchProtection) {
195
+ const protection = syncBranchProtection({
196
+ mode,
197
+ aliases: stores.map((s) => s.alias),
198
+ cwd: process.cwd(),
199
+ });
200
+ logBranchProtectionResult(protection, mode);
201
+ if (protection.applied.length > 0 || protection.removed.length > 0) {
202
+ console.log(
203
+ pc.dim(
204
+ ' Rule: PR required on protected branches; live-* bypass allowed for shopify[bot], github-actions[bot], actions-user.'
205
+ )
206
+ );
207
+ }
208
+ } else {
209
+ console.log(pc.dim(' Branch protection: skipped (declined at prompt).'));
210
+ }
211
+
137
212
  // 6. Scaffold workflows
138
213
  scaffoldWorkflows(mode, {
139
214
  includePreview: enablePreviewWorkflows,
140
215
  includeBuild: enableBuildWorkflows,
141
216
  });
142
217
 
143
- // 7. Optional commitlint + Husky and Cursor bundle (rules, skills, agents)
218
+ // 7. Optional commitlint + Husky and the AI ruleset (rules, skills, agents + editor bridges)
144
219
  if (enableCommitlint) {
145
220
  console.log(pc.dim(' Setting up commitlint + Husky...'));
146
221
  if (scaffoldCommitlint()) {
@@ -150,14 +225,8 @@ async function runInitFlow() {
150
225
  }
151
226
  }
152
227
  if (enableCursorSkills) {
153
- const cursorOk = scaffoldCursorBundle();
154
- if (cursorOk) {
155
- console.log(
156
- pc.green(' Electric Maybe Cursor bundle → .cursor/rules, .cursor/skills, .cursor/agents'),
157
- );
158
- } else {
159
- console.log(pc.yellow(' Cursor bundle not found in package (skipped).'));
160
- }
228
+ const aiResult = scaffoldAiConfig(process.cwd(), { editors: aiEditors });
229
+ logAiConfigResult(aiResult, { pc });
161
230
  }
162
231
 
163
232
  if (enableDevKit) {
@@ -190,12 +259,19 @@ async function runInitFlow() {
190
259
  }
191
260
  console.log(pc.dim(` Preview workflows: ${enablePreviewWorkflows ? 'enabled' : 'disabled'}`));
192
261
  console.log(pc.dim(` Build workflows: ${enableBuildWorkflows ? 'enabled' : 'disabled'}`));
262
+ if (enableBuildWorkflows) {
263
+ console.log(pc.dim(` Lighthouse CI: ${enableLighthouseWorkflows ? 'enabled' : 'disabled'}`));
264
+ }
193
265
  console.log(pc.dim(` Theme dev kit: ${enableDevKit ? 'enabled' : 'disabled'}`));
194
266
  if (enableDevKit) {
195
267
  console.log(pc.dim(` VS Code tasks: ${enableVSCodeTasks ? 'enabled' : 'disabled'}`));
196
268
  }
197
269
  console.log(pc.dim(` commitlint + Husky: ${enableCommitlint ? 'enabled' : 'disabled'}`));
198
- console.log(pc.dim(` Cursor bundle: ${enableCursorSkills ? 'installed' : 'skipped'}`));
270
+ console.log(
271
+ pc.dim(
272
+ ` AI ruleset: ${enableCursorSkills ? `installed (${aiEditors.join(', ') || 'cursor'})` : 'skipped'}`
273
+ )
274
+ );
199
275
 
200
276
  const suggestedTag = getSuggestedTagForRelease();
201
277
  const tagLabel = suggestedTag === 'v1.0.0' ? 'Tag your first release' : 'Tag your next release';
@@ -239,9 +315,30 @@ async function runInitFlow() {
239
315
  return;
240
316
  }
241
317
  if (!setter.checkRemote()) {
242
- console.log(pc.yellow(' This repo has no ' + setter.name + ' remote (origin).'));
243
- console.log(pc.dim(' Add a remote and push first, then add secrets/variables in the repo Settings.\n'));
244
- return;
318
+ console.log(pc.yellow(` This folder has no ${setter.name} "origin" remote yet.`));
319
+ const action = await promptNoRemoteAction(setter.name);
320
+ if (action !== 'add') {
321
+ console.log(pc.dim(' Skipping CI secrets. Add a remote later, then re-run "climaybe init" or set them in the repo Settings.\n'));
322
+ return;
323
+ }
324
+ const slug = await promptOwnerRepo(setter.name);
325
+ if (!slug) {
326
+ console.log(pc.dim(' No repository entered; skipping CI secrets for now.\n'));
327
+ return;
328
+ }
329
+ try {
330
+ const url = addOriginRemote(slug, ciHost, process.cwd());
331
+ console.log(pc.green(` Added origin → ${url}`));
332
+ console.log(pc.dim(' Create the repo on ' + setter.name + ' and "git push -u origin --all" when ready.'));
333
+ } catch (err) {
334
+ console.log(pc.red(` Could not add origin remote: ${err.message}`));
335
+ console.log(pc.dim(' Add it manually with "git remote add origin <url>", then re-run "climaybe init".\n'));
336
+ return;
337
+ }
338
+ if (!setter.checkRemote()) {
339
+ console.log(pc.dim(' Remote added, but it is not recognized as a ' + setter.name + ' URL; skipping CI secrets.\n'));
340
+ return;
341
+ }
245
342
  }
246
343
 
247
344
  const existingNames =
@@ -4,6 +4,7 @@ import {
4
4
  isBuildWorkflowsEnabled,
5
5
  isCommitlintEnabled,
6
6
  isCursorSkillsEnabled,
7
+ getAiEditors,
7
8
  isPreviewWorkflowsEnabled,
8
9
  readConfig,
9
10
  } from '../lib/config.js';
@@ -11,7 +12,7 @@ import { scaffoldWorkflows } from '../lib/workflows.js';
11
12
  import { requireThemeProject } from '../lib/theme-guard.js';
12
13
  import { scaffoldThemeDevKit } from '../lib/theme-dev-kit.js';
13
14
  import { scaffoldCommitlint } from '../lib/commit-tooling.js';
14
- import { scaffoldCursorBundle } from '../lib/cursor-bundle.js';
15
+ import { scaffoldAiConfig } from '../lib/cursor-bundle.js';
15
16
 
16
17
  export async function updateCommand() {
17
18
  console.log(pc.bold('\n climaybe — Update\n'));
@@ -38,7 +39,7 @@ export async function updateCommand() {
38
39
  scaffoldCommitlint(process.cwd(), { skipInstall: true });
39
40
  }
40
41
  if (isCursorSkillsEnabled()) {
41
- scaffoldCursorBundle();
42
+ scaffoldAiConfig(process.cwd(), { editors: getAiEditors() });
42
43
  }
43
44
 
44
45
  scaffoldWorkflows(mode, { includePreview, includeBuild });
@@ -6,13 +6,14 @@ alwaysApply: true
6
6
  ---
7
7
  # Rule Index
8
8
 
9
- When you perform any of the following, **read and apply** the corresponding rule file from `.cursor/rules/`:
9
+ When you perform any of the following, **read and apply** the corresponding rule file from `.config/ai/rules/`:
10
10
 
11
11
  - **Editing `assets/*.js` or `assets/style.css`, build outputs vs source, where to edit JS/CSS** → `project-overview.mdc` (Build Outputs vs Source — edit `_scripts/`/`_styles/`, never the generated `assets/` files)
12
12
  - **Git commits, commit messages** → `commit-rules.mdc`
13
13
  - **Accessibility, a11y, focus, WCAG, UI behavior** → `accessibility-rules.mdc`
14
14
  - **JavaScript, web components, _scripts/, *.js** → `javascript-standards.mdc`
15
15
  - **Tailwind CSS, theme tokens, Liquid/CSS classes, _styles/** → `tailwindcss-rules.mdc`
16
+ - **Store performance, LCP/INP/CLS, head scripts, third-party tags, CSS/JS tiering, images, _head*/_body* snippets** → `performance-guide.mdc`
16
17
  - **Liquid syntax and usage** → `liquid.mdc`
17
18
  - **Section files (sections/*.liquid)** → `sections.mdc`
18
19
  - **Snippets (snippets/*.liquid)** → `snippets.mdc`
@@ -7,9 +7,9 @@ alwaysApply: false
7
7
 
8
8
  How to add new cursor rules to the project
9
9
 
10
- 1. Always place rule files in PROJECT_ROOT/.cursor/rules/:
10
+ 1. Always place rule files in PROJECT_ROOT/.config/ai/rules/:
11
11
  ```
12
- .cursor/rules/
12
+ .config/ai/rules/
13
13
  ├── your-rule-name.mdc
14
14
  ├── another-rule.mdc
15
15
  └── ...
@@ -23,16 +23,17 @@ How to add new cursor rules to the project
23
23
  3. Directory structure:
24
24
  ```
25
25
  PROJECT_ROOT/
26
- ├── .cursor/
27
- │ └── rules/
28
- ├── your-rule-name.mdc
29
- └── ...
26
+ ├── .config/
27
+ │ └── ai/
28
+ └── rules/
29
+ ├── your-rule-name.mdc
30
+ │ └── ...
30
31
  └── ...
31
32
  ```
32
33
 
33
34
  4. Never place rule files:
34
35
  - In the project root
35
- - In subdirectories outside .cursor/rules
36
+ - In subdirectories outside .config/ai/rules
36
37
  - In any other location
37
38
 
38
39
  5. Cursor rules have the following structure:
@@ -56,13 +56,13 @@ This document defines how to translate Figma designs into code for this project.
56
56
 
57
57
  - No React/Vue. UI is Liquid (sections + snippets) plus native JS web components.
58
58
  - New UI from Figma: prefer adding or composing existing snippets/sections; add new snippets/sections only when no fit exists.
59
- - Sections must have a valid `{% schema %}` and semantic HTML; snippets must have LiquidDoc `{%- doc -%}` and follow `.cursor/rules/snippets.mdc` and `.cursor/rules/liquid.mdc`.
59
+ - Sections must have a valid `{% schema %}` and semantic HTML; snippets must have LiquidDoc `{%- doc -%}` and follow `.config/ai/rules/snippets.mdc` and `.config/ai/rules/liquid.mdc`.
60
60
 
61
61
  ### 1.3 Frameworks & Libraries
62
62
 
63
63
  - **Templating:** Liquid only (Shopify theme).
64
64
  - **Styling:** Tailwind CSS v4. Entry: `_styles/main.css` (imports Tailwind, tokens, component CSS). Compiled output: `assets/style.css`.
65
- - **Script:** Native JS only (no React/Vue). Web components with `#` private fields, AbortController for listeners, JSDoc; see `.cursor/rules/javascript-standards.mdc`.
65
+ - **Script:** Native JS only (no React/Vue). Web components with `#` private fields, AbortController for listeners, JSDoc; see `.config/ai/rules/javascript-standards.mdc`.
66
66
  - **Build:** Tailwind processes `_styles/main.css`; content sources (for class scanning) are listed in `_styles/main.css` (`@source` for layout, blocks, sections, snippets, templates, assets).
67
67
 
68
68
  ### 1.4 Asset Management
@@ -127,8 +127,8 @@ config/ # Theme settings
127
127
  - **Reuse existing snippets/sections** from `snippets/` and `sections/` instead of duplicating (e.g. buttons → `a--button`, icons → `a--icon`, cards → `m--*` cards, modals → `m--modal` / electric-modal).
128
128
  - Use the project’s **color system** (semantic tokens from `02.02_colors.css`), **typography** (`02.03_typography.css`, utilities), and **spacing/sizes** (`02.01_sizes.css`, Tailwind utilities that use them).
129
129
  - **Tailwind:** Only static class names; map Figma colors to semantic tokens (e.g. `bg-surface`, `text-primary`); use project breakpoints and spacing scale.
130
- - Respect **accessibility** (WCAG 2.1 AA): semantic HTML, ARIA where needed, keyboard and screen reader support; see `.cursor/rules/accessibility-rules.mdc`.
131
- - Respect **JS standards**: no new dependencies; if adding behavior, use native JS/web components per `.cursor/rules/javascript-standards.mdc`.
130
+ - Respect **accessibility** (WCAG 2.1 AA): semantic HTML, ARIA where needed, keyboard and screen reader support; see `.config/ai/rules/accessibility-rules.mdc`.
131
+ - Respect **JS standards**: no new dependencies; if adding behavior, use native JS/web components per `.config/ai/rules/javascript-standards.mdc`.
132
132
  - Aim for **1:1 visual parity** with the Figma design and validate with the screenshot.
133
133
 
134
134
  ### 2.3 Asset Handling
@@ -144,16 +144,16 @@ config/ # Theme settings
144
144
 
145
145
  ### 3.1 Liquid
146
146
 
147
- - Follow `.cursor/rules/liquid.mdc`: e.g. assign computed values before passing to `render`; no inline `append` in `render` parameters; valid tags/filters only.
148
- - Use `{%- doc -%}` and LiquidDoc for all new snippets; document params and examples per `.cursor/rules/liquid-doc-rules.mdc` and `.cursor/rules/snippets.mdc`.
147
+ - Follow `.config/ai/rules/liquid.mdc`: e.g. assign computed values before passing to `render`; no inline `append` in `render` parameters; valid tags/filters only.
148
+ - Use `{%- doc -%}` and LiquidDoc for all new snippets; document params and examples per `.config/ai/rules/liquid-doc-rules.mdc` and `.config/ai/rules/snippets.mdc`.
149
149
 
150
150
  ### 3.2 Sections
151
151
 
152
- - Every section: valid `{% schema %}`, semantic HTML, section-scoped classes. Follow `.cursor/rules/sections.mdc` and `.cursor/rules/schemas.mdc` for schema definitions.
152
+ - Every section: valid `{% schema %}`, semantic HTML, section-scoped classes. Follow `.config/ai/rules/sections.mdc` and `.config/ai/rules/schemas.mdc` for schema definitions.
153
153
 
154
154
  ### 3.3 Accessibility
155
155
 
156
- - Semantic structure, ARIA where needed, keyboard and focus behavior, WCAG 2.1 AA. See `.cursor/rules/accessibility-rules.mdc`. Use the accessibility-pass skill when asked for an a11y audit.
156
+ - Semantic structure, ARIA where needed, keyboard and focus behavior, WCAG 2.1 AA. See `.config/ai/rules/accessibility-rules.mdc`. Use the accessibility-pass skill when asked for an a11y audit.
157
157
 
158
158
  ### 3.4 Performance
159
159
 
@@ -6,7 +6,7 @@ alwaysApply: false
6
6
  ---
7
7
  # Global Rules Reference
8
8
 
9
- This project uses global rules from ~/.claude/rules/ (when using Claude). **In Cursor, project rules live in `.cursor/rules/` and are applied per the rule index (`00-rule-index.mdc`).**
9
+ This project uses global rules from ~/.claude/rules/ (when using Claude). **In Cursor, project rules live in `.config/ai/rules/` and are applied per the rule index (`00-rule-index.mdc`).**
10
10
 
11
11
  ## Global Rules Location
12
12
  All reusable rules are stored in:
@@ -52,6 +52,7 @@ These rules are synced from ~/.claude/rules/:
52
52
  ### Project-Specific Rules
53
53
  These rules are unique to this project:
54
54
  - `project-overview.mdc` - Electric Maybe theme overview
55
+ - `performance-guide.mdc` - Store performance architecture (CSS/JS tiering, third-party containment, LCP)
55
56
  - `js-refactor-tasks.mdc` - Current refactoring tasks
56
57
 
57
58
  ## Important Notes