dotfiles/.agents/install.sh
Brydon DeWitt 6b07e4ccb2 feat: add shared agent infrastructure (.agents/)
- AGENTS.md: design principles, enforcement hierarchy, deferred loading
- agents/: brainstorm, build, orchestrator, research (auto-discovered by MCP server)
- skills/: research methodology (auto-discovered by MCP server)
- hooks/: pre-tool-use, post-tool-use (BFF block removed), session-start,
  stop, pre-compact, user-prompt-submit
- frameworks/: opencode/plugin.ts (resolves hooks via import.meta.url — works
  as project-local or global plugin), github/hooks.json
- mcp/index.ts: auto-discovers agents/*.md and skills/*.md from frontmatter
  (replaces hand-maintained registry); server renamed all-agents
- docs/: agent-infrastructure.md (generalized), research docs (7 files),
  ai_architectures.md, llama-server-cuda-wsl2.md
- install.sh: idempotent setup — Copilot global hooks, OpenCode global plugin +
  AGENTS.md + MCP entry, VS Code global MCP config
2026-05-22 13:13:43 -04:00

130 lines
6.1 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# install.sh — Wire ~/dotfiles/.agents/ into global tool configs.
# Idempotent: safe to re-run. Creates dirs, symlinks, and config entries.
# Run once per machine after cloning dotfiles.
set -euo pipefail
DOTFILES_AGENTS="$(cd "$(dirname "$0")" && pwd)"
log() { printf '\033[0;32m✓\033[0m %s\n' "$1"; }
warn() { printf '\033[0;33m⚠\033[0m %s\n' "$1"; }
skip() { printf '\033[0;34m\033[0m %s\n' "$1"; }
# ── 1. Copilot global hooks ──────────────────────────────────────────────────
COPILOT_HOOKS_DIR="$HOME/.copilot/hooks"
COPILOT_HOOK_TARGET="$DOTFILES_AGENTS/frameworks/github/hooks.json"
COPILOT_HOOK_LINK="$COPILOT_HOOKS_DIR/agent-support.json"
mkdir -p "$COPILOT_HOOKS_DIR"
if [[ -L "$COPILOT_HOOK_LINK" && "$(readlink "$COPILOT_HOOK_LINK")" == "$COPILOT_HOOK_TARGET" ]]; then
skip "Copilot hook symlink already set: $COPILOT_HOOK_LINK"
else
ln -sf "$COPILOT_HOOK_TARGET" "$COPILOT_HOOK_LINK"
log "Copilot hook symlink: $COPILOT_HOOK_LINK$COPILOT_HOOK_TARGET"
fi
# ── 2. OpenCode global plugin ────────────────────────────────────────────────
OC_PLUGINS_DIR="$HOME/.config/opencode/plugins"
OC_PLUGIN_TARGET="$DOTFILES_AGENTS/frameworks/opencode/plugin.ts"
OC_PLUGIN_LINK="$OC_PLUGINS_DIR/agent-support.ts"
mkdir -p "$OC_PLUGINS_DIR"
if [[ -L "$OC_PLUGIN_LINK" && "$(readlink "$OC_PLUGIN_LINK")" == "$OC_PLUGIN_TARGET" ]]; then
skip "OpenCode plugin symlink already set: $OC_PLUGIN_LINK"
else
ln -sf "$OC_PLUGIN_TARGET" "$OC_PLUGIN_LINK"
log "OpenCode plugin symlink: $OC_PLUGIN_LINK$OC_PLUGIN_TARGET"
fi
# ── 3. OpenCode global AGENTS.md ────────────────────────────────────────────
OC_AGENTS_TARGET="$DOTFILES_AGENTS/AGENTS.md"
OC_AGENTS_LINK="$HOME/.config/opencode/AGENTS.md"
if [[ -L "$OC_AGENTS_LINK" && "$(readlink "$OC_AGENTS_LINK")" == "$OC_AGENTS_TARGET" ]]; then
skip "OpenCode AGENTS.md symlink already set: $OC_AGENTS_LINK"
else
ln -sf "$OC_AGENTS_TARGET" "$OC_AGENTS_LINK"
log "OpenCode AGENTS.md symlink: $OC_AGENTS_LINK$OC_AGENTS_TARGET"
fi
# ── 4. OpenCode global MCP entry ────────────────────────────────────────────
OC_CONFIG="$HOME/.config/opencode/opencode.json"
MCP_KEY="all-agents"
MCP_CMD="[\"node\", \"--experimental-strip-types\", \"$DOTFILES_AGENTS/mcp/index.ts\"]"
if [[ ! -f "$OC_CONFIG" ]]; then
warn "No OpenCode config at $OC_CONFIG — creating minimal config with MCP entry."
printf '{\n "$schema": "https://opencode.ai/config.json",\n "mcp": {\n "%s": {\n "type": "local",\n "command": %s\n }\n }\n}\n' "$MCP_KEY" "$MCP_CMD" > "$OC_CONFIG"
log "Created $OC_CONFIG with all-agents MCP entry"
elif node -e "const c=JSON.parse(require('fs').readFileSync('$OC_CONFIG','utf8')); process.exit(c.mcp && c.mcp['$MCP_KEY'] ? 0 : 1)" 2>/dev/null; then
skip "OpenCode MCP entry '$MCP_KEY' already present in $OC_CONFIG"
else
# Merge the MCP entry using node — jq may not be available everywhere
node -e "
const fs = require('fs');
const path = '$OC_CONFIG';
const config = JSON.parse(fs.readFileSync(path, 'utf8'));
config.mcp = config.mcp || {};
config.mcp['$MCP_KEY'] = { type: 'local', command: $MCP_CMD };
fs.writeFileSync(path, JSON.stringify(config, null, 2) + '\n');
console.log('Merged all-agents MCP entry into ' + path);
"
log "OpenCode MCP entry merged: $OC_CONFIG"
fi
# ── 5. VS Code global MCP ────────────────────────────────────────────────────
# Primary remote/server path; falls back to local if running VS Code locally.
VSCODE_MCP_PATHS=(
"$HOME/.vscode-server/data/User/mcp.json"
"$HOME/.vscode/data/User/mcp.json"
"$HOME/Library/Application Support/Code/User/mcp.json"
)
for VSCODE_MCP in "${VSCODE_MCP_PATHS[@]}"; do
if [[ -d "$(dirname "$VSCODE_MCP")" ]]; then
MCP_SERVER_CMD="node"
MCP_SERVER_ARGS="[\"--experimental-strip-types\", \"$DOTFILES_AGENTS/mcp/index.ts\"]"
if [[ ! -f "$VSCODE_MCP" ]]; then
printf '{\n "servers": {\n "%s": {\n "type": "stdio",\n "command": "%s",\n "args": %s\n }\n }\n}\n' \
"$MCP_KEY" "$MCP_SERVER_CMD" "$MCP_SERVER_ARGS" > "$VSCODE_MCP"
log "Created VS Code global MCP config: $VSCODE_MCP"
elif node -e "const c=JSON.parse(require('fs').readFileSync('$VSCODE_MCP','utf8')); process.exit(c.servers && c.servers['$MCP_KEY'] ? 0 : 1)" 2>/dev/null; then
skip "VS Code MCP entry '$MCP_KEY' already present in $VSCODE_MCP"
else
node -e "
const fs = require('fs');
const path = '$VSCODE_MCP';
const config = JSON.parse(fs.readFileSync(path, 'utf8'));
config.servers = config.servers || {};
config.servers['$MCP_KEY'] = {
type: 'stdio',
command: '$MCP_SERVER_CMD',
args: $MCP_SERVER_ARGS
};
fs.writeFileSync(path, JSON.stringify(config, null, 2) + '\n');
"
log "VS Code MCP entry merged: $VSCODE_MCP"
fi
break
fi
done
# ── 6. VS Code global prompts dir ───────────────────────────────────────────
for VSCODE_PROMPTS_DIR in \
"$HOME/.vscode-server/data/User/prompts" \
"$HOME/.vscode/data/User/prompts"; do
if [[ -d "$(dirname "$(dirname "$VSCODE_PROMPTS_DIR")")" ]]; then
mkdir -p "$VSCODE_PROMPTS_DIR"
log "VS Code prompts dir ensured: $VSCODE_PROMPTS_DIR"
break
fi
done
# ── Done ─────────────────────────────────────────────────────────────────────
printf '\n\033[0;32minstall.sh complete.\033[0m\n'
printf 'Next steps:\n'
printf ' 1. Restart OpenCode to pick up the new global plugin.\n'
printf ' 2. Reload VS Code / reconnect to reload MCP servers.\n'
printf ' 3. Smoke test: /research slash prompt fires; a denied terminal command is blocked.\n'