@wipcomputer/deploy-public 1.0.0

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 ADDED
@@ -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.
package/SKILL.md ADDED
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: deploy-public
3
+ description: Private-to-public repo sync. Copies everything except ai/ to the public mirror. Creates PR, merges, syncs releases.
4
+ license: MIT
5
+ interface: [cli, skill]
6
+ metadata:
7
+ display-name: "Private-to-Public Sync"
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
+ - repo-sync
14
+ - release-sync
15
+ requires:
16
+ bins: [git, gh, bash]
17
+ openclaw:
18
+ requires:
19
+ bins: [git, gh, bash]
20
+ emoji: "🚢"
21
+ compatibility: Requires git, gh (GitHub CLI), bash.
22
+ ---
23
+
24
+ # deploy-public
25
+
26
+ Private-to-public repo sync. One script for all repos. Copies code, creates a PR on the public repo, merges it, and syncs GitHub releases.
27
+
28
+ ## When to Use This Skill
29
+
30
+ **Use deploy-public for:**
31
+ - Publishing a private repo's code to its public counterpart
32
+ - After running `wip-release` on the private repo (release must exist first)
33
+ - Syncing release notes from private to public
34
+
35
+ **CRITICAL: Release order matters.**
36
+ 1. Merge PR to private repo's main
37
+ 2. Run `wip-release` (creates GitHub release with notes on private repo)
38
+ 3. THEN run `deploy-public.sh` (pulls notes from private release)
39
+
40
+ If you skip step 2, the public release gets empty notes.
41
+
42
+ ### Do NOT Use For
43
+
44
+ - Repos without a `-private` counterpart
45
+ - First-time repo setup (create the public repo on GitHub first)
46
+
47
+ ## API Reference
48
+
49
+ ### CLI
50
+
51
+ ```bash
52
+ bash scripts/deploy-public.sh /path/to/private-repo org/public-repo
53
+ ```
54
+
55
+ ### Examples
56
+
57
+ ```bash
58
+ # Deploy memory-crystal
59
+ bash scripts/deploy-public.sh /path/to/memory-crystal-private wipcomputer/memory-crystal
60
+
61
+ # Deploy wip-dev-tools
62
+ bash scripts/deploy-public.sh /path/to/wip-ai-devops-toolbox-private wipcomputer/wip-ai-devops-toolbox
63
+ ```
64
+
65
+ ## What It Does
66
+
67
+ 1. Clones the public repo to a temp directory
68
+ 2. Copies all files from private repo (excluding `ai/`, `.git/`)
69
+ 3. Creates a branch, commits, pushes, creates PR
70
+ 4. Merges the PR (regular merge, never squash)
71
+ 5. Syncs GitHub releases (pulls notes from private repo's releases)
@@ -0,0 +1,170 @@
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
+ # Get the latest commit message from private repo
36
+ COMMIT_MSG=$(cd "$PRIVATE_REPO" && git log -1 --pretty=format:"%s")
37
+ COMMIT_HASH=$(cd "$PRIVATE_REPO" && git log -1 --pretty=format:"%h")
38
+
39
+ TMPDIR=$(mktemp -d)
40
+ trap 'rm -rf "$TMPDIR"' EXIT
41
+
42
+ echo "Cloning public repo $PUBLIC_REPO..."
43
+ gh repo clone "$PUBLIC_REPO" "$TMPDIR/public" -- --depth 1 2>/dev/null || {
44
+ echo "Public repo is empty or doesn't exist. Initializing..."
45
+ mkdir -p "$TMPDIR/public"
46
+ cd "$TMPDIR/public"
47
+ git init
48
+ git remote add origin "git@github.com:${PUBLIC_REPO}.git"
49
+ cd - > /dev/null
50
+ }
51
+
52
+ echo "Syncing files from private repo (excluding ai/, .git/)..."
53
+
54
+ # Remove all tracked files in public (except .git) so deleted files get removed
55
+ find "$TMPDIR/public" -mindepth 1 -maxdepth 1 ! -name .git -exec rm -rf {} +
56
+
57
+ # rsync from private, excluding ai/ and .git/
58
+ rsync -a \
59
+ --exclude='ai/' \
60
+ --exclude='_trash/' \
61
+ --exclude='.git/' \
62
+ --exclude='.DS_Store' \
63
+ --exclude='.wrangler/' \
64
+ --exclude='.claude/' \
65
+ --exclude='CLAUDE.md' \
66
+ "$PRIVATE_REPO/" "$TMPDIR/public/"
67
+
68
+ cd "$TMPDIR/public"
69
+
70
+ # Check if there are changes
71
+ if git diff --quiet HEAD -- 2>/dev/null && git diff --cached --quiet HEAD -- 2>/dev/null && [[ -z "$(git ls-files --others --exclude-standard)" ]]; then
72
+ echo "No changes to deploy."
73
+ exit 0
74
+ fi
75
+
76
+ # Harness ID for branch prefix. Set HARNESS_ID env var, or auto-detect from private repo path.
77
+ if [[ -z "${HARNESS_ID:-}" ]]; then
78
+ case "$PRIVATE_REPO" in
79
+ *"Claude Code - Mini"*) HARNESS_ID="cc-mini" ;;
80
+ *"Claude Code - MBA"*) HARNESS_ID="cc-air" ;;
81
+ *"Lēsa"*) HARNESS_ID="oc-lesa-mini" ;;
82
+ *) HARNESS_ID="deploy" ;;
83
+ esac
84
+ fi
85
+ BRANCH="$HARNESS_ID/deploy-$(date +%Y%m%d-%H%M%S)"
86
+
87
+ git checkout -b "$BRANCH"
88
+ git add -A
89
+ git commit -m "$COMMIT_MSG (from $COMMIT_HASH)"
90
+
91
+ echo "Pushing branch $BRANCH to $PUBLIC_REPO..."
92
+ git push -u origin "$BRANCH"
93
+
94
+ echo "Creating PR..."
95
+ PR_URL=$(gh pr create -R "$PUBLIC_REPO" \
96
+ --head "$BRANCH" \
97
+ --title "$COMMIT_MSG" \
98
+ --body "Synced from private repo (commit $COMMIT_HASH).")
99
+
100
+ echo "Merging PR..."
101
+ PR_NUMBER=$(echo "$PR_URL" | grep -o '[0-9]*$')
102
+ gh pr merge "$PR_NUMBER" -R "$PUBLIC_REPO" --merge
103
+
104
+ # Delete the deploy branch (merged, no longer needed)
105
+ echo "Cleaning up deploy branch..."
106
+ gh api -X DELETE "repos/$PUBLIC_REPO/git/refs/heads/$BRANCH" 2>/dev/null && echo " ✓ Deleted branch $BRANCH" || echo " ! Could not delete branch (non-fatal)"
107
+
108
+ # Clean up any other non-main branches on public repo
109
+ echo "Checking for stale branches on public repo..."
110
+ STALE_BRANCHES=$(gh api "repos/$PUBLIC_REPO/branches" --paginate --jq '.[].name' 2>/dev/null | grep -v '^main$' || true)
111
+ if [[ -n "$STALE_BRANCHES" ]]; then
112
+ STALE_COUNT=$(echo "$STALE_BRANCHES" | wc -l | tr -d ' ')
113
+ echo " Found $STALE_COUNT stale branch(es). Deleting..."
114
+ echo "$STALE_BRANCHES" | while read -r stale; do
115
+ gh api -X DELETE "repos/$PUBLIC_REPO/git/refs/heads/$stale" 2>/dev/null && echo " ✓ Deleted $stale" || echo " ! Could not delete $stale"
116
+ done
117
+ else
118
+ echo " ✓ No stale branches"
119
+ fi
120
+
121
+ echo "Code synced via PR: $PR_URL"
122
+
123
+ # ── Sync release to public repo ──
124
+ # If the private repo has a version tag, create a matching release on the public repo.
125
+ # Pulls full release notes from the private repo and rewrites any private repo references.
126
+
127
+ # Try package.json first, fall back to latest git tag
128
+ VERSION=$(cd "$PRIVATE_REPO" && node -p "require('./package.json').version" 2>/dev/null || echo "")
129
+ if [[ -z "$VERSION" ]]; then
130
+ # No package.json. Use the latest version tag (v*) in the repo
131
+ TAG=$(cd "$PRIVATE_REPO" && git tag -l 'v*' --sort=-version:refname 2>/dev/null | head -1 || echo "")
132
+ if [[ -n "$TAG" ]]; then
133
+ VERSION="${TAG#v}"
134
+ fi
135
+ fi
136
+ if [[ -n "$VERSION" ]]; then
137
+ TAG="v$VERSION"
138
+ EXISTING=$(gh release view "$TAG" -R "$PUBLIC_REPO" --json tagName 2>/dev/null || echo "")
139
+ if [[ -z "$EXISTING" ]]; then
140
+ # Get the private repo's GitHub path (e.g., wipcomputer/memory-crystal-private)
141
+ PRIVATE_GH=$(cd "$PRIVATE_REPO" && git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/')
142
+
143
+ # Pull full release notes from private repo
144
+ NOTES=$(gh release view "$TAG" -R "$PRIVATE_GH" --json body -q '.body' 2>/dev/null || echo "")
145
+
146
+ if [[ -z "$NOTES" || "$NOTES" == "null" ]]; then
147
+ NOTES="Release $TAG"
148
+ else
149
+ # Rewrite private repo references to public repo
150
+ NOTES=$(echo "$NOTES" | sed "s|$PRIVATE_GH|$PUBLIC_REPO|g")
151
+ fi
152
+
153
+ echo "Creating release $TAG on $PUBLIC_REPO..."
154
+ 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)"
155
+ else
156
+ # Update existing release notes (in case they were incomplete)
157
+ PRIVATE_GH=$(cd "$PRIVATE_REPO" && git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/')
158
+ NOTES=$(gh release view "$TAG" -R "$PRIVATE_GH" --json body -q '.body' 2>/dev/null || echo "")
159
+ if [[ -n "$NOTES" && "$NOTES" != "null" ]]; then
160
+ NOTES=$(echo "$NOTES" | sed "s|$PRIVATE_GH|$PUBLIC_REPO|g")
161
+ gh release edit "$TAG" -R "$PUBLIC_REPO" --notes "$NOTES" 2>/dev/null && echo " ✓ Release $TAG notes updated on $PUBLIC_REPO" || true
162
+ fi
163
+ echo " Release $TAG exists on $PUBLIC_REPO (notes synced)"
164
+ fi
165
+ fi
166
+
167
+ echo "Done. Public repo updated."
168
+ echo " PR: $PR_URL"
169
+ echo " Commit: $COMMIT_MSG (from $COMMIT_HASH)"
170
+ [[ -n "${VERSION:-}" ]] && echo " Release: v$VERSION"
package/package.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@wipcomputer/deploy-public",
3
+ "version": "1.0.0",
4
+ "description": "Private-to-public repo sync. Excludes ai/ folder, creates PR, merges, cleans up branches.",
5
+ "bin": {
6
+ "deploy-public": "./deploy-public.sh"
7
+ },
8
+ "license": "MIT"
9
+ }