diff --git a/references/agents-registry.md b/references/agents-registry.md old mode 100644 new mode 100755 index 460e031..6b1696c --- a/references/agents-registry.md +++ b/references/agents-registry.md @@ -18,6 +18,8 @@ The registry is designed to grow: custom agents (see Issue #12) are added as new | librarian | Vault Health & Quality Assurance | Detect/merge duplicates, fix broken links, audit frontmatter, growth analytics. Full Bash access. | Maintenance, audit, cleanup, health check, duplicate detection | Health reports, fixed links, merged duplicates, consistency reports | active | | transcriber | Audio & Meeting Intelligence | Process transcriptions into structured notes, extract action items, speaker detection | Audio recordings, transcriptions, meeting notes, lecture/podcast processing | Structured meeting/lecture notes in `00-Inbox/` with action items, decisions, topics | active | | postman | Email & Calendar Intelligence | Read/archive/delete email (Gmail via `gws`, Hey.com via `hey`), search emails, read/create/update calendar events, draft and send replies. Uses Google Workspace CLI (`gws`) and/or Hey CLI (`hey`) via Bash, with MCP as read-only fallback. | Email triage, calendar queries, deadline tracking, meeting prep, VIP filtering | Email summaries saved as notes in `00-Inbox/`, calendar events created, deadline reports | active | + + --- diff --git a/references/agents.md b/references/agents.md old mode 100644 new mode 100755 index 5d7a138..30b473e --- a/references/agents.md +++ b/references/agents.md @@ -155,6 +155,9 @@ Custom agents are created by the Architect and live in `.claude/agents/` alongsi For the definitive list of all agents (core + custom) with capabilities, inputs, outputs, and status, see `.claude/references/agents-registry.md`. + + + ### How Custom Agents Coordinate Custom agents participate in the same orchestration protocol as core agents: diff --git a/scripts/launchme.sh b/scripts/launchme.sh index 9bf60cb..64ab4c5 100755 --- a/scripts/launchme.sh +++ b/scripts/launchme.sh @@ -7,44 +7,25 @@ # cd /path/to/your-vault/My-Brain-Is-Full-Crew # bash scripts/launchme.sh # -# It copies agents and references into your vault's .claude/ directory. +# It copies agents, skills, references, hooks, and settings into the vault's +# .claude/ directory. # ============================================================================= set -eo pipefail -# ── Colors ────────────────────────────────────────────────────────────────── -if [[ -t 1 ]]; then - GREEN='\033[0;32m'; CYAN='\033[0;36m'; YELLOW='\033[1;33m' - RED='\033[0;31m'; BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m' -else - GREEN=''; CYAN=''; YELLOW=''; RED=''; BOLD=''; DIM=''; NC='' -fi - -info() { echo -e " ${CYAN}>${NC} $*"; } -success() { echo -e " ${GREEN}✓${NC} $*"; } -warn() { echo -e " ${YELLOW}!${NC} $*"; } -die() { echo -e "\n ${RED}Error: $*${NC}\n" >&2; exit 1; } - -# ── Find paths ────────────────────────────────────────────────────────────── SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -VAULT_DIR="$(cd "$REPO_DIR/.." && pwd)" +# shellcheck source=scripts/lib.sh +source "$SCRIPT_DIR/lib.sh" -# Sanity checks -[[ -d "$REPO_DIR/agents" ]] || die "Can't find agents/ in $REPO_DIR — are you running this from the repo?" -[[ -d "$REPO_DIR/references" ]] || die "Can't find references/ in $REPO_DIR" +resolve_paths "${BASH_SOURCE[0]}" -# ── Banner ────────────────────────────────────────────────────────────────── -echo "" -echo -e "${BOLD}╔══════════════════════════════════════════╗${NC}" -echo -e "${BOLD}║ My Brain Is Full - Crew :: Setup ║${NC}" -echo -e "${BOLD}╚══════════════════════════════════════════╝${NC}" -echo "" +# ── Banner ──────────────────────────────────────────────────────────────────── +print_banner "Setup " echo -e " Repo: ${BOLD}${REPO_DIR}${NC}" echo -e " Vault: ${BOLD}${VAULT_DIR}${NC}" echo "" -# ── Confirm vault location ───────────────────────────────────────────────── +# ── Confirm vault location ──────────────────────────────────────────────────── echo -e "${BOLD}Is this your Obsidian vault folder?${NC}" echo -e " ${DIM}${VAULT_DIR}${NC}" echo "" @@ -55,107 +36,65 @@ if ! read -r -p " > " CONFIRM 2>/dev/null; then CONFIRM=""; fi if [[ "$CONFIRM" =~ ^[Nn]$ ]]; then echo "" echo -e "${BOLD}Enter the full path to your Obsidian vault:${NC}" - if ! read -r -p " > " VAULT_DIR 2>/dev/null; then die "Cannot read input — are you running in a non-interactive shell?"; fi + if ! read -r -p " > " VAULT_DIR 2>/dev/null; then + die "Cannot read input — are you running in a non-interactive shell?" + fi VAULT_DIR="${VAULT_DIR/#\~/$HOME}" [[ -d "$VAULT_DIR" ]] || die "Directory not found: $VAULT_DIR" fi -# ── Check for existing installation ─────────────────────────────────────── -echo "" +# ── Check for existing installation ────────────────────────────────────────── EXISTING=0 -if [[ -d "$VAULT_DIR/.claude" ]]; then EXISTING=1; fi -if [[ -f "$VAULT_DIR/CLAUDE.md" ]]; then EXISTING=1; fi +[[ -d "$VAULT_DIR/.claude" ]] && EXISTING=1 +[[ -f "$VAULT_DIR/CLAUDE.md" ]] && EXISTING=1 if [[ $EXISTING -eq 1 ]]; then warn "An existing installation was detected:" [[ -d "$VAULT_DIR/.claude" ]] && warn " .claude/ directory exists" [[ -f "$VAULT_DIR/CLAUDE.md" ]] && warn " CLAUDE.md exists" echo "" - echo -e " ${BOLD}The installer needs to overwrite these files.${NC}" - echo -e " ${DIM}Custom agents in .claude/agents/ will NOT be deleted.${NC}" + echo -e " ${BOLD}The installer will overwrite core files. Custom agents are never deleted.${NC}" echo -e " ${DIM}Your vault notes are never touched.${NC}" echo "" - echo -e " ${BOLD}c)${NC} Continue (overwrite core files, keep custom agents)" + echo -e " ${BOLD}c)${NC} Continue" echo -e " ${BOLD}q)${NC} Quit" - if ! read -r -p " > " OVERWRITE_ANSWER 2>/dev/null; then OVERWRITE_ANSWER=""; fi - if [[ ! "$OVERWRITE_ANSWER" =~ ^[Cc]$ ]]; then - echo "" - info "Installation cancelled." - echo "" - exit 0 + if ! read -r -p " > " ANSWER 2>/dev/null; then ANSWER=""; fi + if [[ ! "$ANSWER" =~ ^[Cc]$ ]]; then + echo ""; info "Installation cancelled."; echo ""; exit 0 fi fi -# ── Deprecate stale core agents on reinstall ───────────────────────────── echo "" -mkdir -p "$VAULT_DIR/.claude/agents" -OLD_MANIFEST="$VAULT_DIR/.claude/agents/.core-manifest" -if [[ $EXISTING -eq 1 && -f "$OLD_MANIFEST" ]]; then - while IFS= read -r old_name; do - [[ -z "$old_name" ]] && continue - [[ -f "$REPO_DIR/agents/$old_name" ]] && continue - vault_file="$VAULT_DIR/.claude/agents/$old_name" - [[ -f "$vault_file" ]] || continue - deprecated_name="${old_name%.md}-DEPRECATED.md" - mkdir -p "$VAULT_DIR/.claude/deprecated" - [[ -f "$VAULT_DIR/.claude/deprecated/$deprecated_name" ]] && continue - mv "$vault_file" "$VAULT_DIR/.claude/deprecated/$deprecated_name" - { echo "########"; echo "DEPRECATED DO NOT USE"; echo "########"; echo ""; cat "$VAULT_DIR/.claude/deprecated/$deprecated_name"; } > "$VAULT_DIR/.claude/deprecated/$deprecated_name.tmp" - mv "$VAULT_DIR/.claude/deprecated/$deprecated_name.tmp" "$VAULT_DIR/.claude/deprecated/$deprecated_name" - warn "Deprecated stale agent: $old_name -> deprecated/$deprecated_name" - done < "$OLD_MANIFEST" + +# ── Migrate legacy manifests (if any) ──────────────────────────────────────── +manifest_migrate + +# ── Deprecate agents/refs removed from repo (reinstall only) ───────────────── +DEP_COUNT=0 +if [[ $EXISTING -eq 1 ]]; then + DEP_COUNT=$(deprecate_removed "agents" "$REPO_DIR/agents" "$VAULT_DIR/.claude/agents") + DEP_COUNT=$((DEP_COUNT + $(deprecate_removed "references" "$REPO_DIR/references" "$VAULT_DIR/.claude/references"))) fi -# ── Copy agents ───────────────────────────────────────────────────────────── -info "Creating .claude/agents/ in vault..." - -AGENT_COUNT=0 -: > "$VAULT_DIR/.claude/agents/.core-manifest" -for agent in "$REPO_DIR/agents/"*.md; do - cp "$agent" "$VAULT_DIR/.claude/agents/" - basename "$agent" >> "$VAULT_DIR/.claude/agents/.core-manifest" - AGENT_COUNT=$((AGENT_COUNT + 1)) -done -success "Copied $AGENT_COUNT agents" - -# ── Create Meta/states/ for agent post-its ────────────────────────────────── +# ── Ensure vault support dirs ───────────────────────────────────────────────── mkdir -p "$VAULT_DIR/Meta/states" -info "Created Meta/states/ (agent post-it directory)" -# ── Copy references ───────────────────────────────────────────────────────── -info "Creating .claude/references/ in vault..." -mkdir -p "$VAULT_DIR/.claude/references" -# User-mutable references (modified by Architect when creating custom agents) -USER_MUTABLE_REFS="agents-registry.md agents.md" +# ── Install components ──────────────────────────────────────────────────────── +info "Installing agents..." +AGENT_COUNT=$(install_agents "$REPO_DIR/agents" "$VAULT_DIR/.claude/agents") +success "Agents: $AGENT_COUNT installed/updated" -: > "$VAULT_DIR/.claude/references/.core-manifest" -for ref in "$REPO_DIR/references/"*.md; do - ref_name="$(basename "$ref")" - # On reinstall, preserve user-mutable reference files - if [[ $EXISTING -eq 1 && -f "$VAULT_DIR/.claude/references/$ref_name" ]]; then - if [[ " $USER_MUTABLE_REFS " == *" $ref_name "* ]]; then - warn "Preserving existing $ref_name (run updateme.sh to merge upstream changes)" - echo "$ref_name" >> "$VAULT_DIR/.claude/references/.core-manifest" - continue - fi - fi - cp "$ref" "$VAULT_DIR/.claude/references/" - echo "$ref_name" >> "$VAULT_DIR/.claude/references/.core-manifest" -done -success "Copied references" +info "Installing references..." +REF_COUNT=$(install_refs "$REPO_DIR/references" "$VAULT_DIR/.claude/references") +success "References: $REF_COUNT installed/updated" -# ── Copy skills ────────────────────────────────────────────────────────────── -SKILL_COUNT=0 -if [[ -d "$REPO_DIR/skills" ]]; then - for skill_dir in "$REPO_DIR/skills/"*/; do - [[ -f "$skill_dir/SKILL.md" ]] || continue - skill_name="$(basename "$skill_dir")" - mkdir -p "$VAULT_DIR/.claude/skills/$skill_name" - cp "$skill_dir"SKILL.md "$VAULT_DIR/.claude/skills/$skill_name/" - SKILL_COUNT=$((SKILL_COUNT + 1)) - done - success "Copied $SKILL_COUNT skills" -fi +info "Installing skills..." +SKILL_COUNT=$(install_skills "$REPO_DIR/skills" "$VAULT_DIR/.claude/skills") +success "Skills: $SKILL_COUNT installed/updated" + +info "Installing hooks..." +HOOK_COUNT=$(install_hooks "$REPO_DIR/hooks" "$VAULT_DIR/.claude/hooks") +success "Hooks: $HOOK_COUNT installed/updated" # ── Deprecate stale orchestra scripts on reinstall ────────────────────────── OLD_ORCH_MANIFEST="$VAULT_DIR/Meta/scripts/.core-manifest" @@ -193,31 +132,11 @@ if [[ -f "$REPO_DIR/CLAUDE.md" ]]; then success "Copied CLAUDE.md" fi -# ── Copy hooks ─────────────────────────────────────────────────────────────── -HOOK_COUNT=0 -if [[ -d "$REPO_DIR/hooks" ]]; then - mkdir -p "$VAULT_DIR/.claude/hooks" - for hook in "$REPO_DIR/hooks/"*.sh; do - [[ -f "$hook" ]] || continue - cp "$hook" "$VAULT_DIR/.claude/hooks/" - chmod +x "$VAULT_DIR/.claude/hooks/$(basename "$hook")" - HOOK_COUNT=$((HOOK_COUNT + 1)) - done - success "Copied $HOOK_COUNT hooks" -fi -# ── Copy settings.json ─────────────────────────────────────────────────────── -if [[ -f "$REPO_DIR/settings.json" ]]; then - if [[ -f "$VAULT_DIR/.claude/settings.json" ]]; then - warn ".claude/settings.json already exists — skipping (won't overwrite)" - else - mkdir -p "$VAULT_DIR/.claude" - cp "$REPO_DIR/settings.json" "$VAULT_DIR/.claude/settings.json" - success "Copied settings.json (hooks configuration)" - fi -fi +install_settings "$REPO_DIR/settings.json" "$VAULT_DIR/.claude" +install_claude_md "$REPO_DIR/CLAUDE.md" "$VAULT_DIR" -# ── MCP servers (Gmail + Calendar) ────────────────────────────────────────── +# ── MCP servers (Gmail + Calendar) ─────────────────────────────────────────── echo "" echo -e "${BOLD}Do you use Gmail, Hey.com, or Google Calendar?${NC}" echo -e " ${DIM}The Postman agent can read your inbox and calendar.${NC}" @@ -240,24 +159,26 @@ else info "Skipped MCP setup" fi -# ── Done ──────────────────────────────────────────────────────────────────── +# ── Done ────────────────────────────────────────────────────────────────────── echo "" echo -e "${GREEN}${BOLD} Setup complete!${NC}" echo "" -echo -e " Your vault is ready. Here's what was installed:" -echo "" echo -e " ${VAULT_DIR}/" echo -e " ├── .claude/" -echo -e " │ ├── agents/ ${DIM}← ${AGENT_COUNT} crew agents${NC}" -echo -e " │ ├── skills/ ${DIM}← ${SKILL_COUNT:-0} crew skills (Desktop/Cowork)${NC}" -echo -e " │ ├── hooks/ ${DIM}← ${HOOK_COUNT:-0} hooks${NC}" +echo -e " │ ├── agents/ ${DIM}← agents${NC}" +echo -e " │ ├── skills/ ${DIM}← skills${NC}" +echo -e " │ ├── hooks/ ${DIM}← hooks${NC}" echo -e " │ ├── settings.json ${DIM}← hooks configuration${NC}" echo -e " │ └── references/ ${DIM}← shared docs${NC}" echo -e " ├── Meta/" echo -e " │ └── scripts/ ${DIM}← ${ORCH_COUNT:-0} orchestra scripts${NC}" echo -e " ├── CLAUDE.md ${DIM}← project instructions${NC}" if [[ "$MCP_ANSWER" =~ ^[Yy]$ ]]; then -echo -e " └── .mcp.json ${DIM}← Gmail + Calendar${NC}" + echo -e " └── .mcp.json ${DIM}← Gmail + Calendar${NC}" +fi +if [[ $DEP_COUNT -gt 0 ]]; then + echo "" + warn "$DEP_COUNT file(s) were deprecated (moved to .claude/deprecated/)" fi echo "" echo -e " ${BOLD}Next steps:${NC}" diff --git a/scripts/lib.sh b/scripts/lib.sh new file mode 100755 index 0000000..5f504aa --- /dev/null +++ b/scripts/lib.sh @@ -0,0 +1,419 @@ +#!/usr/bin/env bash +# ============================================================================= +# My Brain Is Full - Crew :: Shared library +# Sourced by launchme.sh and updateme.sh — do NOT execute directly. +# ============================================================================= + +# ── Colors ──────────────────────────────────────────────────────────────────── +if [[ -t 1 ]]; then + GREEN='\033[0;32m'; CYAN='\033[0;36m'; YELLOW='\033[1;33m' + RED='\033[0;31m'; BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m' +else + GREEN=''; CYAN=''; YELLOW=''; RED=''; BOLD=''; DIM=''; NC='' +fi + +# ── Logging ─────────────────────────────────────────────────────────────────── +# Everything is on stderr to keep stdout clean for machine-readable output in updateme.sh. +info() { echo -e " ${CYAN}>${NC} $*" >&2; } +success() { echo -e " ${GREEN}✓${NC} $*" >&2; } +warn() { echo -e " ${YELLOW}!${NC} $*" >&2; } +die() { echo -e "\n ${RED}Error: $*${NC}\n" >&2; exit 1; } + +# ── Path resolution ─────────────────────────────────────────────────────────── +# Sets SCRIPT_DIR, REPO_DIR, VAULT_DIR globals. +# Usage: resolve_paths "${BASH_SOURCE[0]}" +resolve_paths() { + SCRIPT_DIR="$(cd "$(dirname "$1")" && pwd)" + REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + VAULT_DIR="$(cd "$REPO_DIR/.." && pwd)" + [[ -d "$REPO_DIR/agents" ]] || die "Can't find agents/ in $REPO_DIR — are you running this from the repo?" + [[ -d "$REPO_DIR/references" ]] || die "Can't find references/ in $REPO_DIR" +} + +# ── Change tracking ─────────────────────────────────────────────────────────── +# Set by copy_if_changed and merge_marked_file after every call. +_LAST_CHANGED=0 + +# Controls per-file logging in install_* functions. +# Set VERBOSE_COPY=1 in the caller for per-file change output (used by updateme.sh). +VERBOSE_COPY=0 + +# ── copy_if_changed ─────────────────────────────────────────────── +# Copies src to dst only when they differ or dst doesn't exist. +# Sets _LAST_CHANGED=1 if a copy was made, 0 otherwise. +copy_if_changed() { + local src="$1" dst="$2" + _LAST_CHANGED=0 + if ! diff -q "$src" "$dst" >/dev/null 2>&1; then + mkdir -p "$(dirname "$dst")" + cp "$src" "$dst" + _LAST_CHANGED=1 + fi +} + +# ── _insert_after_start_marker ─────────────────────────────── +# Inserts immediately after the MBIFC:CUSTOM_AGENTS_START line in dst. +# dst must already exist and contain the marker. +_insert_after_start_marker() { + local dst="$1" content="$2" + [[ -z "$content" ]] && return 0 + + local start_line + start_line=$(grep -n '' "$dst" | head -1 | cut -d: -f1) + [[ -z "$start_line" ]] && return 0 + + local saved_file tmpfile + saved_file="$(mktemp)" + tmpfile="$(mktemp)" + # printf '%s\n' ensures a trailing newline so the next file line starts cleanly. + # bash $() strips trailing newlines, so content never has one already. + printf '%s\n' "$content" > "$saved_file" + + { + head -n "$start_line" "$dst" + cat "$saved_file" + tail -n +"$((start_line + 1))" "$dst" + } > "$tmpfile" + + mv "$tmpfile" "$dst" + rm -f "$saved_file" +} + +# ── merge_marked_file ───────────────────────────────────────────── +# Copies src to dst, preserving content between +# and markers from the existing dst. +# +# Handles three cases: +# 1. dst doesn't exist → plain copy +# 2. Both src and dst have markers → marker-based merge (primary path) +# 3. src has markers, dst doesn't → migration: extracts legacy custom rows +# from pre-marker installations +# +# Sets _LAST_CHANGED=1 if dst was written. +merge_marked_file() { + local src="$1" dst="$2" + _LAST_CHANGED=0 + + # Case 1: dst doesn't exist yet + if [[ ! -f "$dst" ]]; then + mkdir -p "$(dirname "$dst")" + cp "$src" "$dst" + _LAST_CHANGED=1 + return 0 + fi + + local src_has_markers=0 dst_has_markers=0 + grep -q '' "$src" 2>/dev/null && src_has_markers=1 + grep -q '' "$dst" 2>/dev/null && dst_has_markers=1 + + # src has no markers → standard copy-if-changed + if [[ $src_has_markers -eq 0 ]]; then + copy_if_changed "$src" "$dst" + return 0 + fi + + # Case 3: src has markers, dst doesn't → migration from old format + if [[ $dst_has_markers -eq 0 ]]; then + local custom_rows="" + local CORE_NAMES="architect scribe sorter seeker connector librarian transcriber postman" + while IFS= read -r row; do + local aname + aname=$(printf '%s' "$row" | awk -F'|' '{gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}') + if [[ -n "$aname" ]] && ! echo " $CORE_NAMES " | grep -qw " $aname "; then + custom_rows="${custom_rows}${row}"$'\n' + fi + done < <(grep "^|" "$dst" 2>/dev/null \ + | grep -v "^|[[:space:]]*Name[[:space:]]*|" \ + | grep -v "^|[-:[:space:]]*|") + + cp "$src" "$dst" + _LAST_CHANGED=1 + + if [[ -n "$custom_rows" ]]; then + _insert_after_start_marker "$dst" "$custom_rows" + warn "Migrated legacy custom agents in $(basename "$dst") to MBIFC marker format" + fi + return 0 + fi + + # Case 2: both have markers → extract saved content, build merged result, + # only update dst if the result actually differs (ensures idempotency). + local saved_content + saved_content=$(awk \ + '//{f=1; next} + //{f=0} + f{print}' \ + "$dst") + + local merged; merged="$(mktemp)" + cp "$src" "$merged" + [[ -n "$saved_content" ]] && _insert_after_start_marker "$merged" "$saved_content" + + if ! diff -q "$merged" "$dst" >/dev/null 2>&1; then + cp "$merged" "$dst" + _LAST_CHANGED=1 + [[ $VERBOSE_COPY -eq 1 && -n "$saved_content" ]] && info "Merged: $(basename "$src") (custom content preserved)" + fi + rm -f "$merged" +} + +# ── Manifest helpers ────────────────────────────────────────────────────────── +# Single unified manifest at $VAULT_DIR/.claude/.mbifc-manifest +# Format: INI-style with [section] headers, one entry per line. + +manifest_read() { + local section="$1" + local file="$VAULT_DIR/.claude/.mbifc-manifest" + [[ -f "$file" ]] || return 0 + awk -v sec="[$section]" ' + $0 == sec { found=1; next } + found && /^\[[a-zA-Z0-9_-]+\]$/ { exit } + found && NF > 0 { print } + ' "$file" +} + +manifest_write() { + local section="$1"; shift + local entries=("$@") + local file="$VAULT_DIR/.claude/.mbifc-manifest" + mkdir -p "$(dirname "$file")" + local tmpfile; tmpfile="$(mktemp)" + local in_section=0 section_written=0 + + if [[ -f "$file" ]]; then + while IFS= read -r line || [[ -n "$line" ]]; do + if [[ "$line" == "[$section]" ]]; then + in_section=1; continue + fi + if [[ "$line" =~ ^\[[a-zA-Z0-9_-]+\]$ ]] && [[ $in_section -eq 1 ]]; then + in_section=0 + # Write the replacement section, then the next section header + { printf '[%s]\n' "$section" + for e in "${entries[@]}"; do [[ -n "$e" ]] && printf '%s\n' "$e"; done + printf '\n' + } >> "$tmpfile" + section_written=1 + fi + [[ $in_section -eq 0 ]] && printf '%s\n' "$line" >> "$tmpfile" + done < "$file" + fi + + # Section wasn't encountered, or was at end of file with no following section + if [[ $section_written -eq 0 ]]; then + { printf '[%s]\n' "$section" + for e in "${entries[@]}"; do [[ -n "$e" ]] && printf '%s\n' "$e"; done + printf '\n' + } >> "$tmpfile" + fi + + mv "$tmpfile" "$file" +} + +manifest_remove() { + local section="$1" name="$2" + local file="$VAULT_DIR/.claude/.mbifc-manifest" + [[ -f "$file" ]] || return 0 + local tmpfile; tmpfile="$(mktemp)" + local in_section=0 + while IFS= read -r line || [[ -n "$line" ]]; do + if [[ "$line" == "[$section]" ]]; then in_section=1; printf '%s\n' "$line" >> "$tmpfile"; continue; fi + if [[ "$line" =~ ^\[[a-zA-Z0-9_-]+\]$ ]]; then in_section=0; fi + if [[ $in_section -eq 1 && "$line" == "$name" ]]; then continue; fi + printf '%s\n' "$line" >> "$tmpfile" + done < "$file" + mv "$tmpfile" "$file" +} + +# Converts legacy per-directory .core-manifest files to the unified format. +# Runs only when legacy files are present; idempotent thereafter. +manifest_migrate() { + local agents_mf="$VAULT_DIR/.claude/agents/.core-manifest" + local refs_mf="$VAULT_DIR/.claude/references/.core-manifest" + [[ -f "$agents_mf" ]] || [[ -f "$refs_mf" ]] || return 0 + + warn "Migrating legacy manifests to unified .mbifc-manifest..." + + if [[ -f "$agents_mf" ]]; then + local entries=() + while IFS= read -r line || [[ -n "$line" ]]; do [[ -n "$line" ]] && entries+=("$line"); done < "$agents_mf" + manifest_write "agents" "${entries[@]}" + rm "$agents_mf" + fi + + if [[ -f "$refs_mf" ]]; then + local entries=() + while IFS= read -r line || [[ -n "$line" ]]; do [[ -n "$line" ]] && entries+=("$line"); done < "$refs_mf" + manifest_write "references" "${entries[@]}" + rm "$refs_mf" + fi + + success "Manifest migrated to .claude/.mbifc-manifest" +} + +# ── Deprecation ─────────────────────────────────────────────────────────────── + +# deprecate_removed
+# Moves files listed in the manifest for
that no longer exist in +# to $VAULT_DIR/.claude/deprecated/, prepending a DEPRECATED header. +# Prints the count of deprecated files to stdout. +deprecate_removed() { + local section="$1" src_dir="$2" dst_dir="$3" + local count=0 + + while IFS= read -r name; do + [[ -z "$name" ]] && continue + [[ -f "$src_dir/$name" ]] && continue # still in repo — keep it + local vault_file="$dst_dir/$name" + [[ -f "$vault_file" ]] || continue # not present — skip + [[ "$name" == *"-DEPRECATED"* ]] && continue # already deprecated + + local dep_name="${name%.md}-DEPRECATED.md" + local dep_dir="$VAULT_DIR/.claude/deprecated" + mkdir -p "$dep_dir" + [[ -f "$dep_dir/$dep_name" ]] && continue # already done in a prior run + + mv "$vault_file" "$dep_dir/$dep_name" + { printf '########\nDEPRECATED DO NOT USE\n########\n\n' + cat "$dep_dir/$dep_name" + } > "$dep_dir/$dep_name.tmp" + mv "$dep_dir/$dep_name.tmp" "$dep_dir/$dep_name" + + manifest_remove "$section" "$name" + warn "Deprecated: $name → .claude/deprecated/$dep_name" + count=$((count + 1)) + done < <(manifest_read "$section") + + printf '%d' "$count" +} + +# ── Component installers ────────────────────────────────────────────────────── +# Each function installs one component type and prints the changed-file count +# to stdout. All respect VERBOSE_COPY for per-file logging. +# +# USER_MUTABLE_REFS: space-separated list of reference filenames that may +# contain user-added content between MBIFC markers. These use merge_marked_file +# instead of copy_if_changed. +USER_MUTABLE_REFS="agents-registry.md agents.md" + +install_agents() { + local src_dir="$1" dst_dir="$2" + local count=0 manifest=() + mkdir -p "$dst_dir" + for src in "$src_dir/"*.md; do + [[ -f "$src" ]] || continue + local name; name="$(basename "$src")" + manifest+=("$name") + copy_if_changed "$src" "$dst_dir/$name" + if [[ $_LAST_CHANGED -eq 1 ]]; then + [[ $VERBOSE_COPY -eq 1 ]] && info "Updated agent: $name" + count=$((count + 1)) + fi + done + manifest_write "agents" "${manifest[@]}" + printf '%d' "$count" +} + +install_refs() { + local src_dir="$1" dst_dir="$2" + local count=0 manifest=() + mkdir -p "$dst_dir" + for src in "$src_dir/"*.md; do + [[ -f "$src" ]] || continue + local name; name="$(basename "$src")" + local dst="$dst_dir/$name" + manifest+=("$name") + if [[ " $USER_MUTABLE_REFS " == *" $name "* ]]; then + merge_marked_file "$src" "$dst" + else + copy_if_changed "$src" "$dst" + fi + if [[ $_LAST_CHANGED -eq 1 ]]; then + [[ $VERBOSE_COPY -eq 1 ]] && info "Updated reference: $name" + count=$((count + 1)) + fi + done + manifest_write "references" "${manifest[@]}" + printf '%d' "$count" +} + +install_skills() { + local src_dir="$1" dst_dir="$2" + local count=0 manifest=() + [[ -d "$src_dir" ]] || { printf '0'; return 0; } + for skill_src in "$src_dir/"*/; do + [[ -f "${skill_src}SKILL.md" ]] || continue + local name; name="$(basename "$skill_src")" + manifest+=("$name") + mkdir -p "$dst_dir/$name" + copy_if_changed "${skill_src}SKILL.md" "$dst_dir/$name/SKILL.md" + if [[ $_LAST_CHANGED -eq 1 ]]; then + [[ $VERBOSE_COPY -eq 1 ]] && info "Updated skill: $name" + count=$((count + 1)) + fi + done + manifest_write "skills" "${manifest[@]}" + printf '%d' "$count" +} + +install_hooks() { + local src_dir="$1" dst_dir="$2" + local count=0 manifest=() + [[ -d "$src_dir" ]] || { printf '0'; return 0; } + mkdir -p "$dst_dir" + for src in "$src_dir/"*.sh; do + [[ -f "$src" ]] || continue + local name; name="$(basename "$src")" + local dst="$dst_dir/$name" + manifest+=("$name") + copy_if_changed "$src" "$dst" + if [[ $_LAST_CHANGED -eq 1 ]]; then + chmod +x "$dst" + [[ $VERBOSE_COPY -eq 1 ]] && info "Updated hook: $name" + count=$((count + 1)) + fi + done + manifest_write "hooks" "${manifest[@]}" + printf '%d' "$count" +} + +# install_settings +# Always syncs settings.json from src to dst when they differ. +# Creates a .bak of the previous version so users can recover custom entries. +# Sets _LAST_CHANGED. +install_settings() { + local src="$1" dst_dir="$2" + local dst="$dst_dir/settings.json" + _LAST_CHANGED=0 + [[ -f "$src" ]] || return 0 + mkdir -p "$dst_dir" + if [[ ! -f "$dst" ]]; then + cp "$src" "$dst" + _LAST_CHANGED=1 + elif ! diff -q "$src" "$dst" >/dev/null 2>&1; then + cp "$dst" "${dst}.bak" + cp "$src" "$dst" + _LAST_CHANGED=1 + [[ $VERBOSE_COPY -eq 1 ]] && info "Updated settings.json (previous version saved as settings.json.bak)" + [[ $VERBOSE_COPY -eq 1 ]] && info "For custom hooks, use settings.local.json instead" + fi +} + +# install_claude_md +# Sets _LAST_CHANGED. +install_claude_md() { + local src="$1" vault_dir="$2" + [[ -f "$src" ]] || return 0 + copy_if_changed "$src" "$vault_dir/CLAUDE.md" + [[ $_LAST_CHANGED -eq 1 && $VERBOSE_COPY -eq 1 ]] && info "Updated CLAUDE.md" +} + +# ── UI helpers ──────────────────────────────────────────────────────────────── + +print_banner() { + local title="$1" + echo "" + echo -e "${BOLD}╔══════════════════════════════════════════╗${NC}" + echo -e "${BOLD}║ My Brain Is Full - Crew :: ${title}${NC}" + echo -e "${BOLD}╚══════════════════════════════════════════╝${NC}" + echo "" +} diff --git a/scripts/updateme.sh b/scripts/updateme.sh index edb902e..49b8426 100755 --- a/scripts/updateme.sh +++ b/scripts/updateme.sh @@ -2,8 +2,7 @@ # ============================================================================= # My Brain Is Full - Crew :: Updater # ============================================================================= -# After pulling new changes from the repo, run this to update the agents -# in your vault: +# After pulling new changes from the repo, run this to update the crew: # # cd /path/to/your-vault/My-Brain-Is-Full-Crew # git pull @@ -13,316 +12,67 @@ set -eo pipefail -# ── Colors ────────────────────────────────────────────────────────────────── -if [[ -t 1 ]]; then - GREEN='\033[0;32m'; CYAN='\033[0;36m'; YELLOW='\033[1;33m' - RED='\033[0;31m'; BOLD='\033[1m'; DIM='\033[2m'; NC='\033[0m' -else - GREEN=''; CYAN=''; YELLOW=''; RED=''; BOLD=''; DIM=''; NC='' -fi - -info() { echo -e " ${CYAN}>${NC} $*"; } -success() { echo -e " ${GREEN}✓${NC} $*"; } -warn() { echo -e " ${YELLOW}!${NC} $*"; } -die() { echo -e "\n ${RED}Error: $*${NC}\n" >&2; exit 1; } - -# ── Find paths ────────────────────────────────────────────────────────────── SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -VAULT_DIR="$(cd "$REPO_DIR/.." && pwd)" +# shellcheck source=scripts/lib.sh +source "$SCRIPT_DIR/lib.sh" -[[ -d "$REPO_DIR/agents" ]] || die "Can't find agents/ — are you running this from the repo?" +resolve_paths "${BASH_SOURCE[0]}" -# ── Check vault has been set up ───────────────────────────────────────────── -if [[ ! -d "$VAULT_DIR/.claude/agents" ]]; then - die "No .claude/agents/ found in $VAULT_DIR — run launchme.sh first" -fi +# ── Banner ──────────────────────────────────────────────────────────────────── +print_banner "Update " -# ── Banner ────────────────────────────────────────────────────────────────── -echo "" -echo -e "${BOLD}╔══════════════════════════════════════════╗${NC}" -echo -e "${BOLD}║ My Brain Is Full - Crew :: Update ║${NC}" -echo -e "${BOLD}╚══════════════════════════════════════════╝${NC}" -echo "" +# ── Check vault has been set up ─────────────────────────────────────────────── +[[ -d "$VAULT_DIR/.claude/agents" ]] \ + || die "No .claude/agents/ found in $VAULT_DIR — run launchme.sh first" -# ── Confirm overwrite ──────────────────────────────────────────────────── -echo -e "${BOLD}This will overwrite core agent files, references, and CLAUDE.md.${NC}" -echo -e " ${DIM}Custom agent files in .claude/agents/ will not be deleted or overwritten.${NC}" -echo -e " ${DIM}Custom agent entries in registry/directory will be preserved during update.${NC}" +# ── Confirm ─────────────────────────────────────────────────────────────────── +echo -e "${BOLD}This will update core agents, skills, references, hooks, and CLAUDE.md.${NC}" +echo -e " ${DIM}Custom agents in .claude/agents/ are never overwritten or deleted.${NC}" +echo -e " ${DIM}Custom content between MBIFC markers in references is preserved.${NC}" echo -e " ${DIM}Your vault notes are never touched.${NC}" echo "" echo -e " ${BOLD}c)${NC} Continue" echo -e " ${BOLD}q)${NC} Quit" -if ! read -r -p " > " UPDATE_ANSWER 2>/dev/null; then UPDATE_ANSWER=""; fi -if [[ ! "$UPDATE_ANSWER" =~ ^[Cc]$ ]]; then - echo "" - info "Update cancelled." - echo "" - exit 0 +if ! read -r -p " > " ANSWER 2>/dev/null; then ANSWER=""; fi +if [[ ! "$ANSWER" =~ ^[Cc]$ ]]; then + echo ""; info "Update cancelled."; echo ""; exit 0 fi echo "" -# ── Deprecate removed core agents ───────────────────────────────────────── -# Read the OLD manifest first (before rewriting it) so we know which files -# were previously installed as core. Agents removed from the repo will still -# be in the old manifest and can be correctly deprecated. -MANIFEST="$VAULT_DIR/.claude/agents/.core-manifest" -DEPRECATED_COUNT=0 -for vault_agent in "$VAULT_DIR/.claude/agents/"*.md; do - [[ -f "$vault_agent" ]] || continue - name="$(basename "$vault_agent")" - # Skip if it still exists in repo - [[ -f "$REPO_DIR/agents/$name" ]] && continue - # Skip if already deprecated - [[ "$name" == *"-DEPRECATED"* ]] && continue - # Require manifest to distinguish core from custom agents - if [[ ! -f "$MANIFEST" ]]; then - continue - fi - # Skip custom agents: only deprecate if listed in the manifest - if ! grep -qxF "$name" "$MANIFEST"; then - continue - fi - deprecated_name="${name%.md}-DEPRECATED.md" - mkdir -p "$VAULT_DIR/.claude/deprecated" - # Skip if already deprecated in a previous run - [[ -f "$VAULT_DIR/.claude/deprecated/$deprecated_name" ]] && continue - mv "$vault_agent" "$VAULT_DIR/.claude/deprecated/$deprecated_name" - # Prepend deprecation header - { echo "########"; echo "DEPRECATED DO NOT USE"; echo "########"; echo ""; cat "$VAULT_DIR/.claude/deprecated/$deprecated_name"; } > "$VAULT_DIR/.claude/deprecated/$deprecated_name.tmp" - mv "$VAULT_DIR/.claude/deprecated/$deprecated_name.tmp" "$VAULT_DIR/.claude/deprecated/$deprecated_name" - warn "Deprecated agent: $name -> deprecated/$deprecated_name" - DEPRECATED_COUNT=$((DEPRECATED_COUNT + 1)) - # Remove deprecated agent from manifest - if [[ -f "$MANIFEST" ]]; then - grep -vxF "$name" "$MANIFEST" > "$MANIFEST.tmp" || true - mv "$MANIFEST.tmp" "$MANIFEST" - fi -done +# ── Migrate legacy manifests (if any) ──────────────────────────────────────── +manifest_migrate -# ── Update agents and rewrite manifest ──────────────────────────────────── -AGENT_COUNT=0 -: > "$VAULT_DIR/.claude/agents/.core-manifest" -for agent in "$REPO_DIR/agents/"*.md; do - name="$(basename "$agent")" - basename "$agent" >> "$VAULT_DIR/.claude/agents/.core-manifest" - if [[ -f "$VAULT_DIR/.claude/agents/$name" ]]; then - if ! diff -q "$agent" "$VAULT_DIR/.claude/agents/$name" >/dev/null 2>&1; then - cp "$agent" "$VAULT_DIR/.claude/agents/" - info "Updated $name" - AGENT_COUNT=$((AGENT_COUNT + 1)) - fi - else - cp "$agent" "$VAULT_DIR/.claude/agents/" - info "Added $name (new agent)" - AGENT_COUNT=$((AGENT_COUNT + 1)) - fi -done +# ── Deprecate agents/refs removed from repo ────────────────────────────────── +DEP_COUNT=$(deprecate_removed "agents" "$REPO_DIR/agents" "$VAULT_DIR/.claude/agents") +DEP_COUNT=$((DEP_COUNT + $(deprecate_removed "references" "$REPO_DIR/references" "$VAULT_DIR/.claude/references"))) -# ── Deprecate removed references ────────────────────────────────────────── -# Read the old manifest before rewriting, same logic as agents. -REF_MANIFEST="$VAULT_DIR/.claude/references/.core-manifest" -for vault_ref in "$VAULT_DIR/.claude/references/"*.md; do - [[ -f "$vault_ref" ]] || continue - name="$(basename "$vault_ref")" - [[ -f "$REPO_DIR/references/$name" ]] && continue - [[ "$name" == *"-DEPRECATED"* ]] && continue - # Require manifest to distinguish core from user-created references - if [[ ! -f "$REF_MANIFEST" ]]; then - continue - fi - # Skip user-created references: only deprecate if listed in the manifest - if ! grep -qxF "$name" "$REF_MANIFEST"; then - continue - fi - deprecated_name="${name%.md}-DEPRECATED.md" - mkdir -p "$VAULT_DIR/.claude/deprecated" - [[ -f "$VAULT_DIR/.claude/deprecated/$deprecated_name" ]] && continue - mv "$vault_ref" "$VAULT_DIR/.claude/deprecated/$deprecated_name" - { echo "########"; echo "DEPRECATED DO NOT USE"; echo "########"; echo ""; cat "$VAULT_DIR/.claude/deprecated/$deprecated_name"; } > "$VAULT_DIR/.claude/deprecated/$deprecated_name.tmp" - mv "$VAULT_DIR/.claude/deprecated/$deprecated_name.tmp" "$VAULT_DIR/.claude/deprecated/$deprecated_name" - warn "Deprecated reference: $name -> deprecated/$deprecated_name" - DEPRECATED_COUNT=$((DEPRECATED_COUNT + 1)) -done - -# ── Update references and rewrite manifest ──────────────────────────────── -# Files the Architect modifies with user content (custom agent rows/sections). -# These need special merge logic to preserve the "## Custom Agents" section. -USER_MUTABLE_REFS="agents-registry.md agents.md" - -# ── Ensure Meta/states/ exists (agent post-its) ───────────────────────────── +# ── Ensure vault support dirs ───────────────────────────────────────────────── mkdir -p "$VAULT_DIR/Meta/states" -REF_COUNT=0 -mkdir -p "$VAULT_DIR/.claude/references" -: > "$VAULT_DIR/.claude/references/.core-manifest" -for ref in "$REPO_DIR/references/"*.md; do - name="$(basename "$ref")" - basename "$ref" >> "$VAULT_DIR/.claude/references/.core-manifest" - vault_copy="$VAULT_DIR/.claude/references/$name" +# ── Update components (per-file logging enabled) ───────────────────────────── +VERBOSE_COPY=1 - # For user-mutable files: preserve custom agent content - if [[ " $USER_MUTABLE_REFS " == *" $name "* ]] && [[ -f "$vault_copy" ]]; then - # Extract user's custom section (from "## Custom Agents" to end of file) - custom_section="" - if grep -qn "^## Custom Agents" "$vault_copy"; then - custom_line=$(grep -n "^## Custom Agents" "$vault_copy" | head -1 | cut -d: -f1) - custom_section=$(tail -n +"$custom_line" "$vault_copy") - fi +AGENT_COUNT=$(install_agents "$REPO_DIR/agents" "$VAULT_DIR/.claude/agents") +REF_COUNT=$(install_refs "$REPO_DIR/references" "$VAULT_DIR/.claude/references") +SKILL_COUNT=$(install_skills "$REPO_DIR/skills" "$VAULT_DIR/.claude/skills") +HOOK_COUNT=$(install_hooks "$REPO_DIR/hooks" "$VAULT_DIR/.claude/hooks") - # For agents-registry.md: also extract custom rows from the Registry table - # Custom rows are table lines whose agent name is NOT a core agent - custom_table_rows="" - if [[ "$name" == "agents-registry.md" ]]; then - CORE_NAMES="architect scribe sorter seeker connector librarian transcriber postman" - while IFS= read -r row; do - # Extract agent name from first column: | name | ... - agent_name=$(echo "$row" | awk -F'|' '{gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2}') - if [[ -n "$agent_name" ]] && ! echo "$CORE_NAMES" | grep -qw "$agent_name"; then - custom_table_rows="${custom_table_rows}${row}"$'\n' - fi - done < <(grep "^|" "$vault_copy" | grep -v "^|[[:space:]]*Name[[:space:]]*|" | grep -v "^|[-[:space:]]*|") - fi +install_settings "$REPO_DIR/settings.json" "$VAULT_DIR/.claude" +SETTINGS_CHANGED=$_LAST_CHANGED - # Copy the new repo version - if ! diff -q "$ref" "$vault_copy" >/dev/null 2>&1; then - cp "$ref" "$vault_copy" +install_claude_md "$REPO_DIR/CLAUDE.md" "$VAULT_DIR" +CLAUDE_MD_CHANGED=$_LAST_CHANGED - # Re-insert custom table rows into the registry table (after the last table row) - if [[ -n "$custom_table_rows" ]]; then - # Find the last table row (any line starting with |) — avoids hard-coding a specific agent name - last_table_line=$(grep -n "^|" "$vault_copy" | tail -1 | cut -d: -f1) - if [[ -n "$last_table_line" ]]; then - { head -n "$last_table_line" "$vault_copy"; printf "%s" "$custom_table_rows"; tail -n +"$((last_table_line + 1))" "$vault_copy"; } > "$vault_copy.tmp" - mv "$vault_copy.tmp" "$vault_copy" - fi - fi - - # Re-append preserved custom section (replace the repo's empty custom section) - if [[ -n "$custom_section" ]]; then - repo_custom_line=$(grep -n "^## Custom Agents" "$vault_copy" | head -1 | cut -d: -f1) - if [[ -n "$repo_custom_line" ]]; then - head -n "$((repo_custom_line - 1))" "$vault_copy" > "$vault_copy.tmp" - printf '%s\n' "$custom_section" >> "$vault_copy.tmp" - mv "$vault_copy.tmp" "$vault_copy" - fi - fi - info "Updated reference: $name (preserved custom content)" - REF_COUNT=$((REF_COUNT + 1)) - fi - continue - fi - - if [[ ! -f "$vault_copy" ]] || ! diff -q "$ref" "$vault_copy" >/dev/null 2>&1; then - cp "$ref" "$vault_copy" - info "Updated reference: $name" - REF_COUNT=$((REF_COUNT + 1)) - fi -done - -# ── Update skills ──────────────────────────────────────────────────────────── -SKILL_COUNT=0 -if [[ -d "$REPO_DIR/skills" ]]; then - for skill_dir in "$REPO_DIR/skills/"*/; do - [[ -f "$skill_dir/SKILL.md" ]] || continue - skill_name="$(basename "$skill_dir")" - src="$skill_dir/SKILL.md" - dst="$VAULT_DIR/.claude/skills/$skill_name/SKILL.md" - if [[ ! -f "$dst" ]] || ! diff -q "$src" "$dst" >/dev/null 2>&1; then - mkdir -p "$VAULT_DIR/.claude/skills/$skill_name" - cp "$src" "$dst" - info "Updated skill: $skill_name" - SKILL_COUNT=$((SKILL_COUNT + 1)) - fi - done -fi - -# ── Update hooks ────────────────────────────────────────────────────────── -HOOK_COUNT=0 -if [[ -d "$REPO_DIR/hooks" ]]; then - mkdir -p "$VAULT_DIR/.claude/hooks" - for hook in "$REPO_DIR/hooks/"*.sh; do - [[ -f "$hook" ]] || continue - name="$(basename "$hook")" - dst="$VAULT_DIR/.claude/hooks/$name" - if [[ ! -f "$dst" ]] || ! diff -q "$hook" "$dst" >/dev/null 2>&1; then - cp "$hook" "$dst" - chmod +x "$dst" - info "Updated hook: $name" - HOOK_COUNT=$((HOOK_COUNT + 1)) - fi - done -fi - -# ── Update settings.json ────────────────────────────────────────────────── -SETTINGS_UPDATED="" -if [[ -f "$REPO_DIR/settings.json" ]]; then - dst="$VAULT_DIR/.claude/settings.json" - if [[ ! -f "$dst" ]] || ! diff -q "$REPO_DIR/settings.json" "$dst" >/dev/null 2>&1; then - mkdir -p "$VAULT_DIR/.claude" - cp "$REPO_DIR/settings.json" "$dst" - info "Updated settings.json" - SETTINGS_UPDATED="1" - fi -fi - -# ── Remove stale orchestra scripts ──────────────────────────────────────── -ORCH_MANIFEST="$VAULT_DIR/Meta/scripts/.core-manifest" -REMOVED_SCRIPTS=0 -if [[ -d "$REPO_DIR/orchestra" && -f "$ORCH_MANIFEST" ]]; then - while IFS= read -r old_script; do - [[ -z "$old_script" ]] && continue - [[ -f "$REPO_DIR/orchestra/$old_script" ]] && continue - vault_script="$VAULT_DIR/Meta/scripts/$old_script" - [[ -f "$vault_script" ]] || continue - rm "$vault_script" - warn "Removed stale script: $old_script" - REMOVED_SCRIPTS=$((REMOVED_SCRIPTS + 1)) - done < "$ORCH_MANIFEST" -fi - -# ── Update orchestra scripts ────────────────────────────────────────────── -ORCH_COUNT=0 -if [[ -d "$REPO_DIR/orchestra" ]]; then - mkdir -p "$VAULT_DIR/Meta/scripts" - : > "$VAULT_DIR/Meta/scripts/.core-manifest" - for script in "$REPO_DIR/orchestra/"*; do - [[ -f "$script" ]] || continue - bname="$(basename "$script")" - [[ "$bname" == "README.md" ]] && continue - echo "$bname" >> "$VAULT_DIR/Meta/scripts/.core-manifest" - dst="$VAULT_DIR/Meta/scripts/$bname" - if [[ ! -f "$dst" ]] || ! diff -q "$script" "$dst" >/dev/null 2>&1; then - cp "$script" "$dst" - chmod +x "$dst" - info "Updated script: $bname" - ORCH_COUNT=$((ORCH_COUNT + 1)) - fi - done -fi - -# ── Update CLAUDE.md ────────────────────────────────────────────────────── -CLAUDE_MD_UPDATED="" -if [[ -f "$REPO_DIR/CLAUDE.md" ]]; then - if [[ ! -f "$VAULT_DIR/CLAUDE.md" ]] || ! diff -q "$REPO_DIR/CLAUDE.md" "$VAULT_DIR/CLAUDE.md" >/dev/null 2>&1; then - cp "$REPO_DIR/CLAUDE.md" "$VAULT_DIR/CLAUDE.md" - info "Updated CLAUDE.md" - CLAUDE_MD_UPDATED="1" - fi -fi - -# ── Summary ───────────────────────────────────────────────────────────────── +# ── Summary ─────────────────────────────────────────────────────────────────── echo "" -if [[ $AGENT_COUNT -eq 0 && $REF_COUNT -eq 0 && $SKILL_COUNT -eq 0 && $HOOK_COUNT -eq 0 && $ORCH_COUNT -eq 0 && $DEPRECATED_COUNT -eq 0 && $REMOVED_SCRIPTS -eq 0 && -z "$CLAUDE_MD_UPDATED" && -z "$SETTINGS_UPDATED" ]]; then +TOTAL=$((AGENT_COUNT + REF_COUNT + SKILL_COUNT + HOOK_COUNT + SETTINGS_CHANGED + CLAUDE_MD_CHANGED)) +if [[ $TOTAL -eq 0 && $DEP_COUNT -eq 0 ]]; then success "Everything is already up to date!" else - success "Updated $AGENT_COUNT agent(s), $SKILL_COUNT skill(s), $REF_COUNT reference(s), $HOOK_COUNT hook(s), $ORCH_COUNT script(s)" - if [[ $DEPRECATED_COUNT -gt 0 ]]; then - warn "Deprecated $DEPRECATED_COUNT file(s) no longer in the project" - fi - if [[ $REMOVED_SCRIPTS -gt 0 ]]; then - warn "Removed $REMOVED_SCRIPTS stale script(s) from Meta/scripts/" - fi + success "Updated $AGENT_COUNT agent(s), $SKILL_COUNT skill(s), $REF_COUNT reference(s), $HOOK_COUNT hook(s)" + [[ $SETTINGS_CHANGED -eq 1 ]] && info "settings.json updated (backup saved as settings.json.bak)" + [[ $CLAUDE_MD_CHANGED -eq 1 ]] && info "CLAUDE.md updated" + [[ $DEP_COUNT -gt 0 ]] && warn "$DEP_COUNT file(s) deprecated (moved to .claude/deprecated/)" fi echo "" echo -e " ${DIM}Restart Claude Code to pick up the changes.${NC}" diff --git a/skills/create-agent/SKILL.md b/skills/create-agent/SKILL.md old mode 100644 new mode 100755 index 999689e..c604de0 --- a/skills/create-agent/SKILL.md +++ b/skills/create-agent/SKILL.md @@ -174,8 +174,8 @@ Before writing the agent .md file, verify you have checked off ALL of these. If - Write a detailed Core Responsibilities section (this is what makes the agent good or bad) - Include concrete examples and templates for any notes the agent creates 4. **Save the file** to `.claude/agents/{name}.md` -5. **Update the registry**: add a new row to `.claude/references/agents-registry.md` -6. **Update the directory**: add a new section under "Custom Agents" in `.claude/references/agents.md` +5. **Update the registry**: add a new row to `.claude/references/agents-registry.md` — insert it between the `` and `` markers in the Registry table (after the postman row) +6. **Update the directory**: add a new section under "Custom Agents" in `.claude/references/agents.md` — insert it between the `` and `` markers in that file 7. **Log the creation** in `Meta/agent-log.md` 8. **Report to the user**: "Your new agent `{name}` is now active. You can try it by saying one of your trigger phrases." diff --git a/skills/manage-agent/SKILL.md b/skills/manage-agent/SKILL.md old mode 100644 new mode 100755 index 83177fd..7c52572 --- a/skills/manage-agent/SKILL.md +++ b/skills/manage-agent/SKILL.md @@ -67,7 +67,7 @@ When the user says "edit my agent", "update agent X", "modify agent X", or equiv 4. **Apply changes.** Modify the agent file at `.claude/agents/{name}.md` with the requested changes. -5. **Update the registry.** If the change affects the agent's description, triggers, or capabilities, update the corresponding row in `.claude/references/agents-registry.md`. +5. **Update the registry.** If the change affects the agent's description, triggers, or capabilities, update the corresponding row in `.claude/references/agents-registry.md`. Custom agent rows live between the `` and `` markers — edit only within that block. 6. **Update agents.md.** If the change affects the agent's role description, update `.claude/references/agents.md`.