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.
- package/README.md +49 -0
- package/agents/README.md +10 -0
- package/agents/horizon-component-library/AGENTS.md +184 -0
- package/agents/horizon-component-library/README.md +10 -0
- package/agents/horizon-component-library/scripts/td-guard.sh +49 -0
- package/bin/cli.js +209 -0
- package/package.json +23 -0
- package/scripts/smoke-install.sh +56 -0
- package/skills/README.md +15 -0
- package/skills/cache-reset/SKILL.md +18 -0
- package/skills/cache-reset/agents/openai.yaml +4 -0
- package/skills/car-ticket-generator/SKILL.md +130 -0
- package/skills/car-ticket-generator/agents/openai.yaml +4 -0
- package/skills/everhour-basecamp-estimates/.env.example +2 -0
- package/skills/everhour-basecamp-estimates/SKILL.md +73 -0
- package/skills/everhour-basecamp-estimates/agents/openai.yaml +4 -0
- package/skills/everhour-basecamp-estimates/scripts/update_estimates.py +518 -0
- package/skills/everhour-basecamp-estimates/tests/test_update_estimates.py +93 -0
- package/skills/horizon-component-migration/SKILL.md +59 -0
- package/skills/horizon-component-migration/agents/openai.yaml +4 -0
- package/skills/pr-solver/SKILL.md +50 -0
- package/skills/pr-solver/agents/openai.yaml +4 -0
- package/skills/pr-solver/references/github-pr-reviewthreads-graphql.md +63 -0
- package/skills/pr-solver/scripts/list_unresolved_threads.py +307 -0
- package/skills/pull-request/SKILL.md +216 -0
- package/skills/pull-request/agents/openai.yaml +4 -0
- package/skills/record-changes/SKILL.md +75 -0
- package/skills/record-changes/agents/openai.yaml +4 -0
- package/skills/record-changes/scripts/branch_diff_context.py +190 -0
- package/skills/stylesheet-migration/SKILL.md +36 -0
- package/skills/stylesheet-migration/agents/openai.yaml +6 -0
- package/skills/stylesheet-migration/scripts/__pycache__/liquid_stylesheet_migrator.cpython-312.pyc +0 -0
- package/skills/stylesheet-migration/scripts/__pycache__/test_liquid_stylesheet_migrator.cpython-312.pyc +0 -0
- package/skills/stylesheet-migration/scripts/liquid_stylesheet_migrator.py +204 -0
- package/skills/stylesheet-migration/scripts/migrate_stylesheet_tags.py +172 -0
- package/skills/stylesheet-migration/scripts/test_liquid_stylesheet_migrator.py +254 -0
- package/skills/td-js-vanilla-rules/SKILL.md +70 -0
- package/skills/td-js-vanilla-rules/agents/openai.yaml +3 -0
- package/skills/td-review/SKILL.md +122 -0
- package/skills/td-review/agents/openai.yaml +4 -0
- 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,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,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
|
+
```
|