mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 17:01:16 +00:00
Add AI skills intaller
This commit is contained in:
@@ -70,3 +70,8 @@ composer.lock
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
|
||||
# Agent skills are installed globally by scripts/install-global-skills.sh
|
||||
/.agents/skills/
|
||||
/.claude/skills/
|
||||
/.cursor/skills/
|
||||
|
||||
@@ -437,6 +437,33 @@ npm run build
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Agent Skills
|
||||
|
||||
The repository keeps the shared agent skill baseline in `skills-lock.json`. The
|
||||
generated Linux installer installs those skills globally under `~/.agents/skills`
|
||||
and bridges them into Codex under `~/.codex/skills`.
|
||||
|
||||
Prerequisites: Bash, Node.js/npm (`npx`), and network access to the skill
|
||||
repositories.
|
||||
|
||||
```bash
|
||||
# Regenerate the installer after changing skills-lock.json
|
||||
./scripts/generate-global-skills-installer.sh
|
||||
|
||||
# Preview global installs and Codex bridge changes
|
||||
./scripts/install-global-skills.sh --dry-run
|
||||
|
||||
# Install globally and create Codex symlinks
|
||||
./scripts/install-global-skills.sh
|
||||
|
||||
# Copy skills into Codex instead of creating symlinks
|
||||
./scripts/install-global-skills.sh --copy
|
||||
```
|
||||
|
||||
Set `SKILLS_GLOBAL_DIR` or `CODEX_HOME` when using non-default global
|
||||
directories. The installer never removes or overwrites unmanaged existing
|
||||
skill paths; resolve reported conflicts manually and rerun it.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
||||
LOCK_FILE="${1:-${PROJECT_ROOT}/skills-lock.json}"
|
||||
OUTPUT_FILE="${2:-${SCRIPT_DIR}/install-global-skills.sh}"
|
||||
|
||||
die() {
|
||||
printf 'Error: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
for command_name in awk chmod mkdir mktemp mv rm sort; do
|
||||
if ! command -v "${command_name}" >/dev/null 2>&1; then
|
||||
die "Required command not found: ${command_name}"
|
||||
fi
|
||||
done
|
||||
|
||||
[[ -f "${LOCK_FILE}" ]] || die "Skills lockfile not found: ${LOCK_FILE}"
|
||||
|
||||
mapfile -t records < <(
|
||||
awk '
|
||||
/^ "[^"]+": \{$/ {
|
||||
skill = $1
|
||||
gsub(/[":]/, "", skill)
|
||||
next
|
||||
}
|
||||
|
||||
$1 == "\"source\":" {
|
||||
source = $2
|
||||
gsub(/[",]/, "", source)
|
||||
print source "\t" skill
|
||||
skill = ""
|
||||
}
|
||||
' "${LOCK_FILE}" | LC_ALL=C sort -t $'\t' -k1,1 -k2,2
|
||||
)
|
||||
|
||||
(( ${#records[@]} > 0 )) || die "No skills found in lockfile: ${LOCK_FILE}"
|
||||
|
||||
temporary_file="$(mktemp "${OUTPUT_FILE}.tmp.XXXXXX")"
|
||||
cleanup() {
|
||||
rm -f -- "${temporary_file}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
{
|
||||
printf '%s\n' '#!/usr/bin/env bash'
|
||||
printf '\n'
|
||||
printf '%s\n' '# This file is generated by scripts/generate-global-skills-installer.sh.'
|
||||
printf '%s\n' '# Do not edit manually; regenerate it after changing skills-lock.json.'
|
||||
printf '%s\n' '# shellcheck shell=bash'
|
||||
printf '\n'
|
||||
printf '%s\n' 'set -Eeuo pipefail'
|
||||
printf '\n'
|
||||
printf 'SKILL_COUNT=%q\n' "${#records[@]}"
|
||||
printf 'DRY_RUN=0\n'
|
||||
printf 'COPY_MODE=0\n'
|
||||
printf 'SHARED_SKILLS_DIR="${SKILLS_GLOBAL_DIR:-${HOME:?HOME must be set}/.agents/skills}"\n'
|
||||
printf 'CODEX_HOME_DIR="${CODEX_HOME:-${HOME:?HOME must be set}/.codex}"\n'
|
||||
printf 'CODEX_SKILLS_DIR="${CODEX_HOME_DIR}/skills"\n'
|
||||
printf '\n'
|
||||
printf '%s\n' 'usage() {'
|
||||
printf '%s\n' ' cat <<'"'"'USAGE'"'"''
|
||||
printf '%s\n' 'Usage: scripts/install-global-skills.sh [options]'
|
||||
printf '\n'
|
||||
printf '%s\n' 'Install the repository skill baseline globally and bridge it into Codex.'
|
||||
printf '\n'
|
||||
printf '%s\n' 'Options:'
|
||||
printf '%s\n' ' --dry-run Show commands and filesystem changes without applying them.'
|
||||
printf '%s\n' ' --copy Copy skills into Codex instead of creating symlinks.'
|
||||
printf '%s\n' ' --help Show this help text.'
|
||||
printf '\n'
|
||||
printf '%s\n' 'Environment:'
|
||||
printf '%s\n' ' SKILLS_GLOBAL_DIR Shared global skills directory (default: ~/.agents/skills).'
|
||||
printf '%s\n' ' CODEX_HOME Codex home directory (default: ~/.codex).'
|
||||
printf '%s\n' 'USAGE'
|
||||
printf '%s\n' '}'
|
||||
printf '\n'
|
||||
printf '%s\n' 'die() {'
|
||||
printf '%s\n' ' printf '"'"'Error: %s\n'"'"' "$1" >&2'
|
||||
printf '%s\n' ' exit 1'
|
||||
printf '%s\n' '}'
|
||||
printf '\n'
|
||||
printf '%s\n' 'print_command() {'
|
||||
printf '%s\n' ' printf '"'"'+'"'"''
|
||||
printf '%s\n' ' printf '"'"' %q'"'"' "$@"'
|
||||
printf '%s\n' ' printf '"'"'\n'"'"''
|
||||
printf '%s\n' '}'
|
||||
printf '\n'
|
||||
printf '%s\n' 'run_command() {'
|
||||
printf '%s\n' ' if (( DRY_RUN )); then'
|
||||
printf '%s\n' ' print_command "$@"'
|
||||
printf '%s\n' ' return 0'
|
||||
printf '%s\n' ' fi'
|
||||
printf '%s\n' ' "$@"'
|
||||
printf '%s\n' '}'
|
||||
printf '\n'
|
||||
printf '%s\n' 'require_command() {'
|
||||
printf '%s\n' ' command -v "$1" >/dev/null 2>&1 || die "Required command not found: $1"'
|
||||
printf '%s\n' '}'
|
||||
printf '\n'
|
||||
printf '%s\n' 'while (( $# > 0 )); do'
|
||||
printf '%s\n' ' case "$1" in'
|
||||
printf '%s\n' ' --dry-run)'
|
||||
printf '%s\n' ' DRY_RUN=1'
|
||||
printf '%s\n' ' ;;'
|
||||
printf '%s\n' ' --copy)'
|
||||
printf '%s\n' ' COPY_MODE=1'
|
||||
printf '%s\n' ' ;;'
|
||||
printf '%s\n' ' --help|-h)'
|
||||
printf '%s\n' ' usage'
|
||||
printf '%s\n' ' exit 0'
|
||||
printf '%s\n' ' ;;'
|
||||
printf '%s\n' ' *)'
|
||||
printf '%s\n' ' die "Unknown option: $1 (use --help for usage)"'
|
||||
printf '%s\n' ' ;;'
|
||||
printf '%s\n' ' esac'
|
||||
printf '%s\n' ' shift'
|
||||
printf '%s\n' 'done'
|
||||
printf '\n'
|
||||
printf '%s\n' 'require_command bash'
|
||||
printf '%s\n' 'require_command npx'
|
||||
printf '%s\n' 'require_command mkdir'
|
||||
printf '%s\n' 'require_command ln'
|
||||
printf '%s\n' 'require_command readlink'
|
||||
printf '%s\n' 'if (( COPY_MODE )); then'
|
||||
printf '%s\n' ' require_command cp'
|
||||
printf '%s\n' ' require_command diff'
|
||||
printf '%s\n' 'fi'
|
||||
printf '\n'
|
||||
printf '%s\n' 'printf '"'"'Installing %d skills globally...\n'"'"' "$SKILL_COUNT"'
|
||||
printf '\n'
|
||||
|
||||
current_source=""
|
||||
source_skill_args=()
|
||||
for record in "${records[@]}"; do
|
||||
source="${record%%$'\t'*}"
|
||||
skill="${record#*$'\t'}"
|
||||
|
||||
if [[ -n "${current_source}" && "${source}" != "${current_source}" ]]; then
|
||||
printf 'run_command npx --yes skills add %q --global --yes' "${current_source}"
|
||||
for skill_arg in "${source_skill_args[@]}"; do
|
||||
printf ' --skill %q' "${skill_arg}"
|
||||
done
|
||||
printf '\n\n'
|
||||
source_skill_args=()
|
||||
fi
|
||||
|
||||
current_source="${source}"
|
||||
source_skill_args+=("${skill}")
|
||||
done
|
||||
|
||||
printf 'run_command npx --yes skills add %q --global --yes' "${current_source}"
|
||||
for skill_arg in "${source_skill_args[@]}"; do
|
||||
printf ' --skill %q' "${skill_arg}"
|
||||
done
|
||||
printf '\n\n'
|
||||
|
||||
printf '%s\n' 'SKILLS=('
|
||||
for record in "${records[@]}"; do
|
||||
skill="${record#*$'\t'}"
|
||||
printf ' %q\n' "${skill}"
|
||||
done
|
||||
printf '%s\n' ')'
|
||||
printf '\n'
|
||||
printf '%s\n' 'if (( DRY_RUN )); then'
|
||||
printf '%s\n' ' printf '"'"'Would bridge skills from %s to %s\n'"'"' "$SHARED_SKILLS_DIR" "$CODEX_SKILLS_DIR"'
|
||||
printf '%s\n' ' for skill in "${SKILLS[@]}"; do'
|
||||
printf '%s\n' ' if (( COPY_MODE )); then'
|
||||
printf '%s\n' ' printf '"'"'+ copy %s -> %s/%s\n'"'"' "$SHARED_SKILLS_DIR/$skill" "$CODEX_SKILLS_DIR" "$skill"'
|
||||
printf '%s\n' ' else'
|
||||
printf '%s\n' ' printf '"'"'+ ln -s %s %s/%s\n'"'"' "$SHARED_SKILLS_DIR/$skill" "$CODEX_SKILLS_DIR" "$skill"'
|
||||
printf '%s\n' ' fi'
|
||||
printf '%s\n' ' done'
|
||||
printf '%s\n' ' exit 0'
|
||||
printf '%s\n' 'fi'
|
||||
printf '\n'
|
||||
printf '%s\n' 'run_command mkdir -p "$CODEX_SKILLS_DIR"'
|
||||
printf '%s\n' 'conflict_count=0'
|
||||
printf '%s\n' 'for skill in "${SKILLS[@]}"; do'
|
||||
printf '%s\n' ' source_path="$SHARED_SKILLS_DIR/$skill"'
|
||||
printf '%s\n' ' target_path="$CODEX_SKILLS_DIR/$skill"'
|
||||
printf '%s\n' ' [[ -d "$source_path" ]] || { printf '"'"'Error: Installed skill is missing: %s\n'"'"' "$source_path" >&2; conflict_count=$((conflict_count + 1)); continue; }'
|
||||
printf '%s\n' ' if [[ -L "$target_path" ]]; then'
|
||||
printf '%s\n' ' if [[ "$(readlink "$target_path")" == "$source_path" ]]; then'
|
||||
printf '%s\n' ' printf '"'"'Already linked: %s\n'"'"' "$skill"'
|
||||
printf '%s\n' ' continue'
|
||||
printf '%s\n' ' fi'
|
||||
printf '%s\n' ' printf '"'"'Error: Refusing to replace unmanaged symlink: %s\n'"'"' "$target_path" >&2'
|
||||
printf '%s\n' ' conflict_count=$((conflict_count + 1))'
|
||||
printf '%s\n' ' continue'
|
||||
printf '%s\n' ' fi'
|
||||
printf '%s\n' ' if [[ -e "$target_path" ]]; then'
|
||||
printf '%s\n' ' if (( COPY_MODE )) && [[ -d "$target_path" ]] && diff -qr -- "$source_path" "$target_path" >/dev/null; then'
|
||||
printf '%s\n' ' printf '"'"'Already copied: %s\n'"'"' "$skill"'
|
||||
printf '%s\n' ' continue'
|
||||
printf '%s\n' ' fi'
|
||||
printf '%s\n' ' printf '"'"'Error: Refusing to overwrite existing path: %s\n'"'"' "$target_path" >&2'
|
||||
printf '%s\n' ' conflict_count=$((conflict_count + 1))'
|
||||
printf '%s\n' ' continue'
|
||||
printf '%s\n' ' fi'
|
||||
printf '%s\n' ' if (( COPY_MODE )); then'
|
||||
printf '%s\n' ' run_command cp -R -- "$source_path" "$target_path"'
|
||||
printf '%s\n' ' printf '"'"'Copied: %s\n'"'"' "$skill"'
|
||||
printf '%s\n' ' else'
|
||||
printf '%s\n' ' run_command ln -s -- "$source_path" "$target_path"'
|
||||
printf '%s\n' ' printf '"'"'Linked: %s\n'"'"' "$skill"'
|
||||
printf '%s\n' ' fi'
|
||||
printf '%s\n' 'done'
|
||||
printf '\n'
|
||||
printf '%s\n' '(( conflict_count == 0 )) || die "${conflict_count} skill bridge conflict(s) require manual resolution"'
|
||||
printf '%s\n' 'printf '"'"'Global skills installation complete.\n'"'"''
|
||||
} >"${temporary_file}"
|
||||
|
||||
chmod 755 "${temporary_file}"
|
||||
mkdir -p -- "$(dirname -- "${OUTPUT_FILE}")"
|
||||
mv -- "${temporary_file}" "${OUTPUT_FILE}"
|
||||
trap - EXIT
|
||||
|
||||
printf 'Generated %s from %s (%d skills).\n' "${OUTPUT_FILE}" "${LOCK_FILE}" "${#records[@]}"
|
||||
@@ -0,0 +1,265 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This file is generated by scripts/generate-global-skills-installer.sh.
|
||||
# Do not edit manually; regenerate it after changing skills-lock.json.
|
||||
# shellcheck shell=bash
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
SKILL_COUNT=119
|
||||
DRY_RUN=0
|
||||
COPY_MODE=0
|
||||
SHARED_SKILLS_DIR="${SKILLS_GLOBAL_DIR:-${HOME:?HOME must be set}/.agents/skills}"
|
||||
CODEX_HOME_DIR="${CODEX_HOME:-${HOME:?HOME must be set}/.codex}"
|
||||
CODEX_SKILLS_DIR="${CODEX_HOME_DIR}/skills"
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Usage: scripts/install-global-skills.sh [options]
|
||||
|
||||
Install the repository skill baseline globally and bridge it into Codex.
|
||||
|
||||
Options:
|
||||
--dry-run Show commands and filesystem changes without applying them.
|
||||
--copy Copy skills into Codex instead of creating symlinks.
|
||||
--help Show this help text.
|
||||
|
||||
Environment:
|
||||
SKILLS_GLOBAL_DIR Shared global skills directory (default: ~/.agents/skills).
|
||||
CODEX_HOME Codex home directory (default: ~/.codex).
|
||||
USAGE
|
||||
}
|
||||
|
||||
die() {
|
||||
printf 'Error: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
print_command() {
|
||||
printf '+'
|
||||
printf ' %q' "$@"
|
||||
printf '\n'
|
||||
}
|
||||
|
||||
run_command() {
|
||||
if (( DRY_RUN )); then
|
||||
print_command "$@"
|
||||
return 0
|
||||
fi
|
||||
"$@"
|
||||
}
|
||||
|
||||
require_command() {
|
||||
command -v "$1" >/dev/null 2>&1 || die "Required command not found: $1"
|
||||
}
|
||||
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
--dry-run)
|
||||
DRY_RUN=1
|
||||
;;
|
||||
--copy)
|
||||
COPY_MODE=1
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
die "Unknown option: $1 (use --help for usage)"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
require_command bash
|
||||
require_command npx
|
||||
require_command mkdir
|
||||
require_command ln
|
||||
require_command readlink
|
||||
if (( COPY_MODE )); then
|
||||
require_command cp
|
||||
require_command diff
|
||||
fi
|
||||
|
||||
printf 'Installing %d skills globally...\n' "$SKILL_COUNT"
|
||||
|
||||
run_command npx --yes skills add asyrafhussin/agent-skills --global --yes --skill api-design-patterns --skill clean-code-principles --skill code-slop --skill e2e-playwright-testing --skill git-workflow --skill laravel-ai-sdk --skill laravel-best-practices --skill laravel-database-optimization --skill laravel-inertia-react --skill laravel-mcp --skill laravel-owasp-security --skill laravel-queues --skill laravel-testing --skill php-best-practices --skill prd-writing --skill project-docs --skill react-vite-best-practices --skill seo-best-practices --skill state-management --skill tailwind-best-practices --skill technical-debt --skill testing-best-practices --skill typescript-react-patterns --skill web-design-guidelines
|
||||
|
||||
run_command npx --yes skills add iserter/laravel-claude-agents --global --yes --skill eloquent-best-practices --skill laravel-api-resource-patterns --skill laravel-authorization-patterns --skill laravel-blade-component-patterns --skill laravel-brainstorming --skill laravel-caching-strategies --skill laravel-event-driven-architecture --skill laravel-feature-flags --skill laravel-middleware-patterns --skill laravel-notification-patterns --skill laravel-queue-patterns --skill laravel-systematic-debugging --skill laravel-task-scheduling --skill laravel-tdd --skill laravel-validation-patterns
|
||||
|
||||
run_command npx --yes skills add jeffallan/claude-skills --global --yes --skill angular-architect --skill api-designer --skill architecture-designer --skill atlassian-mcp --skill chaos-engineer --skill cli-developer --skill cloud-architect --skill code-documenter --skill code-reviewer --skill cpp-pro --skill csharp-developer --skill database-optimizer --skill debugging-wizard --skill devops-engineer --skill django-expert --skill dotnet-core-expert --skill embedded-systems --skill fastapi-expert --skill feature-forge --skill fine-tuning-expert --skill flutter-expert --skill fullstack-guardian --skill game-developer --skill golang-pro --skill graphql-architect --skill java-architect --skill javascript-pro --skill kotlin-specialist --skill kubernetes-specialist --skill laravel-specialist --skill legacy-modernizer --skill mcp-developer --skill microservices-architect --skill ml-pipeline --skill monitoring-expert --skill nestjs-expert --skill nextjs-developer --skill pandas-pro --skill php-pro --skill playwright-expert --skill postgres-pro --skill prompt-engineer --skill python-pro --skill rag-architect --skill rails-expert --skill react-expert --skill react-native-expert --skill rust-engineer --skill salesforce-developer --skill secure-code-guardian --skill security-reviewer --skill shopify-expert --skill spark-engineer --skill spec-miner --skill spring-boot-engineer --skill sql-pro --skill sre-engineer --skill swift-expert --skill terraform-engineer --skill test-master --skill the-fool --skill typescript-pro --skill vue-expert --skill vue-expert-js --skill websocket-engineer --skill wordpress-pro
|
||||
|
||||
run_command npx --yes skills add leeovery/claude-laravel --global --yes --skill laravel-quality
|
||||
|
||||
run_command npx --yes skills add thienanblog/awesome-ai-agent-skills --global --yes --skill agents-md-generator --skill ask-questions-if-underspecified --skill design-system-generator --skill docker-local-dev --skill documentation-guidelines --skill find-scene --skill laravel-11-12-app-guidelines --skill noizai-voice-workflow --skill office-web-ui-system --skill project-development-mindset --skill symcli-skill --skill ui-mockup-visualizer --skill vps-docker-traefik-deploy
|
||||
|
||||
SKILLS=(
|
||||
api-design-patterns
|
||||
clean-code-principles
|
||||
code-slop
|
||||
e2e-playwright-testing
|
||||
git-workflow
|
||||
laravel-ai-sdk
|
||||
laravel-best-practices
|
||||
laravel-database-optimization
|
||||
laravel-inertia-react
|
||||
laravel-mcp
|
||||
laravel-owasp-security
|
||||
laravel-queues
|
||||
laravel-testing
|
||||
php-best-practices
|
||||
prd-writing
|
||||
project-docs
|
||||
react-vite-best-practices
|
||||
seo-best-practices
|
||||
state-management
|
||||
tailwind-best-practices
|
||||
technical-debt
|
||||
testing-best-practices
|
||||
typescript-react-patterns
|
||||
web-design-guidelines
|
||||
eloquent-best-practices
|
||||
laravel-api-resource-patterns
|
||||
laravel-authorization-patterns
|
||||
laravel-blade-component-patterns
|
||||
laravel-brainstorming
|
||||
laravel-caching-strategies
|
||||
laravel-event-driven-architecture
|
||||
laravel-feature-flags
|
||||
laravel-middleware-patterns
|
||||
laravel-notification-patterns
|
||||
laravel-queue-patterns
|
||||
laravel-systematic-debugging
|
||||
laravel-task-scheduling
|
||||
laravel-tdd
|
||||
laravel-validation-patterns
|
||||
angular-architect
|
||||
api-designer
|
||||
architecture-designer
|
||||
atlassian-mcp
|
||||
chaos-engineer
|
||||
cli-developer
|
||||
cloud-architect
|
||||
code-documenter
|
||||
code-reviewer
|
||||
cpp-pro
|
||||
csharp-developer
|
||||
database-optimizer
|
||||
debugging-wizard
|
||||
devops-engineer
|
||||
django-expert
|
||||
dotnet-core-expert
|
||||
embedded-systems
|
||||
fastapi-expert
|
||||
feature-forge
|
||||
fine-tuning-expert
|
||||
flutter-expert
|
||||
fullstack-guardian
|
||||
game-developer
|
||||
golang-pro
|
||||
graphql-architect
|
||||
java-architect
|
||||
javascript-pro
|
||||
kotlin-specialist
|
||||
kubernetes-specialist
|
||||
laravel-specialist
|
||||
legacy-modernizer
|
||||
mcp-developer
|
||||
microservices-architect
|
||||
ml-pipeline
|
||||
monitoring-expert
|
||||
nestjs-expert
|
||||
nextjs-developer
|
||||
pandas-pro
|
||||
php-pro
|
||||
playwright-expert
|
||||
postgres-pro
|
||||
prompt-engineer
|
||||
python-pro
|
||||
rag-architect
|
||||
rails-expert
|
||||
react-expert
|
||||
react-native-expert
|
||||
rust-engineer
|
||||
salesforce-developer
|
||||
secure-code-guardian
|
||||
security-reviewer
|
||||
shopify-expert
|
||||
spark-engineer
|
||||
spec-miner
|
||||
spring-boot-engineer
|
||||
sql-pro
|
||||
sre-engineer
|
||||
swift-expert
|
||||
terraform-engineer
|
||||
test-master
|
||||
the-fool
|
||||
typescript-pro
|
||||
vue-expert
|
||||
vue-expert-js
|
||||
websocket-engineer
|
||||
wordpress-pro
|
||||
laravel-quality
|
||||
agents-md-generator
|
||||
ask-questions-if-underspecified
|
||||
design-system-generator
|
||||
docker-local-dev
|
||||
documentation-guidelines
|
||||
find-scene
|
||||
laravel-11-12-app-guidelines
|
||||
noizai-voice-workflow
|
||||
office-web-ui-system
|
||||
project-development-mindset
|
||||
symcli-skill
|
||||
ui-mockup-visualizer
|
||||
vps-docker-traefik-deploy
|
||||
)
|
||||
|
||||
if (( DRY_RUN )); then
|
||||
printf 'Would bridge skills from %s to %s\n' "$SHARED_SKILLS_DIR" "$CODEX_SKILLS_DIR"
|
||||
for skill in "${SKILLS[@]}"; do
|
||||
if (( COPY_MODE )); then
|
||||
printf '+ copy %s -> %s/%s\n' "$SHARED_SKILLS_DIR/$skill" "$CODEX_SKILLS_DIR" "$skill"
|
||||
else
|
||||
printf '+ ln -s %s %s/%s\n' "$SHARED_SKILLS_DIR/$skill" "$CODEX_SKILLS_DIR" "$skill"
|
||||
fi
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
run_command mkdir -p "$CODEX_SKILLS_DIR"
|
||||
conflict_count=0
|
||||
for skill in "${SKILLS[@]}"; do
|
||||
source_path="$SHARED_SKILLS_DIR/$skill"
|
||||
target_path="$CODEX_SKILLS_DIR/$skill"
|
||||
[[ -d "$source_path" ]] || { printf 'Error: Installed skill is missing: %s\n' "$source_path" >&2; conflict_count=$((conflict_count + 1)); continue; }
|
||||
if [[ -L "$target_path" ]]; then
|
||||
if [[ "$(readlink "$target_path")" == "$source_path" ]]; then
|
||||
printf 'Already linked: %s\n' "$skill"
|
||||
continue
|
||||
fi
|
||||
printf 'Error: Refusing to replace unmanaged symlink: %s\n' "$target_path" >&2
|
||||
conflict_count=$((conflict_count + 1))
|
||||
continue
|
||||
fi
|
||||
if [[ -e "$target_path" ]]; then
|
||||
if (( COPY_MODE )) && [[ -d "$target_path" ]] && diff -qr -- "$source_path" "$target_path" >/dev/null; then
|
||||
printf 'Already copied: %s\n' "$skill"
|
||||
continue
|
||||
fi
|
||||
printf 'Error: Refusing to overwrite existing path: %s\n' "$target_path" >&2
|
||||
conflict_count=$((conflict_count + 1))
|
||||
continue
|
||||
fi
|
||||
if (( COPY_MODE )); then
|
||||
run_command cp -R -- "$source_path" "$target_path"
|
||||
printf 'Copied: %s\n' "$skill"
|
||||
else
|
||||
run_command ln -s -- "$source_path" "$target_path"
|
||||
printf 'Linked: %s\n' "$skill"
|
||||
fi
|
||||
done
|
||||
|
||||
(( conflict_count == 0 )) || die "${conflict_count} skill bridge conflict(s) require manual resolution"
|
||||
printf 'Global skills installation complete.\n'
|
||||
@@ -0,0 +1,176 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
||||
INSTALLER="${SCRIPT_DIR}/install-global-skills.sh"
|
||||
GENERATOR="${SCRIPT_DIR}/generate-global-skills-installer.sh"
|
||||
LOCK_FILE="${PROJECT_ROOT}/skills-lock.json"
|
||||
TEMP_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/global-skills-test.XXXXXX")"
|
||||
|
||||
cleanup() {
|
||||
rm -rf -- "${TEMP_ROOT}"
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
fail() {
|
||||
printf 'Test failure: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
assert_contains() {
|
||||
local needle="$1"
|
||||
local haystack="$2"
|
||||
|
||||
[[ "${haystack}" == *"${needle}"* ]] || fail "Expected output to contain: ${needle}"
|
||||
}
|
||||
|
||||
assert_file_exists() {
|
||||
[[ -e "$1" ]] || fail "Expected file to exist: $1"
|
||||
}
|
||||
|
||||
assert_equals() {
|
||||
local expected="$1"
|
||||
local actual="$2"
|
||||
local description="$3"
|
||||
|
||||
[[ "${expected}" == "${actual}" ]] || fail "${description}: expected ${expected}, got ${actual}"
|
||||
}
|
||||
|
||||
expected_skill_count="$(awk '
|
||||
/^SKILLS=\(/ { inside = 1; next }
|
||||
inside && /^\)/ { inside = 0 }
|
||||
inside && /^ / { count++ }
|
||||
END { print count + 0 }
|
||||
' "${INSTALLER}")"
|
||||
assert_equals 119 "${expected_skill_count}" "generated skill count"
|
||||
|
||||
generated_installer="${TEMP_ROOT}/generated-installer.sh"
|
||||
"${GENERATOR}" "${LOCK_FILE}" "${generated_installer}" >/dev/null
|
||||
bash -n "${generated_installer}"
|
||||
generated_count="$(awk '
|
||||
/^SKILLS=\(/ { inside = 1; next }
|
||||
inside && /^\)/ { inside = 0 }
|
||||
inside && /^ / { count++ }
|
||||
END { print count + 0 }
|
||||
' "${generated_installer}")"
|
||||
assert_equals "${expected_skill_count}" "${generated_count}" "regenerated skill count"
|
||||
assert_equals 5 "$(rg -c '^run_command npx --yes skills add' "${generated_installer}")" "source command count"
|
||||
if ! diff -u \
|
||||
<(awk '/^ "[^"]+": \{$/ { skill = $1; gsub(/[":]/, "", skill); print skill }' "${LOCK_FILE}" | LC_ALL=C sort) \
|
||||
<(awk '
|
||||
/^SKILLS=\(/ { inside = 1; next }
|
||||
inside && /^\)/ { inside = 0 }
|
||||
inside && /^ / { print $1 }
|
||||
' "${generated_installer}" | LC_ALL=C sort); then
|
||||
fail 'generated installer skill names differ from skills-lock.json'
|
||||
fi
|
||||
|
||||
mock_bin="${TEMP_ROOT}/bin"
|
||||
mkdir -p -- "${mock_bin}"
|
||||
cat >"${mock_bin}/npx" <<'MOCK_NPX'
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
printf '%s\n' "$*" >>"${MOCK_NPX_LOG}"
|
||||
[[ "${1:-}" == "--yes" ]] || exit 2
|
||||
shift
|
||||
[[ "${1:-}" == "skills" ]] || exit 2
|
||||
shift
|
||||
[[ "${1:-}" == "add" ]] || exit 2
|
||||
shift
|
||||
shift
|
||||
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
--global|--yes)
|
||||
shift
|
||||
;;
|
||||
--skill)
|
||||
skill="$2"
|
||||
mkdir -p -- "${SKILLS_GLOBAL_DIR}/${skill}"
|
||||
printf 'mock skill: %s\n' "${skill}" >"${SKILLS_GLOBAL_DIR}/${skill}/SKILL.md"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
MOCK_NPX
|
||||
chmod 755 "${mock_bin}/npx"
|
||||
|
||||
run_installer() {
|
||||
local home_dir="$1"
|
||||
local shared_dir="$2"
|
||||
local codex_home="$3"
|
||||
shift 3
|
||||
|
||||
HOME="${home_dir}" \
|
||||
SKILLS_GLOBAL_DIR="${shared_dir}" \
|
||||
CODEX_HOME="${codex_home}" \
|
||||
MOCK_NPX_LOG="${TEMP_ROOT}/npx.log" \
|
||||
PATH="${mock_bin}:${PATH}" \
|
||||
"${INSTALLER}" "$@"
|
||||
}
|
||||
|
||||
home_dir="${TEMP_ROOT}/home"
|
||||
shared_dir="${TEMP_ROOT}/shared"
|
||||
codex_home="${TEMP_ROOT}/codex"
|
||||
mkdir -p -- "${home_dir}" "${codex_home}/skills/.system"
|
||||
printf 'preserve me\n' >"${codex_home}/skills/.system/SKILL.md"
|
||||
: >"${TEMP_ROOT}/npx.log"
|
||||
run_installer "${home_dir}" "${shared_dir}" "${codex_home}" >"${TEMP_ROOT}/install.log" 2>&1 \
|
||||
|| { cat "${TEMP_ROOT}/install.log" >&2; fail 'initial installation failed'; }
|
||||
|
||||
assert_equals "${expected_skill_count}" "$(find "${codex_home}/skills" -mindepth 1 -maxdepth 1 -type l | wc -l | tr -d ' ')" "symlink count"
|
||||
assert_file_exists "${codex_home}/skills/.system/SKILL.md"
|
||||
system_contents="$(<"${codex_home}/skills/.system/SKILL.md")"
|
||||
assert_contains 'preserve me' "${system_contents}"
|
||||
npx_call_count="$(wc -l < "${TEMP_ROOT}/npx.log" | tr -d ' ')"
|
||||
assert_equals 5 "${npx_call_count}" "global source install count"
|
||||
npx_log_contents="$(<"${TEMP_ROOT}/npx.log")"
|
||||
assert_contains '--global' "${npx_log_contents}"
|
||||
|
||||
run_installer "${home_dir}" "${shared_dir}" "${codex_home}" >"${TEMP_ROOT}/rerun.log" 2>&1 \
|
||||
|| { cat "${TEMP_ROOT}/rerun.log" >&2; fail 'idempotent symlink rerun failed'; }
|
||||
assert_equals "${expected_skill_count}" "$(rg -c '^Already linked:' "${TEMP_ROOT}/rerun.log")" "idempotent link count"
|
||||
|
||||
dry_home="${TEMP_ROOT}/dry-home"
|
||||
dry_shared="${TEMP_ROOT}/dry-shared"
|
||||
dry_codex="${TEMP_ROOT}/dry-codex"
|
||||
dry_output="$(run_installer "${dry_home}" "${dry_shared}" "${dry_codex}" --dry-run 2>&1)"
|
||||
assert_contains 'Would bridge skills' "${dry_output}"
|
||||
[[ ! -e "${dry_shared}" ]] || fail 'dry run created the shared skill directory'
|
||||
[[ ! -e "${dry_codex}" ]] || fail 'dry run created the Codex directory'
|
||||
|
||||
copy_home="${TEMP_ROOT}/copy-home"
|
||||
copy_shared="${TEMP_ROOT}/copy-shared"
|
||||
copy_codex="${TEMP_ROOT}/copy-codex"
|
||||
mkdir -p -- "${copy_home}" "${copy_codex}/skills/.system"
|
||||
run_installer "${copy_home}" "${copy_shared}" "${copy_codex}" --copy >"${TEMP_ROOT}/copy.log" 2>&1 \
|
||||
|| { cat "${TEMP_ROOT}/copy.log" >&2; fail 'copy installation failed'; }
|
||||
assert_equals "${expected_skill_count}" "$(find "${copy_codex}/skills" -mindepth 1 -maxdepth 1 -type d ! -name .system | wc -l | tr -d ' ')" "copy count"
|
||||
run_installer "${copy_home}" "${copy_shared}" "${copy_codex}" --copy >"${TEMP_ROOT}/copy-rerun.log" 2>&1 \
|
||||
|| { cat "${TEMP_ROOT}/copy-rerun.log" >&2; fail 'idempotent copy rerun failed'; }
|
||||
assert_equals "${expected_skill_count}" "$(rg -c '^Already copied:' "${TEMP_ROOT}/copy-rerun.log")" "idempotent copy count"
|
||||
|
||||
conflict_home="${TEMP_ROOT}/conflict-home"
|
||||
conflict_shared="${TEMP_ROOT}/conflict-shared"
|
||||
conflict_codex="${TEMP_ROOT}/conflict-codex"
|
||||
first_skill="$(awk '
|
||||
/^SKILLS=\(/ { inside = 1; next }
|
||||
inside && /^ / { print $1; exit }
|
||||
' "${INSTALLER}")"
|
||||
mkdir -p -- "${conflict_home}" "${conflict_codex}/skills/${first_skill}"
|
||||
printf 'unmanaged\n' >"${conflict_codex}/skills/${first_skill}/marker.txt"
|
||||
if run_installer "${conflict_home}" "${conflict_shared}" "${conflict_codex}" >"${TEMP_ROOT}/conflict.log" 2>&1; then
|
||||
cat "${TEMP_ROOT}/conflict.log" >&2
|
||||
fail 'unmanaged conflict was not rejected'
|
||||
fi
|
||||
conflict_log_contents="$(<"${TEMP_ROOT}/conflict.log")"
|
||||
assert_contains 'Refusing to overwrite existing path' "${conflict_log_contents}"
|
||||
|
||||
printf 'Global skills installer tests passed (%d skills).\n' "${expected_skill_count}"
|
||||
@@ -0,0 +1,600 @@
|
||||
{
|
||||
"version": 1,
|
||||
"skills": {
|
||||
"agents-md-generator": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "b5b5d0dde3127aa10f6d7db1208d49919fdcbaf1374062b30ddc68dabb83b001"
|
||||
},
|
||||
"angular-architect": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "d93b695494c81c076a7c837007762f6e04b204ee19eccd7ff77969ff76835dfd"
|
||||
},
|
||||
"api-design-patterns": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "3f15c74774287c26486439158e2f7454907b6751fbd2e7842f034555e47df796"
|
||||
},
|
||||
"api-designer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "06e7906fe1ca4d1db195ca244ff7cc05e87e2c8b634662abeedd501c4657e88e"
|
||||
},
|
||||
"architecture-designer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "ecb729710037e01080fd2c342f37d2c25b3597bec70b8d529f9604abd8ccc142"
|
||||
},
|
||||
"ask-questions-if-underspecified": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "79458ea62d3f88fccd2c9936ebfcb025ce9a43d3302417bbee9d0e2edec30109"
|
||||
},
|
||||
"atlassian-mcp": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "4513b7e0d937979a80b774ef9220b0074c5c4230ea5cbb39cca4f1c402529491"
|
||||
},
|
||||
"chaos-engineer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "bc0cdbf36e1860a66d4f8d967c78ee31b1daed917c1ab9d7a015237ff071e718"
|
||||
},
|
||||
"clean-code-principles": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "4c22dca6110d58f1454523dc3f192ef20d91f538233da9132b407edd041a4762"
|
||||
},
|
||||
"cli-developer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "8ac5b5dc1cc784f255f4ebde0c65d0185da4a7d6b02d8d38838be178b62cfd7a"
|
||||
},
|
||||
"cloud-architect": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "9082e59c3dc8f05378bc52dc043724e22da525eea38916becb8778e2d320ac92"
|
||||
},
|
||||
"code-documenter": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "49709db09641a9ab4196459835bfcbe565eb0581c23cb4eeb50ff80d2af88272"
|
||||
},
|
||||
"code-reviewer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "57ab3eba6fa596bc52d73ca7312afc2f389d9622714d25b2ab3d4bbf03dc293a"
|
||||
},
|
||||
"code-slop": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "a4362f272da2f81751108d0bbfb8b5128e5067329619645d24b100c95dc3edd9"
|
||||
},
|
||||
"cpp-pro": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "a5632d28a479fe433c7fd9ab98903b9cd010926b3ddd73785ff0325d0277dbe6"
|
||||
},
|
||||
"csharp-developer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "90bd8e86b9c139379d225f4692b4e9deb588db680055439dc3b463833ef6adfb"
|
||||
},
|
||||
"database-optimizer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "2feb5b0765151417dab90bf014df41514386e4bdb25aad9ab38498c0bd18a1d8"
|
||||
},
|
||||
"debugging-wizard": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "9f39c248ae9588423cd12ea5197adf1530d7308eaf51a6d018ad08d52658a2ed"
|
||||
},
|
||||
"design-system-generator": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "402854c08c678a14b302a66bf48e43ea803bca8247fb1f6735fe9cabfe662535"
|
||||
},
|
||||
"devops-engineer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "6de5e562151fe9c227234e81bdc1e647066d6b1822463eadf296a5344b47e35a"
|
||||
},
|
||||
"django-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "f64e47ac397e308dde77144592cfc2fc2b60815c7ee653ef8bdc8cf860de3c27"
|
||||
},
|
||||
"docker-local-dev": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "2d81a4cea16c22c5404fef6f932aa8b22e2fe5cddc0b7ba4650f26b812afa585"
|
||||
},
|
||||
"documentation-guidelines": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "af9ad9dc6e7e18ab6896fad8bf23e19037671d2d06461452d7a6052119237334"
|
||||
},
|
||||
"dotnet-core-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "ceb0245bce4c20ad0760d7f589311e3ac2cdf110636a1581fa6d3018c7b27890"
|
||||
},
|
||||
"e2e-playwright-testing": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "ee097dfeaa4d731a35ab47bd930859f17d7d0d073d0df3720435b02d97d12210"
|
||||
},
|
||||
"eloquent-best-practices": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "370e1502efc9d179f5df7470a45a10302de81de9cf378641403e4ade9eb7d67f"
|
||||
},
|
||||
"embedded-systems": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "1631345781a5ed3ba2a780a710b8c23cb1b0abaaf576164c40d15b20683d2f6e"
|
||||
},
|
||||
"fastapi-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "eb70cfcb3a06badfbdf51262ecb31b868a983963b9d6654e02856752828b312f"
|
||||
},
|
||||
"feature-forge": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "a6ed33cfbfc0259c39f42ad69cc55ace984da805c4f4197df437770cf7c1b671"
|
||||
},
|
||||
"find-scene": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "2a5ebaf950698a1751270337b9eb80dd37c3ebd459be3920d787506cc2455f84"
|
||||
},
|
||||
"fine-tuning-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "8e70137cf3de9a6edba12d3f523c087c0407002f1206b0981b767323e0f5a54e"
|
||||
},
|
||||
"flutter-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "c7849f39cf34d91999f573b8ad39315dd68c7717bcd38c42b5e49cd83785d9c1"
|
||||
},
|
||||
"fullstack-guardian": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "2d3533f91951f2c8626eaeb7ffb33e40727bca85545a8e63f97e35939957e1a4"
|
||||
},
|
||||
"game-developer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "5310da9a7910ae7e9d119abb7377b6213b1dc7767e4aacd818b8fdb60abab36f"
|
||||
},
|
||||
"git-workflow": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "e6a28779208771a57940a14e1f9e463ab65c1f8e660fcc52d05b9ec05de3fab1"
|
||||
},
|
||||
"golang-pro": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "12b4cac8f65228f82cbc26f0da9232aba87ffa45ccd01afa3998fb8ec61dc288"
|
||||
},
|
||||
"graphql-architect": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "78c6dd863af986f7f409e26ba25dc14f76985f892a0340383dc56a7b8439ec43"
|
||||
},
|
||||
"java-architect": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "02a7bcc716c9338aedcb0727be38a86d6addbadb1c17b485d019f654d2b04af6"
|
||||
},
|
||||
"javascript-pro": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "d5d4526309a674a2ddfd99aa9fb31fe061af225a7b3750eed52a2d38c8ce6041"
|
||||
},
|
||||
"kotlin-specialist": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "7119693c0ce1ebf7de447ccafef33cd319b9a8bfc057b6dfcb137caac2fea274"
|
||||
},
|
||||
"kubernetes-specialist": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "9c5eb68fc9d553ee29e745258bc6198563158c4b2c57436d63647e61010b5f0a"
|
||||
},
|
||||
"laravel-11-12-app-guidelines": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "9505833bc35846abbfbb5ab93e1c45a7da179e7cccc3122223a4881afefab7cd"
|
||||
},
|
||||
"laravel-ai-sdk": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "6e7fb4360bcbe6eea2a634d7b96a46b41887f60eca806f54b7400f3efa508ce0"
|
||||
},
|
||||
"laravel-api-resource-patterns": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "b140eaa32c967c9bbde994a47dc56491132efd97f06a534920e13dbbc36db887"
|
||||
},
|
||||
"laravel-authorization-patterns": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "57418ddc3eea7b850c96dbcd431070e75b2abff5a4bd010f759133e225c5e216"
|
||||
},
|
||||
"laravel-best-practices": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "6eb357774a2416b3e632cf4f7dec1ff9558af2d70c4b8ade802f5a65ce118fb5"
|
||||
},
|
||||
"laravel-blade-component-patterns": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "4fe35eb514db82613a195b4c3d790618adb88e70e68a84ff9c50d086fa288759"
|
||||
},
|
||||
"laravel-brainstorming": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "ff3aa9135e3e2573bb7edb664b611baefeef893c9425f52ccda87a56618e9089"
|
||||
},
|
||||
"laravel-caching-strategies": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "7b5d23808f7355be3de5328f8c0f5ca80ab194b252aeed697c3ee505fc90b270"
|
||||
},
|
||||
"laravel-database-optimization": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "564cbba91a281420e077178d7b367ef1c367576ff6f050f9ee6eaa99d30d2a1c"
|
||||
},
|
||||
"laravel-event-driven-architecture": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "5b43a13e97cc0b9dcd5df9bf819a15b254f1dd016ccadb94bb5e6d3c77710de9"
|
||||
},
|
||||
"laravel-feature-flags": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "46214cd3e065d109cfcba59dce63cb75563b97efc200deac8b6c1333bda48f75"
|
||||
},
|
||||
"laravel-inertia-react": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "b05144f7f9df5fd3cd03ce13cba822ac61970449fdf7c4c4208684258e8b1724"
|
||||
},
|
||||
"laravel-mcp": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "31de735b826f5c8e7b64ca133b10f2fc6b4a1789bb6b144aecccc948fe8ef689"
|
||||
},
|
||||
"laravel-middleware-patterns": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "44414ad9a3dbe8753d0861673b8fdf10d9bec931564c0e552c9accecdefbedf3"
|
||||
},
|
||||
"laravel-notification-patterns": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "658eaf3f166438e7d5e5403c3bd0b9e2670a2858a45d70da68289fa18c01ce60"
|
||||
},
|
||||
"laravel-owasp-security": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "35f74b7fb37c9b0cb1a274e7e25f7425e793dacd73620c3507c7e9462e4c9c9d"
|
||||
},
|
||||
"laravel-quality": {
|
||||
"source": "leeovery/claude-laravel",
|
||||
"sourceType": "github",
|
||||
"computedHash": "bffa603f3f1128d2d3b1c2dcbbbffdec1bd239d4a799c74419deb627fa64a518"
|
||||
},
|
||||
"laravel-queue-patterns": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "4bfe5b51ed89506df59a32de0f4be4ab2cc106356b98149953441a109bd2f951"
|
||||
},
|
||||
"laravel-queues": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "75391b4d5635e0db3ef8a02bd512a2974b98bae97375fdfd9a18fe7ad936dbf8"
|
||||
},
|
||||
"laravel-specialist": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "d58e2ed3488398cb94a039f25b9d270e55dc434e16102abff9035608bec3db90"
|
||||
},
|
||||
"laravel-systematic-debugging": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "82db3f7d4e3cfc3b3d1605a96c06612f93121dd3c879208d9dba23f30495518d"
|
||||
},
|
||||
"laravel-task-scheduling": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "833b36a2ae73833137431c6b7b5d9d393adfe93b3ab4d135e87acead31a7cc20"
|
||||
},
|
||||
"laravel-tdd": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "f895a09949a45fb610d8f033c168fc7ed70ef33323c38ef176add410ddd58e8e"
|
||||
},
|
||||
"laravel-testing": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "9627c977341aa7a9a11e5f500838409c1e39e1ca0714c6a6038fba4d3a5203c9"
|
||||
},
|
||||
"laravel-validation-patterns": {
|
||||
"source": "iserter/laravel-claude-agents",
|
||||
"sourceType": "github",
|
||||
"computedHash": "66fb92309a38bba54c8730a0efccc0f3092cf7dbfb71b294ff33c1becae91285"
|
||||
},
|
||||
"legacy-modernizer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "703bc6b068b60f1ca32c2892f3aa3875c986fa17b65676f612810eb52c21b5eb"
|
||||
},
|
||||
"mcp-developer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "e94458c5a3ca95938decbcf071e1fa3d1bb44a8b878c5a7cab7b48b7612dc5db"
|
||||
},
|
||||
"microservices-architect": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "674b7d4c18eb009295213cbb49ccdc112db1d2f60bb65848ceb8771bdc69a25f"
|
||||
},
|
||||
"ml-pipeline": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "5e80b6260cabb7e8705b04627f1ec1a70341ecf2e77cbc5df1b6fcb5242e18e5"
|
||||
},
|
||||
"monitoring-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "928f8e068a5c3c85e4a8d515241f21e5cf6a38b39c597cf54b681197fa107853"
|
||||
},
|
||||
"nestjs-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "0775f4ba14e4f372b894cc86feb0bf58a51b2038bc98b3ff18f2021565cea494"
|
||||
},
|
||||
"nextjs-developer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "e53bdeaf766e6d5d29d1328f424777a8236f80f489134f1661bbda6c8c4149e9"
|
||||
},
|
||||
"noizai-voice-workflow": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "1bf4fba1bd0c3bd4c453a9aec4f981409bc64b17775361db55c2cba7863cb881"
|
||||
},
|
||||
"office-web-ui-system": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "574a097be28bab7f80d5bd998da1323501eb0adf755671c4020def825e5313d1"
|
||||
},
|
||||
"pandas-pro": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "386d7588ba685df487079293be0f6d026467db579df9337c798aeb20e2d82a59"
|
||||
},
|
||||
"php-best-practices": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "1b25a60572ddd8b206eaf68b067cde70a9d002df572de8fefda703532cecfdad"
|
||||
},
|
||||
"php-pro": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "c163f6d5d26ddbf4a4d79e8dc95d3b41e447f1659486cf0aae8c070d950a9d86"
|
||||
},
|
||||
"playwright-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "2715b8412ae840555d77d3d2c566e6f75ca42900637363d7574356af409ae10c"
|
||||
},
|
||||
"postgres-pro": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "b5385f29408d4bd80666e608dbd7da3d4bed9153afa53b71bda94c6bf7ba8d51"
|
||||
},
|
||||
"prd-writing": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "4c3141b2fdc77aac6a528bd9cee5e07d8122d75a89295f4020ceab112c1d44a9"
|
||||
},
|
||||
"project-development-mindset": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "b8bf39985a51545efb84b396bf9c262bdd99f7b412be6d70a6f2ce28933324e3"
|
||||
},
|
||||
"project-docs": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "d2da7474d61edf37883e91b31dec49efbcb5bc6979e8d132dceaa26c3fad1b61"
|
||||
},
|
||||
"prompt-engineer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "c2574f1d0c4120117727dbfe79da8bf087b50635df30920ae1d2bc9b256ce7c6"
|
||||
},
|
||||
"python-pro": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "fae3b07d03d2eb9f9112ceab0ef498ebafab33f1e095dff8c5a36de55ef68445"
|
||||
},
|
||||
"rag-architect": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "650ce80b998ce2c3004c5276a1eabaa2ad4131d4256832eed9a5e06cdc98454d"
|
||||
},
|
||||
"rails-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "e67a8886ff2a11da8133188a0bc0b48b9df213c6fc4bac4cbdd1ddacabb628c1"
|
||||
},
|
||||
"react-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "498e8247c701522e0a63496a439680a409dafe67c3d8d7d5e4902db0e6222252"
|
||||
},
|
||||
"react-native-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "f617f83be990728fef1ea2192c9b8ae85ef2c362e97f18782438f8bab357b02a"
|
||||
},
|
||||
"react-vite-best-practices": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "82994934665a490b227fabdfec3d148b1fa291d77d82ccf978e761b9e1ff6e4c"
|
||||
},
|
||||
"rust-engineer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "f8093c6253afe24bbac3c3328c3ca07e9ef089758896ba10221ed0f2078cb2a0"
|
||||
},
|
||||
"salesforce-developer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "a4b5ae7acb98027b4aeb6a3eb31f301af20e30c6e0701b1d237b5714f159a479"
|
||||
},
|
||||
"secure-code-guardian": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "36e0b6460df5ea86c0a6aeeb1d33ad6dfa8f8a404ba1dc47feb3cf93341cb2c6"
|
||||
},
|
||||
"security-reviewer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "7a1ed4f4ca78a50b97e3e8c5725e494dc8aae0895bd1efde681a75ab22ff89d3"
|
||||
},
|
||||
"seo-best-practices": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "4bc88f564290e835fd5f486bdacce1c3a867afaafa118363c9e80f6e6466a8d7"
|
||||
},
|
||||
"shopify-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "b44431e08c55a0439ee41ed8893e6f6698f5e75e216b0a8f6c756cb5d461c016"
|
||||
},
|
||||
"spark-engineer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "4c66f4104d2780f8075ca8e38084d009dfe7d2f8c594424f570611e50d4943b6"
|
||||
},
|
||||
"spec-miner": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "91822456789ffa6f5641d4f586df7533757fbc02629b76cb6e68cce5e369b13a"
|
||||
},
|
||||
"spring-boot-engineer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "ed065f5db45afe9dc2739cff713927d0b6b6ad3e667bdf7b40340d1a5543bb0f"
|
||||
},
|
||||
"sql-pro": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "4bbeda009afc2d98d07cdcd5ad318ad7b8921073f74a3118b452b9c01947db0d"
|
||||
},
|
||||
"sre-engineer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "f3bcde0381f316487e2475f01ed6951d6e1d5636c46c807c29f5efc5a802381e"
|
||||
},
|
||||
"state-management": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "0bad07f74366ae633503a6f256eae7d7335c5ba9277110b4d788263d56a7a07a"
|
||||
},
|
||||
"swift-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "3486707c8581c84d35d3da765ad9afd3744f93e9d208505bcb91c093e70d95c1"
|
||||
},
|
||||
"symcli-skill": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "7e565fc813d15787deb8341c56e2bd964ce669ce8fbaad065b47841d635e28b6"
|
||||
},
|
||||
"tailwind-best-practices": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "39145b4b9d12b154d9ff9261805d225557a1dcb5c881b1da8dcc027004aefd44"
|
||||
},
|
||||
"technical-debt": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "a127f457928fb6dc439751ec0cdb6edef14c78e90b6fd6e26ff31eb18b2e90c3"
|
||||
},
|
||||
"terraform-engineer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "04e717ca5d883a2839863f371f8ebba8b3f89cde3b2292cf90a3186c30b2d24a"
|
||||
},
|
||||
"test-master": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "176d5be77c9fb4e64335a4ad9e38dfb82ccb029dc302c417db99a11e2d880180"
|
||||
},
|
||||
"testing-best-practices": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "590eb4064d9fa41854f7871991a3c1ef566553593338632c6cf88d9984194d61"
|
||||
},
|
||||
"the-fool": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "41aa64b8ccd474bd3c693454f4e0fc01a190512e01264817285a0527362d9756"
|
||||
},
|
||||
"typescript-pro": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "b53b57340243eab4b75acee9096f0444319bb1b9e8530fdab4d1d75e1568fa6c"
|
||||
},
|
||||
"typescript-react-patterns": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "650048e53310097d1e9029a668c0b39e5738ce70fbe3b23f35cd875fc05b48e5"
|
||||
},
|
||||
"ui-mockup-visualizer": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "42248697304475f800e799899431c03845fb9f8841edb3f7b5fb9f8ba8fd1a10"
|
||||
},
|
||||
"vps-docker-traefik-deploy": {
|
||||
"source": "thienanblog/awesome-ai-agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "fdb0cfdbebd039ddec2d8f3a2ee5734188c05e6b4bc85be377114f821f790895"
|
||||
},
|
||||
"vue-expert": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "7276996f25e0e22316d480d12a51ea8f7441cc9855e79590ed0f5e2a25da4714"
|
||||
},
|
||||
"vue-expert-js": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "f9480e6f932c64f0f87a609691bbf587978f21017f9104b4010c4890b03dea16"
|
||||
},
|
||||
"web-design-guidelines": {
|
||||
"source": "asyrafhussin/agent-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "e27800d4c6a4cf98c50776af70d0b0ea1ebf5b81a03992b2019309f0ea9e7012"
|
||||
},
|
||||
"websocket-engineer": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "8e5e1a8313d92d2d9631b163672291f7edd4cfdc4a7ede545fbcd863c0ab7f7b"
|
||||
},
|
||||
"wordpress-pro": {
|
||||
"source": "jeffallan/claude-skills",
|
||||
"sourceType": "github",
|
||||
"computedHash": "ef569ff0920fa0948aca9a464118e13b9a9d655f40fd5b61526b7e53a80f451c"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user