sync_skills.sh #1

  • //
  • p4-sdp/
  • dev/
  • ai_dev_support/
  • skills/
  • skills-sync/
  • sync_skills.sh
  • View
  • Commits
  • Open Download .zip Download (4 KB)
#!/bin/bash
# sync_skills.sh
#
# Walks the manifest table in ai_dev_support/SKILLS_INDEX.md (this skill's
# sibling directory) and, for each skill whose ~/.claude/skills/<name>
# symlink already exists and resolves into a real P4 client workspace,
# syncs that workspace's skill subtree to head.
#
# This is the "keep what I already have up to date" half of the skills-sync
# skill. It deliberately does NOT auto-create P4 clients for skills that
# aren't set up yet on this machine -- see the skill's SKILL.md for the
# guided bootstrap procedure for that case, since choosing a client Root
# and reusing (vs. creating) a workspace is a judgment call, not something
# safe to script unattended.
set -u

declare ThisScript=${0##*/}
declare -i ErrorCount=0
declare IndexFile="${1:-$HOME/pub/p4-sdp_dev_bot/ai_dev_support/SKILLS_INDEX.md}"
declare SkillsDir="$HOME/.claude/skills"

function msg () { echo -e "$*"; }
function errmsg () { msg "\\nError: ${1:-Unknown Error}\\n"; ErrorCount+=1; }

[[ -r "$IndexFile" ]] || { errmsg "Cannot read manifest [$IndexFile]."; exit 1; }

# Find the nearest ancestor of $1 containing a '.p4config*' file and echo
# its basename -- each client in this project may use a differently-named
# config file (.p4config, .p4config.bot_Claude_Anthropic, etc.), and this
# script must not assume the invoking shell's own P4CONFIG applies to every
# skill's workspace.
function find_p4config_name () {
   declare dir="$1"
   while [[ "$dir" != "/" && -n "$dir" ]]; do
      declare hit
      hit=$(find "$dir" -maxdepth 1 -name ".p4config*" 2>/dev/null | head -1)
      if [[ -n "$hit" ]]; then
         basename "$hit"
         return 0
      fi
      dir=$(dirname "$dir")
   done
   return 1
}

# Parse manifest table rows: | Skill | Server | Depot Path | Purpose |
# Only real rows have a Depot Path starting with '//' -- this also skips
# the header, the separator row, and any prose elsewhere in the file that
# happens to contain a literal '|' (e.g. this file's own "|-delimited"
# phrase in the naming note).
while IFS='|' read -r _ name server path _; do
   name=$(echo "$name" | xargs)
   server=$(echo "$server" | xargs)
   path=$(echo "$path" | xargs)
   name=${name//\`/}
   server=${server//\`/}
   path=${path//\`/}
   [[ "$path" == //* ]] || continue

   msg "=== $name ==="
   LinkTarget=$(readlink "$SkillsDir/$name" 2>/dev/null)
   if [[ -z "$LinkTarget" ]]; then
      msg "  Not set up on this machine yet (no ~/.claude/skills/$name symlink)."
      msg "  See this skill's SKILL.md for the bootstrap procedure (server: $server, path: $path)."
      continue
   fi
   if [[ ! -d "$LinkTarget" ]]; then
      errmsg "$name: symlink target [$LinkTarget] does not exist. Investigate before re-syncing."
      continue
   fi

   ConfigName=$(find_p4config_name "$LinkTarget")
   if [[ -z "$ConfigName" ]]; then
      errmsg "$name: no .p4config* found in [$LinkTarget] or any ancestor. Skipping."
      continue
   fi

   ClientRoot=$(cd "$LinkTarget" && P4CONFIG="$ConfigName" p4 -ztag -F %clientRoot% info 2>/dev/null)
   ClientStream=$(cd "$LinkTarget" && P4CONFIG="$ConfigName" p4 -ztag -F %Stream% client -o 2>/dev/null)
   msg "  Symlink target: $LinkTarget (P4CONFIG=$ConfigName)"
   msg "  P4 client root: ${ClientRoot:-<unknown>}, stream: ${ClientStream:-<unknown>}"
   (cd "$LinkTarget" && P4CONFIG="$ConfigName" p4 sync ./... 2>&1 | sed 's/^/  /')
done < "$IndexFile"

if [[ "$ErrorCount" -eq 0 ]]; then
   msg "\\nDone: $ThisScript completed with no errors."
else
   errmsg "$ErrorCount skill(s) had problems; see above."
fi
exit "$ErrorCount"
# Change User Description Committed
#1 33424 Claude (AI Agent by Anthropic) Add ai_dev_support/ scaffolding to //p4-sdp/dev: master skills index and the skills-sync skill.

SKILLS_INDEX.md is the master manifest of every Claude Code Skill across
this effort (currently 6: 2 in test-install_sdp, 3 in BattleSchool/Gen7 on
PPN, this new skills-sync here) -- name, P4 server, depot path, purpose.
Kept as a markdown table that doubles as skills-sync's parseable manifest,
so the two can't drift out of sync with each other.

skills-sync covers both halves of the 'get a new machine set up' problem:
sync_skills.sh automates re-syncing already-symlinked skills to head, and
the SKILL.md documents the guided (not scripted) bootstrap procedure for
wiring up ~/.claude/skills/* symlinks on a machine that doesn't have them
yet, since picking a new P4 client's Root is a per-person, per-machine
judgment call.

This is our own internal dev-process tooling (isolate ai_dev_support/...
on main), distinct from the still-open SDP-1386 ai/dev + ai/ops plan for
shipped, customer/contributor-facing skills.

Agent: Claude Code, Model: Claude Sonnet 5 (claude-sonnet-5), operating as bot_Claude_Anthropic.