buildwright 0.0.5 → 0.0.6
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/package.json +1 -1
- package/templates/.buildwright/agents/README.md +53 -0
- package/templates/.buildwright/agents/architect.md +143 -0
- package/templates/.buildwright/agents/security-engineer.md +193 -0
- package/templates/.buildwright/agents/staff-engineer.md +134 -0
- package/templates/.buildwright/claws/README.md +89 -0
- package/templates/.buildwright/claws/TEMPLATE.md +71 -0
- package/templates/.buildwright/claws/backend.md +114 -0
- package/templates/.buildwright/claws/database.md +120 -0
- package/templates/.buildwright/claws/devops.md +175 -0
- package/templates/.buildwright/claws/frontend.md +111 -0
- package/templates/.buildwright/commands/bw-analyse.md +82 -0
- package/templates/.buildwright/commands/bw-claw.md +332 -0
- package/templates/.buildwright/commands/bw-help.md +85 -0
- package/templates/.buildwright/commands/bw-new-feature.md +504 -0
- package/templates/.buildwright/commands/bw-quick.md +245 -0
- package/templates/.buildwright/commands/bw-ship.md +288 -0
- package/templates/.buildwright/commands/bw-verify.md +108 -0
- package/templates/.buildwright/steering/naming-conventions.md +40 -0
- package/templates/.buildwright/steering/product.md +16 -0
- package/templates/.buildwright/steering/quality-gates.md +35 -0
- package/templates/.buildwright/steering/tech.md +27 -0
- package/templates/.buildwright/tasks/TEMPLATE.md +79 -0
- package/templates/.env.example +11 -1
- package/templates/.github/workflows/quality-gates.yml +150 -0
- package/templates/BUILDWRIGHT.md +99 -1
- package/templates/CLAUDE.md +150 -1
- package/templates/Makefile +82 -1
- package/templates/docs/requirements/TEMPLATE.md +33 -0
- package/templates/scripts/bump-version.sh +37 -0
- package/templates/scripts/hooks/post-checkout +24 -0
- package/templates/scripts/hooks/post-merge +14 -0
- package/templates/scripts/hooks/pre-commit +14 -0
- package/templates/scripts/install-hooks.sh +35 -0
- package/templates/scripts/sync-agents.sh +294 -0
- package/templates/scripts/validate-skill.sh +156 -0
- package/templates/.buildwright +0 -1
- package/templates/.github +0 -1
- package/templates/docs +0 -1
- package/templates/scripts +0 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# npm versions that are reserved/broken and must never be published
|
|
5
|
+
BLOCKED_VERSIONS=("1.0.0" "1.0.1" "1.0.2")
|
|
6
|
+
|
|
7
|
+
BUMP="${1:-patch}" # patch | minor | major
|
|
8
|
+
|
|
9
|
+
# 1. Bump cli/package.json (no git tag yet)
|
|
10
|
+
cd cli
|
|
11
|
+
npm version "$BUMP" --no-git-tag-version
|
|
12
|
+
NEW_VERSION=$(node -p "require('./package.json').version")
|
|
13
|
+
|
|
14
|
+
# 2. Check if new version is blocked — if so, keep patching until clear
|
|
15
|
+
while printf '%s\n' "${BLOCKED_VERSIONS[@]}" | grep -qx "$NEW_VERSION"; do
|
|
16
|
+
echo "⚠️ Version $NEW_VERSION is reserved on npm — skipping to next patch..."
|
|
17
|
+
npm version patch --no-git-tag-version
|
|
18
|
+
NEW_VERSION=$(node -p "require('./package.json').version")
|
|
19
|
+
done
|
|
20
|
+
cd ..
|
|
21
|
+
|
|
22
|
+
# 3. Update SKILL.md frontmatter
|
|
23
|
+
sed -i.bak "s/^ version: \".*\"/ version: \"$NEW_VERSION\"/" SKILL.md
|
|
24
|
+
rm -f SKILL.md.bak
|
|
25
|
+
|
|
26
|
+
# 4. Sync dist/
|
|
27
|
+
make sync
|
|
28
|
+
|
|
29
|
+
echo ""
|
|
30
|
+
echo "✓ Bumped to v$NEW_VERSION"
|
|
31
|
+
echo ""
|
|
32
|
+
echo "Next steps:"
|
|
33
|
+
echo " git add cli/package.json SKILL.md"
|
|
34
|
+
echo " git commit -m \"chore: bump version to $NEW_VERSION\""
|
|
35
|
+
echo " git tag v$NEW_VERSION"
|
|
36
|
+
echo " cd cli && npm publish"
|
|
37
|
+
echo " make dist # then upload dist/buildwright/ to clawhub.ai"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Buildwright post-checkout hook
|
|
3
|
+
# Runs after git checkout.
|
|
4
|
+
# $1 = previous HEAD, $2 = new HEAD, $3 = 1 (branch switch) or 0 (file checkout)
|
|
5
|
+
# Only acts on branch switches ($3 == 1) where .buildwright/ content differs.
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
PREV_HEAD="$1"
|
|
10
|
+
NEW_HEAD="$2"
|
|
11
|
+
BRANCH_SWITCH="$3"
|
|
12
|
+
|
|
13
|
+
# Skip file-level checkouts
|
|
14
|
+
if [ "$BRANCH_SWITCH" != "1" ]; then
|
|
15
|
+
exit 0
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
if git diff --name-only "$PREV_HEAD" "$NEW_HEAD" 2>/dev/null | grep -q '^\.buildwright/'; then
|
|
19
|
+
echo "Buildwright: .buildwright/ differs between branches — running make sync..."
|
|
20
|
+
make sync
|
|
21
|
+
echo "Buildwright: sync complete."
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
exit 0
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Buildwright post-merge hook
|
|
3
|
+
# Runs after git pull / git merge.
|
|
4
|
+
# If any file under .buildwright/ changed in the merge, run make sync automatically.
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
if git diff --name-only ORIG_HEAD HEAD 2>/dev/null | grep -q '^\.buildwright/'; then
|
|
9
|
+
echo "Buildwright: .buildwright/ changed in merge — running make sync..."
|
|
10
|
+
make sync
|
|
11
|
+
echo "Buildwright: sync complete."
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
exit 0
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Buildwright pre-commit hook
|
|
3
|
+
# If any staged file is under .buildwright/, run make sync before committing.
|
|
4
|
+
# Never blocks the commit — sync is a convenience to keep generated files current.
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
if git diff --cached --name-only | grep -q '^\.buildwright/'; then
|
|
9
|
+
echo "Buildwright: .buildwright/ changes detected — running make sync..."
|
|
10
|
+
make sync
|
|
11
|
+
echo "Buildwright: sync complete."
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
exit 0
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Buildwright hook installer
|
|
3
|
+
# Copies scripts/hooks/* to .git/hooks/ and makes them executable.
|
|
4
|
+
# Idempotent — safe to run multiple times.
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
if ! git rev-parse --show-toplevel >/dev/null 2>&1; then
|
|
9
|
+
echo "Not inside a git repository — skipping hook installation."
|
|
10
|
+
echo "Run 'git init && make install-hooks' to enable auto-sync hooks."
|
|
11
|
+
exit 0
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
HOOKS_SRC="$(cd "$(dirname "$0")/hooks" && pwd)"
|
|
15
|
+
HOOKS_DEST="$(git rev-parse --show-toplevel)/.git/hooks"
|
|
16
|
+
|
|
17
|
+
if [ ! -d "$HOOKS_SRC" ]; then
|
|
18
|
+
echo "Error: hooks source directory not found at $HOOKS_SRC" >&2
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
if [ ! -d "$HOOKS_DEST" ]; then
|
|
23
|
+
echo "Error: .git/hooks directory not found. Are you inside a git repo?" >&2
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
for hook in "$HOOKS_SRC"/*; do
|
|
28
|
+
name="$(basename "$hook")"
|
|
29
|
+
dest="$HOOKS_DEST/$name"
|
|
30
|
+
cp "$hook" "$dest"
|
|
31
|
+
chmod +x "$dest"
|
|
32
|
+
echo " Installed: .git/hooks/$name"
|
|
33
|
+
done
|
|
34
|
+
|
|
35
|
+
echo "Buildwright hooks installed successfully."
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Sync agent configurations across Claude Code, OpenCode, Cursor, and OpenClaw
|
|
3
|
+
#
|
|
4
|
+
# Source of truth: .buildwright/ (tool-agnostic canonical config)
|
|
5
|
+
# Generates:
|
|
6
|
+
# .claude/commands/ ← from .buildwright/commands/ (paths rewritten to .claude/)
|
|
7
|
+
# .claude/agents/ ← from .buildwright/agents/
|
|
8
|
+
# .claude/claws/ ← from .buildwright/claws/
|
|
9
|
+
# .claude/steering/ ← from .buildwright/steering/
|
|
10
|
+
# .claude/tasks/ ← from .buildwright/tasks/
|
|
11
|
+
# .opencode/commands/ ← from .buildwright/commands/ (paths rewritten to .opencode/)
|
|
12
|
+
# .opencode/agents/ ← from .buildwright/agents/
|
|
13
|
+
# .opencode/claws/ ← from .buildwright/claws/
|
|
14
|
+
# .opencode/steering/ ← from .buildwright/steering/
|
|
15
|
+
# .cursor/rules/steering/ ← .mdc files with alwaysApply: true
|
|
16
|
+
# .cursor/rules/commands/ ← .mdc files with alwaysApply: false
|
|
17
|
+
# .cursor/rules/agents/ ← .mdc files with alwaysApply: false
|
|
18
|
+
# .cursor/rules/claws/ ← .mdc files with alwaysApply: false
|
|
19
|
+
# AGENTS.md ← CLAUDE.md with OpenCode header prepended
|
|
20
|
+
# dist/buildwright/ ← SKILL.md packaged for ClawHub
|
|
21
|
+
#
|
|
22
|
+
# Usage: scripts/sync-agents.sh [--check]
|
|
23
|
+
# --check: Verify sync without modifying files (exit 1 if out of sync)
|
|
24
|
+
|
|
25
|
+
set -e
|
|
26
|
+
|
|
27
|
+
CHECK_ONLY=false
|
|
28
|
+
if [ "$1" = "--check" ]; then
|
|
29
|
+
CHECK_ONLY=true
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
33
|
+
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
34
|
+
cd "$ROOT_DIR"
|
|
35
|
+
|
|
36
|
+
# ============================================================================
|
|
37
|
+
# Helpers
|
|
38
|
+
# ============================================================================
|
|
39
|
+
|
|
40
|
+
# sync_dir SRC DST [REWRITE_FROM REWRITE_TO]
|
|
41
|
+
# Copies directory, optionally rewriting path references in .md files
|
|
42
|
+
sync_dir() {
|
|
43
|
+
local src="$1"
|
|
44
|
+
local dst="$2"
|
|
45
|
+
local rewrite_from="${3:-}"
|
|
46
|
+
local rewrite_to="${4:-}"
|
|
47
|
+
|
|
48
|
+
if [ ! -d "$src" ]; then
|
|
49
|
+
return
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
if [ "$CHECK_ONLY" = true ]; then
|
|
53
|
+
if [ ! -d "$dst" ]; then
|
|
54
|
+
echo "MISSING: $dst (should be synced from $src)"
|
|
55
|
+
SYNC_NEEDED=true
|
|
56
|
+
return
|
|
57
|
+
fi
|
|
58
|
+
# Generate expected output to temp dir and compare
|
|
59
|
+
local tmpdir
|
|
60
|
+
tmpdir=$(mktemp -d)
|
|
61
|
+
cp -R "$src/"* "$tmpdir/" 2>/dev/null || true
|
|
62
|
+
if [ -n "$rewrite_from" ] && [ -n "$rewrite_to" ]; then
|
|
63
|
+
find "$tmpdir" -name "*.md" -exec sed -i "s|$rewrite_from|$rewrite_to|g" {} + 2>/dev/null || true
|
|
64
|
+
fi
|
|
65
|
+
if ! diff -rq "$tmpdir" "$dst" > /dev/null 2>&1; then
|
|
66
|
+
echo "OUT OF SYNC: $dst differs from $src"
|
|
67
|
+
SYNC_NEEDED=true
|
|
68
|
+
fi
|
|
69
|
+
rm -rf "$tmpdir"
|
|
70
|
+
else
|
|
71
|
+
mkdir -p "$dst"
|
|
72
|
+
rsync -a --delete "$src/" "$dst/" 2>/dev/null || (rm -rf "$dst"/* && cp -R "$src/"* "$dst/")
|
|
73
|
+
# Rewrite path references for tool-specific copies
|
|
74
|
+
if [ -n "$rewrite_from" ] && [ -n "$rewrite_to" ]; then
|
|
75
|
+
find "$dst" -name "*.md" -exec sed -i "s|$rewrite_from|$rewrite_to|g" {} + 2>/dev/null || true
|
|
76
|
+
fi
|
|
77
|
+
echo " synced $src → $dst"
|
|
78
|
+
fi
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# Global vars used by set_cursor_frontmatter / sync_cursor_dir
|
|
82
|
+
CURSOR_ALWAYS_APPLY=""
|
|
83
|
+
CURSOR_DESCRIPTION=""
|
|
84
|
+
|
|
85
|
+
# set_cursor_frontmatter PRESET FILENAME
|
|
86
|
+
# Sets CURSOR_ALWAYS_APPLY and CURSOR_DESCRIPTION globals for the given file.
|
|
87
|
+
set_cursor_frontmatter() {
|
|
88
|
+
local preset="$1"
|
|
89
|
+
local filename="$2"
|
|
90
|
+
|
|
91
|
+
case "$preset" in
|
|
92
|
+
steering|codebase) CURSOR_ALWAYS_APPLY="true" ;;
|
|
93
|
+
*) CURSOR_ALWAYS_APPLY="false" ;;
|
|
94
|
+
esac
|
|
95
|
+
|
|
96
|
+
case "${preset}:${filename}" in
|
|
97
|
+
steering:product) CURSOR_DESCRIPTION="Buildwright product context: goals, features, user personas, business constraints" ;;
|
|
98
|
+
steering:tech) CURSOR_DESCRIPTION="Buildwright technical context: stack, commands, architecture patterns" ;;
|
|
99
|
+
steering:quality-gates) CURSOR_DESCRIPTION="Buildwright quality gates: automated checks that must pass before merge" ;;
|
|
100
|
+
steering:naming-conventions) CURSOR_DESCRIPTION="Buildwright naming conventions: canonical field and endpoint registry" ;;
|
|
101
|
+
codebase:STACK) CURSOR_DESCRIPTION="Codebase tech stack: languages, runtime, frameworks, dependencies, integrations" ;;
|
|
102
|
+
codebase:ARCHITECTURE) CURSOR_DESCRIPTION="Codebase architecture: layers, data flow, entry points, directory structure" ;;
|
|
103
|
+
codebase:CONVENTIONS) CURSOR_DESCRIPTION="Codebase conventions: naming, code style, imports, error handling, testing patterns" ;;
|
|
104
|
+
codebase:CONCERNS) CURSOR_DESCRIPTION="Codebase concerns: tech debt, bugs, security risks, performance bottlenecks" ;;
|
|
105
|
+
command:bw-new-feature) CURSOR_DESCRIPTION="Buildwright bw-new-feature: full pipeline for new features with spec and TDD" ;;
|
|
106
|
+
command:bw-claw) CURSOR_DESCRIPTION="Buildwright bw-claw: multi-agent cross-domain feature development" ;;
|
|
107
|
+
command:bw-quick) CURSOR_DESCRIPTION="Buildwright bw-quick: fast path for bug fixes and small tasks" ;;
|
|
108
|
+
command:bw-ship) CURSOR_DESCRIPTION="Buildwright bw-ship: quality pipeline then commit, push, and PR" ;;
|
|
109
|
+
command:bw-verify) CURSOR_DESCRIPTION="Buildwright bw-verify: quick quality checks (typecheck, lint, test, build)" ;;
|
|
110
|
+
command:bw-help) CURSOR_DESCRIPTION="Buildwright bw-help: list all available Buildwright commands" ;;
|
|
111
|
+
command:bw-analyse) CURSOR_DESCRIPTION="Buildwright bw-analyse: analyse codebase, write structured docs to .buildwright/codebase/, update tech.md" ;;
|
|
112
|
+
agent:architect) CURSOR_DESCRIPTION="Buildwright Architect agent persona" ;;
|
|
113
|
+
agent:staff-engineer) CURSOR_DESCRIPTION="Buildwright Staff Engineer agent persona" ;;
|
|
114
|
+
agent:security-engineer) CURSOR_DESCRIPTION="Buildwright Security Engineer agent persona" ;;
|
|
115
|
+
claw:frontend) CURSOR_DESCRIPTION="Buildwright Frontend domain specialist claw" ;;
|
|
116
|
+
claw:backend) CURSOR_DESCRIPTION="Buildwright Backend domain specialist claw" ;;
|
|
117
|
+
claw:database) CURSOR_DESCRIPTION="Buildwright Database domain specialist claw" ;;
|
|
118
|
+
claw:devops) CURSOR_DESCRIPTION="Buildwright DevOps domain specialist claw" ;;
|
|
119
|
+
*) CURSOR_DESCRIPTION="Buildwright ${preset}: ${filename}" ;;
|
|
120
|
+
esac
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# sync_cursor_dir SRC DST_SUBDIR PRESET
|
|
124
|
+
# Converts .md files in SRC to .mdc files in .cursor/rules/DST_SUBDIR,
|
|
125
|
+
# prepending YAML frontmatter and rewriting @.buildwright/ → @.cursor/rules/.
|
|
126
|
+
# Skips README and TEMPLATE files.
|
|
127
|
+
sync_cursor_dir() {
|
|
128
|
+
local src="$1"
|
|
129
|
+
local dst_subdir="$2"
|
|
130
|
+
local preset="$3"
|
|
131
|
+
local dst=".cursor/rules/$dst_subdir"
|
|
132
|
+
|
|
133
|
+
if [ ! -d "$src" ]; then
|
|
134
|
+
return
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
if [ "$CHECK_ONLY" = false ]; then
|
|
138
|
+
mkdir -p "$dst"
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
for src_file in "$src"/*.md; do
|
|
142
|
+
[ -f "$src_file" ] || continue
|
|
143
|
+
local filename
|
|
144
|
+
filename=$(basename "$src_file" .md)
|
|
145
|
+
|
|
146
|
+
# Skip meta files — they're internal docs, not rules
|
|
147
|
+
case "$filename" in
|
|
148
|
+
README|TEMPLATE) continue ;;
|
|
149
|
+
esac
|
|
150
|
+
|
|
151
|
+
local dst_file="$dst/$filename.mdc"
|
|
152
|
+
set_cursor_frontmatter "$preset" "$filename"
|
|
153
|
+
|
|
154
|
+
if [ "$CHECK_ONLY" = true ]; then
|
|
155
|
+
if [ ! -f "$dst_file" ]; then
|
|
156
|
+
echo "MISSING: $dst_file"
|
|
157
|
+
SYNC_NEEDED=true
|
|
158
|
+
else
|
|
159
|
+
local tmpfile
|
|
160
|
+
tmpfile=$(mktemp)
|
|
161
|
+
{
|
|
162
|
+
printf '%s\n' "---"
|
|
163
|
+
printf 'description: "%s"\n' "$CURSOR_DESCRIPTION"
|
|
164
|
+
printf '%s\n' "globs: []"
|
|
165
|
+
printf 'alwaysApply: %s\n' "$CURSOR_ALWAYS_APPLY"
|
|
166
|
+
printf '%s\n' "---"
|
|
167
|
+
sed 's|@\.buildwright/|@.cursor/rules/|g' "$src_file"
|
|
168
|
+
} > "$tmpfile"
|
|
169
|
+
if ! diff -q "$dst_file" "$tmpfile" > /dev/null 2>&1; then
|
|
170
|
+
echo "OUT OF SYNC: $dst_file"
|
|
171
|
+
SYNC_NEEDED=true
|
|
172
|
+
fi
|
|
173
|
+
rm -f "$tmpfile"
|
|
174
|
+
fi
|
|
175
|
+
else
|
|
176
|
+
{
|
|
177
|
+
printf '%s\n' "---"
|
|
178
|
+
printf 'description: "%s"\n' "$CURSOR_DESCRIPTION"
|
|
179
|
+
printf '%s\n' "globs: []"
|
|
180
|
+
printf 'alwaysApply: %s\n' "$CURSOR_ALWAYS_APPLY"
|
|
181
|
+
printf '%s\n' "---"
|
|
182
|
+
sed 's|@\.buildwright/|@.cursor/rules/|g' "$src_file"
|
|
183
|
+
} > "$dst_file"
|
|
184
|
+
fi
|
|
185
|
+
done
|
|
186
|
+
|
|
187
|
+
if [ "$CHECK_ONLY" = false ]; then
|
|
188
|
+
echo " synced $src → $dst (*.mdc)"
|
|
189
|
+
fi
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
# ============================================================================
|
|
193
|
+
# 1. .buildwright/ → .claude/ (rewrite .buildwright/ → .claude/)
|
|
194
|
+
# ============================================================================
|
|
195
|
+
|
|
196
|
+
if [ "$CHECK_ONLY" = false ]; then
|
|
197
|
+
echo "Syncing agent configurations..."
|
|
198
|
+
echo ""
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
SYNC_NEEDED=false
|
|
202
|
+
|
|
203
|
+
sync_dir ".buildwright/commands" ".claude/commands" ".buildwright/" ".claude/"
|
|
204
|
+
sync_dir ".buildwright/agents" ".claude/agents" ".buildwright/" ".claude/"
|
|
205
|
+
sync_dir ".buildwright/claws" ".claude/claws" ".buildwright/" ".claude/"
|
|
206
|
+
sync_dir ".buildwright/steering" ".claude/steering"
|
|
207
|
+
sync_dir ".buildwright/codebase" ".claude/codebase"
|
|
208
|
+
sync_dir ".buildwright/tasks" ".claude/tasks"
|
|
209
|
+
|
|
210
|
+
# ============================================================================
|
|
211
|
+
# 2. .buildwright/ → .opencode/ (rewrite .buildwright/ → .opencode/)
|
|
212
|
+
# ============================================================================
|
|
213
|
+
|
|
214
|
+
sync_dir ".buildwright/commands" ".opencode/commands" ".buildwright/" ".opencode/"
|
|
215
|
+
sync_dir ".buildwright/agents" ".opencode/agents" ".buildwright/" ".opencode/"
|
|
216
|
+
sync_dir ".buildwright/claws" ".opencode/claws" ".buildwright/" ".opencode/"
|
|
217
|
+
sync_dir ".buildwright/steering" ".opencode/steering"
|
|
218
|
+
sync_dir ".buildwright/codebase" ".opencode/codebase"
|
|
219
|
+
|
|
220
|
+
# ============================================================================
|
|
221
|
+
# 3. CLAUDE.md → AGENTS.md
|
|
222
|
+
# ============================================================================
|
|
223
|
+
|
|
224
|
+
generate_agents_md() {
|
|
225
|
+
local target="$1"
|
|
226
|
+
printf '%s\n' "---" \
|
|
227
|
+
"# OpenCode agent instructions" \
|
|
228
|
+
"# Auto-generated from CLAUDE.md — do not edit directly" \
|
|
229
|
+
"# Run: scripts/sync-agents.sh to regenerate" \
|
|
230
|
+
"---" \
|
|
231
|
+
"" > "$target"
|
|
232
|
+
cat CLAUDE.md >> "$target"
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if [ "$CHECK_ONLY" = true ]; then
|
|
236
|
+
if [ ! -f "AGENTS.md" ]; then
|
|
237
|
+
echo "MISSING: AGENTS.md (should be generated from CLAUDE.md)"
|
|
238
|
+
SYNC_NEEDED=true
|
|
239
|
+
else
|
|
240
|
+
TMPFILE=$(mktemp)
|
|
241
|
+
generate_agents_md "$TMPFILE"
|
|
242
|
+
if ! diff -q "AGENTS.md" "$TMPFILE" > /dev/null 2>&1; then
|
|
243
|
+
echo "OUT OF SYNC: AGENTS.md differs from CLAUDE.md"
|
|
244
|
+
SYNC_NEEDED=true
|
|
245
|
+
fi
|
|
246
|
+
rm -f "$TMPFILE"
|
|
247
|
+
fi
|
|
248
|
+
else
|
|
249
|
+
generate_agents_md "AGENTS.md"
|
|
250
|
+
echo " generated AGENTS.md from CLAUDE.md"
|
|
251
|
+
fi
|
|
252
|
+
|
|
253
|
+
# ============================================================================
|
|
254
|
+
# 4. .buildwright/ → .cursor/rules/ (convert to .mdc with frontmatter)
|
|
255
|
+
# ============================================================================
|
|
256
|
+
|
|
257
|
+
sync_cursor_dir ".buildwright/steering" "steering" "steering"
|
|
258
|
+
sync_cursor_dir ".buildwright/codebase" "codebase" "codebase"
|
|
259
|
+
sync_cursor_dir ".buildwright/commands" "commands" "command"
|
|
260
|
+
sync_cursor_dir ".buildwright/agents" "agents" "agent"
|
|
261
|
+
sync_cursor_dir ".buildwright/claws" "claws" "claw"
|
|
262
|
+
|
|
263
|
+
# ============================================================================
|
|
264
|
+
# 5. Package for ClawHub (dist/)
|
|
265
|
+
# ============================================================================
|
|
266
|
+
|
|
267
|
+
if [ "$CHECK_ONLY" = false ] && [ -f "SKILL.md" ]; then
|
|
268
|
+
mkdir -p dist/buildwright
|
|
269
|
+
cp SKILL.md dist/buildwright/
|
|
270
|
+
echo " packaged dist/buildwright/SKILL.md for ClawHub"
|
|
271
|
+
fi
|
|
272
|
+
|
|
273
|
+
# ============================================================================
|
|
274
|
+
# Result
|
|
275
|
+
# ============================================================================
|
|
276
|
+
|
|
277
|
+
if [ "$CHECK_ONLY" = true ]; then
|
|
278
|
+
if [ "$SYNC_NEEDED" = true ]; then
|
|
279
|
+
echo ""
|
|
280
|
+
echo "Run 'scripts/sync-agents.sh' to fix."
|
|
281
|
+
exit 1
|
|
282
|
+
else
|
|
283
|
+
echo "All synced."
|
|
284
|
+
exit 0
|
|
285
|
+
fi
|
|
286
|
+
else
|
|
287
|
+
echo ""
|
|
288
|
+
echo "Sync complete. Source of truth: .buildwright/"
|
|
289
|
+
echo " .buildwright/ → .claude/ (paths rewritten)"
|
|
290
|
+
echo " .buildwright/ → .opencode/ (paths rewritten)"
|
|
291
|
+
echo " .buildwright/ → .cursor/rules/ (.mdc with frontmatter)"
|
|
292
|
+
echo " CLAUDE.md → AGENTS.md"
|
|
293
|
+
echo " SKILL.md → dist/buildwright/SKILL.md"
|
|
294
|
+
fi
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Validate SKILL.md against the Agent Skills specification (agentskills.io)
|
|
3
|
+
#
|
|
4
|
+
# Checks:
|
|
5
|
+
# 1. YAML frontmatter exists and is valid
|
|
6
|
+
# 2. Required fields: name, description
|
|
7
|
+
# 3. Recommended fields: license, compatibility, metadata
|
|
8
|
+
# 4. File size under 500 lines (best practice)
|
|
9
|
+
#
|
|
10
|
+
# Usage: scripts/validate-skill.sh [path/to/SKILL.md]
|
|
11
|
+
|
|
12
|
+
set -e
|
|
13
|
+
|
|
14
|
+
SKILL_FILE="${1:-SKILL.md}"
|
|
15
|
+
|
|
16
|
+
if [ ! -f "$SKILL_FILE" ]; then
|
|
17
|
+
echo "ERROR: $SKILL_FILE not found"
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
ERRORS=0
|
|
22
|
+
WARNINGS=0
|
|
23
|
+
|
|
24
|
+
echo "Validating $SKILL_FILE against Agent Skills spec..."
|
|
25
|
+
echo ""
|
|
26
|
+
|
|
27
|
+
# ============================================================================
|
|
28
|
+
# Check 1: YAML frontmatter exists
|
|
29
|
+
# ============================================================================
|
|
30
|
+
|
|
31
|
+
if ! head -1 "$SKILL_FILE" | grep -q "^---$"; then
|
|
32
|
+
echo "ERROR: Missing YAML frontmatter (file must start with ---)"
|
|
33
|
+
ERRORS=$((ERRORS + 1))
|
|
34
|
+
else
|
|
35
|
+
echo " [PASS] YAML frontmatter exists"
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Check frontmatter closing (count lines that are exactly ---)
|
|
39
|
+
DELIM_COUNT=$(grep -c "^---$" "$SKILL_FILE" || true)
|
|
40
|
+
if [ "$DELIM_COUNT" -lt 2 ]; then
|
|
41
|
+
echo "ERROR: YAML frontmatter not properly closed (missing second ---)"
|
|
42
|
+
ERRORS=$((ERRORS + 1))
|
|
43
|
+
else
|
|
44
|
+
echo " [PASS] YAML frontmatter properly closed"
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# ============================================================================
|
|
48
|
+
# Check 2: Required fields
|
|
49
|
+
# ============================================================================
|
|
50
|
+
|
|
51
|
+
# Extract frontmatter
|
|
52
|
+
FRONTMATTER=$(awk '/^---$/{n++; next} n==1{print} n==2{exit}' "$SKILL_FILE")
|
|
53
|
+
|
|
54
|
+
if echo "$FRONTMATTER" | grep -q "^name:"; then
|
|
55
|
+
echo " [PASS] Required field: name"
|
|
56
|
+
else
|
|
57
|
+
echo "ERROR: Missing required field: name"
|
|
58
|
+
ERRORS=$((ERRORS + 1))
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
if echo "$FRONTMATTER" | grep -q "^description:"; then
|
|
62
|
+
echo " [PASS] Required field: description"
|
|
63
|
+
else
|
|
64
|
+
echo "ERROR: Missing required field: description"
|
|
65
|
+
ERRORS=$((ERRORS + 1))
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# ============================================================================
|
|
69
|
+
# Check 3: Recommended fields
|
|
70
|
+
# ============================================================================
|
|
71
|
+
|
|
72
|
+
if echo "$FRONTMATTER" | grep -q "^license:"; then
|
|
73
|
+
echo " [PASS] Recommended field: license"
|
|
74
|
+
else
|
|
75
|
+
echo " [WARN] Missing recommended field: license"
|
|
76
|
+
WARNINGS=$((WARNINGS + 1))
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
if echo "$FRONTMATTER" | grep -q "^compatibility:"; then
|
|
80
|
+
echo " [PASS] Recommended field: compatibility"
|
|
81
|
+
else
|
|
82
|
+
echo " [WARN] Missing recommended field: compatibility"
|
|
83
|
+
WARNINGS=$((WARNINGS + 1))
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
if echo "$FRONTMATTER" | grep -q "^metadata:"; then
|
|
87
|
+
echo " [PASS] Recommended field: metadata"
|
|
88
|
+
else
|
|
89
|
+
echo " [WARN] Missing recommended field: metadata"
|
|
90
|
+
WARNINGS=$((WARNINGS + 1))
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# ============================================================================
|
|
94
|
+
# Check 4: Metadata sub-fields
|
|
95
|
+
# ============================================================================
|
|
96
|
+
|
|
97
|
+
if echo "$FRONTMATTER" | grep -q "version:"; then
|
|
98
|
+
echo " [PASS] Metadata: version"
|
|
99
|
+
else
|
|
100
|
+
echo " [WARN] Missing metadata: version"
|
|
101
|
+
WARNINGS=$((WARNINGS + 1))
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
if echo "$FRONTMATTER" | grep -q "author:"; then
|
|
105
|
+
echo " [PASS] Metadata: author"
|
|
106
|
+
else
|
|
107
|
+
echo " [WARN] Missing metadata: author"
|
|
108
|
+
WARNINGS=$((WARNINGS + 1))
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
if echo "$FRONTMATTER" | grep -q "tags:"; then
|
|
112
|
+
echo " [PASS] Metadata: tags (improves discoverability)"
|
|
113
|
+
else
|
|
114
|
+
echo " [WARN] Missing metadata: tags (recommended for ClawHub/marketplace discoverability)"
|
|
115
|
+
WARNINGS=$((WARNINGS + 1))
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
# ============================================================================
|
|
119
|
+
# Check 5: File size
|
|
120
|
+
# ============================================================================
|
|
121
|
+
|
|
122
|
+
LINE_COUNT=$(wc -l < "$SKILL_FILE")
|
|
123
|
+
if [ "$LINE_COUNT" -gt 500 ]; then
|
|
124
|
+
echo " [WARN] SKILL.md is $LINE_COUNT lines (recommended: under 500)"
|
|
125
|
+
WARNINGS=$((WARNINGS + 1))
|
|
126
|
+
else
|
|
127
|
+
echo " [PASS] File size: $LINE_COUNT lines (under 500)"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# ============================================================================
|
|
131
|
+
# Check 6: Markdown body exists after frontmatter
|
|
132
|
+
# ============================================================================
|
|
133
|
+
|
|
134
|
+
BODY_LINES=$(awk '/^---$/{n++; next} n>=2{print}' "$SKILL_FILE" | grep -c "." || true)
|
|
135
|
+
if [ "$BODY_LINES" -lt 5 ]; then
|
|
136
|
+
echo " [WARN] Markdown body is very short ($BODY_LINES non-empty lines)"
|
|
137
|
+
WARNINGS=$((WARNINGS + 1))
|
|
138
|
+
else
|
|
139
|
+
echo " [PASS] Markdown body: $BODY_LINES non-empty lines"
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# ============================================================================
|
|
143
|
+
# Result
|
|
144
|
+
# ============================================================================
|
|
145
|
+
|
|
146
|
+
echo ""
|
|
147
|
+
echo "═══════════════════════════════════════"
|
|
148
|
+
if [ "$ERRORS" -gt 0 ]; then
|
|
149
|
+
echo " FAILED: $ERRORS error(s), $WARNINGS warning(s)"
|
|
150
|
+
echo "═══════════════════════════════════════"
|
|
151
|
+
exit 1
|
|
152
|
+
else
|
|
153
|
+
echo " PASSED: 0 errors, $WARNINGS warning(s)"
|
|
154
|
+
echo "═══════════════════════════════════════"
|
|
155
|
+
exit 0
|
|
156
|
+
fi
|
package/templates/.buildwright
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
../../.buildwright
|
package/templates/.github
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
../../.github
|
package/templates/docs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
../../docs
|
package/templates/scripts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
../../scripts
|