From 3475e89406691cd7cdc61e6f7eea9697360670c8 Mon Sep 17 00:00:00 2001 From: Akshan Krithick <97239696+akshan-main@users.noreply.github.com> Date: Sun, 1 Mar 2026 13:19:07 -0800 Subject: [PATCH] skill: add /update-nanoclaw for syncing customized installs with upstream (#217) Merge-first workflow that previews upstream changes, lets user choose full merge / cherry-pick / rebase / abort, resolves only conflicted files, and validates with build + test. --- .claude/skills/update-nanoclaw/SKILL.md | 196 ++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 .claude/skills/update-nanoclaw/SKILL.md diff --git a/.claude/skills/update-nanoclaw/SKILL.md b/.claude/skills/update-nanoclaw/SKILL.md new file mode 100644 index 0000000..ea74e3a --- /dev/null +++ b/.claude/skills/update-nanoclaw/SKILL.md @@ -0,0 +1,196 @@ +--- +name: update-nanoclaw +description: Efficiently bring upstream NanoClaw updates into a customized install, with preview, selective cherry-pick, and low token usage. +--- + +# About + +Your NanoClaw fork drifts from upstream as you customize it. This skill pulls upstream changes into your install without losing your modifications. + +Run `/update-nanoclaw` in Claude Code. + +## How it works + +**Preflight**: checks for clean working tree (`git status --porcelain`). If `upstream` remote is missing, asks you for the URL (defaults to `https://github.com/qwibitai/nanoclaw.git`) and adds it. Detects the upstream branch name (`main` or `master`). + +**Backup**: creates a timestamped backup branch and tag (`backup/pre-update--`, `pre-update--`) before touching anything. Safe to run multiple times. + +**Preview**: runs `git log` and `git diff` against the merge base to show upstream changes since your last sync. Groups changed files into categories: +- **Skills** (`.claude/skills/`): unlikely to conflict unless you edited an upstream skill +- **Source** (`src/`): may conflict if you modified the same files +- **Build/config** (`package.json`, `tsconfig*.json`, `container/`): review needed + +**Update paths** (you pick one): +- `merge` (default): `git merge upstream/`. Resolves all conflicts in one pass. +- `cherry-pick`: `git cherry-pick `. Pull in only the commits you want. +- `rebase`: `git rebase upstream/`. Linear history, but conflicts resolve per-commit. +- `abort`: just view the changelog, change nothing. + +**Conflict preview**: before merging, runs a dry-run (`git merge --no-commit --no-ff`) to show which files would conflict. You can still abort at this point. + +**Conflict resolution**: opens only conflicted files, resolves the conflict markers, keeps your local customizations intact. + +**Validation**: runs `npm run build` and `npm test`. + +## Rollback + +The backup tag is printed at the end of each run: +``` +git reset --hard pre-update-- +``` + +Backup branch `backup/pre-update--` also exists. + +## Token usage + +Only opens files with actual conflicts. Uses `git log`, `git diff`, and `git status` for everything else. Does not scan or refactor unrelated code. + +--- + +# Goal +Help a user with a customized NanoClaw install safely incorporate upstream changes without a fresh reinstall and without blowing tokens. + +# Operating principles +- Never proceed with a dirty working tree. +- Always create a rollback point (backup branch + tag) before touching anything. +- Prefer git-native operations (fetch, merge, cherry-pick). Do not manually rewrite files except conflict markers. +- Default to MERGE (one-pass conflict resolution). Offer REBASE as an explicit option. +- Keep token usage low: rely on `git status`, `git log`, `git diff`, and open only conflicted files. + +# Step 0: Preflight (stop early if unsafe) +Run: +- `git status --porcelain` +If output is non-empty: +- Tell the user to commit or stash first, then stop. + +Confirm remotes: +- `git remote -v` +If `upstream` is missing: +- Ask the user for the upstream repo URL (default: `https://github.com/qwibitai/nanoclaw.git`). +- Add it: `git remote add upstream ` +- Then: `git fetch upstream --prune` + +Determine the upstream branch name: +- `git branch -r | grep upstream/` +- If `upstream/main` exists, use `main`. +- If only `upstream/master` exists, use `master`. +- Otherwise, ask the user which branch to use. +- Store this as UPSTREAM_BRANCH for all subsequent commands. Every command below that references `upstream/main` should use `upstream/$UPSTREAM_BRANCH` instead. + +Fetch: +- `git fetch upstream --prune` + +# Step 1: Create a safety net +Capture current state: +- `HASH=$(git rev-parse --short HEAD)` +- `TIMESTAMP=$(date +%Y%m%d-%H%M%S)` + +Create backup branch and tag (using timestamp to avoid collisions on retry): +- `git branch backup/pre-update-$HASH-$TIMESTAMP` +- `git tag pre-update-$HASH-$TIMESTAMP` + +Save the tag name for later reference in the summary and rollback instructions. + +# Step 2: Preview what upstream changed (no edits yet) +Compute common base: +- `BASE=$(git merge-base HEAD upstream/$UPSTREAM_BRANCH)` + +Show upstream commits since BASE: +- `git log --oneline $BASE..upstream/$UPSTREAM_BRANCH` + +Show local commits since BASE (custom drift): +- `git log --oneline $BASE..HEAD` + +Show file-level impact from upstream: +- `git diff --name-only $BASE..upstream/$UPSTREAM_BRANCH` + +Bucket the upstream changed files: +- **Skills** (`.claude/skills/`): unlikely to conflict unless the user edited an upstream skill +- **Source** (`src/`): may conflict if user modified the same files +- **Build/config** (`package.json`, `package-lock.json`, `tsconfig*.json`, `container/`, `launchd/`): review needed +- **Other**: docs, tests, misc + +Present these buckets to the user and ask them to choose one path using AskUserQuestion: +- A) **Full update**: merge all upstream changes +- B) **Selective update**: cherry-pick specific upstream commits +- C) **Abort**: they only wanted the preview +- D) **Rebase mode**: advanced, linear history (warn: resolves conflicts per-commit) + +If Abort: stop here. + +# Step 3: Conflict preview (before committing anything) +If Full update or Rebase: +- Dry-run merge to preview conflicts. Run these as a single chained command so the abort always executes: + ``` + git merge --no-commit --no-ff upstream/$UPSTREAM_BRANCH; git diff --name-only --diff-filter=U; git merge --abort + ``` +- If conflicts were listed: show them and ask user if they want to proceed. +- If no conflicts: tell user it is clean and proceed. + +# Step 4A: Full update (MERGE, default) +Run: +- `git merge upstream/$UPSTREAM_BRANCH --no-edit` + +If conflicts occur: +- Run `git status` and identify conflicted files. +- For each conflicted file: + - Open the file. + - Resolve only conflict markers. + - Preserve intentional local customizations. + - Incorporate upstream fixes/improvements. + - Do not refactor surrounding code. + - `git add ` +- When all resolved: + - If merge did not auto-commit: `git commit --no-edit` + +# Step 4B: Selective update (CHERRY-PICK) +If user chose Selective: +- Recompute BASE if needed: `BASE=$(git merge-base HEAD upstream/$UPSTREAM_BRANCH)` +- Show commit list again: `git log --oneline $BASE..upstream/$UPSTREAM_BRANCH` +- Ask user which commit hashes they want. +- Apply: `git cherry-pick ...` + +If conflicts during cherry-pick: +- Resolve only conflict markers, then: + - `git add ` + - `git cherry-pick --continue` +If user wants to stop: + - `git cherry-pick --abort` + +# Step 4C: Rebase (only if user explicitly chose option D) +Run: +- `git rebase upstream/$UPSTREAM_BRANCH` + +If conflicts: +- Resolve conflict markers only, then: + - `git add ` + - `git rebase --continue` +If it gets messy (more than 3 rounds of conflicts): + - `git rebase --abort` + - Recommend merge instead. + +# Step 5: Validation +Run: +- `npm run build` +- `npm test` (do not fail the flow if tests are not configured) + +If build fails: +- Show the error. +- Only fix issues clearly caused by the merge (missing imports, type mismatches from merged code). +- Do not refactor unrelated code. +- If unclear, ask the user before making changes. + +# Step 6: Summary + rollback instructions +Show: +- Backup tag: the tag name created in Step 1 +- New HEAD: `git rev-parse --short HEAD` +- Upstream HEAD: `git rev-parse --short upstream/$UPSTREAM_BRANCH` +- Conflicts resolved (list files, if any) +- Remaining local diff vs upstream: `git diff --name-only upstream/$UPSTREAM_BRANCH..HEAD` + +Tell the user: +- To rollback: `git reset --hard ` +- Backup branch also exists: `backup/pre-update--` +- Restart the service to apply changes: + - If using launchd: `launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist && launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist` + - If running manually: restart `npm run dev`