Audit and update vendor submodules. Lists every submodule under vendor/, fetches latest, reports per-submodule current/latest commits and changed file counts, prompts…
Scanned 9/3/2026
Install to Claude Code
npx -y skills add KevinZai/commander --skill ccc-upgrade --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Ccc Upgrade?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/kevinzai-ccc-upgrade-commander)More formats (shields.io, HTML) on the badges page.
---
name: ccc-upgrade
description: "Audit and update vendor submodules. Lists every submodule under vendor/, fetches latest, reports per-submodule current/latest commits and changed file counts, prompts…"
model: sonnet
effort: medium
allowed-tools:
- Read
- Bash
- Edit
- WebSearch
argument-hint: "[--all | --check]"
---
# /ccc-upgrade — Vendor Submodule Updater
> 🔎 **Looking to update the CC Commander plugin itself** (not this repo's
> vendor submodules)? That's `/ccc-update` — a different, end-user-facing
> tool with a similarly-spelled name. This skill is maintainer-only.
> ⚠️ **Run only from the CC Commander repo root.** Verify `pwd` ends in `/cc-commander` (or your fork's name) and `ls .claude-plugin/marketplace.json` succeeds. Running this skill in the wrong cwd would touch unrelated submodules.
Interactive workflow that audits the 19+ vendor submodules under `vendor/`, surfaces what changed upstream, lets the user pick which to update via AskUserQuestion, then runs the update + test + commit cycle one submodule at a time.
Similar in spirit to `/ccc-doctor` (read-only diagnostic) — this one writes (commits per submodule) but only after explicit user approval.
## When to fire
User types `/ccc-upgrade`, or says any of:
- "update vendors"
- "refresh submodules"
- "pull latest vendor changes"
- "sync the ecosystem"
- "are any vendors out of date"
- "check vendor drift"
Args:
- `--check` — read-only audit (no fetch, no update, no commit)
- `--all` — skip the picker and update every submodule with available updates
## Steps (always in this order)
### 1. Locate the repo root + sanity check
Resolve repo root via `git rev-parse --show-toplevel`. If that fails, output: "Not in a git repo — /ccc-upgrade only works inside the cc-commander checkout." and exit.
Before proceeding, verify you are at the cc-commander repo root:
```bash
# Guard: must be at the cc-commander repo root
if [ ! -f ".claude-plugin/marketplace.json" ]; then
echo "❌ Not at cc-commander repo root. Refusing to update vendor submodules."
exit 1
fi
```
If the guard fails, output the error message and exit.
Verify `vendor/` exists:
```bash
test -d vendor || echo "no-vendor-dir"
```
If missing, output: "No vendor/ directory at repo root — nothing to upgrade." and exit.
### 2. List submodules
```bash
git submodule status
```
Parse each line: format is ` <sha> <path> (<ref>)` or `-<sha> <path>` (uninitialized) or `+<sha> <path>` (local-modified).
Skip uninitialized (`-` prefix) entries — flag them in the report so user can `git submodule update --init <path>` separately.
### 3. Per-submodule scan
For each initialised submodule, gather:
```bash
cd vendor/<name>
CURRENT_SHA=$(git rev-parse --short HEAD)
git fetch --quiet origin 2>/dev/null || git fetch --quiet
DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@' || echo main)
LATEST_SHA=$(git rev-parse --short "origin/$DEFAULT_BRANCH" 2>/dev/null || echo unknown)
CHANGED_FILES=$(git diff --name-only "$CURRENT_SHA..$LATEST_SHA" 2>/dev/null | wc -l | tr -d ' ')
COMMITS_BEHIND=$(git rev-list --count "$CURRENT_SHA..$LATEST_SHA" 2>/dev/null || echo 0)
cd -
```
Use `Bash` in a single call per submodule. Handle missing remotes gracefully — output `unknown` rather than failing.
If a submodule has `LATEST_SHA == CURRENT_SHA`, mark it ✅ up-to-date and skip from the picker.
Optional star count: if available offline, use cached info; do not block on `WebSearch` for stars — it's nice-to-have, not required. Skip the star column when unknown.
### 4. Render the audit table
```
## Vendor submodule audit — <UTC timestamp>
| # | Submodule | Current | Latest | Δ commits | Δ files | Status |
|---|-----------|---------|--------|-----------|---------|--------|
| 1 | acpx | abc1234 | def5678 | 12 | 27 | 🔄 update available |
| 2 | repomix | aaa1111 | aaa1111 | 0 | 0 | ✅ up to date |
| ... | ... | ... | ... | ... | ... | ... |
**Summary:** N submodules · M with updates · K up-to-date
```
Always show every submodule, even up-to-date ones (transparency).
### 5. Stop here on `--check`
If invoked with `--check`, print the table and exit. No fetch (already done — that's fine, fetch is read-only), no prompt, no update.
### 6. Ask which to update (skip on `--all`)
If at least one submodule has updates, fire AskUserQuestion with a multi-select chip list:
```
Question: "Pick the submodules to update. Selected ones will be rebased to latest and committed individually."
Options:
- acpx (12 commits, 27 files)
- everything-claude-code (3 commits, 8 files)
- ... (one chip per submodule with available updates)
- 🌐 All available
- ❌ Cancel
```
If user picks "All available", treat as every update-eligible submodule. If "Cancel", exit with no changes.
On `--all`, skip the picker — auto-select every update-eligible submodule.
### 7. Update each selected submodule
For each chosen submodule, in sequence (NOT parallel — one commit at a time):
```bash
OLD_SHA=$(git -C vendor/<name> rev-parse --short HEAD)
git submodule update --remote --rebase vendor/<name>
NEW_SHA=$(git -C vendor/<name> rev-parse --short HEAD)
```
If the rebase fails (conflicts, detached state, etc.), abort that submodule, log the failure, and continue to the next. Never `--force`.
### 8. Verify tests still pass
After each successful submodule update — BEFORE committing — run a fast smoke test:
```bash
node scripts/audit-frontmatter.js --check
node scripts/audit-counts.js --check
```
If either fails, roll back that one submodule:
```bash
git checkout -- vendor/<name>
```
and report the failure. Do NOT continue with other submodules until the user resolves.
If both pass, proceed to commit step.
(Avoid running the full `npm test` per submodule — too slow. The audits cover the registry/count drift surface that vendor updates can affect. Full `npm test` happens at PR review time, not per-submodule.)
### 9. Commit one chore(vendor) per submodule
```bash
git add vendor/<name>
git commit -m "chore(vendor): update <name> <OLD_SHA>..<NEW_SHA>"
```
Commit message format MUST be exact: `chore(vendor): update <submodule-name> <old-sha>..<new-sha>` — lowercase, two dots between SHAs, no trailing period.
### 10. Final summary
```
## Vendor upgrade complete
✅ Updated: N submodules
- acpx: abc1234 → def5678 (12 commits)
- repomix: aaa1111 → bbb2222 (5 commits)
⚠️ Skipped: M submodules
- foo: rebase conflict — manual resolution required
❌ Test failures rolled back: K submodules
Next steps:
- Review the new commits with `git log --oneline -<N>`
- Push when ready: `git push`
- Open a PR if the changes are non-trivial (any submodule with >50 changed files)
```
## Anti-patterns — DO NOT
- Never `git push` automatically — let the user push.
- Never `--force` a rebase. If it fails, skip and report.
- Never bundle multiple submodules into one commit — one submodule per commit (atomic, revertable, bisectable).
- Never run the full `npm test` per submodule — use the targeted audits in step 8.
- Never silently skip a failed submodule — always log it in the final summary.
- Never write WebSearch results into the report unless they were already obtained quickly — star counts are optional polish, not blocking.
- Never modify `.gitmodules` — the workflow is just a wrapper around `git submodule update --remote`.
## Tips
1. The scan in step 3 can be parallelised across submodules (independent `git fetch` calls). Updates in step 7 must be sequential (commit ordering matters).
2. If the user has uncommitted vendor changes (the `+` prefix in `git submodule status`), warn them up front: "Vendor X has uncommitted local changes. Stash or commit before continuing." Then exit unless they pass `--all` (in which case still skip that submodule, never trample local work).
3. The weekly cron at `.github/workflows/vendor-update.yml` runs the same audit unattended. Skill is the human-in-the-loop variant.
4. Star counts (when fetched) come from `vendor/<name>/.git/config` URL → GitHub API. Do not block on this. Cache results in `~/.claude/commander/vendor-stars.json` if you implement it later.
---
> ⚙️ **Fable contract:** plan before build · verifier ≠ worker · prove before alarm · loops need gates · leave durable state — `rules/fable-method.md`
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!