218 lines
6.3 KiB
Bash
Executable File
218 lines
6.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Install the DeepSeek Harness side of claude-harness.
|
|
#
|
|
# This script never installs the Cordis bundle into a profile: the Desktop
|
|
# profile is Electron-managed, so the bundle goes through the GUI Plugins page
|
|
# or the model-facing `plugin_manager` tool. The script prepares the global
|
|
# instructions, the user skill root, and the role files, then prints the bundle
|
|
# path.
|
|
#
|
|
# Usage:
|
|
# bash dsh/install.sh --check
|
|
# bash dsh/install.sh --global
|
|
# bash dsh/install.sh --skills
|
|
# bash dsh/install.sh --roles
|
|
# bash dsh/install.sh --all
|
|
#
|
|
# Run it from a terminal, not from inside a DSH session: --global, --skills and
|
|
# --roles write outside the session workspace and would require approval.
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
BUNDLE="$ROOT/dsh/bundle"
|
|
DSH_HOME="${DSH_HOME:-$HOME/.dsh}"
|
|
DO_CHECK=0
|
|
DO_GLOBAL=0
|
|
DO_SKILLS=0
|
|
DO_ROLES=0
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: bash dsh/install.sh [--check] [--global] [--skills] [--roles] [--all]
|
|
|
|
--check verify python3, git, node, hooks, bundle, skills, and roles
|
|
--global back up and write \$DSH_HOME/AGENTS.md from global/CLAUDE.md
|
|
--skills copy installed superpowers skills into \$DSH_HOME/skills
|
|
--roles copy roles/ into \$DSH_HOME/roles
|
|
--all --check + --global + --skills + --roles, then print the bundle step
|
|
|
|
Bundle installation itself is done in DSH:
|
|
Plugins -> install a bundle from $BUNDLE
|
|
or ask the agent to call plugin_manager install_bundle with that target.
|
|
EOF
|
|
}
|
|
|
|
if [ "$#" -eq 0 ]; then
|
|
DO_CHECK=1
|
|
fi
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--check) DO_CHECK=1 ;;
|
|
--global) DO_GLOBAL=1 ;;
|
|
--skills) DO_SKILLS=1 ;;
|
|
--roles) DO_ROLES=1 ;;
|
|
--all) DO_CHECK=1; DO_GLOBAL=1; DO_SKILLS=1; DO_ROLES=1 ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) echo "unknown option: $arg" >&2; usage >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
superpowers_skills() {
|
|
local dir
|
|
dir="$(ls -d "$HOME"/.claude/plugins/cache/claude-plugins-official/superpowers/*/skills 2>/dev/null | sort -V | tail -1 || true)"
|
|
if [ -n "$dir" ] && [ -d "$dir" ]; then
|
|
printf '%s\n' "$dir"
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
check() {
|
|
local failed=0
|
|
for cmd in python3 git node; do
|
|
if command -v "$cmd" >/dev/null 2>&1; then
|
|
echo "ok: $cmd ($("$cmd" --version 2>&1 | head -1))"
|
|
else
|
|
echo "WARN: $cmd not found" >&2
|
|
failed=1
|
|
fi
|
|
done
|
|
if [ -f "$ROOT/hooks/harness_target.py" ]; then
|
|
echo "ok: hooks/harness_target.py"
|
|
else
|
|
echo "FAIL: $ROOT/hooks/harness_target.py is missing" >&2
|
|
failed=1
|
|
fi
|
|
if [ -f "$ROOT/global/CLAUDE.md" ]; then
|
|
echo "ok: global/CLAUDE.md"
|
|
else
|
|
echo "FAIL: $ROOT/global/CLAUDE.md is missing" >&2
|
|
failed=1
|
|
fi
|
|
if [ -f "$BUNDLE/index.js" ] && [ -f "$BUNDLE/cordis.patch.yml" ]; then
|
|
echo "ok: bundle $BUNDLE"
|
|
else
|
|
echo "FAIL: bundle is incomplete: $BUNDLE" >&2
|
|
failed=1
|
|
fi
|
|
if [ -f "$BUNDLE/hooks/guard-main.sh" ] && [ -f "$BUNDLE/hooks/require-plan.sh" ]; then
|
|
echo "ok: hook bridge"
|
|
else
|
|
echo "FAIL: hook bridge is missing (is dsh/bundle/hooks a symlink to ../../hooks?)" >&2
|
|
failed=1
|
|
fi
|
|
if [ -f "$DSH_HOME/skills/using-superpowers/SKILL.md" ]; then
|
|
echo "ok: dsh skills ($DSH_HOME/skills)"
|
|
elif superpowers_skills >/dev/null 2>&1; then
|
|
echo "ok: superpowers source ($(superpowers_skills)); run --skills to copy"
|
|
else
|
|
echo "WARN: superpowers plugin not found; the bootstrap will be skipped" >&2
|
|
fi
|
|
if [ -f "$DSH_HOME/roles/dev.md" ]; then
|
|
echo "ok: roles ($DSH_HOME/roles)"
|
|
elif [ -f "$HOME/.claude/roles/dev.md" ]; then
|
|
echo "ok: roles (~/.claude/roles; run --roles to copy)"
|
|
elif [ -f "$ROOT/roles/dev.md" ]; then
|
|
echo "ok: roles ($ROOT/roles; run --roles to install)"
|
|
else
|
|
echo "WARN: roles not found; /role will fail until --roles is run" >&2
|
|
fi
|
|
echo "DSH_HOME=$DSH_HOME"
|
|
return "$failed"
|
|
}
|
|
|
|
install_global() {
|
|
mkdir -p "$DSH_HOME"
|
|
local target="$DSH_HOME/AGENTS.md"
|
|
if [ -f "$target" ]; then
|
|
local backup="$target.bak.$(date +%s)"
|
|
cp "$target" "$backup"
|
|
echo "backup: $backup"
|
|
fi
|
|
{
|
|
echo "# DeepSeek Harness global instructions"
|
|
echo
|
|
echo "Installed from $ROOT/global/CLAUDE.md by dsh/install.sh."
|
|
echo "The dsh-harness bundle enforces guard-main/require-plan and provides /role."
|
|
echo "DSH adapter: role hints come from the first message or /role; there is no SessionStart hint."
|
|
echo "DSH adapter: /role reads ~/.dsh/roles, then ~/.claude/roles, then $ROOT/roles."
|
|
echo "DSH adapter: bootstrap prefers ~/.dsh/skills; the ~/.claude cache is a fallback."
|
|
echo "DSH adapter: codegraph MCP tools are named mcp__codegraph__codegraph_explore."
|
|
echo
|
|
cat "$ROOT/global/CLAUDE.md"
|
|
} > "$target"
|
|
echo "written: $target"
|
|
}
|
|
|
|
install_skills() {
|
|
mkdir -p "$DSH_HOME/skills"
|
|
local skills
|
|
if ! skills="$(superpowers_skills)"; then
|
|
echo "WARN: superpowers skills not found; nothing copied" >&2
|
|
return 0
|
|
fi
|
|
local count=0
|
|
local dir name dest
|
|
for dir in "$skills"/*; do
|
|
[ -f "$dir/SKILL.md" ] || continue
|
|
name="$(basename "$dir")"
|
|
dest="$DSH_HOME/skills/$name"
|
|
rm -rf "$dest"
|
|
cp -R "$dir" "$dest"
|
|
count=$((count + 1))
|
|
done
|
|
echo "copied $count superpowers skills into $DSH_HOME/skills"
|
|
}
|
|
|
|
install_roles() {
|
|
mkdir -p "$DSH_HOME/roles"
|
|
local src="$ROOT/roles"
|
|
local count=0
|
|
local file name
|
|
for file in "$src"/*.md; do
|
|
[ -f "$file" ] || continue
|
|
name="$(basename "$file")"
|
|
cp "$file" "$DSH_HOME/roles/$name"
|
|
count=$((count + 1))
|
|
done
|
|
if [ "$count" -eq 0 ]; then
|
|
echo "WARN: no role files found in $src" >&2
|
|
return 0
|
|
fi
|
|
echo "installed $count roles into $DSH_HOME/roles"
|
|
}
|
|
|
|
print_bundle_step() {
|
|
cat <<EOF
|
|
|
|
Bundle: $BUNDLE
|
|
|
|
Install it in the current DSH profile (the Desktop profile is Electron-managed):
|
|
- GUI: Plugins -> install a bundle from the directory above;
|
|
- or ask the agent to call plugin_manager install_bundle with target "$BUNDLE".
|
|
Do not edit \$DSH_HOME/profiles/desktop/package.json or cordis.patch.yml by hand.
|
|
|
|
Optional: add CodeGraph as an MCP server from dsh/mcp.codegraph.yml.
|
|
EOF
|
|
}
|
|
|
|
status=0
|
|
if [ "$DO_CHECK" = 1 ]; then
|
|
check || status=1
|
|
fi
|
|
if [ "$DO_GLOBAL" = 1 ]; then
|
|
install_global
|
|
fi
|
|
if [ "$DO_SKILLS" = 1 ]; then
|
|
install_skills
|
|
fi
|
|
if [ "$DO_ROLES" = 1 ]; then
|
|
install_roles
|
|
fi
|
|
if [ "$DO_GLOBAL" = 1 ] || [ "$DO_SKILLS" = 1 ] || [ "$DO_ROLES" = 1 ]; then
|
|
print_bundle_step
|
|
fi
|
|
|
|
exit "$status"
|