td-ai-tools 1.0.2

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 (41) hide show
  1. package/README.md +49 -0
  2. package/agents/README.md +10 -0
  3. package/agents/horizon-component-library/AGENTS.md +184 -0
  4. package/agents/horizon-component-library/README.md +10 -0
  5. package/agents/horizon-component-library/scripts/td-guard.sh +49 -0
  6. package/bin/cli.js +209 -0
  7. package/package.json +23 -0
  8. package/scripts/smoke-install.sh +56 -0
  9. package/skills/README.md +15 -0
  10. package/skills/cache-reset/SKILL.md +18 -0
  11. package/skills/cache-reset/agents/openai.yaml +4 -0
  12. package/skills/car-ticket-generator/SKILL.md +130 -0
  13. package/skills/car-ticket-generator/agents/openai.yaml +4 -0
  14. package/skills/everhour-basecamp-estimates/.env.example +2 -0
  15. package/skills/everhour-basecamp-estimates/SKILL.md +73 -0
  16. package/skills/everhour-basecamp-estimates/agents/openai.yaml +4 -0
  17. package/skills/everhour-basecamp-estimates/scripts/update_estimates.py +518 -0
  18. package/skills/everhour-basecamp-estimates/tests/test_update_estimates.py +93 -0
  19. package/skills/horizon-component-migration/SKILL.md +59 -0
  20. package/skills/horizon-component-migration/agents/openai.yaml +4 -0
  21. package/skills/pr-solver/SKILL.md +50 -0
  22. package/skills/pr-solver/agents/openai.yaml +4 -0
  23. package/skills/pr-solver/references/github-pr-reviewthreads-graphql.md +63 -0
  24. package/skills/pr-solver/scripts/list_unresolved_threads.py +307 -0
  25. package/skills/pull-request/SKILL.md +216 -0
  26. package/skills/pull-request/agents/openai.yaml +4 -0
  27. package/skills/record-changes/SKILL.md +75 -0
  28. package/skills/record-changes/agents/openai.yaml +4 -0
  29. package/skills/record-changes/scripts/branch_diff_context.py +190 -0
  30. package/skills/stylesheet-migration/SKILL.md +36 -0
  31. package/skills/stylesheet-migration/agents/openai.yaml +6 -0
  32. package/skills/stylesheet-migration/scripts/__pycache__/liquid_stylesheet_migrator.cpython-312.pyc +0 -0
  33. package/skills/stylesheet-migration/scripts/__pycache__/test_liquid_stylesheet_migrator.cpython-312.pyc +0 -0
  34. package/skills/stylesheet-migration/scripts/liquid_stylesheet_migrator.py +204 -0
  35. package/skills/stylesheet-migration/scripts/migrate_stylesheet_tags.py +172 -0
  36. package/skills/stylesheet-migration/scripts/test_liquid_stylesheet_migrator.py +254 -0
  37. package/skills/td-js-vanilla-rules/SKILL.md +70 -0
  38. package/skills/td-js-vanilla-rules/agents/openai.yaml +3 -0
  39. package/skills/td-review/SKILL.md +122 -0
  40. package/skills/td-review/agents/openai.yaml +4 -0
  41. package/skills/td-review/agents/td-theme-reviewer.md +221 -0
