@wipcomputer/wip-ai-devops-toolbox 1.9.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.license-guard.json +7 -0
- package/.publish-skill.json +4 -0
- package/CHANGELOG.md +1120 -0
- package/CLA.md +19 -0
- package/DEV-GUIDE-GENERAL-PUBLIC.md +882 -0
- package/LICENSE +52 -0
- package/README.md +238 -0
- package/SKILL.md +728 -0
- package/TECHNICAL.md +282 -0
- package/UNIVERSAL-INTERFACE.md +180 -0
- package/_trash/RELEASE-NOTES-v1-8-0.md +29 -0
- package/_trash/RELEASE-NOTES-v1-8-1.md +7 -0
- package/_trash/RELEASE-NOTES-v1-8-2.md +7 -0
- package/_trash/RELEASE-NOTES-v1-9-0.md +37 -0
- package/_trash/RELEASE-NOTES-v1-9-1.md +38 -0
- package/_trash/RELEASE-NOTES-v1-9-10.md +40 -0
- package/_trash/RELEASE-NOTES-v1-9-2.md +40 -0
- package/_trash/RELEASE-NOTES-v1-9-6.md +72 -0
- package/_trash/RELEASE-NOTES-v1-9-7.md +23 -0
- package/_trash/RELEASE-NOTES-v1-9-9.md +75 -0
- package/_trash/guide 2/DEV-GUIDE.md +487 -0
- package/_trash/guide 2/scripts/deploy-public.sh +152 -0
- package/package.json +27 -0
- package/scripts/SKILL-deploy-public.md +61 -0
- package/scripts/SKILL-post-merge-rename.md +47 -0
- package/scripts/deploy-public.sh +264 -0
- package/scripts/post-merge-rename.sh +205 -0
- package/scripts/publish-skill.sh +134 -0
- package/tools/deploy-public/LICENSE +52 -0
- package/tools/deploy-public/README.md +31 -0
- package/tools/deploy-public/SKILL.md +71 -0
- package/tools/deploy-public/deploy-public.sh +264 -0
- package/tools/deploy-public/package.json +9 -0
- package/tools/ldm-jobs/LICENSE +52 -0
- package/tools/ldm-jobs/README.md +46 -0
- package/tools/ldm-jobs/backup.sh +16 -0
- package/tools/ldm-jobs/branch-protect.sh +39 -0
- package/tools/ldm-jobs/crystal-capture.sh +19 -0
- package/tools/ldm-jobs/setup-shell.sh +27 -0
- package/tools/ldm-jobs/visibility-audit.sh +27 -0
- package/tools/post-merge-rename/LICENSE +52 -0
- package/tools/post-merge-rename/README.md +29 -0
- package/tools/post-merge-rename/SKILL.md +57 -0
- package/tools/post-merge-rename/package.json +9 -0
- package/tools/post-merge-rename/post-merge-rename.sh +122 -0
- package/tools/wip-branch-guard/INSTALL.md +41 -0
- package/tools/wip-branch-guard/guard.mjs +259 -0
- package/tools/wip-branch-guard/package.json +11 -0
- package/tools/wip-file-guard/CHANGELOG.md +6 -0
- package/tools/wip-file-guard/LICENSE +52 -0
- package/tools/wip-file-guard/README.md +113 -0
- package/tools/wip-file-guard/REFERENCE.md +86 -0
- package/tools/wip-file-guard/SKILL.md +105 -0
- package/tools/wip-file-guard/guard.mjs +128 -0
- package/tools/wip-file-guard/openclaw.plugin.json +8 -0
- package/tools/wip-file-guard/package.json +27 -0
- package/tools/wip-file-guard/test.sh +119 -0
- package/tools/wip-license-guard/LICENSE +52 -0
- package/tools/wip-license-guard/README.md +32 -0
- package/tools/wip-license-guard/SKILL.md +65 -0
- package/tools/wip-license-guard/cli.mjs +464 -0
- package/tools/wip-license-guard/core.mjs +310 -0
- package/tools/wip-license-guard/hook.mjs +146 -0
- package/tools/wip-license-guard/package.json +15 -0
- package/tools/wip-license-hook/CHANGELOG.md +17 -0
- package/tools/wip-license-hook/LICENSE +52 -0
- package/tools/wip-license-hook/README.md +200 -0
- package/tools/wip-license-hook/SKILL.md +111 -0
- package/tools/wip-license-hook/dist/cli/index.d.ts +15 -0
- package/tools/wip-license-hook/dist/cli/index.js +170 -0
- package/tools/wip-license-hook/dist/cli/index.js.map +1 -0
- package/tools/wip-license-hook/dist/core/detector.d.ts +12 -0
- package/tools/wip-license-hook/dist/core/detector.js +104 -0
- package/tools/wip-license-hook/dist/core/detector.js.map +1 -0
- package/tools/wip-license-hook/dist/core/index.d.ts +4 -0
- package/tools/wip-license-hook/dist/core/index.js +5 -0
- package/tools/wip-license-hook/dist/core/index.js.map +1 -0
- package/tools/wip-license-hook/dist/core/ledger.d.ts +49 -0
- package/tools/wip-license-hook/dist/core/ledger.js +72 -0
- package/tools/wip-license-hook/dist/core/ledger.js.map +1 -0
- package/tools/wip-license-hook/dist/core/reporter.d.ts +14 -0
- package/tools/wip-license-hook/dist/core/reporter.js +227 -0
- package/tools/wip-license-hook/dist/core/reporter.js.map +1 -0
- package/tools/wip-license-hook/dist/core/scanner.d.ts +39 -0
- package/tools/wip-license-hook/dist/core/scanner.js +325 -0
- package/tools/wip-license-hook/dist/core/scanner.js.map +1 -0
- package/tools/wip-license-hook/hooks/pre-pull.sh +55 -0
- package/tools/wip-license-hook/hooks/pre-push.sh +51 -0
- package/tools/wip-license-hook/mcp-server.mjs +119 -0
- package/tools/wip-license-hook/package-lock.json +54 -0
- package/tools/wip-license-hook/package.json +43 -0
- package/tools/wip-license-hook/src/cli/index.ts +189 -0
- package/tools/wip-license-hook/src/core/detector.ts +130 -0
- package/tools/wip-license-hook/src/core/index.ts +4 -0
- package/tools/wip-license-hook/src/core/ledger.ts +116 -0
- package/tools/wip-license-hook/src/core/reporter.ts +255 -0
- package/tools/wip-license-hook/src/core/scanner.ts +367 -0
- package/tools/wip-license-hook/tsconfig.json +16 -0
- package/tools/wip-readme-format/README.md +49 -0
- package/tools/wip-readme-format/SKILL.md +84 -0
- package/tools/wip-readme-format/format.mjs +570 -0
- package/tools/wip-readme-format/package.json +15 -0
- package/tools/wip-release/CHANGELOG.md +42 -0
- package/tools/wip-release/LICENSE +52 -0
- package/tools/wip-release/README.md +45 -0
- package/tools/wip-release/REFERENCE.md +100 -0
- package/tools/wip-release/SKILL.md +139 -0
- package/tools/wip-release/cli.js +161 -0
- package/tools/wip-release/core.mjs +1174 -0
- package/tools/wip-release/mcp-server.mjs +109 -0
- package/tools/wip-release/package.json +36 -0
- package/tools/wip-repo-init/README.md +38 -0
- package/tools/wip-repo-init/SKILL.md +77 -0
- package/tools/wip-repo-init/init.mjs +142 -0
- package/tools/wip-repo-init/package.json +11 -0
- package/tools/wip-repo-permissions-hook/LICENSE +52 -0
- package/tools/wip-repo-permissions-hook/README.md +86 -0
- package/tools/wip-repo-permissions-hook/SKILL.md +73 -0
- package/tools/wip-repo-permissions-hook/cli.js +83 -0
- package/tools/wip-repo-permissions-hook/core.mjs +122 -0
- package/tools/wip-repo-permissions-hook/guard.mjs +64 -0
- package/tools/wip-repo-permissions-hook/mcp-server.mjs +92 -0
- package/tools/wip-repo-permissions-hook/openclaw.plugin.json +8 -0
- package/tools/wip-repo-permissions-hook/package.json +31 -0
- package/tools/wip-repos/LICENSE +52 -0
- package/tools/wip-repos/README.md +77 -0
- package/tools/wip-repos/SKILL.md +80 -0
- package/tools/wip-repos/cli.mjs +176 -0
- package/tools/wip-repos/core.mjs +290 -0
- package/tools/wip-repos/mcp-server.mjs +157 -0
- package/tools/wip-repos/package.json +34 -0
- package/tools/wip-universal-installer/CHANGELOG.md +57 -0
- package/tools/wip-universal-installer/LICENSE +52 -0
- package/tools/wip-universal-installer/README.md +81 -0
- package/tools/wip-universal-installer/REFERENCE.md +122 -0
- package/tools/wip-universal-installer/SKILL.md +87 -0
- package/tools/wip-universal-installer/SPEC.md +180 -0
- package/tools/wip-universal-installer/detect.mjs +130 -0
- package/tools/wip-universal-installer/examples/minimal/README.md +20 -0
- package/tools/wip-universal-installer/examples/minimal/SKILL.md +28 -0
- package/tools/wip-universal-installer/examples/minimal/cli.mjs +4 -0
- package/tools/wip-universal-installer/examples/minimal/core.mjs +8 -0
- package/tools/wip-universal-installer/examples/minimal/mcp-server.mjs +27 -0
- package/tools/wip-universal-installer/examples/minimal/package.json +12 -0
- package/tools/wip-universal-installer/install.js +930 -0
- package/tools/wip-universal-installer/package.json +36 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# deploy-public.sh ... sync a private repo to its public counterpart
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# bash deploy-public.sh <private-repo-path> <public-github-repo>
|
|
7
|
+
#
|
|
8
|
+
# Example:
|
|
9
|
+
# bash deploy-public.sh /path/to/memory-crystal wipcomputer/memory-crystal
|
|
10
|
+
#
|
|
11
|
+
# Convention:
|
|
12
|
+
# - Private repo: {name}-private (where all work happens)
|
|
13
|
+
# - Public repo: {name} (deployment target, never work here directly)
|
|
14
|
+
# - ai/ folder is excluded from public deploys
|
|
15
|
+
# - Old ai/ in public git history is fine, just not going forward
|
|
16
|
+
#
|
|
17
|
+
# Location: wip-dev-guide-private/scripts/deploy-public.sh (one script for all repos)
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
PRIVATE_REPO="$1"
|
|
22
|
+
PUBLIC_REPO="$2"
|
|
23
|
+
|
|
24
|
+
if [[ -z "$PRIVATE_REPO" || -z "$PUBLIC_REPO" ]]; then
|
|
25
|
+
echo "Usage: bash deploy-public.sh <private-repo-path> <public-github-repo>"
|
|
26
|
+
echo "Example: bash deploy-public.sh /path/to/memory-crystal wipcomputer/memory-crystal"
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
if [[ ! -d "$PRIVATE_REPO/.git" ]]; then
|
|
31
|
+
echo "Error: $PRIVATE_REPO is not a git repository"
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# ── Safety: never deploy back to the source repo ──
|
|
36
|
+
# Extract the private repo's GitHub org/name from its remote URL
|
|
37
|
+
PRIVATE_REMOTE=$(cd "$PRIVATE_REPO" && git remote get-url origin 2>/dev/null | sed 's/.*github.com[:/]\(.*\)\.git/\1/' || echo "")
|
|
38
|
+
|
|
39
|
+
if [[ -n "$PRIVATE_REMOTE" && "$PRIVATE_REMOTE" == "$PUBLIC_REPO" ]]; then
|
|
40
|
+
echo "ERROR: PUBLIC_REPO ($PUBLIC_REPO) is the same as the private repo's origin ($PRIVATE_REMOTE)."
|
|
41
|
+
echo "This would deploy sanitized code (no ai/) back to the source repo and destroy files."
|
|
42
|
+
echo "Did you mean to target the public counterpart instead?"
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
if [[ "$PUBLIC_REPO" == *"-private"* ]]; then
|
|
47
|
+
echo "ERROR: PUBLIC_REPO ($PUBLIC_REPO) contains '-private'."
|
|
48
|
+
echo "deploy-public.sh should only target public repos. Private repos have ai/ folders that would be destroyed."
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Get the latest commit message from private repo
|
|
53
|
+
COMMIT_MSG=$(cd "$PRIVATE_REPO" && git log -1 --pretty=format:"%s")
|
|
54
|
+
COMMIT_HASH=$(cd "$PRIVATE_REPO" && git log -1 --pretty=format:"%h")
|
|
55
|
+
|
|
56
|
+
TMPDIR=$(mktemp -d)
|
|
57
|
+
trap 'rm -rf "$TMPDIR"' EXIT
|
|
58
|
+
|
|
59
|
+
# ── Auto-create public repo if it doesn't exist ──
|
|
60
|
+
REPO_EXISTS=$(gh repo view "$PUBLIC_REPO" --json name -q '.name' 2>/dev/null || echo "")
|
|
61
|
+
if [[ -z "$REPO_EXISTS" ]]; then
|
|
62
|
+
echo "Public repo $PUBLIC_REPO does not exist. Creating..."
|
|
63
|
+
DESCRIPTION=$(cd "$PRIVATE_REPO" && node -p "require('./package.json').description" 2>/dev/null || echo "")
|
|
64
|
+
gh repo create "$PUBLIC_REPO" --public --description "${DESCRIPTION:-Synced from private repo}" 2>/dev/null
|
|
65
|
+
echo " + Created $PUBLIC_REPO"
|
|
66
|
+
EMPTY_REPO=true
|
|
67
|
+
else
|
|
68
|
+
EMPTY_REPO=false
|
|
69
|
+
# Verify the resolved repo is actually the one we asked for (catch GitHub redirects)
|
|
70
|
+
RESOLVED_NAME=$(gh repo view "$PUBLIC_REPO" --json nameWithOwner -q '.nameWithOwner' 2>/dev/null || echo "")
|
|
71
|
+
if [[ -n "$RESOLVED_NAME" && "$RESOLVED_NAME" != "$PUBLIC_REPO" ]]; then
|
|
72
|
+
echo "ERROR: GitHub redirected $PUBLIC_REPO to $RESOLVED_NAME."
|
|
73
|
+
echo "The public repo doesn't actually exist. A repo with a similar name is redirecting."
|
|
74
|
+
echo "Create the public repo first: gh repo create $PUBLIC_REPO --public"
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
echo "Cloning public repo $PUBLIC_REPO..."
|
|
80
|
+
gh repo clone "$PUBLIC_REPO" "$TMPDIR/public" -- --depth 1 2>/dev/null || {
|
|
81
|
+
echo "Public repo is empty. Initializing..."
|
|
82
|
+
mkdir -p "$TMPDIR/public"
|
|
83
|
+
cd "$TMPDIR/public"
|
|
84
|
+
git init
|
|
85
|
+
git remote add origin "git@github.com:${PUBLIC_REPO}.git"
|
|
86
|
+
cd - > /dev/null
|
|
87
|
+
EMPTY_REPO=true
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
echo "Syncing files from private repo (excluding ai/, .git/)..."
|
|
91
|
+
|
|
92
|
+
# Remove all tracked files in public (except .git) so deleted files get removed
|
|
93
|
+
find "$TMPDIR/public" -mindepth 1 -maxdepth 1 ! -name .git -exec rm -rf {} +
|
|
94
|
+
|
|
95
|
+
# rsync from private, excluding ai/ and .git/
|
|
96
|
+
rsync -a \
|
|
97
|
+
--exclude='ai/' \
|
|
98
|
+
--exclude='_trash/' \
|
|
99
|
+
--exclude='.git/' \
|
|
100
|
+
--exclude='.DS_Store' \
|
|
101
|
+
--exclude='.wrangler/' \
|
|
102
|
+
--exclude='.claude/' \
|
|
103
|
+
--exclude='CLAUDE.md' \
|
|
104
|
+
"$PRIVATE_REPO/" "$TMPDIR/public/"
|
|
105
|
+
|
|
106
|
+
cd "$TMPDIR/public"
|
|
107
|
+
|
|
108
|
+
# Check if there are changes
|
|
109
|
+
if git diff --quiet HEAD -- 2>/dev/null && git diff --cached --quiet HEAD -- 2>/dev/null && [[ -z "$(git ls-files --others --exclude-standard)" ]]; then
|
|
110
|
+
echo "No changes to deploy."
|
|
111
|
+
exit 0
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# Harness ID for branch prefix. Set HARNESS_ID env var, or auto-detect from private repo path.
|
|
115
|
+
if [[ -z "${HARNESS_ID:-}" ]]; then
|
|
116
|
+
case "$PRIVATE_REPO" in
|
|
117
|
+
*"Claude Code - Mini"*) HARNESS_ID="cc-mini" ;;
|
|
118
|
+
*"Claude Code - MBA"*) HARNESS_ID="cc-air" ;;
|
|
119
|
+
*"Lēsa"*) HARNESS_ID="oc-lesa-mini" ;;
|
|
120
|
+
*) HARNESS_ID="deploy" ;;
|
|
121
|
+
esac
|
|
122
|
+
fi
|
|
123
|
+
BRANCH="$HARNESS_ID/deploy-$(date +%Y%m%d-%H%M%S)"
|
|
124
|
+
|
|
125
|
+
git add -A
|
|
126
|
+
git commit -m "$COMMIT_MSG (from $COMMIT_HASH)"
|
|
127
|
+
|
|
128
|
+
if [[ "$EMPTY_REPO" == "true" ]]; then
|
|
129
|
+
# Empty repo: push directly to main (no base branch to PR against)
|
|
130
|
+
echo "Pushing initial commit to main on $PUBLIC_REPO..."
|
|
131
|
+
git branch -M main
|
|
132
|
+
git push -u origin main
|
|
133
|
+
gh repo edit "$PUBLIC_REPO" --default-branch main 2>/dev/null || true
|
|
134
|
+
PR_URL="(initial push, no PR)"
|
|
135
|
+
echo " + Initial commit pushed to main"
|
|
136
|
+
else
|
|
137
|
+
git checkout -b "$BRANCH"
|
|
138
|
+
|
|
139
|
+
echo "Pushing branch $BRANCH to $PUBLIC_REPO..."
|
|
140
|
+
git push -u origin "$BRANCH"
|
|
141
|
+
|
|
142
|
+
echo "Creating PR..."
|
|
143
|
+
PR_URL=$(gh pr create -R "$PUBLIC_REPO" \
|
|
144
|
+
--head "$BRANCH" \
|
|
145
|
+
--title "$COMMIT_MSG" \
|
|
146
|
+
--body "Synced from private repo (commit $COMMIT_HASH).")
|
|
147
|
+
|
|
148
|
+
echo "Merging PR..."
|
|
149
|
+
PR_NUMBER=$(echo "$PR_URL" | grep -o '[0-9]*$')
|
|
150
|
+
gh pr merge "$PR_NUMBER" -R "$PUBLIC_REPO" --merge --delete-branch
|
|
151
|
+
|
|
152
|
+
# Clean up any other non-main branches on public repo
|
|
153
|
+
echo "Checking for stale branches on public repo..."
|
|
154
|
+
STALE_BRANCHES=$(gh api "repos/$PUBLIC_REPO/branches" --paginate --jq '.[].name' 2>/dev/null | grep -v '^main$' || true)
|
|
155
|
+
if [[ -n "$STALE_BRANCHES" ]]; then
|
|
156
|
+
STALE_COUNT=$(echo "$STALE_BRANCHES" | wc -l | tr -d ' ')
|
|
157
|
+
echo " Found $STALE_COUNT stale branch(es). Deleting..."
|
|
158
|
+
echo "$STALE_BRANCHES" | while read -r stale; do
|
|
159
|
+
gh api -X DELETE "repos/$PUBLIC_REPO/git/refs/heads/$stale" 2>/dev/null && echo " ✓ Deleted $stale" || echo " ! Could not delete $stale"
|
|
160
|
+
done
|
|
161
|
+
else
|
|
162
|
+
echo " ✓ No stale branches"
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
echo "Code synced via PR: $PR_URL"
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
# ── Sync release to public repo ──
|
|
169
|
+
# If the private repo has a version tag, create a matching release on the public repo.
|
|
170
|
+
# Pulls full release notes from the private repo and rewrites any private repo references.
|
|
171
|
+
|
|
172
|
+
# Try package.json first, fall back to latest git tag
|
|
173
|
+
VERSION=$(cd "$PRIVATE_REPO" && node -p "require('./package.json').version" 2>/dev/null || echo "")
|
|
174
|
+
if [[ -z "$VERSION" ]]; then
|
|
175
|
+
# No package.json. Use the latest version tag (v*) in the repo
|
|
176
|
+
TAG=$(cd "$PRIVATE_REPO" && git tag -l 'v*' --sort=-version:refname 2>/dev/null | head -1 || echo "")
|
|
177
|
+
if [[ -n "$TAG" ]]; then
|
|
178
|
+
VERSION="${TAG#v}"
|
|
179
|
+
fi
|
|
180
|
+
fi
|
|
181
|
+
if [[ -n "$VERSION" ]]; then
|
|
182
|
+
TAG="v$VERSION"
|
|
183
|
+
EXISTING=$(gh release view "$TAG" -R "$PUBLIC_REPO" --json tagName 2>/dev/null || echo "")
|
|
184
|
+
if [[ -z "$EXISTING" ]]; then
|
|
185
|
+
# Get the private repo's GitHub path (e.g., wipcomputer/memory-crystal-private)
|
|
186
|
+
PRIVATE_GH=$(cd "$PRIVATE_REPO" && git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/')
|
|
187
|
+
|
|
188
|
+
# Pull full release notes from private repo
|
|
189
|
+
NOTES=$(gh release view "$TAG" -R "$PRIVATE_GH" --json body -q '.body' 2>/dev/null || echo "")
|
|
190
|
+
|
|
191
|
+
if [[ -z "$NOTES" || "$NOTES" == "null" ]]; then
|
|
192
|
+
NOTES="Release $TAG"
|
|
193
|
+
else
|
|
194
|
+
# Rewrite private repo references to public repo
|
|
195
|
+
NOTES=$(echo "$NOTES" | sed "s|$PRIVATE_GH|$PUBLIC_REPO|g")
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
echo "Creating release $TAG on $PUBLIC_REPO..."
|
|
199
|
+
gh release create "$TAG" -R "$PUBLIC_REPO" --title "$TAG" --notes "$NOTES" 2>/dev/null && echo " ✓ Release $TAG created on $PUBLIC_REPO" || echo " ✗ Release creation failed (non-fatal)"
|
|
200
|
+
else
|
|
201
|
+
# Update existing release notes (in case they were incomplete)
|
|
202
|
+
PRIVATE_GH=$(cd "$PRIVATE_REPO" && git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/')
|
|
203
|
+
NOTES=$(gh release view "$TAG" -R "$PRIVATE_GH" --json body -q '.body' 2>/dev/null || echo "")
|
|
204
|
+
if [[ -n "$NOTES" && "$NOTES" != "null" ]]; then
|
|
205
|
+
NOTES=$(echo "$NOTES" | sed "s|$PRIVATE_GH|$PUBLIC_REPO|g")
|
|
206
|
+
gh release edit "$TAG" -R "$PUBLIC_REPO" --notes "$NOTES" 2>/dev/null && echo " ✓ Release $TAG notes updated on $PUBLIC_REPO" || true
|
|
207
|
+
fi
|
|
208
|
+
echo " Release $TAG exists on $PUBLIC_REPO (notes synced)"
|
|
209
|
+
fi
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
# ── npm publish from public repo (#100) ──
|
|
213
|
+
# After syncing code and release, publish to npm from the public clone.
|
|
214
|
+
# Only if package.json exists and private !== true.
|
|
215
|
+
|
|
216
|
+
if [[ -n "${VERSION:-}" ]]; then
|
|
217
|
+
# Re-clone public for npm publish (the previous tmpdir might be gone)
|
|
218
|
+
NPM_TMPDIR=$(mktemp -d)
|
|
219
|
+
gh repo clone "$PUBLIC_REPO" "$NPM_TMPDIR/public" -- --depth 1 2>/dev/null
|
|
220
|
+
|
|
221
|
+
if [[ -f "$NPM_TMPDIR/public/package.json" ]]; then
|
|
222
|
+
IS_PRIVATE=$(cd "$NPM_TMPDIR/public" && node -p "require('./package.json').private || false" 2>/dev/null)
|
|
223
|
+
echo "Publishing to npm from public repo..."
|
|
224
|
+
NPM_TOKEN=$(OP_SERVICE_ACCOUNT_TOKEN=$(cat ~/.openclaw/secrets/op-sa-token) \
|
|
225
|
+
op item get "npm Token" --vault "Agent Secrets" --fields label=password --reveal 2>/dev/null || echo "")
|
|
226
|
+
if [[ -n "$NPM_TOKEN" ]]; then
|
|
227
|
+
cd "$NPM_TMPDIR/public"
|
|
228
|
+
|
|
229
|
+
# Publish root package (if not private)
|
|
230
|
+
if [[ "$IS_PRIVATE" != "true" ]]; then
|
|
231
|
+
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc
|
|
232
|
+
npm publish --access public 2>/dev/null && echo " ✓ Published root package to npm" || echo " ✗ Root npm publish failed (non-fatal)"
|
|
233
|
+
rm -f .npmrc
|
|
234
|
+
else
|
|
235
|
+
echo " - Root package is private. Skipping root npm publish."
|
|
236
|
+
fi
|
|
237
|
+
|
|
238
|
+
# For toolbox repos: publish each sub-tool regardless of root private status
|
|
239
|
+
if [[ -d "tools" ]]; then
|
|
240
|
+
for TOOL_DIR in tools/*/; do
|
|
241
|
+
if [[ -f "${TOOL_DIR}package.json" ]]; then
|
|
242
|
+
TOOL_PRIVATE=$(node -p "require('./${TOOL_DIR}package.json').private || false" 2>/dev/null)
|
|
243
|
+
if [[ "$TOOL_PRIVATE" != "true" ]]; then
|
|
244
|
+
TOOL_NAME=$(node -p "require('./${TOOL_DIR}package.json').name" 2>/dev/null)
|
|
245
|
+
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > "${TOOL_DIR}.npmrc"
|
|
246
|
+
(cd "$TOOL_DIR" && npm publish --access public 2>/dev/null) && echo " ✓ Published $TOOL_NAME to npm" || echo " ✗ npm publish failed for $TOOL_NAME (non-fatal)"
|
|
247
|
+
rm -f "${TOOL_DIR}.npmrc"
|
|
248
|
+
fi
|
|
249
|
+
fi
|
|
250
|
+
done
|
|
251
|
+
fi
|
|
252
|
+
|
|
253
|
+
cd - > /dev/null
|
|
254
|
+
else
|
|
255
|
+
echo " ! npm Token not found in 1Password. Skipping npm publish."
|
|
256
|
+
fi
|
|
257
|
+
fi
|
|
258
|
+
rm -rf "$NPM_TMPDIR"
|
|
259
|
+
fi
|
|
260
|
+
|
|
261
|
+
echo "Done. Public repo updated."
|
|
262
|
+
echo " PR: $PR_URL"
|
|
263
|
+
echo " Commit: $COMMIT_MSG (from $COMMIT_HASH)"
|
|
264
|
+
[[ -n "${VERSION:-}" ]] && echo " Release: v$VERSION"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Dual License: MIT + AGPLv3
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 WIP Computer, Inc.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
1. MIT License (local and personal use)
|
|
7
|
+
---------------------------------------
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
2. GNU Affero General Public License v3.0 (commercial and cloud use)
|
|
29
|
+
--------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
If you run this software as part of a hosted service, cloud platform,
|
|
32
|
+
marketplace listing, or any network-accessible offering for commercial
|
|
33
|
+
purposes, the AGPLv3 terms apply. You must either:
|
|
34
|
+
|
|
35
|
+
a) Release your complete source code under AGPLv3, or
|
|
36
|
+
b) Obtain a commercial license.
|
|
37
|
+
|
|
38
|
+
This program is free software: you can redistribute it and/or modify
|
|
39
|
+
it under the terms of the GNU Affero General Public License as published
|
|
40
|
+
by the Free Software Foundation, either version 3 of the License, or
|
|
41
|
+
(at your option) any later version.
|
|
42
|
+
|
|
43
|
+
This program is distributed in the hope that it will be useful,
|
|
44
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
45
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
46
|
+
GNU Affero General Public License for more details.
|
|
47
|
+
|
|
48
|
+
You should have received a copy of the GNU Affero General Public License
|
|
49
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
AGPLv3 for personal use is free. Commercial licenses available.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# LDM Dev Tools Jobs
|
|
2
|
+
|
|
3
|
+
Shell scripts that power the LDM Dev Tools.app scheduled automation. These are the same scripts bundled inside the `.app` at `Contents/Resources/jobs/`. Committed here so the logic is fully readable and auditable without installing the app.
|
|
4
|
+
|
|
5
|
+
## Jobs
|
|
6
|
+
|
|
7
|
+
### backup.sh
|
|
8
|
+
|
|
9
|
+
Daily backup. Delegates to Lesa's backup script.
|
|
10
|
+
|
|
11
|
+
### branch-protect.sh
|
|
12
|
+
|
|
13
|
+
Audits all repos in the `wipcomputer` GitHub org. Enforces branch protection on any repo missing it. Reports results.
|
|
14
|
+
|
|
15
|
+
### visibility-audit.sh
|
|
16
|
+
|
|
17
|
+
Audits all public repos in the `wipcomputer` GitHub org for missing `-private` counterparts. Uses `wip-repo-permissions-hook` CLI.
|
|
18
|
+
|
|
19
|
+
### setup-shell.sh
|
|
20
|
+
|
|
21
|
+
One-time shell environment setup for new machines. Configures:
|
|
22
|
+
- **tmux mouse scrolling** ... `set -g mouse on` in `~/.tmux.conf`. Trackpad scrolling works inside tmux sessions.
|
|
23
|
+
|
|
24
|
+
Idempotent. Safe to re-run.
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
These scripts can be run standalone (no `.app` required):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
bash tools/ldm-jobs/backup.sh
|
|
32
|
+
bash tools/ldm-jobs/branch-protect.sh
|
|
33
|
+
bash tools/ldm-jobs/visibility-audit.sh
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or via the macOS app wrapper (which provides Full Disk Access for scripts that need it):
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
open -W ~/Applications/LDMDevTools.app --args backup
|
|
40
|
+
open -W ~/Applications/LDMDevTools.app --args branch-protect
|
|
41
|
+
open -W ~/Applications/LDMDevTools.app --args visibility-audit
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## App Source
|
|
45
|
+
|
|
46
|
+
The LDM Dev Tools.app is a minimal native macOS launcher that runs these shell scripts with Full Disk Access permissions. The app binary source is not yet committed. The automation logic lives entirely in these `.sh` files.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Job: daily backup
|
|
3
|
+
# Calls Lesa's existing backup script
|
|
4
|
+
|
|
5
|
+
SCRIPT="$HOME/Documents/wipcomputer--mac-mini-01/staff/Lēsa/scripts/daily-backup.sh"
|
|
6
|
+
|
|
7
|
+
echo "=== Backup started: $(date) ==="
|
|
8
|
+
|
|
9
|
+
if [ -f "$SCRIPT" ]; then
|
|
10
|
+
/bin/bash "$SCRIPT"
|
|
11
|
+
else
|
|
12
|
+
echo "ERROR: backup script not found at $SCRIPT"
|
|
13
|
+
exit 1
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
echo "=== Backup finished: $(date) ==="
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Job: audit and enforce branch protection across all org repos
|
|
3
|
+
# Runs daily. Adds protection to any repo missing it.
|
|
4
|
+
|
|
5
|
+
echo "=== Branch protection audit: $(date) ==="
|
|
6
|
+
|
|
7
|
+
ORG="wipcomputer"
|
|
8
|
+
FIXED=0
|
|
9
|
+
SKIPPED=0
|
|
10
|
+
ALREADY=0
|
|
11
|
+
|
|
12
|
+
repos=$(gh repo list "$ORG" --limit 200 --json name,isArchived -q '.[] | select(.isArchived == false) | .name')
|
|
13
|
+
|
|
14
|
+
for repo in $repos; do
|
|
15
|
+
result=$(gh api "repos/$ORG/$repo/branches/main/protection" 2>&1)
|
|
16
|
+
|
|
17
|
+
if echo "$result" | grep -q "enforce_admins"; then
|
|
18
|
+
ALREADY=$((ALREADY + 1))
|
|
19
|
+
elif echo "$result" | grep -q "Branch not protected"; then
|
|
20
|
+
echo "FIXING: $repo"
|
|
21
|
+
gh api "repos/$ORG/$repo/branches/main/protection" -X PUT \
|
|
22
|
+
-F "required_pull_request_reviews[required_approving_review_count]=0" \
|
|
23
|
+
-F "enforce_admins=true" \
|
|
24
|
+
-F "restrictions=null" \
|
|
25
|
+
-F "required_status_checks=null" > /dev/null 2>&1
|
|
26
|
+
if [ $? -eq 0 ]; then
|
|
27
|
+
echo " Protected: $repo"
|
|
28
|
+
FIXED=$((FIXED + 1))
|
|
29
|
+
else
|
|
30
|
+
echo " FAILED: $repo"
|
|
31
|
+
fi
|
|
32
|
+
else
|
|
33
|
+
SKIPPED=$((SKIPPED + 1))
|
|
34
|
+
fi
|
|
35
|
+
done
|
|
36
|
+
|
|
37
|
+
echo ""
|
|
38
|
+
echo "Results: $ALREADY already protected, $FIXED fixed, $SKIPPED skipped (no main branch or error)"
|
|
39
|
+
echo "=== Branch protection audit complete: $(date) ==="
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Job: crystal-capture
|
|
3
|
+
#
|
|
4
|
+
# SOURCE OF TRUTH: memory-crystal-private/scripts/crystal-capture.sh
|
|
5
|
+
# This copy is for LDM Dev Tools.app manual runs only.
|
|
6
|
+
# The cron job runs from ~/.ldm/bin/crystal-capture.sh (installed via crystal init).
|
|
7
|
+
# Memory Crystal does not depend on this app.
|
|
8
|
+
#
|
|
9
|
+
# If updating: update the source in memory-crystal-private first, then copy here.
|
|
10
|
+
|
|
11
|
+
POLLER="$HOME/.ldm/extensions/memory-crystal/dist/cc-poller.js"
|
|
12
|
+
NODE="/opt/homebrew/bin/node"
|
|
13
|
+
|
|
14
|
+
if [ ! -f "$POLLER" ]; then
|
|
15
|
+
echo "ERROR: cc-poller not found at $POLLER"
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
$NODE "$POLLER" 2>&1
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# setup-shell.sh ... Configure shell environment for LDM OS development.
|
|
3
|
+
# Run once on a new machine. Idempotent (safe to re-run).
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
echo "LDM OS shell setup"
|
|
8
|
+
echo ""
|
|
9
|
+
|
|
10
|
+
# ── tmux: enable mouse scrolling ──
|
|
11
|
+
|
|
12
|
+
TMUX_CONF="$HOME/.tmux.conf"
|
|
13
|
+
|
|
14
|
+
if [ -f "$TMUX_CONF" ] && grep -q "set -g mouse on" "$TMUX_CONF"; then
|
|
15
|
+
echo "[OK] tmux mouse scrolling already configured"
|
|
16
|
+
else
|
|
17
|
+
echo "set -g mouse on" >> "$TMUX_CONF"
|
|
18
|
+
echo "[OK] tmux mouse scrolling enabled ($TMUX_CONF)"
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# Reload if tmux is running
|
|
22
|
+
if command -v tmux &>/dev/null && tmux list-sessions &>/dev/null 2>&1; then
|
|
23
|
+
tmux source-file "$TMUX_CONF" 2>/dev/null && echo "[OK] tmux config reloaded" || true
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
echo ""
|
|
27
|
+
echo "Done. Shell environment configured."
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# visibility-audit.sh ... audit all public repos for missing -private counterparts
|
|
3
|
+
# Runs via LDMDevTools.app cron job
|
|
4
|
+
# Same pattern as branch-protect.sh
|
|
5
|
+
|
|
6
|
+
echo "=== Visibility audit: $(date) ==="
|
|
7
|
+
|
|
8
|
+
ORG="wipcomputer"
|
|
9
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
10
|
+
HOOK_DIR="$SCRIPT_DIR/../wip-repo-permissions-hook"
|
|
11
|
+
|
|
12
|
+
if [[ ! -f "$HOOK_DIR/cli.js" ]]; then
|
|
13
|
+
echo "Error: wip-repo-permissions-hook not found at $HOOK_DIR"
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
node "$HOOK_DIR/cli.js" audit "$ORG"
|
|
18
|
+
EXIT_CODE=$?
|
|
19
|
+
|
|
20
|
+
if [[ $EXIT_CODE -ne 0 ]]; then
|
|
21
|
+
echo ""
|
|
22
|
+
echo "VIOLATIONS FOUND. Some public repos lack -private counterparts."
|
|
23
|
+
echo "Run: node $HOOK_DIR/cli.js audit $ORG"
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
echo "=== Done ==="
|
|
27
|
+
exit $EXIT_CODE
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Dual License: MIT + AGPLv3
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 WIP Computer, Inc.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
1. MIT License (local and personal use)
|
|
7
|
+
---------------------------------------
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
2. GNU Affero General Public License v3.0 (commercial and cloud use)
|
|
29
|
+
--------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
If you run this software as part of a hosted service, cloud platform,
|
|
32
|
+
marketplace listing, or any network-accessible offering for commercial
|
|
33
|
+
purposes, the AGPLv3 terms apply. You must either:
|
|
34
|
+
|
|
35
|
+
a) Release your complete source code under AGPLv3, or
|
|
36
|
+
b) Obtain a commercial license.
|
|
37
|
+
|
|
38
|
+
This program is free software: you can redistribute it and/or modify
|
|
39
|
+
it under the terms of the GNU Affero General Public License as published
|
|
40
|
+
by the Free Software Foundation, either version 3 of the License, or
|
|
41
|
+
(at your option) any later version.
|
|
42
|
+
|
|
43
|
+
This program is distributed in the hope that it will be useful,
|
|
44
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
45
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
46
|
+
GNU Affero General Public License for more details.
|
|
47
|
+
|
|
48
|
+
You should have received a copy of the GNU Affero General Public License
|
|
49
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
AGPLv3 for personal use is free. Commercial licenses available.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
###### WIP Computer
|
|
2
|
+
|
|
3
|
+
# Post-Merge Branch Naming
|
|
4
|
+
|
|
5
|
+
Cleans up after itself. Merged branches get renamed with dates automatically.
|
|
6
|
+
|
|
7
|
+
## What it does
|
|
8
|
+
|
|
9
|
+
- Scans for merged branches that haven't been renamed
|
|
10
|
+
- Appends `--merged-YYYY-MM-DD` to preserve history
|
|
11
|
+
- We never delete branches. We rename them.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bash post-merge-rename.sh
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- git
|
|
22
|
+
- bash
|
|
23
|
+
|
|
24
|
+
## Interfaces
|
|
25
|
+
|
|
26
|
+
- **CLI**: Shell script
|
|
27
|
+
- **Skill**: SKILL.md for agent instructions
|
|
28
|
+
|
|
29
|
+
## Part of [AI DevOps Toolbox](https://github.com/wipcomputer/wip-ai-devops-toolbox)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: post-merge-rename
|
|
3
|
+
description: Post-merge branch renaming. Appends --merged-YYYY-MM-DD to preserve history.
|
|
4
|
+
license: MIT
|
|
5
|
+
interface: [cli, skill]
|
|
6
|
+
metadata:
|
|
7
|
+
display-name: "Post-Merge Branch Naming"
|
|
8
|
+
version: "1.3.0"
|
|
9
|
+
homepage: "https://github.com/wipcomputer/wip-ai-devops-toolbox"
|
|
10
|
+
author: "Parker Todd Brooks"
|
|
11
|
+
category: dev-tools
|
|
12
|
+
capabilities:
|
|
13
|
+
- branch-rename
|
|
14
|
+
- history-preservation
|
|
15
|
+
requires:
|
|
16
|
+
bins: [git, bash]
|
|
17
|
+
openclaw:
|
|
18
|
+
requires:
|
|
19
|
+
bins: [git, bash]
|
|
20
|
+
emoji: "🏷️"
|
|
21
|
+
compatibility: Requires git, bash.
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# post-merge-rename
|
|
25
|
+
|
|
26
|
+
Scans for merged branches that haven't been renamed and appends `--merged-YYYY-MM-DD` to preserve history. We never delete branches. We rename them.
|
|
27
|
+
|
|
28
|
+
## When to Use This Skill
|
|
29
|
+
|
|
30
|
+
**Use post-merge-rename for:**
|
|
31
|
+
- After merging PRs, to rename the source branch
|
|
32
|
+
- Cleaning up branches that were merged but not renamed
|
|
33
|
+
- Runs automatically as step 10 of `wip-release`
|
|
34
|
+
|
|
35
|
+
### Do NOT Use For
|
|
36
|
+
|
|
37
|
+
- Unmerged branches
|
|
38
|
+
- Branches you're currently working on
|
|
39
|
+
|
|
40
|
+
## API Reference
|
|
41
|
+
|
|
42
|
+
### CLI
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
bash scripts/post-merge-rename.sh # scan + rename all merged branches
|
|
46
|
+
bash scripts/post-merge-rename.sh --dry-run # preview only
|
|
47
|
+
bash scripts/post-merge-rename.sh <branch> # rename specific branch
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## What It Does
|
|
51
|
+
|
|
52
|
+
1. Lists all local branches merged into main
|
|
53
|
+
2. Skips branches already renamed (containing `--merged-`)
|
|
54
|
+
3. Finds the merge date from git history
|
|
55
|
+
4. Renames: `feature-branch` -> `feature-branch--merged-2026-03-09`
|
|
56
|
+
5. Pushes the renamed branch to origin
|
|
57
|
+
6. Deletes the old branch name from origin
|