chore: migrate repository to standard knowledge base layout

This commit is contained in:
tukuaiai
2026-05-02 03:29:06 +08:00
parent 40a721c24d
commit 628a3bc832
565 changed files with 687 additions and 711 deletions
+1
View File
@@ -0,0 +1 @@
../../../tools/external/Skill_Seekers-development
+181
View File
@@ -0,0 +1,181 @@
#!/usr/bin/env bash
set -euo pipefail
# ==================== Help ====================
usage() {
cat <<'EOF'
Usage:
create-skill.sh <skill-name> [--minimal|--full] [--output <dir>] [--force]
Notes:
- <skill-name> MUST be lowercase, start with a letter, and only contain letters, digits, and hyphens
- Default mode: --full
- Default output: current directory (creates ./<skill-name>/)
Examples:
./skills/auto-skill/scripts/create-skill.sh postgresql --full --output skills
./skills/auto-skill/scripts/create-skill.sh my-api --minimal --output skills
EOF
}
die() {
echo "Error: $*" >&2
exit 1
}
# ==================== Arg Parsing ====================
skill_name=""
mode="full"
output_dir="."
force=0
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--minimal)
mode="minimal"
shift
;;
--full)
mode="full"
shift
;;
-o|--output)
[[ $# -ge 2 ]] || die "--output requires a directory argument"
output_dir="$2"
shift 2
;;
-f|--force)
force=1
shift
;;
--)
shift
break
;;
-*)
die "Unknown argument: $1 (use --help)"
;;
*)
if [[ -z "$skill_name" ]]; then
skill_name="$1"
shift
else
die "Extra argument: $1 (only one <skill-name> is allowed)"
fi
;;
esac
done
[[ -n "$skill_name" ]] || { usage; exit 1; }
if [[ ! "$skill_name" =~ ^[a-z][a-z0-9-]*$ ]]; then
die "skill-name must be lowercase, start with a letter, and only contain letters/digits/hyphens (e.g. my-skill-name)"
fi
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
assets_dir="${script_dir}/../assets"
template_path=""
case "$mode" in
minimal) template_path="${assets_dir}/template-minimal.md" ;;
full) template_path="${assets_dir}/template-complete.md" ;;
*) die "Internal error: unknown mode=$mode" ;;
esac
[[ -f "$template_path" ]] || die "Template not found: $template_path"
mkdir -p "$output_dir"
target_dir="${output_dir%/}/${skill_name}"
if [[ -e "$target_dir" && "$force" -ne 1 ]]; then
die "Target already exists: $target_dir (use --force to overwrite)"
fi
mkdir -p "$target_dir"/{assets,scripts,references}
# ==================== Write Files ====================
render_template() {
local src="$1"
local dest="$2"
sed "s/{{skill_name}}/${skill_name}/g" "$src" > "$dest"
}
render_template "$template_path" "$target_dir/SKILL.md"
cat > "$target_dir/references/index.md" <<EOF
# ${skill_name} Reference Index
## Quick Links
- Getting started: \`getting_started.md\`
- API/CLI/config: \`api.md\` (if applicable)
- Examples: \`examples.md\`
- Troubleshooting: \`troubleshooting.md\`
## Notes
- Put long-form content here: excerpts, evidence links, edge cases, FAQ
- Keep \`SKILL.md\` Quick Reference short and directly usable
EOF
if [[ "$mode" == "full" ]]; then
cat > "$target_dir/references/getting_started.md" <<'EOF'
# Getting Started & Vocabulary
## Goals
- Define the 10 most important terms in this domain
- Provide the shortest path from zero to working
EOF
cat > "$target_dir/references/api.md" <<'EOF'
# API / CLI / Config Reference (If Applicable)
## Suggested Structure
- Organize by use case, not alphabetically
- Key parameters: defaults, boundaries, common misuse
- Common errors: message -> cause -> fix steps
EOF
cat > "$target_dir/references/examples.md" <<'EOF'
# Long Examples
Put examples longer than ~20 lines here, split by use case:
- Use case 1: ...
- Use case 2: ...
EOF
cat > "$target_dir/references/troubleshooting.md" <<'EOF'
# Troubleshooting & Edge Cases
Write as: symptom -> likely causes -> diagnosis -> fix.
EOF
fi
# ==================== Summary ====================
echo ""
echo "OK: Skill generated: $target_dir/"
echo ""
echo "Layout:"
echo " $target_dir/"
echo " |-- SKILL.md"
echo " |-- assets/"
echo " |-- scripts/"
echo " \\-- references/"
echo " \\-- index.md"
echo ""
echo "Next steps:"
echo " 1) Edit $target_dir/SKILL.md (triggers/boundaries/quick reference/examples)"
echo " 2) Put long-form docs into $target_dir/references/ and update index.md"
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env bash
set -euo pipefail
# ==================== Purpose ====================
# Bootstraps a local venv for the linked Skill Seekers source code.
#
# Output:
# - Creates: skills/auto-skill/scripts/.venv-skill-seekers/
usage() {
cat <<'EOF'
Usage:
skill-seekers-bootstrap.sh [--venv <dir>]
Examples:
./skills/auto-skill/scripts/skill-seekers-bootstrap.sh
./skills/auto-skill/scripts/skill-seekers-bootstrap.sh --venv ./skills/auto-skill/scripts/.venv-skill-seekers
EOF
}
die() {
echo "Error: $*" >&2
exit 1
}
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
tool_dir="${script_dir}/Skill_Seekers-development"
default_venv="${script_dir}/.venv-skill-seekers"
venv_dir="$default_venv"
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--venv)
[[ $# -ge 2 ]] || die "--venv requires a directory argument"
venv_dir="$2"
shift 2
;;
--)
shift
break
;;
-*)
die "Unknown argument: $1 (use --help)"
;;
*)
die "Unexpected positional argument: $1 (use --help)"
;;
esac
done
[[ -d "$tool_dir" ]] || die "Missing linked tool dir: $tool_dir"
[[ -f "$tool_dir/requirements.txt" ]] || die "Missing requirements.txt: $tool_dir/requirements.txt"
command -v python3 >/dev/null 2>&1 || die "python3 not found"
if [[ ! -d "$venv_dir" ]]; then
python3 -m venv "$venv_dir"
fi
"$venv_dir/bin/python" -m pip install --upgrade pip >/dev/null
"$venv_dir/bin/pip" install -r "$tool_dir/requirements.txt"
echo "OK: venv ready: $venv_dir"
+1
View File
@@ -0,0 +1 @@
Skill_Seekers-development/configs
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env bash
set -euo pipefail
# ==================== Purpose ====================
# Import Skill Seekers output/NAME/ into this repo's skills/NAME/.
usage() {
cat <<'EOF'
Usage:
skill-seekers-import.sh <skill-name> [--force]
Behavior:
- Source: ./output/<skill-name>/
- Dest: ./skills/<skill-name>/
- By default, refuses to overwrite an existing skills/<skill-name>/SKILL.md
Examples:
./skills/auto-skill/scripts/skill-seekers-import.sh react
./skills/auto-skill/scripts/skill-seekers-import.sh react --force
EOF
}
die() {
echo "Error: $*" >&2
exit 1
}
force=0
skill_name=""
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--force)
force=1
shift
;;
--)
shift
break
;;
-*)
die "Unknown argument: $1 (use --help)"
;;
*)
if [[ -z "$skill_name" ]]; then
skill_name="$1"
shift
else
die "Extra argument: $1 (only one <skill-name> is allowed)"
fi
;;
esac
done
[[ -n "$skill_name" ]] || { usage; exit 1; }
if [[ ! "$skill_name" =~ ^[a-z][a-z0-9-]*$ ]]; then
die "skill-name must match ^[a-z][a-z0-9-]*$ (e.g. my-skill)"
fi
repo_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../../../.." && pwd)"
src_dir="${repo_root}/output/${skill_name}"
dest_dir="${repo_root}/skills/${skill_name}"
[[ -d "$src_dir" ]] || die "Missing Skill Seekers output dir: $src_dir"
[[ -f "$src_dir/SKILL.md" ]] || die "Missing output SKILL.md: $src_dir/SKILL.md"
mkdir -p "$dest_dir"
if [[ -f "$dest_dir/SKILL.md" && "$force" -ne 1 ]]; then
die "Refusing to overwrite existing: $dest_dir/SKILL.md (use --force)"
fi
rsync -a --delete "$src_dir"/ "$dest_dir"/
echo "OK: imported to: $dest_dir"
+1
View File
@@ -0,0 +1 @@
Skill_Seekers-development/src
+123
View File
@@ -0,0 +1,123 @@
#!/usr/bin/env bash
set -euo pipefail
# ==================== Purpose ====================
# Legacy updater for the old vendored Skill Seekers source snapshot.
#
# Notes:
# - Skill Seekers now lives under tools/external/Skill_Seekers-development.
# - The auto-skill scripts directory only exposes it through a relative symlink.
# - This script refuses to overwrite the linked repository; update tools/external directly instead.
usage() {
cat <<'EOF'
Usage:
skill-seekers-update.sh [--repo <owner/repo>] [--ref <git-ref>] [--dry-run]
Defaults:
--repo yusufkaraaslan/Skill_Seekers
--ref main
Examples:
./skills/auto-skill/scripts/skill-seekers-update.sh --dry-run
EOF
}
die() {
echo "Error: $*" >&2
exit 1
}
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
target_dir="${script_dir}/Skill_Seekers-development"
repo="yusufkaraaslan/Skill_Seekers"
ref="main"
dry_run=0
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--repo)
[[ $# -ge 2 ]] || die "--repo requires an argument like owner/repo"
repo="$2"
shift 2
;;
--ref)
[[ $# -ge 2 ]] || die "--ref requires a git ref (branch/tag/commit)"
ref="$2"
shift 2
;;
--dry-run)
dry_run=1
shift
;;
--)
shift
break
;;
*)
die "Unknown argument: $1 (use --help)"
;;
esac
done
command -v curl >/dev/null 2>&1 || die "curl not found"
command -v tar >/dev/null 2>&1 || die "tar not found"
command -v rsync >/dev/null 2>&1 || die "rsync not found"
if [[ -L "$target_dir" && "$dry_run" -eq 0 ]]; then
die "Skill_Seekers-development is linked to tools/external. Update tools/external/Skill_Seekers-development directly instead of overwriting through this legacy updater."
fi
tmp_dir="$(mktemp -d)"
cleanup() { rm -rf "$tmp_dir"; }
trap cleanup EXIT
archive_url="https://codeload.github.com/${repo}/tar.gz/${ref}"
archive_path="${tmp_dir}/skill-seekers.tgz"
curl -fsSL "$archive_url" -o "$archive_path"
tar -xzf "$archive_path" -C "$tmp_dir"
extracted_root="$(find "$tmp_dir" -mindepth 1 -maxdepth 1 -type d | head -n 1)"
[[ -n "$extracted_root" ]] || die "Failed to locate extracted archive root"
if [[ "$dry_run" -eq 1 ]]; then
echo "DRY RUN:"
echo " repo: $repo"
echo " ref: $ref"
echo " from: $extracted_root"
echo " to: $target_dir"
if [[ -L "$target_dir" ]]; then
echo " note: target is a symlink; non-dry-run update is intentionally blocked"
fi
exit 0
fi
mkdir -p "$target_dir"
rsync -a --delete \
--exclude '.git' \
--exclude '*.md' \
--exclude 'docs/' \
--exclude 'tests/' \
--exclude '.claude/' \
--exclude '.gitignore' \
--exclude 'CHANGELOG.md' \
--exclude 'ROADMAP.md' \
--exclude 'FUTURE_RELEASES.md' \
--exclude 'ASYNC_SUPPORT.md' \
--exclude 'STRUCTURE.md' \
--exclude 'CONTRIBUTING.md' \
--exclude 'QUICKSTART.md' \
--exclude 'BULLETPROOF_QUICKSTART.md' \
--exclude 'FLEXIBLE_ROADMAP.md' \
"$extracted_root"/ \
"$target_dir"/
echo "OK: updated source in: $target_dir"
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
set -euo pipefail
# ==================== Purpose ====================
# Run Skill Seekers from linked source with a local venv.
#
# This script does NOT auto-install dependencies.
# Run skill-seekers-bootstrap.sh once if you see ImportError.
usage() {
cat <<'EOF'
Usage:
skill-seekers.sh [--venv <dir>] -- <skill-seekers args...>
Examples:
./skills/auto-skill/scripts/skill-seekers.sh -- --version
./skills/auto-skill/scripts/skill-seekers.sh -- scrape --config ./skills/auto-skill/scripts/Skill_Seekers-development/configs/react.json
./skills/auto-skill/scripts/skill-seekers.sh -- github --repo facebook/react --name react
EOF
}
die() {
echo "Error: $*" >&2
exit 1
}
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
tool_dir="${script_dir}/Skill_Seekers-development"
tool_src="${tool_dir}/src"
default_venv="${script_dir}/.venv-skill-seekers"
venv_dir="$default_venv"
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--venv)
[[ $# -ge 2 ]] || die "--venv requires a directory argument"
venv_dir="$2"
shift 2
;;
--)
shift
break
;;
*)
die "Expected '--' before skill-seekers arguments (use --help)"
;;
esac
done
[[ -d "$tool_src" ]] || die "Missing linked source dir: $tool_src"
python_bin="python3"
if [[ -x "$venv_dir/bin/python" ]]; then
python_bin="$venv_dir/bin/python"
fi
export PYTHONPATH="$tool_src${PYTHONPATH:+:$PYTHONPATH}"
exec "$python_bin" -m skill_seekers.cli.main "$@"
+212
View File
@@ -0,0 +1,212 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage:
validate-skill.sh <skill-dir> [--strict]
What it does:
- Validates SKILL.md YAML frontmatter (name/description)
- Performs lightweight structural checks
- In --strict mode, enforces the recommended section layout
Examples:
./skills/auto-skill/scripts/validate-skill.sh skills/postgresql
./skills/auto-skill/scripts/validate-skill.sh skills/my-skill --strict
EOF
}
die() {
echo "Error: $*" >&2
exit 1
}
warn() {
echo "Warning: $*" >&2
}
strict=0
skill_dir=""
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--strict)
strict=1
shift
;;
--)
shift
break
;;
-*)
die "Unknown argument: $1 (use --help)"
;;
*)
if [[ -z "$skill_dir" ]]; then
skill_dir="$1"
shift
else
die "Extra argument: $1 (only one <skill-dir> is allowed)"
fi
;;
esac
done
[[ -n "$skill_dir" ]] || { usage; exit 1; }
[[ -d "$skill_dir" ]] || die "Not a directory: $skill_dir"
skill_md="$skill_dir/SKILL.md"
[[ -f "$skill_md" ]] || die "Missing SKILL.md: $skill_md"
base_name="$(basename -- "${skill_dir%/}")"
# -------------------- Parse YAML frontmatter --------------------
frontmatter=""
if frontmatter="$(
awk '
BEGIN { in_fm=0; closed=0 }
NR==1 {
if ($0 != "---") exit 2
in_fm=1
next
}
in_fm==1 {
if ($0 == "---") { closed=1; exit 0 }
print
next
}
END {
if (closed == 0) exit 3
}
' "$skill_md"
)"; then
:
else
rc=$?
case "$rc" in
2) die "SKILL.md must start with YAML frontmatter (--- as the first line)" ;;
3) die "YAML frontmatter is not closed (missing ---)" ;;
*) die "Failed to parse YAML frontmatter (awk exit=$rc)" ;;
esac
fi
name="$(
printf "%s\n" "$frontmatter" | awk -F: '
tolower($1) ~ /^name$/ {
sub(/^[^:]*:[[:space:]]*/, "", $0)
gsub(/[[:space:]]+$/, "", $0)
print
exit
}
'
)"
description="$(
printf "%s\n" "$frontmatter" | awk -F: '
tolower($1) ~ /^description$/ {
sub(/^[^:]*:[[:space:]]*/, "", $0)
gsub(/[[:space:]]+$/, "", $0)
print
exit
}
'
)"
[[ -n "$name" ]] || die "Missing frontmatter field: name"
[[ -n "$description" ]] || die "Missing frontmatter field: description"
if [[ ! "$name" =~ ^[a-z][a-z0-9-]*$ ]]; then
die "Invalid name: '$name' (expected ^[a-z][a-z0-9-]*$)"
fi
if [[ "$strict" -eq 1 && "$name" != "$base_name" ]]; then
die "Strict mode: frontmatter name ('$name') must match directory name ('$base_name')"
fi
# -------------------- Strip fenced code blocks for section checks --------------------
filtered_md="$(mktemp)"
trap 'rm -f "$filtered_md"' EXIT
awk '
BEGIN { in_fence=0 }
/^[[:space:]]*```/ { in_fence = !in_fence; next }
in_fence==0 { print }
' "$skill_md" > "$filtered_md"
# -------------------- Structural checks --------------------
required_h2=(
"When to Use This Skill"
"Not For / Boundaries"
"Quick Reference"
"Examples"
"References"
"Maintenance"
)
for title in "${required_h2[@]}"; do
if ! grep -Eq "^##[[:space:]]+${title}([[:space:]]*)$" "$filtered_md"; then
if [[ "$strict" -eq 1 ]]; then
die "Strict mode: missing required section heading: '## ${title}'"
fi
warn "Missing recommended section heading: '## ${title}'"
fi
done
# references/index.md presence (only enforced in strict mode when references/ exists)
if [[ -d "$skill_dir/references" && "$strict" -eq 1 && ! -f "$skill_dir/references/index.md" ]]; then
die "Strict mode: references/ exists but references/index.md is missing"
fi
# -------------------- Heuristics: Quick Reference size --------------------
quick_start="$(awk 'match($0, /^##[[:space:]]+Quick Reference([[:space:]]*)$/){print NR; exit}' "$filtered_md" || true)"
if [[ -n "$quick_start" ]]; then
quick_end="$(awk -v s="$quick_start" 'NR>s && match($0, /^##[[:space:]]+/){print NR; exit}' "$filtered_md" || true)"
total_lines="$(wc -l < "$filtered_md" | tr -d ' ')"
if [[ -z "$quick_end" ]]; then
quick_end="$((total_lines + 1))"
fi
quick_len="$((quick_end - quick_start - 1))"
if [[ "$quick_len" -gt 250 ]]; then
if [[ "$strict" -eq 1 ]]; then
die "Strict mode: Quick Reference section is too long (${quick_len} lines). Move long-form text into references/."
fi
warn "Quick Reference section is large (${quick_len} lines). Consider moving long-form text into references/."
fi
fi
# -------------------- Heuristics: Examples count --------------------
examples_start="$(awk 'match($0, /^##[[:space:]]+Examples([[:space:]]*)$/){print NR; exit}' "$filtered_md" || true)"
if [[ -n "$examples_start" ]]; then
examples_end="$(awk -v s="$examples_start" 'NR>s && match($0, /^##[[:space:]]+/){print NR; exit}' "$filtered_md" || true)"
total_lines="$(wc -l < "$filtered_md" | tr -d ' ')"
if [[ -z "$examples_end" ]]; then
examples_end="$((total_lines + 1))"
fi
example_count="$(
awk -v s="$examples_start" -v e="$examples_end" '
NR>s && NR<e && match($0, /^###[[:space:]]+Example([[:space:]]|$)/) { c++ }
END { print c+0 }
' "$filtered_md"
)"
if [[ "$example_count" -lt 3 ]]; then
if [[ "$strict" -eq 1 ]]; then
die "Strict mode: expected >= 3 examples (found ${example_count})."
fi
warn "Recommended: >= 3 examples (found ${example_count})."
fi
fi
echo "OK: $skill_dir"