@@ -0,0 +1,254 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ import subprocess
5
+ import sys
6
+ import tempfile
7
+ import unittest
8
+
9
+ from liquid_stylesheet_migrator import MigrationError, plan_migration, validate_migration
10
+
11
+
12
+ class PlanMigrationTests(unittest.TestCase):
13
+ def test_inserts_include_below_leading_doc_comment(self) -> None:
14
+ with tempfile.TemporaryDirectory() as tmp:
15
+ root = Path(tmp)
16
+ source_path = root / "snippets" / "td-card.liquid"
17
+ source_path.parent.mkdir(parents=True)
18
+ source_path.write_text(
19
+ "{%- comment -%}\n"
20
+ " Card docs.\n"
21
+ "{%- endcomment -%}\n"
22
+ "\n"
23
+ "<div>Before</div>\n"
24
+ "{% stylesheet %}\n"
25
+ " .card { color: red; }\n"
26
+ "{% endstylesheet %}\n"
27
+ "<div>After</div>\n"
28
+ )
29
+
30
+ plan = plan_migration(root, source_path)
31
+
32
+ self.assertIsNotNone(plan)
33
+ assert plan is not None
34
+ self.assertEqual(
35
+ plan.updated_source,
36
+ "{%- comment -%}\n"
37
+ " Card docs.\n"
38
+ "{%- endcomment -%}\n"
39
+ "\n"
40
+ "{{ 'component-td-card.css' | asset_url | stylesheet_tag }}\n"
41
+ "\n"
42
+ "<div>Before</div>\n"
43
+ "<div>After</div>\n",
44
+ )
45
+
46
+ def test_inserts_include_at_file_start_without_doc_comment(self) -> None:
47
+ with tempfile.TemporaryDirectory() as tmp:
48
+ root = Path(tmp)
49
+ source_path = root / "sections" / "td-banner.liquid"
50
+ source_path.parent.mkdir(parents=True)
51
+ source_path.write_text(
52
+ "\n"
53
+ "{% stylesheet %}\n"
54
+ ".banner { color: blue; }\n"
55
+ "{% endstylesheet %}\n"
56
+ "<section>Banner</section>\n"
57
+ )
58
+
59
+ plan = plan_migration(root, source_path)
60
+
61
+ self.assertIsNotNone(plan)
62
+ assert plan is not None
63
+ self.assertEqual(
64
+ plan.updated_source,
65
+ "{{ 'section-td-banner.css' | asset_url | stylesheet_tag }}\n"
66
+ "\n"
67
+ "<section>Banner</section>\n",
68
+ )
69
+
70
+ def test_validate_migration_reports_conflicting_asset(self) -> None:
71
+ with tempfile.TemporaryDirectory() as tmp:
72
+ root = Path(tmp)
73
+ source_path = root / "sections" / "td-banner.liquid"
74
+ asset_path = root / "assets" / "section-td-banner.css"
75
+ source_path.parent.mkdir(parents=True)
76
+ asset_path.parent.mkdir(parents=True)
77
+ source_path.write_text(
78
+ "{% stylesheet %}\n"
79
+ ".banner { color: blue; }\n"
80
+ "{% endstylesheet %}\n"
81
+ "<section>Banner</section>\n"
82
+ )
83
+ asset_path.write_text(".banner { color: red; }\n")
84
+
85
+ plan = plan_migration(root, source_path)
86
+
87
+ self.assertIsNotNone(plan)
88
+ assert plan is not None
89
+ with self.assertRaises(MigrationError):
90
+ validate_migration(plan)
91
+
92
+ def test_reuses_existing_whitespace_control_include(self) -> None:
93
+ with tempfile.TemporaryDirectory() as tmp:
94
+ root = Path(tmp)
95
+ source_path = root / "sections" / "td-banner.liquid"
96
+ source_path.parent.mkdir(parents=True)
97
+ source_path.write_text(
98
+ "{{- 'section-td-banner.css' | asset_url | stylesheet_tag -}}\n"
99
+ "\n"
100
+ "{% stylesheet %}\n"
101
+ ".banner { color: blue; }\n"
102
+ "{% endstylesheet %}\n"
103
+ "<section>Banner</section>\n"
104
+ )
105
+
106
+ plan = plan_migration(root, source_path)
107
+
108
+ self.assertIsNotNone(plan)
109
+ assert plan is not None
110
+ self.assertFalse(plan.include_inserted)
111
+ self.assertEqual(
112
+ plan.updated_source,
113
+ "{{- 'section-td-banner.css' | asset_url | stylesheet_tag -}}\n"
114
+ "\n"
115
+ "<section>Banner</section>\n",
116
+ )
117
+
118
+ def test_reuses_existing_include_with_stylesheet_tag_arguments(self) -> None:
119
+ with tempfile.TemporaryDirectory() as tmp:
120
+ root = Path(tmp)
121
+ source_path = root / "sections" / "td-banner.liquid"
122
+ source_path.parent.mkdir(parents=True)
123
+ source_path.write_text(
124
+ "{{ 'section-td-banner.css' | asset_url | stylesheet_tag: preload: true }}\n"
125
+ "\n"
126
+ "{% stylesheet %}\n"
127
+ ".banner { color: blue; }\n"
128
+ "{% endstylesheet %}\n"
129
+ "<section>Banner</section>\n"
130
+ )
131
+
132
+ plan = plan_migration(root, source_path)
133
+
134
+ self.assertIsNotNone(plan)
135
+ assert plan is not None
136
+ self.assertFalse(plan.include_inserted)
137
+ self.assertEqual(
138
+ plan.updated_source,
139
+ "{{ 'section-td-banner.css' | asset_url | stylesheet_tag: preload: true }}\n"
140
+ "\n"
141
+ "<section>Banner</section>\n",
142
+ )
143
+
144
+ def test_ignores_stylesheet_blocks_inside_liquid_comments(self) -> None:
145
+ with tempfile.TemporaryDirectory() as tmp:
146
+ root = Path(tmp)
147
+ source_path = root / "sections" / "td-banner.liquid"
148
+ source_path.parent.mkdir(parents=True)
149
+ source_path.write_text(
150
+ "{% comment %}\n"
151
+ "{% stylesheet %}\n"
152
+ ".banner { color: red; }\n"
153
+ "{% endstylesheet %}\n"
154
+ "{% endcomment %}\n"
155
+ "{% stylesheet %}\n"
156
+ ".banner { color: blue; }\n"
157
+ "{% endstylesheet %}\n"
158
+ "<section>Banner</section>\n"
159
+ )
160
+
161
+ plan = plan_migration(root, source_path)
162
+
163
+ self.assertIsNotNone(plan)
164
+ assert plan is not None
165
+ self.assertEqual(
166
+ plan.updated_source,
167
+ "{% comment %}\n"
168
+ "{% stylesheet %}\n"
169
+ ".banner { color: red; }\n"
170
+ "{% endstylesheet %}\n"
171
+ "{% endcomment %}\n"
172
+ "\n"
173
+ "{{ 'section-td-banner.css' | asset_url | stylesheet_tag }}\n"
174
+ "\n"
175
+ "<section>Banner</section>\n",
176
+ )
177
+ self.assertEqual(plan.asset_content, ".banner { color: blue; }\n")
178
+
179
+ def test_returns_none_when_only_commented_stylesheet_blocks_exist(self) -> None:
180
+ with tempfile.TemporaryDirectory() as tmp:
181
+ root = Path(tmp)
182
+ source_path = root / "sections" / "td-banner.liquid"
183
+ source_path.parent.mkdir(parents=True)
184
+ source_path.write_text(
185
+ "{% comment %}\n"
186
+ "{% stylesheet %}\n"
187
+ ".banner { color: red; }\n"
188
+ "{% endstylesheet %}\n"
189
+ "{% endcomment %}\n"
190
+ "<section>Banner</section>\n"
191
+ )
192
+
193
+ self.assertIsNone(plan_migration(root, source_path))
194
+
195
+ def test_preserves_crlf_line_endings_when_planning(self) -> None:
196
+ with tempfile.TemporaryDirectory() as tmp:
197
+ root = Path(tmp)
198
+ source_path = root / "snippets" / "td-card.liquid"
199
+ source_path.parent.mkdir(parents=True)
200
+ source_text = (
201
+ "{% stylesheet %}\r\n"
202
+ ".card { color: red; }\r\n"
203
+ "{% endstylesheet %}\r\n"
204
+ "<div>Card</div>\r\n"
205
+ )
206
+ source_path.write_text(source_text)
207
+
208
+ plan = plan_migration(root, source_path)
209
+
210
+ self.assertIsNotNone(plan)
211
+ assert plan is not None
212
+ self.assertEqual(
213
+ plan.updated_source,
214
+ "{{ 'component-td-card.css' | asset_url | stylesheet_tag }}\r\n"
215
+ "\r\n"
216
+ "<div>Card</div>\r\n",
217
+ )
218
+ self.assertEqual(plan.asset_content, ".card { color: red; }\r\n")
219
+
220
+ def test_dry_run_fails_when_existing_asset_conflicts(self) -> None:
221
+ with tempfile.TemporaryDirectory() as tmp:
222
+ root = Path(tmp)
223
+ source_path = root / "sections" / "td-banner.liquid"
224
+ asset_path = root / "assets" / "section-td-banner.css"
225
+ source_path.parent.mkdir(parents=True)
226
+ asset_path.parent.mkdir(parents=True)
227
+ source_path.write_text(
228
+ "{% stylesheet %}\n"
229
+ ".banner { color: blue; }\n"
230
+ "{% endstylesheet %}\n"
231
+ "<section>Banner</section>\n"
232
+ )
233
+ asset_path.write_text(".banner { color: red; }\n")
234
+
235
+ result = subprocess.run(
236
+ [
237
+ sys.executable,
238
+ str(Path(__file__).with_name("migrate_stylesheet_tags.py")),
239
+ "--root",
240
+ str(root),
241
+ "--dry-run",
242
+ ],
243
+ capture_output=True,
244
+ text=True,
245
+ check=False,
246
+ )
247
+
248
+ self.assertEqual(result.returncode, 1)
249
+ self.assertIn("ERROR sections/td-banner.liquid:", result.stderr)
250
+ self.assertNotIn("Would migrate sections/td-banner.liquid", result.stdout)
251
+
252
+
253
+ if __name__ == "__main__":
254
+ unittest.main()
@@ -0,0 +1,70 @@
1
+ ---
2
+ name: td-js-vanilla-rules
3
+ description: Theory Digital vanilla JavaScript standards for Shopify theme work. Use when creating, modifying, refactoring, or debugging JavaScript in Shopify themes, including Web Component lifecycle, selector strategy, Swiper usage, accessibility state sync, and Shopify editor interaction hooks.
4
+ ---
5
+
6
+ # TD Vanilla JavaScript Rules
7
+
8
+
9
+ ## Implementation Pattern
10
+
11
+ - Implement JavaScript via Liquid `{% javascript %}` blocks with Web Components.
12
+ - Guard custom element registration:
13
+ - `if (!customElements.get('td-component-name')) { customElements.define('td-component-name', ComponentClass); }`
14
+ - Keep JavaScript minimal and event-driven.
15
+ - Do not import unapproved third-party JavaScript.
16
+ - If code directly uses/calls the Swiper custom element, ensure Swiper assets are included in that file.
17
+
18
+ ## Lifecycle Discipline
19
+
20
+ - Use `disconnectedCallback` cleanup for listeners, timers, observers, and pending animation frames.
21
+ - Keep interactive state deterministic across connect/disconnect/reconnect.
22
+
23
+ ## Accessibility Baseline
24
+
25
+ - Use real buttons/links for interaction surfaces.
26
+ - Keep `aria-expanded` and `aria-controls` synchronized with UI state.
27
+ - Support Escape to close interactive UI.
28
+ - Respect `prefers-reduced-motion` where motion/animation exists.
29
+
30
+ ## Selector and Hook Strategy
31
+
32
+ - Use `data-td-*` attributes as behavior hooks for binding, lookup, targeting, and state reads/writes.
33
+ - Use class selectors only for visual state toggles via `classList`.
34
+ - Do not use classes as primary JavaScript query hooks when markup is editable.
35
+ - If a new behavior hook is required, add a matching `data-td-*` attribute in the same change.
36
+ - Centralize selectors/config in module or static constants (for example `SELECTORS`, limits, timeouts).
37
+
38
+ ## Exception Policy
39
+
40
+ Class-based querying is allowed only when:
41
+
42
+ - Markup is third-party or not editable, or
43
+ - A framework/library API explicitly requires class targeting.
44
+
45
+ Add a short inline comment when applying an exception.
46
+
47
+ ## Shopify Editor Hooks
48
+
49
+ When component behavior depends on selected blocks, support:
50
+
51
+ - `shopify:block:select`
52
+ - `shopify:block:deselect`
53
+
54
+ ## Consistency and PR Safety
55
+
56
+ - If markup hook attributes change, update corresponding JavaScript selectors in the same PR.
57
+ - Before finishing, verify behavior queries are `data-td-*` based and class querying is limited to approved exceptions.
58
+
59
+ ## Completion Checklist
60
+
61
+ Confirm before handing off:
62
+
63
+ - Registration guard present.
64
+ - Cleanup implemented in `disconnectedCallback`.
65
+ - Behavior selectors use `data-td-*` hooks.
66
+ - Dynamic selector inputs are escaped.
67
+ - Accessibility attributes/Escape behavior are synchronized.
68
+ - Reduced-motion behavior is handled when relevant.
69
+ - Shopify block hooks are added where relevant.
70
+ - Swiper assets are included where Swiper custom element usage exists.
@@ -0,0 +1,3 @@
1
+ interface:
2
+ display_name: "TD JS Rules"
3
+ short_description: "Apply Theory Digital JavaScript rules for Horizon components"
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: td-review
3
+ description: Run parallel code review agents on a PR (including TD theme compliance) and produce a synthesized findings report. Does not post comments or take action — output is for human decision-making.
4
+ user_invocable: true
5
+ arguments:
6
+ - name: target
7
+ description: "PR number, GitHub URL, or blank for current branch"
8
+ required: false
9
+ ---
10
+
11
+ # TD Review
12
+
13
+ Run a multi-agent code review on a Shopify theme PR and produce a synthesized findings report with severity ratings and a TD compliance score.
14
+
15
+ This skill **only produces findings**. It does not post PR comments, request changes, or take any action on the PR.
16
+
17
+ ## Prerequisites
18
+
19
+ This skill depends on external agent definitions that must be available at runtime.
20
+
21
+ **Claude Code plugin:**
22
+ - `compound-engineering` — Provides the following review and research agents:
23
+ - `compound-engineering:review:security-sentinel`
24
+ - `compound-engineering:review:performance-oracle`
25
+ - `compound-engineering:review:julik-frontend-races-reviewer`
26
+ - `compound-engineering:review:pattern-recognition-specialist`
27
+ - `compound-engineering:review:architecture-strategist`
28
+ - `compound-engineering:review:code-simplicity-reviewer`
29
+ - `compound-engineering:research:git-history-analyzer`
30
+
31
+ **Custom agent (this repository):**
32
+ - `td-theme-reviewer` — Theory Digital's theme compliance reviewer. Must be registered as a custom agent type in Claude Code settings.
33
+
34
+ **CLI tools:**
35
+ - `gh` — GitHub CLI, authenticated with access to the target repository.
36
+
37
+ ## Workflow
38
+
39
+ ### Step 1: Determine Review Target
40
+
41
+ 1. If `$ARGUMENTS` contains a number or URL, use that as the PR target
42
+ 2. Otherwise, check the current branch for an associated PR via `gh pr view`
43
+ 3. Fetch PR metadata: `gh pr view --json number,title,body,files,headRefName,baseRefName,url`
44
+ 4. Ensure you are on the PR branch (use `gh pr checkout` if needed)
45
+
46
+ ### Step 2: Launch Review Agents in Parallel
47
+
48
+ Launch ALL of these agents simultaneously using the Agent tool. Each agent receives the PR number, title, file list, and branch name.
49
+
50
+ **Always launch:**
51
+
52
+ 1. **TD Theme Reviewer** (custom agent: `td-theme-reviewer`) — Enforces Theory Digital's theme customization ruleset. Produces a scored compliance report (0-100). This is the primary reviewer.
53
+
54
+ 2. **Security Sentinel** (`compound-engineering:review:security-sentinel`) — XSS in Liquid templates, unescaped output in JS contexts, third-party script risks, open redirects.
55
+
56
+ 3. **Performance Oracle** (`compound-engineering:review:performance-oracle`) — Bundle sizes, render-blocking resources, image optimization, Core Web Vitals impact.
57
+
58
+ 4. **Frontend Race Reviewer** (`compound-engineering:review:julik-frontend-races-reviewer`) — JS race conditions, `transitionend` without fallback, timer/observer cleanup in `disconnectedCallback`, async initialization timing.
59
+
60
+ 5. **Pattern Recognition** (`compound-engineering:review:pattern-recognition-specialist`) — Code consistency, naming conventions, duplication, anti-patterns across Liquid/CSS/JS.
61
+
62
+ 6. **Architecture Strategist** (`compound-engineering:review:architecture-strategist`) — Asset organization, section structure, component boundaries, configuration architecture.
63
+
64
+ 7. **Code Simplicity** (`compound-engineering:review:code-simplicity-reviewer`) — Unnecessary complexity, dead code, YAGNI violations.
65
+
66
+ **Conditionally launch:**
67
+
68
+ 8. **Git History Analyzer** (`compound-engineering:research:git-history-analyzer`) — Only if the PR has 10+ commits. Analyzes commit progression, risk areas, rollbacks.
69
+
70
+ ### Step 3: Synthesize Findings
71
+
72
+ Once all agents complete:
73
+
74
+ 1. Collect all findings from every agent
75
+ 2. Deduplicate — if multiple agents flag the same issue, merge into one finding and note which agents found it
76
+ 3. Categorize by severity:
77
+ - **P1 CRITICAL** — Security vulnerabilities, data loss, site-breaking bugs, CRITICAL TD compliance violations
78
+ - **P2 IMPORTANT** — Performance issues, memory leaks, MAJOR TD compliance violations
79
+ - **P3 NICE-TO-HAVE** — Code quality, minor consistency issues, MODERATE/MINOR TD violations
80
+ 4. Include the TD Compliance Score prominently
81
+
82
+ ### Step 4: Present Findings Report
83
+
84
+ Present the final findings report using this exact format:
85
+
86
+ ```
87
+ ## Review Findings
88
+
89
+ **TD Compliance Score: XX/100** — [verdict]
90
+ **PR:** #[number] — [title]
91
+ **Agents used:** [list]
92
+
93
+ | # | P | Finding | File | Source |
94
+ |----|----|---------|------|--------|
95
+ | 1 | P1 | description | file:line | agent(s) |
96
+ | 2 | P1 | description | file:line | agent(s) |
97
+ | 3 | P2 | description | file:line | agent(s) |
98
+ | ...| ...| ... | ... | ... |
99
+ ```
100
+
101
+ This is the final output. Do not prompt the user for further action — the report is complete.
102
+
103
+ ### Prompt Templates for Agents
104
+
105
+ When launching each agent, provide this context:
106
+
107
+ ```
108
+ Review PR #[number] on branch `[branch]` — "[title]".
109
+
110
+ Changed files:
111
+ [file list from PR metadata]
112
+
113
+ PR description:
114
+ [body]
115
+
116
+ Focus on [agent-specific focus area]. Read changed files using `git diff main...HEAD -- [file]` for context. Report findings with file path, line number, description, and severity.
117
+ ```
118
+
119
+ For the TD Theme Reviewer agent specifically, also include:
120
+ ```
121
+ Produce your full scored compliance report. Start at 100 and deduct per the scoring rubric.
122
+ ```
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "TD Review"
3
+ short_description: "Multi-agent PR review findings report"
4
+ default_prompt: "Use $td-review to run parallel code review agents and produce a findings report."
@@ -0,0 +1,221 @@
1
+ ---
2
+ name: td-theme-reviewer
3
+ description: Reviews Shopify theme PRs against Theory Digital's strict theme customization ruleset. Enforces vendor isolation, file naming conventions, upgrade safety, and documentation requirements. Produces a scored compliance report.
4
+ ---
5
+
6
+ You are a strict Shopify theme code reviewer enforcing Theory Digital's theme customization standards. Your job is to audit every changed file in a PR and flag violations. You do not suggest improvements — you enforce rules. Every violation must include the file path, line number, rule violated, and severity.
7
+
8
+ ## Scoring Rubric
9
+
10
+ Score each PR from 0 to 100. Start at 100 and deduct points per violation:
11
+
12
+ | Severity | Deduction | Examples |
13
+ |----------|-----------|----------|
14
+ | CRITICAL (-15 each) | Vendor file edited without TD CHANGE delimiters, hardcoded tracking scripts in layout/sections, `include` tag usage |
15
+ | MAJOR (-10 each) | Custom file missing `td-` prefix, CSS/JS in vendor files, missing docs/changes.md entry, JSON template pointing to vendor section when custom logic exists |
16
+ | MODERATE (-5 each) | Hardcoded values that should be settings/metafields, missing aria-labels or alt text, CSS not using variables, script tag in section/layout file |
17
+ | MINOR (-2 each) | Missing web component definition guard, library not from assets, unorganized CSS blocks, missing templates-map entry |
18
+
19
+ **Thresholds:**
20
+ - 90-100: Ship it
21
+ - 70-89: Fix before merge
22
+ - 50-69: Significant rework needed
23
+ - 0-49: Reject — structural violations
24
+
25
+ ## Rules
26
+
27
+ ### 1. Global Principles
28
+
29
+ - Prefer extension points, theme settings, metafields, and app embeds over editing vendor files.
30
+ - All custom code must live in clearly named files using the `td-` or `_td-` prefix.
31
+ - Vendor files must remain untouched unless absolutely unavoidable.
32
+ - JSON templates must activate custom sections rather than modifying vendor sections.
33
+ - All global styling must be in `assets/td-updates.css` or `assets/td-base.css`.
34
+ - All global JS must be in `assets/td-globals.js`.
35
+ - All changes must be documented in `docs/changes.md`.
36
+
37
+ **REJECT** any change that violates these principles without documented justification.
38
+
39
+ ### 2. Allowed vs Forbidden File Changes
40
+
41
+ **Allowed:**
42
+ - Creating new files with `td-` or `_td-` prefix in: `sections/`, `snippets/`, `assets/`, `blocks/`
43
+ - Editing JSON templates to point to custom sections or change settings
44
+ - Vendor file edits ONLY when delimited with:
45
+ ```
46
+ // ------------TD CHANGE-----------
47
+ // ----------END TD CHANGE---------
48
+ ```
49
+
50
+ **Forbidden — flag immediately:**
51
+ - Modifying vendor layout or template files unless unavoidable
52
+ - Modifying vendor theme schema settings unless unavoidable
53
+ - Adding tracking scripts directly into Liquid templates
54
+ - Addition of `{% include %}` tags (must use `{% render %}`)
55
+
56
+ ### 3. Layout and Asset Rules
57
+
58
+ **Required:**
59
+ - All global CSS overrides in `assets/td-updates.css` or `assets/td-base.css`
60
+ - All global JS in `assets/td-globals.js`
61
+ - Global inclusion only via `snippets/td-globals.liquid`
62
+
63
+ **Flag:**
64
+ - Any CSS added to vendor files
65
+ - Any JS added to vendor files
66
+ - Any `<script>` tags added inside layout or section files
67
+ - Missing or duplicated `td-globals` loading mechanism
68
+
69
+ ### 4. Section Customization Rules
70
+
71
+ **Required workflow when modifying vendor UX:**
72
+ 1. Copy vendor section to `td-` prefixed file
73
+ 2. Make changes only in the copy
74
+ 3. Update JSON template to use the custom section
75
+
76
+ **Flag:**
77
+ - Direct edits in vendor sections (without TD CHANGE delimiters)
78
+ - Changing vendor markup, loops, or settings in original files
79
+ - JSON templates pointing to vendor sections when custom logic is introduced
80
+
81
+ ### 5. JavaScript and CSS Rules
82
+
83
+ - Section/snippet-specific JS must be in `{% javascript %}` tags
84
+ - JS should use custom web components wherever possible
85
+ - Web components MUST check for definition before defining: `if (!customElements.get("name")) {`
86
+ - Third-party libraries must not be imported — must come from `assets/`
87
+ - Approved libraries: Swiper.js (only)
88
+ - Section/snippet-specific CSS must be in `{% stylesheet %}` tags
89
+ - CSS must use variables wherever possible
90
+
91
+ ### 6. Settings and Metafields Rules
92
+
93
+ - All hardcoded values should be extracted to: theme settings, metafields, metaobjects, or dynamic sources
94
+ - Custom copy, colors, toggles, and labels must be adjustable in settings
95
+ - Colors should first be defined via color schemes, then provide override options
96
+
97
+ **Flag:**
98
+ - Hardcoded literals that should be configurable
99
+ - Missing metafield-driven values for product or collection data
100
+
101
+ ### 7. Script and Integration Rules
102
+
103
+ - App embeds must be used for pixels, analytics, and integrations wherever possible
104
+ - Shopify's Customer Events and Pixels should be used when possible
105
+
106
+ **Flag:**
107
+ - Integration snippets placed in `theme.liquid`, section files, or template files
108
+ - Hardcoded scripts outside `td-globals.js`
109
+ - Missing documentation for integrations in `docs/changes.md`
110
+
111
+ ### 8. CSS Strategy Rules
112
+
113
+ - No edits to vendor CSS
114
+ - CSS variables should be used where the theme exposes them
115
+ - Overrides must target only custom sections or scoped selectors
116
+
117
+ **Flag:**
118
+ - Global selectors affecting vendor code unintentionally
119
+ - Overrides that should be variables
120
+ - Large or unorganized custom CSS blocks
121
+
122
+ ### 9. Accessibility and Performance Rules
123
+
124
+ **Check for:**
125
+ - Missing `alt` text on images in custom sections
126
+ - Buttons or links missing `aria-labels`
127
+ - Keyboard inaccessibility
128
+ - Excess DOM reflows or heavy loops
129
+ - Oversized custom CSS or JS bundles
130
+ - Liquid loops that are unoptimized or nested excessively
131
+
132
+ ### 10. Documentation Rules
133
+
134
+ Every customization must be logged in `docs/changes.md` including:
135
+ - File path
136
+ - Purpose
137
+ - Notes about upgrade impact
138
+ - Whether it is an unavoidable vendor-file edit
139
+
140
+ **Flag:**
141
+ - New custom files without documentation
142
+ - Vendor edits not documented as hotspots
143
+ - Missing or outdated `templates-map` entries
144
+
145
+ ### 11. Upgrade-Safe Structure Enforcement
146
+
147
+ **Required structure:**
148
+ ```
149
+ layout/
150
+ theme.liquid (only td-globals injected)
151
+ sections/
152
+ vendor files untouched
153
+ td-*.liquid (all modifications)
154
+ snippets/
155
+ td-globals.liquid
156
+ assets/
157
+ td-base.css
158
+ td-updates.css
159
+ td-globals.js
160
+ templates/
161
+ *.json (point to td-* sections where applicable)
162
+ docs/
163
+ changes.md
164
+ templates-map.md
165
+ hotspots.md (if vendor edits exist)
166
+ ```
167
+
168
+ **Flag any deviations** from this structure when custom functionality is introduced.
169
+
170
+ ### 12. Vendor File Edit Protocol
171
+
172
+ Only permitted when unavoidable. **Require:**
173
+ 1. The smallest possible change
174
+ 2. Comments marking the edit:
175
+ ```
176
+ // ------------TD CHANGE-----------
177
+ // ----------END TD CHANGE---------
178
+ ```
179
+ 3. Documentation in `docs/changes.md` with reapply steps
180
+
181
+ **Flag immediately:** Any vendor file change not annotated AND documented.
182
+
183
+ ## Review Process
184
+
185
+ 1. Get the list of changed files from the PR
186
+ 2. Categorize each file: vendor, custom (`td-*`), JSON template, config, docs, other
187
+ 3. For each vendor file changed — check for TD CHANGE delimiters and documentation
188
+ 4. For each custom file — check naming, isolation, settings usage, accessibility
189
+ 5. For each JSON template — verify it points to custom sections where custom logic exists
190
+ 6. Check `docs/changes.md` for completeness
191
+ 7. Check for forbidden patterns: `include` tags, hardcoded scripts, inline tracking
192
+ 8. Calculate score (start at 100, deduct per violation)
193
+ 9. Produce the report
194
+
195
+ ## Output Format
196
+
197
+ ```markdown
198
+ ## TD Theme Compliance Report
199
+
200
+ **Score: XX/100** — [Ship it | Fix before merge | Significant rework | Reject]
201
+
202
+ ### Violations
203
+
204
+ | # | Severity | Rule | File:Line | Description |
205
+ |---|----------|------|-----------|-------------|
206
+ | 1 | CRITICAL | 2.Forbidden | path:line | description |
207
+
208
+ ### File Audit
209
+
210
+ | File | Type | Status | Notes |
211
+ |------|------|--------|-------|
212
+ | path | vendor/custom/template | PASS/FAIL | details |
213
+
214
+ ### Documentation Check
215
+ - [ ] docs/changes.md updated
216
+ - [ ] All new files documented
217
+ - [ ] Vendor hotspots logged
218
+
219
+ ### Summary
220
+ [Brief paragraph on overall compliance]
221
+ ```