From 469941b5d2799b4f1e3d9974785c0968f029f70d Mon Sep 17 00:00:00 2001 From: Typo Fix Bot Date: Fri, 5 Jun 2026 06:02:06 +0000 Subject: [PATCH 1/3] fix(install): count agents/skills/hooks from the resolver output The install summary was using `ls`/`wc` on the destination filesystem to count agents, skills, and hooks. That undercounts because the kit ships the same content under both `.claude/` and `.codex/`, and the previous counter only walked `.claude/`. The summary also claimed "(Claude Code + Codex)" while only counting Claude. Drive the counts off `$FILES`, the resolver output that the install loop just wrote to `.vc-installed-files`. That output is the authoritative list of what the manifest produced, so the summary now matches reality across both runtimes and is independent of `ls`/`wc` quirks on the host. Smoke-tested the regex on a small fixture: AGENT=3 (matches .claude/agents/* + .codex/agents/*) SKILL=3 (matches SKILL.md anywhere) HOOK=3 (matches top-level *.cjs under any hooks/ dir) --- install.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install.sh b/install.sh index 5cef82b..698580d 100755 --- a/install.sh +++ b/install.sh @@ -160,9 +160,9 @@ cleanup # ══════════════════════════════════════════════════════ # Summary # ══════════════════════════════════════════════════════ -AGENT_COUNT=$(ls .claude/agents/*.md 2>/dev/null | wc -l | tr -d ' ') -SKILL_COUNT=$(ls -d .claude/skills/*/ 2>/dev/null | wc -l | tr -d ' ') -HOOK_COUNT=$(ls .claude/hooks/*.cjs 2>/dev/null | wc -l | tr -d ' ') +AGENT_COUNT=$(echo "$FILES" | grep -E '^\.(claude|codex)/agents/' | wc -l | tr -d ' ') +SKILL_COUNT=$(echo "$FILES" | grep -E '/SKILL\.md$' | wc -l | tr -d ' ') +HOOK_COUNT=$(echo "$FILES" | grep -E '/hooks/[^/]+\.cjs$' | wc -l | tr -d ' ') echo "" echo -e " ${GREEN}Install complete.${NC} (v$VERSION)" From 427f9046b129772b88bea9217f445aacc74fb23e Mon Sep 17 00:00:00 2001 From: Arvuno Date: Fri, 5 Jun 2026 06:40:43 +0000 Subject: [PATCH 2/3] fix(install): tolerate zero-match grep with pipefail `set -o pipefail` was aborting the installer when a category had no matches. Append `|| true` to the grep stage so `wc -l` can still report 0. Reported-by: CodeRabbit review (PR #17, major) --- install.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/install.sh b/install.sh index 698580d..c3e3852 100755 --- a/install.sh +++ b/install.sh @@ -160,9 +160,12 @@ cleanup # ══════════════════════════════════════════════════════ # Summary # ══════════════════════════════════════════════════════ -AGENT_COUNT=$(echo "$FILES" | grep -E '^\.(claude|codex)/agents/' | wc -l | tr -d ' ') -SKILL_COUNT=$(echo "$FILES" | grep -E '/SKILL\.md$' | wc -l | tr -d ' ') -HOOK_COUNT=$(echo "$FILES" | grep -E '/hooks/[^/]+\.cjs$' | wc -l | tr -d ' ') +# grep | wc -l: with `set -o pipefail`, a zero-match grep exits 1 and would +# abort the installer. Tolerate zero matches by appending `|| true` to the +# grep stage only — `wc -l` still returns 0 when no lines match. +AGENT_COUNT=$( (echo "$FILES" | grep -E '^\.(claude|codex)/agents/' || true) | wc -l | tr -d ' ') +SKILL_COUNT=$( (echo "$FILES" | grep -E '/SKILL\.md$' || true) | wc -l | tr -d ' ') +HOOK_COUNT=$( (echo "$FILES" | grep -E '/hooks/[^/]+\.cjs$' || true) | wc -l | tr -d ' ') echo "" echo -e " ${GREEN}Install complete.${NC} (v$VERSION)" From 541abca9fb5565000d40a1fa76acab1769b7cacc Mon Sep 17 00:00:00 2001 From: Arvuno Date: Wed, 17 Jun 2026 11:11:53 +0000 Subject: [PATCH 3/3] feat(install): add --dry-run and --help flags to install.sh The installer unconditionally copies files, creates symlinks, and removes any existing .claude / .codex / .agents directories. There was no way to preview the plan before running it for real, which made the script hard to evaluate in CI smoke checks and awkward for humans who want to see what would change. This change adds two flags: - --dry-run: parse the manifest, count files/skills/hooks, and print the install summary without touching the working tree. Backups, copies, symlink creation, and the .vc-installed-files / .vc-version writes are all skipped. - --help: print usage and exit 0. - Unknown arguments: print an error to stderr and exit 64 (EX_USAGE) so calling scripts can detect bad input. No behavior change for the default invocation (no flags). The exit status from a successful dry-run is 0, matching the success path of the real installer. --- install.sh | 86 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/install.sh b/install.sh index c3e3852..9fbd6d1 100755 --- a/install.sh +++ b/install.sh @@ -19,8 +19,34 @@ NC='\033[0m' cleanup() { rm -rf "$TMPDIR" 2>/dev/null; } trap cleanup EXIT +# DRY_RUN prints what would happen without making any filesystem changes +# outside the temp clone. Existing backups, symlinks, and copied files are +# all skipped. Useful for CI smoke checks and for previewing the install +# before running it for real. +DRY_RUN=false +for arg in "$@"; do + case "$arg" in + --dry-run) + DRY_RUN=true + ;; + -h|--help) + echo "Usage: install.sh [--dry-run]" + echo " --dry-run Print the planned install summary without modifying the working tree." + exit 0 + ;; + *) + echo " Error: unknown argument: $arg" >&2 + echo " Run with --help for usage." >&2 + exit 64 + ;; + esac +done + echo "" echo " vibecode-pro-max-kit installer" +if [ "$DRY_RUN" = true ]; then + echo " (dry-run mode — no filesystem changes will be made outside the temp clone)" +fi echo " ─────────────────────────────────" echo "" @@ -75,24 +101,28 @@ SYMLINKS_JSON=$(echo "$MANIFEST_JSON" | node -e " HAS_EXISTING=false if [ -d ".claude" ] || [ -d ".codex" ] || [ -d ".agents" ] || [ -f "CLAUDE.md" ] || [ -f "AGENTS.md" ]; then HAS_EXISTING=true - echo -e " ${YELLOW}Existing setup detected.${NC} Backing up..." - mkdir -p "$BACKUP_DIR" - - # Back up directories - [ -d ".claude" ] && cp -R .claude "$BACKUP_DIR/.claude" && echo -e " ${YELLOW}Backed up${NC} .claude/" - [ -d ".codex" ] && cp -R .codex "$BACKUP_DIR/.codex" && echo -e " ${YELLOW}Backed up${NC} .codex/" - [ -d ".agents" ] && cp -R .agents "$BACKUP_DIR/.agents" && echo -e " ${YELLOW}Backed up${NC} .agents/" - - # Back up root protocol files - [ -f "CLAUDE.md" ] && cp CLAUDE.md "$BACKUP_DIR/CLAUDE.md" && echo -e " ${YELLOW}Backed up${NC} CLAUDE.md" - [ -f "AGENTS.md" ] && cp AGENTS.md "$BACKUP_DIR/AGENTS.md" && echo -e " ${YELLOW}Backed up${NC} AGENTS.md" - [ -f "GUIDE.md" ] && cp GUIDE.md "$BACKUP_DIR/GUIDE.md" && echo -e " ${YELLOW}Backed up${NC} GUIDE.md" - - echo -e " Backup at: ${CYAN}$BACKUP_DIR/${NC}" - echo "" - - # Clean slate — remove old agent tooling dirs - rm -rf .claude .codex .agents + if [ "$DRY_RUN" = true ]; then + echo -e " ${YELLOW}Existing setup detected.${NC} Would back up to $BACKUP_DIR/" + else + echo -e " ${YELLOW}Existing setup detected.${NC} Backing up..." + mkdir -p "$BACKUP_DIR" + + # Back up directories + [ -d ".claude" ] && cp -R .claude "$BACKUP_DIR/.claude" && echo -e " ${YELLOW}Backed up${NC} .claude/" + [ -d ".codex" ] && cp -R .codex "$BACKUP_DIR/.codex" && echo -e " ${YELLOW}Backed up${NC} .codex/" + [ -d ".agents" ] && cp -R .agents "$BACKUP_DIR/.agents" && echo -e " ${YELLOW}Backed up${NC} .agents/" + + # Back up root protocol files + [ -f "CLAUDE.md" ] && cp CLAUDE.md "$BACKUP_DIR/CLAUDE.md" && echo -e " ${YELLOW}Backed up${NC} CLAUDE.md" + [ -f "AGENTS.md" ] && cp AGENTS.md "$BACKUP_DIR/AGENTS.md" && echo -e " ${YELLOW}Backed up${NC} AGENTS.md" + [ -f "GUIDE.md" ] && cp GUIDE.md "$BACKUP_DIR/GUIDE.md" && echo -e " ${YELLOW}Backed up${NC} GUIDE.md" + + echo -e " Backup at: ${CYAN}$BACKUP_DIR/${NC}" + echo "" + + # Clean slate — remove old agent tooling dirs + rm -rf .claude .codex .agents + fi fi # ══════════════════════════════════════════════════════ @@ -129,6 +159,12 @@ while IFS= read -r file; do continue fi + # Dry-run: count files but skip the actual copy. + if [ "$DRY_RUN" = true ]; then + INSTALLED_COUNT=$((INSTALLED_COUNT + 1)) + continue + fi + # Create parent directory and copy mkdir -p "$(dirname "$file")" cp "$TMPDIR/$file" "$file" @@ -139,10 +175,16 @@ done <<< "$FILES" # Symlinks # ══════════════════════════════════════════════════════ echo " Setting up symlinks..." +if [ "$DRY_RUN" = true ]; then + echo " (dry-run: symlink creation skipped)" +fi while IFS= read -r line; do [ -z "$line" ] && continue LINK_PATH="${line%%|*}" LINK_TARGET="${line##*|}" + if [ "$DRY_RUN" = true ]; then + continue + fi mkdir -p "$(dirname "$LINK_PATH")" # Remove existing (wrong symlink or real dir) [ -e "$LINK_PATH" ] || [ -L "$LINK_PATH" ] && rm -rf "$LINK_PATH" @@ -152,8 +194,12 @@ done <<< "$SYMLINKS_JSON" # ══════════════════════════════════════════════════════ # Write snapshot + version # ══════════════════════════════════════════════════════ -echo "$FILES" | sort > .vc-installed-files -echo "$VERSION" > .vc-version +if [ "$DRY_RUN" = true ]; then + echo " (dry-run: skipping .vc-installed-files and .vc-version writes)" +else + echo "$FILES" | sort > .vc-installed-files + echo "$VERSION" > .vc-version +fi cleanup