-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathpack_skills.sh
More file actions
181 lines (155 loc) · 6.21 KB
/
pack_skills.sh
File metadata and controls
181 lines (155 loc) · 6.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#!/usr/bin/env bash
# pack_skills.sh — Packages the monorepo's shared skills into a self-contained ZIP
# Usage: bash pack_skills.sh [--name <name>] [--skill <skill-name>] [--lang <code>]
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MONOREPO_ROOT="$SCRIPT_DIR"
SOURCE_DATE_EPOCH=$(git -C "$SCRIPT_DIR" log -1 --format=%ct 2>/dev/null || echo 0)
export SOURCE_DATE_EPOCH
# ---------------------------------------------------------------------------
# Phase 0 — Parsing and validation
# ---------------------------------------------------------------------------
PACK_NAME=""
SKILL_FILTER=""
LANG_CODE=""
while [[ $# -gt 0 ]]; do
case "$1" in
--name) PACK_NAME="$2"; shift 2 ;;
--skill) SKILL_FILTER="$2"; shift 2 ;;
--lang) LANG_CODE="$2"; shift 2 ;;
*) echo "ERROR: unknown argument: $1" >&2; echo "Usage: bash pack_skills.sh [--name <name>] [--skill <skill-name>] [--lang <code>]" >&2; exit 1 ;;
esac
done
# Language resolution
_LANG_TMPDIR=""
if [[ -n "$LANG_CODE" && "$LANG_CODE" != "en" ]]; then
_LANG_TMPDIR=$(mktemp -d "/tmp/pack-lang-${LANG_CODE}-XXXXXX")
bash "$MONOREPO_ROOT/bin/resolve-lang.sh" --lang "$LANG_CODE" --source "$MONOREPO_ROOT" --target "$_LANG_TMPDIR"
MONOREPO_ROOT="$_LANG_TMPDIR"
fi
trap '[[ -n "$_LANG_TMPDIR" ]] && rm -rf "$_LANG_TMPDIR"' EXIT
if [[ -n "$SKILL_FILTER" ]]; then
PACK_NAME="${PACK_NAME:-$SKILL_FILTER}"
else
PACK_NAME="${PACK_NAME:-skills}"
fi
if [[ ! -d "$MONOREPO_ROOT/skills" ]]; then
echo "ERROR: skills/ directory not found in $MONOREPO_ROOT" >&2
exit 1
fi
if [[ -n "$SKILL_FILTER" && ! -d "$MONOREPO_ROOT/skills/$SKILL_FILTER" ]]; then
echo "ERROR: skill '$SKILL_FILTER' not found in skills/" >&2
exit 1
fi
if [[ -n "$SKILL_FILTER" ]]; then
echo "==> Packaging individual skill '$SKILL_FILTER' as '$PACK_NAME'"
else
echo "==> Packaging skills as '$PACK_NAME'"
fi
# ---------------------------------------------------------------------------
# Phase 1 — Staging
# ---------------------------------------------------------------------------
STAGING=$(mktemp -d)
trap 'rm -rf "$STAGING"' EXIT
# ---------------------------------------------------------------------------
# Phase 2 — Function to process a skill + iterate
# ---------------------------------------------------------------------------
N_SKILLS=0
N_GUIDES=0
_pack_one_skill() {
local skill_dir="$1"
local dest_dir="$2"
# Copy skill content
mkdir -p "$dest_dir"
cp -r "$skill_dir"/. "$dest_dir/"
# Read `guides` manifest and copy guides to the skill root
if [[ -f "$skill_dir/guides" ]]; then
while IFS= read -r guide || [[ -n "$guide" ]]; do
[[ -z "$guide" || "$guide" == \#* ]] && continue
guide_src="$MONOREPO_ROOT/guides/$guide"
if [[ -d "$guide_src" ]]; then
cp -r "$guide_src" "$dest_dir/$guide"
N_GUIDES=$((N_GUIDES + 1))
elif [[ -f "$guide_src" ]]; then
cp "$guide_src" "$dest_dir/$guide"
N_GUIDES=$((N_GUIDES + 1))
else
echo " WARN: guide '$guide' not found in $guide_src — skipped" >&2
fi
done < "$skill_dir/guides"
fi
# Remove `guides` manifest from output
rm -f "$dest_dir/guides"
N_SKILLS=$((N_SKILLS + 1))
}
if [[ -n "$SKILL_FILTER" ]]; then
# Individual mode: files directly at the staging root
_pack_one_skill "$MONOREPO_ROOT/skills/$SKILL_FILTER" "$STAGING"
else
# Bulk mode: each skill in its own subfolder
for skill_dir in "$MONOREPO_ROOT/skills"/*/; do
[[ -d "$skill_dir" ]] || continue
skill_name="$(basename "$skill_dir")"
_pack_one_skill "$skill_dir" "$STAGING/$skill_name"
done
fi
echo " $N_SKILLS skill(s), $N_GUIDES guide(s) copied"
# ---------------------------------------------------------------------------
# Phase 3 — Path substitutions in .md and .txt
# ---------------------------------------------------------------------------
find "$STAGING" \
-type f \( -name '*.md' -o -name '*.txt' \) \
-exec sed -i 's|guides/||g' {} \;
echo " Path substitutions applied"
# ---------------------------------------------------------------------------
# Phase 3b — Non-runtime sweep (tests, caches, editor junk) BEFORE zipping
# ---------------------------------------------------------------------------
bash "$SCRIPT_DIR/bin/sweep-nonruntime.sh" "$STAGING"
# ---------------------------------------------------------------------------
# Phase 4 — Generate ZIP
# ---------------------------------------------------------------------------
REAL_DIST="$SCRIPT_DIR/dist"
mkdir -p "$REAL_DIST"
ZIP_PATH="$REAL_DIST/${PACK_NAME}.zip"
rm -f "$ZIP_PATH"
bash "$SCRIPT_DIR/bin/zip-deterministic.sh" "$STAGING" "$ZIP_PATH"
ZIP_SIZE=$(du -sh "$ZIP_PATH" | cut -f1)
echo " ZIP generated: dist/${PACK_NAME}.zip ($ZIP_SIZE)"
# ---------------------------------------------------------------------------
# Phase 5 — Verification
# ---------------------------------------------------------------------------
echo " Verifying integrity..."
ERRORS=0
# No residual references to guides/ in the output (they must be flattened)
REFS=$(grep -rl 'guides/' "$STAGING" --include='*.md' --include='*.txt' 2>/dev/null | wc -l) || true
if [[ "$REFS" -gt 0 ]]; then
echo " ERROR: $REFS file(s) still contain 'guides/':" >&2
grep -rl 'guides/' "$STAGING" --include='*.md' --include='*.txt' 2>/dev/null >&2 || true
ERRORS=$((ERRORS + 1))
fi
# Verify SKILL.md — in bulk mode, check subfolders; in individual mode, check root
if [[ -n "$SKILL_FILTER" ]]; then
if [[ ! -f "$STAGING/SKILL.md" ]]; then
echo " ERROR: SKILL.md not found in the output" >&2
ERRORS=$((ERRORS + 1))
fi
else
for skill_dir in "$STAGING"/*/; do
[[ -d "$skill_dir" ]] || continue
if [[ ! -f "$skill_dir/SKILL.md" ]]; then
echo " ERROR: $(basename "$skill_dir") does not have SKILL.md" >&2
ERRORS=$((ERRORS + 1))
fi
done
fi
# No `guides` manifest file should remain in skill subfolders
LEFTOVER=$(find "$STAGING" -name 'guides' -type f 2>/dev/null | wc -l) || true
if [[ "$LEFTOVER" -gt 0 ]]; then
echo " ERROR: residual guides manifest file(s) in the output" >&2
ERRORS=$((ERRORS + 1))
fi
if [[ "$ERRORS" -gt 0 ]]; then
echo "==> FAILED: $ERRORS verification error(s)" >&2
exit 1
fi
echo "==> OK — $N_SKILLS skill(s) packaged in dist/${PACK_NAME}.zip"