@wipcomputer/deploy-public 1.9.7 → 1.9.8

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.
Files changed (2) hide show
  1. package/deploy-public.sh +125 -27
  2. package/package.json +1 -1
package/deploy-public.sh CHANGED
@@ -32,6 +32,23 @@ if [[ ! -d "$PRIVATE_REPO/.git" ]]; then
32
32
  exit 1
33
33
  fi
34
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
+
35
52
  # Get the latest commit message from private repo
36
53
  COMMIT_MSG=$(cd "$PRIVATE_REPO" && git log -1 --pretty=format:"%s")
37
54
  COMMIT_HASH=$(cd "$PRIVATE_REPO" && git log -1 --pretty=format:"%h")
@@ -39,14 +56,35 @@ COMMIT_HASH=$(cd "$PRIVATE_REPO" && git log -1 --pretty=format:"%h")
39
56
  TMPDIR=$(mktemp -d)
40
57
  trap 'rm -rf "$TMPDIR"' EXIT
41
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
+
42
79
  echo "Cloning public repo $PUBLIC_REPO..."
43
80
  gh repo clone "$PUBLIC_REPO" "$TMPDIR/public" -- --depth 1 2>/dev/null || {
44
- echo "Public repo is empty or doesn't exist. Initializing..."
81
+ echo "Public repo is empty. Initializing..."
45
82
  mkdir -p "$TMPDIR/public"
46
83
  cd "$TMPDIR/public"
47
84
  git init
48
85
  git remote add origin "git@github.com:${PUBLIC_REPO}.git"
49
86
  cd - > /dev/null
87
+ EMPTY_REPO=true
50
88
  }
51
89
 
52
90
  echo "Syncing files from private repo (excluding ai/, .git/)..."
@@ -84,37 +122,48 @@ if [[ -z "${HARNESS_ID:-}" ]]; then
84
122
  fi
85
123
  BRANCH="$HARNESS_ID/deploy-$(date +%Y%m%d-%H%M%S)"
86
124
 
87
- git checkout -b "$BRANCH"
88
125
  git add -A
89
126
  git commit -m "$COMMIT_MSG (from $COMMIT_HASH)"
90
127
 
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 --delete-branch
103
-
104
- # Clean up any other non-main branches on public repo
105
- echo "Checking for stale branches on public repo..."
106
- STALE_BRANCHES=$(gh api "repos/$PUBLIC_REPO/branches" --paginate --jq '.[].name' 2>/dev/null | grep -v '^main$' || true)
107
- if [[ -n "$STALE_BRANCHES" ]]; then
108
- STALE_COUNT=$(echo "$STALE_BRANCHES" | wc -l | tr -d ' ')
109
- echo " Found $STALE_COUNT stale branch(es). Deleting..."
110
- echo "$STALE_BRANCHES" | while read -r stale; do
111
- gh api -X DELETE "repos/$PUBLIC_REPO/git/refs/heads/$stale" 2>/dev/null && echo " ✓ Deleted $stale" || echo " ! Could not delete $stale"
112
- done
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"
113
136
  else
114
- echo " ✓ No stale branches"
115
- fi
137
+ git checkout -b "$BRANCH"
116
138
 
117
- echo "Code synced via PR: $PR_URL"
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
118
167
 
119
168
  # ── Sync release to public repo ──
120
169
  # If the private repo has a version tag, create a matching release on the public repo.
@@ -160,6 +209,55 @@ if [[ -n "$VERSION" ]]; then
160
209
  fi
161
210
  fi
162
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
+
163
261
  echo "Done. Public repo updated."
164
262
  echo " PR: $PR_URL"
165
263
  echo " Commit: $COMMIT_MSG (from $COMMIT_HASH)"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipcomputer/deploy-public",
3
- "version": "1.9.7",
3
+ "version": "1.9.8",
4
4
  "description": "Private-to-public repo sync. Excludes ai/ folder, creates PR, merges, cleans up branches.",
5
5
  "bin": {
6
6
  "deploy-public": "./deploy-public.sh"