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
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# AgentToolkit
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
This repository is a lightweight foundation for organizing reusable agent packs, skills, workflows, and evaluation assets.
|
|
5
|
+
|
|
6
|
+
<!-- TODO: Add project mission, scope, and ownership details. -->
|
|
7
|
+
|
|
8
|
+
## Repository Layout
|
|
9
|
+
- `AGENTS.md`: Repository-specific operating instructions.
|
|
10
|
+
- `agents/`: Reusable agent packs (`AGENTS.md` + helper assets per pack).
|
|
11
|
+
- `skills/`: Reusable skills (`SKILL.md`, optional scripts/references, model metadata).
|
|
12
|
+
- `workflows/`: Reusable multi-step orchestration workflows.
|
|
13
|
+
- `evals/`: Evaluation cases, datasets, and runners.
|
|
14
|
+
|
|
15
|
+
## Basic Usage
|
|
16
|
+
1. Add agent packs in `agents/` and index them in `agents/README.md`.
|
|
17
|
+
2. Add capability specifications in `skills/` and index them in `skills/README.md`.
|
|
18
|
+
3. Define orchestrations in `workflows/` and index them in `workflows/README.md`.
|
|
19
|
+
4. Maintain evaluation assets in `evals/`.
|
|
20
|
+
|
|
21
|
+
## CLI Usage
|
|
22
|
+
Run the packaged installer from inside a target project:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx td-ai-tools
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Useful commands:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx td-ai-tools list
|
|
32
|
+
npx td-ai-tools install
|
|
33
|
+
npx td-ai-tools install --all
|
|
34
|
+
npx td-ai-tools install pr-solver
|
|
35
|
+
npx td-ai-tools install pr-solver horizon-component-library
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The installer copies requested items into both agent layouts:
|
|
39
|
+
|
|
40
|
+
- Skills: `.claude/skills/<name>/` and `.agents/skills/<name>/`
|
|
41
|
+
|
|
42
|
+
This keeps the installed assets available to both Claude-style and `.agents`-style project conventions.
|
|
43
|
+
|
|
44
|
+
## Local Verification
|
|
45
|
+
Run the local smoke test to package the repo and verify installation into a throwaway project:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm run smoke:install
|
|
49
|
+
```
|
package/agents/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# agents
|
|
2
|
+
|
|
3
|
+
## Available Agent Packs
|
|
4
|
+
- `horizon-component-library/`: Theory Digital Horizon component-library agent rules, with guard script.
|
|
5
|
+
|
|
6
|
+
## Pack Structure Convention
|
|
7
|
+
- `<pack-name>/AGENTS.md`
|
|
8
|
+
- `<pack-name>/README.md`
|
|
9
|
+
- `<pack-name>/scripts/*` (optional)
|
|
10
|
+
- `<pack-name>/assets/*` (optional)
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# .codex/AGENTS.md — Theory Digital
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
Default rules for Theory Digital component-library sections built with theme blocks.
|
|
5
|
+
|
|
6
|
+
## Core Principles
|
|
7
|
+
- Prefer isolated TD implementations over vendor patching.
|
|
8
|
+
- Keep responsibilities separated:
|
|
9
|
+
- Liquid derives and normalizes state.
|
|
10
|
+
- Markup renders only the active structure.
|
|
11
|
+
- CSS handles layout and presentation.
|
|
12
|
+
- JavaScript handles behavior only.
|
|
13
|
+
- Build the simplest implementation that satisfies the requirement.
|
|
14
|
+
- Keep DOM, CSS, and JS minimal and maintainable.
|
|
15
|
+
- Every change must be logged in `docs/changes.md`.
|
|
16
|
+
|
|
17
|
+
## File Conventions
|
|
18
|
+
- Custom code must live in `td-` or `_td-` prefixed files only.
|
|
19
|
+
- Vendor files are READ-ONLY unless wrapped in TD CHANGE delimiters and documented in `docs/hotspots.md`.
|
|
20
|
+
- Custom sections: `sections/td-*.liquid`
|
|
21
|
+
- Custom blocks: `blocks/td-*.liquid`
|
|
22
|
+
- Private blocks: `blocks/_td-*.liquid`
|
|
23
|
+
- Custom snippets: `snippets/td-*.liquid`
|
|
24
|
+
- Put generic, reusable styles in `assets/td-base.css`.
|
|
25
|
+
- Every file that directly renders or calls the Swiper custom element must also include the Swiper assets.
|
|
26
|
+
- Use vendor code only when it already solves the requirement as-is.
|
|
27
|
+
- Otherwise, build an isolated TD implementation instead of patching vendor internals.
|
|
28
|
+
|
|
29
|
+
## Forbidden
|
|
30
|
+
- Never modify vendor section schemas.
|
|
31
|
+
- Never use `{% include %}`. Use `{% render %}` only.
|
|
32
|
+
- Never add inline scripts to `layout/` files.
|
|
33
|
+
- Never import unapproved third-party JavaScript.
|
|
34
|
+
- Never add non-`td`-prefixed custom CSS variables.
|
|
35
|
+
- Never add non-`data-td-*` custom data attributes.
|
|
36
|
+
- Never declare unnecessary Liquid variables for single-use values.
|
|
37
|
+
- Never overload one setting to drive incompatible behaviors.
|
|
38
|
+
- Never emit parallel desktop/mobile or alternate-mode structures unless needed.
|
|
39
|
+
- Never rely on CSS alone to hide unused structural markup when Liquid can resolve it.
|
|
40
|
+
- Never let invalid or legacy state leak into classes, attributes, or CSS variables.
|
|
41
|
+
- Do not add redundant fallback guards or defensive reassignment for schema-backed primitive settings.
|
|
42
|
+
- Avoid unnecessary conditionals, wrappers, and listeners.
|
|
43
|
+
|
|
44
|
+
## Required Patterns
|
|
45
|
+
|
|
46
|
+
### JavaScript
|
|
47
|
+
- Author JavaScript via `{% javascript %}` and Web Components.
|
|
48
|
+
- When creating or modifying JavaScript, load and follow the `$td-js-vanilla-rules` skill.
|
|
49
|
+
- If `$td-js-vanilla-rules` is unavailable, enforce the JavaScript baseline rules in this file.
|
|
50
|
+
- Always guard custom element registration:
|
|
51
|
+
- `if (!customElements.get(...))`
|
|
52
|
+
- Always clean up in `disconnectedCallback`:
|
|
53
|
+
- event listeners
|
|
54
|
+
- timers
|
|
55
|
+
- observers
|
|
56
|
+
- external subscriptions
|
|
57
|
+
- Keep JavaScript minimal, event-driven, and component-scoped.
|
|
58
|
+
|
|
59
|
+
### CSS
|
|
60
|
+
- Author CSS via `{% stylesheet %}` and CSS variables.
|
|
61
|
+
- All custom properties must use the `--td-*` prefix.
|
|
62
|
+
- Use BEM naming for all classes.
|
|
63
|
+
- Use BEM modifier classes for discrete state:
|
|
64
|
+
- mode
|
|
65
|
+
- layout
|
|
66
|
+
- alignment
|
|
67
|
+
- position
|
|
68
|
+
- variant
|
|
69
|
+
- Use CSS variables for dynamic values:
|
|
70
|
+
- sizes
|
|
71
|
+
- spacing
|
|
72
|
+
- offsets
|
|
73
|
+
- dimensions
|
|
74
|
+
- Use inline CSS variables only when truly dynamic.
|
|
75
|
+
- Keep CSS ordered as:
|
|
76
|
+
- shared/base rules
|
|
77
|
+
- mobile-only rules
|
|
78
|
+
- desktop-only rules
|
|
79
|
+
|
|
80
|
+
### Liquid
|
|
81
|
+
- Derive and normalize state at the top of the file before rendering.
|
|
82
|
+
- Trust schema-backed primitive settings to provide valid values.
|
|
83
|
+
- Normalize only values that are:
|
|
84
|
+
- derived
|
|
85
|
+
- cross-dependent
|
|
86
|
+
- legacy-sensitive
|
|
87
|
+
- conditionally invalid
|
|
88
|
+
- externally sourced
|
|
89
|
+
- For straightforward values, prefer inline Liquid over one-time-use variables.
|
|
90
|
+
- Only introduce variables when they improve reuse, clarity, or state normalization.
|
|
91
|
+
- Use clear breakpoint-specific names when behavior differs by breakpoint.
|
|
92
|
+
- Use `block.settings.<id>` directly when used once.
|
|
93
|
+
- Use `default` only when truly needed.
|
|
94
|
+
- Support deterministic fallbacks:
|
|
95
|
+
- explicit setting
|
|
96
|
+
- product/metafield
|
|
97
|
+
- placeholder
|
|
98
|
+
- Do not output unresolved or invalid state into markup, classes, attributes, or CSS variables.
|
|
99
|
+
|
|
100
|
+
### Markup
|
|
101
|
+
- Render only the active structure.
|
|
102
|
+
- Keep DOM output minimal.
|
|
103
|
+
- Render only the wrappers required for the active mode.
|
|
104
|
+
- In component-library sections built with theme blocks, parent/child composition must use `{% content_for 'blocks' %}` for nested private blocks.
|
|
105
|
+
- Accessibility baseline:
|
|
106
|
+
- use real buttons/links for interaction
|
|
107
|
+
- keep `aria-expanded` and `aria-controls` synchronized in JS
|
|
108
|
+
- support Escape to close interactive UI
|
|
109
|
+
- respect `prefers-reduced-motion`
|
|
110
|
+
|
|
111
|
+
## Section Architecture Rules
|
|
112
|
+
- Resolve layout decisions in Liquid whenever possible.
|
|
113
|
+
- If desktop and mobile behavior differ, use separate schema settings.
|
|
114
|
+
- Use `visible_if` to improve settings organization only when the setting type supports it and the dependency is valid under Shopify schema rules.
|
|
115
|
+
- Do not rely on `visible_if` for behavior enforcement, required logic, or unsupported setting relationships.
|
|
116
|
+
- Normalize invalid settings defensively in Liquid.
|
|
117
|
+
- Use BEM modifier classes for discrete state and CSS variables for dynamic values.
|
|
118
|
+
|
|
119
|
+
## Schema Rules
|
|
120
|
+
- All hardcoded values must be settings or metafields unless they are true implementation constants.
|
|
121
|
+
- Schema labels, options, and headers should use translation keys (`t:*`) whenever possible.
|
|
122
|
+
- Reuse existing `td` translation keys first.
|
|
123
|
+
- New translation keys must be created under the `td` namespace when needed.
|
|
124
|
+
- Keep new keys simple and reusable.
|
|
125
|
+
- Add `info` text only when the setting is not self-explanatory.
|
|
126
|
+
- Use `visible_if` only where supported and only for editor organization, not as a substitute for Liquid validation.
|
|
127
|
+
- Model schema around actual user-facing behavior.
|
|
128
|
+
|
|
129
|
+
## Global Schema Requirements
|
|
130
|
+
- All sections must include padding settings.
|
|
131
|
+
- All sections must include color scheme picker settings.
|
|
132
|
+
- All sections must include custom ID settings.
|
|
133
|
+
- All blocks must inherit the color scheme by default.
|
|
134
|
+
- All blocks must provide a custom scheme override option.
|
|
135
|
+
|
|
136
|
+
## Rendering Rules
|
|
137
|
+
- Image URL width must be 2x the displayed maximum width.
|
|
138
|
+
- Example:
|
|
139
|
+
- displayed max width `80px`
|
|
140
|
+
- `image_url: width: 160`
|
|
141
|
+
- Render only the assets and markup required for the active implementation.
|
|
142
|
+
|
|
143
|
+
## Performance Rules
|
|
144
|
+
- Keep JavaScript minimal and event-driven.
|
|
145
|
+
- Avoid unnecessary listeners, observers, timers, and DOM work.
|
|
146
|
+
- Prefer solving state once in Liquid instead of repeatedly in CSS or JS.
|
|
147
|
+
|
|
148
|
+
## Editor Rules
|
|
149
|
+
- Add Shopify editor hooks when needed:
|
|
150
|
+
- `shopify:block:select`
|
|
151
|
+
- `shopify:block:deselect`
|
|
152
|
+
- Interactive UI must work in both storefront and theme editor contexts.
|
|
153
|
+
|
|
154
|
+
## Hard Output Gate
|
|
155
|
+
- For any edits in `sections/td-*.liquid`, `blocks/td-*.liquid`, `blocks/_td-*.liquid`, or `snippets/td-*.liquid`, run `.claude/agents/horizon-component-library/scripts/td-guard.sh` before final output.
|
|
156
|
+
- If `td-guard` fails, fix the code and rerun the guard before responding.
|
|
157
|
+
|
|
158
|
+
## Guard Retry Budget
|
|
159
|
+
- Auto-fix attempts after a failing required guard are capped at 2 retries per task.
|
|
160
|
+
- If the guard still fails after 2 retries, stop and ask the user for direction.
|
|
161
|
+
- Do not continue retrying without new user input.
|
|
162
|
+
|
|
163
|
+
## Escalation Message Format
|
|
164
|
+
- When retry budget is exhausted, report:
|
|
165
|
+
- failing check name
|
|
166
|
+
- exact failing files and lines
|
|
167
|
+
- fixes attempted
|
|
168
|
+
- one recommended next action
|
|
169
|
+
|
|
170
|
+
## Pre-Output Checklist
|
|
171
|
+
- Custom code is isolated in TD-prefixed files.
|
|
172
|
+
- Vendor internals were not patched unless allowed and documented.
|
|
173
|
+
- State is derived and normalized at the top of the file.
|
|
174
|
+
- Schema-backed primitive settings are not wrapped in redundant fallback guards.
|
|
175
|
+
- `.claude/agents/horizon-component-library/scripts/td-guard.sh` passes when TD Liquid files were changed.
|
|
176
|
+
- Desktop/mobile differences use explicit settings where needed.
|
|
177
|
+
- Invalid or legacy states are normalized defensively.
|
|
178
|
+
- Markup renders only the active structure.
|
|
179
|
+
- CSS uses BEM modifier classes for discrete state and variables for dynamic values.
|
|
180
|
+
- Inline CSS variables are used only when necessary.
|
|
181
|
+
- Accessibility requirements are satisfied.
|
|
182
|
+
- Required assets are rendered where needed.
|
|
183
|
+
- Schema follows translation and visibility rules.
|
|
184
|
+
- All changes are logged in `docs/changes.md`.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Horizon Component Library Agent
|
|
2
|
+
|
|
3
|
+
This folder contains the reusable agent policy and helper script imported from `../HorizonComponentLibrary`.
|
|
4
|
+
|
|
5
|
+
## Files
|
|
6
|
+
- `AGENTS.md`: Theory Digital agent rules for Horizon component-library section work.
|
|
7
|
+
- `scripts/td-guard.sh`: Guard script referenced by the agent rules.
|
|
8
|
+
|
|
9
|
+
## Related Skill
|
|
10
|
+
- `skills/td-js-vanilla-rules/`: JavaScript standards skill referenced by this agent (`$td-js-vanilla-rules`).
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
cd "$ROOT_DIR"
|
|
6
|
+
|
|
7
|
+
if ! command -v rg >/dev/null 2>&1; then
|
|
8
|
+
echo "ERROR: ripgrep (rg) is required for td-guard checks."
|
|
9
|
+
exit 1
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
changed_files=()
|
|
13
|
+
while IFS= read -r file; do
|
|
14
|
+
changed_files+=("$file")
|
|
15
|
+
done < <(
|
|
16
|
+
{
|
|
17
|
+
git diff --name-only --diff-filter=ACMRTUXB HEAD
|
|
18
|
+
git ls-files --others --exclude-standard
|
|
19
|
+
} | awk 'NF' | awk '!seen[$0]++'
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
td_targets=()
|
|
23
|
+
for file in "${changed_files[@]}"; do
|
|
24
|
+
case "$file" in
|
|
25
|
+
sections/td-*.liquid|blocks/td-*.liquid|blocks/_td-*.liquid|snippets/td-*.liquid)
|
|
26
|
+
if [[ -f "$file" ]]; then
|
|
27
|
+
td_targets+=("$file")
|
|
28
|
+
fi
|
|
29
|
+
;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
if [[ "${#td_targets[@]}" -eq 0 ]]; then
|
|
34
|
+
echo "td-guard: no changed TD liquid files to validate."
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
schema_default_pattern='(section|block)\.settings\.[A-Za-z0-9_]+\s*\|\s*default\s*:'
|
|
39
|
+
|
|
40
|
+
schema_default_hits="$(rg -n --pcre2 "$schema_default_pattern" "${td_targets[@]}" || true)"
|
|
41
|
+
if [[ -n "$schema_default_hits" ]]; then
|
|
42
|
+
echo "td-guard: FAIL - redundant schema fallback detected in changed TD files."
|
|
43
|
+
echo "Rule: do not use '| default:' with schema-backed section/block settings."
|
|
44
|
+
echo ""
|
|
45
|
+
echo "$schema_default_hits"
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
echo "td-guard: PASS"
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const readline = require('readline');
|
|
7
|
+
|
|
8
|
+
const TOOLKIT_ROOT = path.resolve(__dirname, '..');
|
|
9
|
+
const SKILLS_DIR = path.join(TOOLKIT_ROOT, 'skills');
|
|
10
|
+
const AGENTS_DIR = path.join(TOOLKIT_ROOT, 'agents');
|
|
11
|
+
const TARGET_ROOT = process.cwd();
|
|
12
|
+
const INSTALL_TARGETS = [
|
|
13
|
+
{ label: 'claude', root: '.claude' },
|
|
14
|
+
{ label: 'agents', root: '.agents' }
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
function copyDir(src, dest) {
|
|
18
|
+
const srcStat = fs.statSync(src);
|
|
19
|
+
fs.mkdirSync(dest, { recursive: true, mode: srcStat.mode });
|
|
20
|
+
for (const entry of fs.readdirSync(src)) {
|
|
21
|
+
const srcPath = path.join(src, entry);
|
|
22
|
+
const destPath = path.join(dest, entry);
|
|
23
|
+
const entryStat = fs.statSync(srcPath);
|
|
24
|
+
if (entryStat.isDirectory()) {
|
|
25
|
+
copyDir(srcPath, destPath);
|
|
26
|
+
} else {
|
|
27
|
+
fs.copyFileSync(srcPath, destPath);
|
|
28
|
+
fs.chmodSync(destPath, entryStat.mode);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getAvailable(dir) {
|
|
34
|
+
if (!fs.existsSync(dir)) return [];
|
|
35
|
+
return fs.readdirSync(dir).filter(d =>
|
|
36
|
+
fs.statSync(path.join(dir, d)).isDirectory()
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readFrontmatterField(mdPath, field) {
|
|
41
|
+
if (!fs.existsSync(mdPath)) return '';
|
|
42
|
+
const content = fs.readFileSync(mdPath, 'utf8');
|
|
43
|
+
const match = content.match(new RegExp(`^${field}:\\s*(.+)$`, 'm'));
|
|
44
|
+
return match ? match[1].trim() : '';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function installSkill(name) {
|
|
48
|
+
const src = path.join(SKILLS_DIR, name);
|
|
49
|
+
if (!fs.existsSync(src)) {
|
|
50
|
+
console.error(` [error] Skill "${name}" not found.`);
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
for (const target of INSTALL_TARGETS) {
|
|
54
|
+
const dest = path.join(TARGET_ROOT, target.root, 'skills', name);
|
|
55
|
+
copyDir(src, dest);
|
|
56
|
+
console.log(` [skill] ${name} -> ${target.root}/skills/${name}/`);
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function installAgent(name) {
|
|
62
|
+
const src = path.join(AGENTS_DIR, name);
|
|
63
|
+
if (!fs.existsSync(src)) {
|
|
64
|
+
console.error(` [error] Agent pack "${name}" not found.`);
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
for (const target of INSTALL_TARGETS) {
|
|
68
|
+
const dest = path.join(TARGET_ROOT, target.root, 'agents', name);
|
|
69
|
+
copyDir(src, dest);
|
|
70
|
+
console.log(` [agent] ${name} -> ${target.root}/agents/${name}/`);
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function printList() {
|
|
76
|
+
const skills = getAvailable(SKILLS_DIR);
|
|
77
|
+
const agents = getAvailable(AGENTS_DIR);
|
|
78
|
+
|
|
79
|
+
console.log('\nSkills:');
|
|
80
|
+
for (const name of skills) {
|
|
81
|
+
const desc = readFrontmatterField(path.join(SKILLS_DIR, name, 'SKILL.md'), 'description');
|
|
82
|
+
const truncated = desc.length > 72 ? desc.slice(0, 72) + '...' : desc;
|
|
83
|
+
console.log(` ${name}`);
|
|
84
|
+
if (truncated) console.log(` ${truncated}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log('\nAgent Packs:');
|
|
88
|
+
for (const name of agents) {
|
|
89
|
+
console.log(` ${name}`);
|
|
90
|
+
}
|
|
91
|
+
console.log('');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function buildMenu() {
|
|
95
|
+
const skills = getAvailable(SKILLS_DIR).map(name => ({ type: 'skill', name }));
|
|
96
|
+
const agents = getAvailable(AGENTS_DIR).map(name => ({ type: 'agent', name }));
|
|
97
|
+
return [...skills, ...agents];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function installItems(items) {
|
|
101
|
+
for (const item of items) {
|
|
102
|
+
if (item.type === 'skill') installSkill(item.name);
|
|
103
|
+
else installAgent(item.name);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function interactiveInstall() {
|
|
108
|
+
const menu = buildMenu();
|
|
109
|
+
if (menu.length === 0) {
|
|
110
|
+
console.log('No skills or agent packs available.');
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
console.log('\nAvailable (enter numbers separated by spaces, or "all"):\n');
|
|
115
|
+
menu.forEach((item, i) => {
|
|
116
|
+
const label = item.type === 'skill' ? 'skill' : 'agent';
|
|
117
|
+
console.log(` [${i + 1}] ${label}: ${item.name}`);
|
|
118
|
+
});
|
|
119
|
+
console.log('');
|
|
120
|
+
|
|
121
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
122
|
+
return new Promise(resolve => {
|
|
123
|
+
rl.question('Select items to install: ', answer => {
|
|
124
|
+
rl.close();
|
|
125
|
+
const trimmed = answer.trim().toLowerCase();
|
|
126
|
+
let selected;
|
|
127
|
+
if (trimmed === 'all') {
|
|
128
|
+
selected = menu;
|
|
129
|
+
} else {
|
|
130
|
+
const indices = trimmed.split(/\s+/).map(n => parseInt(n, 10) - 1);
|
|
131
|
+
selected = indices.filter(i => i >= 0 && i < menu.length).map(i => menu[i]);
|
|
132
|
+
}
|
|
133
|
+
console.log('');
|
|
134
|
+
installItems(selected);
|
|
135
|
+
resolve();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function resolveNames(names) {
|
|
141
|
+
const skills = getAvailable(SKILLS_DIR);
|
|
142
|
+
const agents = getAvailable(AGENTS_DIR);
|
|
143
|
+
const items = [];
|
|
144
|
+
for (const name of names) {
|
|
145
|
+
if (skills.includes(name)) {
|
|
146
|
+
items.push({ type: 'skill', name });
|
|
147
|
+
} else if (agents.includes(name)) {
|
|
148
|
+
items.push({ type: 'agent', name });
|
|
149
|
+
} else {
|
|
150
|
+
console.error(` [error] "${name}" not found as a skill or agent pack.`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return items;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function main() {
|
|
157
|
+
const args = process.argv.slice(2);
|
|
158
|
+
|
|
159
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
160
|
+
console.log(`
|
|
161
|
+
Usage:
|
|
162
|
+
npx td-ai-tools Interactive install
|
|
163
|
+
npx td-ai-tools list List available skills and agent packs
|
|
164
|
+
npx td-ai-tools install Interactive install
|
|
165
|
+
npx td-ai-tools install --all Install everything
|
|
166
|
+
npx td-ai-tools install <name...> Install specific skills or agent packs
|
|
167
|
+
|
|
168
|
+
Skills are installed to: .claude/skills/<name>/
|
|
169
|
+
.agents/skills/<name>/
|
|
170
|
+
Agent packs installed to: .claude/agents/<name>/
|
|
171
|
+
.agents/agents/<name>/
|
|
172
|
+
`);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const cmd = args[0];
|
|
177
|
+
console.log('AgentToolkit');
|
|
178
|
+
console.log('------------');
|
|
179
|
+
|
|
180
|
+
if (!cmd || cmd === 'install' && args.length === 1) {
|
|
181
|
+
await interactiveInstall();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (cmd === 'list') {
|
|
186
|
+
printList();
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (cmd === 'install') {
|
|
191
|
+
const rest = args.slice(1);
|
|
192
|
+
if (rest[0] === '--all') {
|
|
193
|
+
console.log('');
|
|
194
|
+
installItems(buildMenu());
|
|
195
|
+
} else {
|
|
196
|
+
console.log('');
|
|
197
|
+
installItems(resolveNames(rest));
|
|
198
|
+
}
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
console.error(`Unknown command: "${cmd}". Run with --help for usage.`);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
main().catch(err => {
|
|
207
|
+
console.error(err.message);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "td-ai-tools",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Install agent skills and packs into your project",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"smoke:install": "./scripts/smoke-install.sh"
|
|
7
|
+
},
|
|
8
|
+
"bin": {
|
|
9
|
+
"td-ai-tools": "bin/cli.js",
|
|
10
|
+
"agent-toolkit": "bin/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/",
|
|
14
|
+
"scripts/",
|
|
15
|
+
"skills/",
|
|
16
|
+
"agents/"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=16"
|
|
20
|
+
},
|
|
21
|
+
"keywords": ["claude", "agents", "skills", "shopify", "theory-digital"],
|
|
22
|
+
"license": "MIT"
|
|
23
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
tmpdir="$(mktemp -d "${TMPDIR:-/tmp}/agent-toolkit-smoke.XXXXXX")"
|
|
6
|
+
cache_dir="$tmpdir/npm-cache"
|
|
7
|
+
project_dir="$tmpdir/project"
|
|
8
|
+
|
|
9
|
+
cleanup() {
|
|
10
|
+
rm -rf "$tmpdir"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
trap cleanup EXIT
|
|
14
|
+
|
|
15
|
+
mkdir -p "$project_dir"
|
|
16
|
+
|
|
17
|
+
pushd "$tmpdir" >/dev/null
|
|
18
|
+
tarball="$(npm pack --quiet --cache "$cache_dir" "$repo_root")"
|
|
19
|
+
popd >/dev/null
|
|
20
|
+
|
|
21
|
+
tarball_path="$tmpdir/$tarball"
|
|
22
|
+
|
|
23
|
+
pushd "$project_dir" >/dev/null
|
|
24
|
+
npm exec --yes --cache "$cache_dir" --package "$tarball_path" td-ai-tools install pr-solver horizon-component-library
|
|
25
|
+
popd >/dev/null
|
|
26
|
+
|
|
27
|
+
required_paths=(
|
|
28
|
+
"$project_dir/.claude/skills/pr-solver/SKILL.md"
|
|
29
|
+
"$project_dir/.agents/skills/pr-solver/SKILL.md"
|
|
30
|
+
"$project_dir/.claude/agents/horizon-component-library/AGENTS.md"
|
|
31
|
+
"$project_dir/.agents/agents/horizon-component-library/AGENTS.md"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
for required_path in "${required_paths[@]}"; do
|
|
35
|
+
if [[ ! -f "$required_path" ]]; then
|
|
36
|
+
echo "Missing expected installed file: $required_path" >&2
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
required_executables=(
|
|
42
|
+
"$project_dir/.claude/agents/horizon-component-library/scripts/td-guard.sh"
|
|
43
|
+
"$project_dir/.agents/agents/horizon-component-library/scripts/td-guard.sh"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
for required_executable in "${required_executables[@]}"; do
|
|
47
|
+
if [[ ! -x "$required_executable" ]]; then
|
|
48
|
+
echo "Expected executable bit on: $required_executable" >&2
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
echo "Smoke install passed."
|
|
54
|
+
echo "Verified packaged install into:"
|
|
55
|
+
echo " $project_dir/.claude"
|
|
56
|
+
echo " $project_dir/.agents"
|
package/skills/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# skills
|
|
2
|
+
|
|
3
|
+
## Available Skills
|
|
4
|
+
- `cache-reset`: Clear and warm Laravel and Statamic caches after content/template changes.
|
|
5
|
+
- `horizon-component-migration`: Bundle Horizon components and recursive dependencies into a migration package for another theme.
|
|
6
|
+
- `pr-solver`: Resolve unresolved GitHub PR review threads with GraphQL-driven workflow.
|
|
7
|
+
- `pull-request`: Generate structured pull request descriptions for Shopify theme work.
|
|
8
|
+
- `td-js-vanilla-rules`: Theory Digital vanilla JavaScript standards for Shopify themes.
|
|
9
|
+
- `td-review`: Multi-agent PR review that produces a findings report with TD compliance scoring.
|
|
10
|
+
|
|
11
|
+
## Skill Structure Convention
|
|
12
|
+
- `<skill-name>/SKILL.md`
|
|
13
|
+
- `<skill-name>/agents/openai.yaml`
|
|
14
|
+
- `<skill-name>/scripts/*` (optional)
|
|
15
|
+
- `<skill-name>/references/*` (optional)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cache-reset
|
|
3
|
+
description: Clear and warm Laravel and Statamic caches after content or template changes.
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Use this skill when the user asks to reset cache, clear stale Statamic output, or warm cache after deployments.
|
|
8
|
+
|
|
9
|
+
Run from project root in this order:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
php artisan cache:clear
|
|
13
|
+
php artisan config:cache
|
|
14
|
+
php artisan route:cache
|
|
15
|
+
php please stache:warm
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
After running, report which commands succeeded and include any failing command output verbatim.
|