update-saasmail
GitHub自动同步本地 saasmail 仓库至上游最新版本,通过 rebase 保留本地提交并优先采用上游代码解决冲突。
Trigger Scenarios
Install
npx skills add choyiny/saasmail --skill update-saasmail -g -y
SKILL.md
Frontmatter
{
"name": "update-saasmail",
"description": "Sync the local saasmail repo with the latest upstream changes from https:\/\/github.com\/choyiny\/saasmail. Use this skill whenever the user wants to update saasmail, pull upstream changes, sync with upstream, rebase on upstream, get the latest saasmail, or says \"\/update-saasmail\". Handles adding the upstream remote if missing, rebases local commits on top of upstream\/main, auto-stashes uncommitted work, and resolves conflicts by preferring upstream."
}
Update saasmail from upstream
Sync the local saasmail fork with the latest changes from choyiny/saasmail while preserving the user's local commits on top.
Why this exists
The user maintains a fork (or local clone) of https://github.com/choyiny/saasmail with their own commits layered on top. They want a one-shot command that:
- Grabs the latest upstream state.
- Replays their local commits on top (so local work stays at HEAD).
- Doesn't get stuck on conflicts they don't care about — when a hunk can't auto-merge, upstream wins.
Regular git pull creates merge commits and doesn't give conflict preference. Regular git rebase halts on conflicts. This skill wraps the right invocation.
Preconditions
Before running anything, confirm:
- Working directory is the saasmail repo (check for
wrangler.jsoncorwrangler.jsonc.exampleandworker/directory). If not, stop and tell the user. - The current branch is the one they want to update. Usually
main. If they're on a feature branch, ask which branch to rebase onto upstream/main before proceeding.
Steps
1. Ensure the upstream remote exists
Run git remote -v and check for an upstream entry pointing at https://github.com/choyiny/saasmail (allow .git suffix and git@github.com:choyiny/saasmail.git SSH form).
- If missing:
git remote add upstream https://github.com/choyiny/saasmail.git - If present but pointing elsewhere: stop and ask the user — don't silently rewrite a remote they configured deliberately.
2. Stash uncommitted changes if any
Run git status --porcelain. If there is any output (tracked modifications or staged changes):
git stash push -u -m "update-saasmail auto-stash"
Remember that you stashed, so you can restore at the end. Untracked-but-ignored files are fine to leave alone (-u covers untracked, not ignored).
3. Fetch upstream
git fetch upstream
4. Rebase onto upstream/main with upstream-wins conflict strategy
git rebase upstream/main -X ours
About the -X ours flag: Inside a rebase, "ours" is the branch being rebased onto (upstream/main) and "theirs" is the commits being replayed (the user's local commits). So -X ours means: when a hunk can't be auto-merged, take upstream's version. Local commits are still replayed — their non-conflicting changes stay. This matches the user's intent: keep local work, but if a conflict is unresolvable, let upstream win.
If the rebase still stops (e.g., a whole file conflict that -X ours can't resolve, like add/add or delete/modify), report the conflicted paths to the user and ask whether to:
- abort (
git rebase --abort) and let them resolve manually, or - accept upstream's version wholesale for those paths (
git checkout --theirs -- <path>is wrong here because we're in a rebase — usegit checkout --ours -- <path>to take the upstream version, thengit addandgit rebase --continue).
Never run git rebase --skip without asking — that silently drops one of the user's commits.
5. Check for new VAPID configuration
Run:
wrangler secret list
grep "VAPID_PUBLIC_KEY" wrangler.jsonc
If VAPID_PRIVATE_KEY is missing from wrangler secret list or VAPID_PUBLIC_KEY is missing from wrangler.jsonc, prompt the user:
This update adds browser push notifications. Generate VAPID keys now? (If skipped, push remains disabled until you run
yarn vapid:generate.)
If yes, run the same flow as the onboarding step:
yarn vapid:generate— copy the printedVAPID_PUBLIC_KEYandVAPID_PRIVATE_KEY.wrangler secret put VAPID_PRIVATE_KEY— paste the private key when prompted.- Edit
wrangler.jsoncto add undervars:"VAPID_PUBLIC_KEY": "<paste VAPID_PUBLIC_KEY here>", "VAPID_SUBJECT": "mailto:admin@<host-of-BASE_URL>"
If no, proceed without blocking.
5a. Apply database migrations
Run:
yarn db:migrate:prod
This ensures any new migrations (including the push-subscriptions table) are applied to the remote D1 database. If the command reports nothing to migrate, that's fine — continue.
6. Restore stashed changes
If you stashed in step 2:
git stash pop
If stash pop itself conflicts, leave the stash entry in place and tell the user — don't drop their uncommitted work.
7. Report what happened
Give the user a concise summary:
- Whether
upstreamwas newly added or already configured. - How many commits were pulled from upstream (
git rev-list --count HEAD@{1}..HEADafter the rebase, or count from the fetch output). - Whether any conflicts were auto-resolved in favor of upstream (check rebase output for
CONFLICTlines that were resolved by the strategy). - Whether stashed changes were restored cleanly.
Non-goals
- Do NOT push to
originafterward. The user pushes when they're ready. - Do NOT touch branches other than the current one.
- Do NOT rewrite the
upstreamremote if it already points somewhere unexpected — ask first.
Version History
- 5c23b27 Current 2026-07-24 21:10


