mirror of
https://github.com/warpdotdev/common-skills.git
synced 2026-09-14 19:03:05 +08:00
15142ef26b
* Add common skills management scripts Co-Authored-By: Oz <oz-agent@warp.dev> * Install all common skills dynamically Co-Authored-By: Oz <oz-agent@warp.dev> * Share common skills script helpers Co-Authored-By: Oz <oz-agent@warp.dev> * Update common skills script structure Co-Authored-By: Oz <oz-agent@warp.dev> * Handle verify-only without lock file Co-Authored-By: Oz <oz-agent@warp.dev> * Refine common skills installer Co-Authored-By: Oz <oz-agent@warp.dev> * Add common skills repair helpers Co-Authored-By: Oz <oz-agent@warp.dev> * Add update-skill lockfile test marker Co-Authored-By: Oz <oz-agent@warp.dev> * Add common skills installer update path Co-Authored-By: Oz <oz-agent@warp.dev> * Refine common skills update workflow Co-Authored-By: Oz <oz-agent@warp.dev> * Run skills CLI non-interactively Co-Authored-By: Oz <oz-agent@warp.dev> * Remove common skills script dead code Co-Authored-By: Oz <oz-agent@warp.dev> * Document common skills client invocation Co-Authored-By: Oz <oz-agent@warp.dev> * Fix common skills lock restore flows Ensure no-target non-interactive flows fail before attempting TTY prompts, and restore global common skills from a temporary lock checkout so restore paths do not rewrite the client repo lock. Co-Authored-By: Oz <oz-agent@warp.dev> * Validate common skills script dependencies Co-Authored-By: Oz <oz-agent@warp.dev> --------- Co-authored-by: Oz <oz-agent@warp.dev>
297 lines
6.4 KiB
Bash
Executable File
297 lines
6.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -eo pipefail
|
|
|
|
REPO_ROOT="${WARP_COMMON_SKILLS_TARGET_REPO_ROOT:-$(pwd)}"
|
|
LOCK_FILE=""
|
|
STAMP_RELATIVE_PATH="warp/common-skills-lock.hash"
|
|
CLEAR_LOCK=0
|
|
|
|
TARGET="${WARP_COMMON_SKILLS_INSTALL_TARGET:-project}"
|
|
|
|
resolve_repo_root() {
|
|
cd "$1" && pwd
|
|
}
|
|
|
|
project_stamp_file() {
|
|
local git_path=""
|
|
|
|
if git_path="$(git -C "${REPO_ROOT}" rev-parse --git-path "${STAMP_RELATIVE_PATH}" 2>/dev/null)"; then
|
|
case "${git_path}" in
|
|
/*)
|
|
echo "${git_path}"
|
|
;;
|
|
*)
|
|
echo "${REPO_ROOT}/${git_path}"
|
|
;;
|
|
esac
|
|
return
|
|
fi
|
|
|
|
echo "${REPO_ROOT}/.agents/skills/.common-skills-lock.hash"
|
|
}
|
|
|
|
project_exclude_file() {
|
|
local git_path=""
|
|
|
|
if git_path="$(git -C "${REPO_ROOT}" rev-parse --git-path "info/exclude" 2>/dev/null)"; then
|
|
case "${git_path}" in
|
|
/*)
|
|
echo "${git_path}"
|
|
;;
|
|
*)
|
|
echo "${REPO_ROOT}/${git_path}"
|
|
;;
|
|
esac
|
|
return
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
global_stamp_file() {
|
|
echo "${HOME}/.agents/warp/common-skills-lock.hash"
|
|
}
|
|
|
|
stamp_file() {
|
|
if [[ "${TARGET}" = "global" ]]; then
|
|
global_stamp_file
|
|
else
|
|
project_stamp_file
|
|
fi
|
|
}
|
|
|
|
normalize_common_skills_target() {
|
|
local target
|
|
target="$(printf "%s" "$1" | tr '[:upper:]' '[:lower:]')"
|
|
|
|
case "${target}" in
|
|
""|p|project|1)
|
|
echo "project"
|
|
;;
|
|
g|global|2)
|
|
echo "global"
|
|
;;
|
|
*)
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
locked_skill_names() {
|
|
node -e '
|
|
const fs = require("fs");
|
|
const lock = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
for (const name of Object.keys(lock.skills || {})) {
|
|
console.log(name);
|
|
}
|
|
' "${LOCK_FILE}"
|
|
}
|
|
|
|
locked_skill_paths() {
|
|
node -e '
|
|
const fs = require("fs");
|
|
const lock = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
for (const skill of Object.values(lock.skills || {})) {
|
|
console.log(skill.skillPath);
|
|
}
|
|
' "${LOCK_FILE}"
|
|
}
|
|
|
|
target_description() {
|
|
if [[ "${TARGET}" = "global" ]]; then
|
|
echo "~/.agents/skills"
|
|
else
|
|
echo ".agents/skills"
|
|
fi
|
|
}
|
|
|
|
validate_required_commands() {
|
|
local missing=0
|
|
local tool=""
|
|
|
|
for tool in "$@"; do
|
|
if ! command -v "${tool}" >/dev/null 2>&1; then
|
|
echo "error: required command '${tool}' is not installed or not on PATH." >&2
|
|
missing=1
|
|
fi
|
|
done
|
|
|
|
if [[ "${missing}" -eq 1 ]]; then
|
|
echo "Install the missing tools, then rerun scripts/remove_common_skills." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: scripts/remove_common_skills [options]
|
|
|
|
Remove common agent skills listed in the standard project skills-lock.json.
|
|
|
|
Options:
|
|
--repo-root <path> Repository containing skills-lock.json and project skills.
|
|
--project Remove from this checkout's .agents/skills directory (default).
|
|
--global Remove from ~/.agents/skills for the current user.
|
|
--clear-lock Also remove skills-lock.json after removing locked skills.
|
|
-h, --help Show this help message.
|
|
|
|
Environment:
|
|
WARP_COMMON_SKILLS_INSTALL_TARGET=project|global
|
|
Choose the removal target when no explicit --project/--global flag is provided.
|
|
WARP_COMMON_SKILLS_TARGET_REPO_ROOT=/path/to/repo
|
|
Repository containing skills-lock.json and project-local .agents/skills.
|
|
EOF
|
|
}
|
|
|
|
remove_project_from_lock() {
|
|
local path=""
|
|
local skill_dir=""
|
|
|
|
while IFS= read -r path; do
|
|
if [[ -z "${path}" ]]; then
|
|
continue
|
|
fi
|
|
|
|
case "${path}" in
|
|
.agents/skills/*/SKILL.md)
|
|
skill_dir="$(dirname "${REPO_ROOT}/${path}")"
|
|
;;
|
|
*)
|
|
echo "error: refusing to remove unexpected skill path from lock file: ${path}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
case "${skill_dir}" in
|
|
"${REPO_ROOT}/.agents/skills/"*)
|
|
rm -rf -- "${skill_dir}"
|
|
;;
|
|
*)
|
|
echo "error: refusing to remove path outside .agents/skills: ${skill_dir}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done < <(locked_skill_paths)
|
|
}
|
|
|
|
remove_global_from_lock() {
|
|
local name=""
|
|
local skill_dir=""
|
|
|
|
while IFS= read -r name; do
|
|
if [[ -z "${name}" ]]; then
|
|
continue
|
|
fi
|
|
|
|
case "${name}" in
|
|
*/*|.|..)
|
|
echo "error: refusing to remove unexpected skill name from lock file: ${name}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
skill_dir="${HOME}/.agents/skills/${name}"
|
|
rm -rf -- "${skill_dir}"
|
|
done < <(locked_skill_names)
|
|
}
|
|
|
|
remove_from_lock() {
|
|
if [[ "${TARGET}" = "global" ]]; then
|
|
remove_global_from_lock
|
|
else
|
|
remove_project_from_lock
|
|
remove_project_common_skills_ignore_block
|
|
fi
|
|
|
|
rm -f -- "$(stamp_file)"
|
|
}
|
|
|
|
remove_project_common_skills_ignore_block() {
|
|
local exclude_file=""
|
|
local tmp_file=""
|
|
local marker_start="# BEGIN warp common-skills"
|
|
local marker_end="# END warp common-skills"
|
|
|
|
if ! exclude_file="$(project_exclude_file)"; then
|
|
return 0
|
|
fi
|
|
|
|
if [[ ! -f "${exclude_file}" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
tmp_file="$(mktemp)"
|
|
awk -v start="${marker_start}" -v end="${marker_end}" '
|
|
$0 == start { skipping = 1; next }
|
|
$0 == end { skipping = 0; next }
|
|
!skipping { print }
|
|
' "${exclude_file}" > "${tmp_file}"
|
|
cat "${tmp_file}" > "${exclude_file}"
|
|
rm -f "${tmp_file}"
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--repo-root)
|
|
if [[ -n "${2:-}" ]]; then
|
|
REPO_ROOT="$2"
|
|
shift 2
|
|
else
|
|
echo "error: argument for $1 is missing" >&2
|
|
usage >&2
|
|
exit 1
|
|
fi
|
|
;;
|
|
--project)
|
|
TARGET="project"
|
|
shift
|
|
;;
|
|
--global)
|
|
TARGET="global"
|
|
shift
|
|
;;
|
|
--clear-lock)
|
|
CLEAR_LOCK=1
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "error: unknown argument: $1" >&2
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if ! REPO_ROOT="$(resolve_repo_root "${REPO_ROOT}")"; then
|
|
echo "error: repo root does not exist: ${REPO_ROOT}" >&2
|
|
exit 1
|
|
fi
|
|
LOCK_FILE="${REPO_ROOT}/skills-lock.json"
|
|
|
|
if [[ "${TARGET}" != "project" && "${TARGET}" != "global" ]]; then
|
|
echo "error: invalid common skills removal target: ${TARGET} (expected project or global)" >&2
|
|
usage >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "${LOCK_FILE}" ]]; then
|
|
if [[ "${CLEAR_LOCK}" -eq 1 ]]; then
|
|
echo "Skills lock file is already absent: ${LOCK_FILE}"
|
|
exit 0
|
|
fi
|
|
echo "error: missing skills lock file: ${LOCK_FILE}" >&2
|
|
exit 1
|
|
fi
|
|
validate_required_commands git node
|
|
|
|
echo "Removing common agent skills listed in skills-lock.json from $(target_description)."
|
|
remove_from_lock
|
|
if [[ "${CLEAR_LOCK}" -eq 1 ]]; then
|
|
rm -f -- "${LOCK_FILE}"
|
|
fi
|