| … | … | @@ -0,0 +1,319 @@ |
| 1 | # Hyper-Wallet Deployment Workflow | |
| 2 | ||
| 3 | **Status**: Active (as of 2026-01-27) | |
| 4 | **Purpose**: Two-channel deployment strategy for safe production releases | |
| 5 | ||
| 6 | --- | |
| 7 | ||
| 8 | ## Overview | |
| 9 | ||
| 10 | Hyper-wallet uses a **two-channel deployment system** to ensure stability: | |
| 11 | ||
| 12 | 1. **Testing Channel** (`hyper-wallet-test`) - Active development and verification | |
| 13 | 2. **Production Channel** (`wdk-bare-wallet`) - Stable public release | |
| 14 | ||
| 15 | ## Channels | |
| 16 | ||
| 17 | ### Testing Channel | |
| 18 | ||
| 19 | - **Name**: `hyper-wallet-test` | |
| 20 | - **Purpose**: Pre-production verification | |
| 21 | - **Tmux Window**: `pear-seed:3` (hw-test) | |
| 22 | - **Seeder Command**: `pear seed hyper-wallet-test .` | |
| 23 | - **Deploy Command**: `./scripts/pear-deploy.sh --testing "message"` | |
| 24 | - **Pear Key**: Generated on first stage | |
| 25 | ||
| 26 | **When to use:** | |
| 27 | - All new features | |
| 28 | - Bug fixes | |
| 29 | - Security updates | |
| 30 | - UI changes | |
| 31 | - ANY code changes | |
| 32 | ||
| 33 | ### Production Channel | |
| 34 | ||
| 35 | - **Name**: `wdk-bare-wallet` | |
| 36 | - **Purpose**: Stable public release | |
| 37 | - **Tmux Window**: `pear-seed:0` (hyper-wallet) | |
| 38 | - **Seeder Command**: `pear seed pear://18x3enb54ttcr6uuhg5hh1cqzwi8ydnm658fmgyyjkzoqxd1ybso .` | |
| 39 | - **Deploy Command**: `./scripts/pear-deploy.sh --production "message"` | |
| 40 | - **Pear Key**: `pear://18x3enb54ttcr6uuhg5hh1cqzwi8ydnm658fmgyyjkzoqxd1ybso` | |
| 41 | ||
| 42 | **When to use:** | |
| 43 | - ONLY after testing verification complete | |
| 44 | - User-facing releases | |
| 45 | - Requires explicit approval | |
| 46 | ||
| 47 | --- | |
| 48 | ||
| 49 | ## Deployment Process | |
| 50 | ||
| 51 | ### Step 1: Deploy to Testing | |
| 52 | ||
| 53 | ```bash | |
| 54 | cd /storage/projects/code/hypercore-kb/hyper-fleeky/hyper-wallet | |
| 55 | ||
| 56 | # Create wallet backup FIRST | |
| 57 | cp -r ~/.hyper-wallet/ ~/.hyper-wallet.backup-$(date +%Y%m%d-%H%M%S) | |
| 58 | ||
| 59 | # Deploy to testing channel | |
| 60 | ./scripts/pear-deploy.sh --testing "Fix contact list multi-address support" | |
| 61 | ``` | |
| 62 | ||
| 63 | **What happens:** | |
| 64 | 1. Git commit created with message + "Deployment: testing" tag | |
| 65 | 2. Pear stage creates new version | |
| 66 | 3. Pear release makes it default for testing channel | |
| 67 | 4. Testing seeder (pear-seed:3) automatically restarted | |
| 68 | 5. Testing pear:// key displayed | |
| 69 | ||
| 70 | ### Step 2: Verify on Testing | |
| 71 | ||
| 72 | #### Local Testing (tabertron) | |
| 73 | ||
| 74 | ```bash | |
| 75 | # Run testing version | |
| 76 | pear run hyper-wallet-test web 4004 --network | |
| 77 | ||
| 78 | # Test checklist: | |
| 79 | # - Web UI loads | |
| 80 | # - Password unlock works | |
| 81 | # - All features work as expected | |
| 82 | # - No console errors | |
| 83 | ``` | |
| 84 | ||
| 85 | #### Network Testing (ashatron) | |
| 86 | ||
| 87 | ```bash | |
| 88 | # On ashatron.local: | |
| 89 | pear run hyper-wallet-test web 4004 --network | |
| 90 | ||
| 91 | # Access from browser: http://ashatron.local:4004 | |
| 92 | ||
| 93 | # Test checklist: | |
| 94 | # - Network access works | |
| 95 | # - CORS properly configured | |
| 96 | # - Multi-device features work | |
| 97 | # - Sync works correctly | |
| 98 | ``` | |
| 99 | ||
| 100 | #### Multi-Device Testing (if needed) | |
| 101 | ||
| 102 | ```bash | |
| 103 | # Test device pairing between tabertron and ashatron | |
| 104 | # Test transaction sync | |
| 105 | # Test contact sync | |
| 106 | ``` | |
| 107 | ||
| 108 | ### Step 3: Get Approval | |
| 109 | ||
| 110 | **CRITICAL**: Do NOT deploy to production without explicit approval. | |
| 111 | ||
| 112 | Ask: **"Testing verification complete. Ready to push to production?"** | |
| 113 | ||
| 114 | ### Step 4: Deploy to Production | |
| 115 | ||
| 116 | **ONLY after approval received:** | |
| 117 | ||
| 118 | ```bash | |
| 119 | cd /storage/projects/code/hypercore-kb/hyper-fleeky/hyper-wallet | |
| 120 | ||
| 121 | # Deploy to production | |
| 122 | ./scripts/pear-deploy.sh --production "Fix contact list multi-address support (verified on testing)" | |
| 123 | ``` | |
| 124 | ||
| 125 | **What happens:** | |
| 126 | 1. Git commit created with message + "Deployment: production" tag | |
| 127 | 2. Pear stage creates new version for production channel | |
| 128 | 3. Pear release makes it default for wdk-bare-wallet | |
| 129 | 4. Production seeder (pear-seed:0) automatically restarted | |
| 130 | 5. Production pear:// key displayed | |
| 131 | ||
| 132 | ### Step 5: Verify Production | |
| 133 | ||
| 134 | ```bash | |
| 135 | # Check production seeder running | |
| 136 | tmux attach -t pear-seed | |
| 137 | # Window 0 should show: "pear seed pear://18x3enb..." | |
| 138 | ||
| 139 | # Test production access | |
| 140 | pear run pear://18x3enb54ttcr6uuhg5hh1cqzwi8ydnm658fmgyyjkzoqxd1ybso web 4004 --network | |
| 141 | ``` | |
| 142 | ||
| 143 | ### Step 6: Update Documentation | |
| 144 | ||
| 145 | 1. Update `.claude/tmux-registry.json`: | |
| 146 | - Latest version number | |
| 147 | - Last deployed date | |
| 148 | - Features summary | |
| 149 | ||
| 150 | 2. Update `CHANGELOG.md`: | |
| 151 | - Version number | |
| 152 | - Changes description | |
| 153 | - Date | |
| 154 | ||
| 155 | 3. Announce to users (if public release) | |
| 156 | ||
| 157 | --- | |
| 158 | ||
| 159 | ## Quick Reference | |
| 160 | ||
| 161 | ### Deploy Commands | |
| 162 | ||
| 163 | ```bash | |
| 164 | # Testing deployment | |
| 165 | ./scripts/pear-deploy.sh --testing "your message" | |
| 166 | ./scripts/pear-deploy.sh -t "your message" | |
| 167 | ||
| 168 | # Production deployment | |
| 169 | ./scripts/pear-deploy.sh --production "your message" | |
| 170 | ./scripts/pear-deploy.sh -p "your message" | |
| 171 | ``` | |
| 172 | ||
| 173 | ### Check What's Running | |
| 174 | ||
| 175 | ```bash | |
| 176 | # List all seeders | |
| 177 | tmux list-windows -t pear-seed | |
| 178 | ||
| 179 | # Attach to seeder session | |
| 180 | tmux attach -t pear-seed | |
| 181 | ||
| 182 | # Check specific window | |
| 183 | tmux capture-pane -t pear-seed:0 -p # Production | |
| 184 | tmux capture-pane -t pear-seed:3 -p # Testing | |
| 185 | ``` | |
| 186 | ||
| 187 | ### Emergency Rollback | |
| 188 | ||
| 189 | **If production breaks:** | |
| 190 | ||
| 191 | ```bash | |
| 192 | # Option 1: Redeploy previous version | |
| 193 | cd /storage/projects/code/hypercore-kb/hyper-fleeky/hyper-wallet | |
| 194 | git log --oneline # Find previous commit | |
| 195 | git checkout <previous-commit> | |
| 196 | ./scripts/pear-deploy.sh --production "Rollback to stable version" | |
| 197 | ||
| 198 | # Option 2: Clear cache and force re-download | |
| 199 | rm -rf ~/.config/pear/app-storage/* | |
| 200 | pear run pear://18x3enb54ttcr6uuhg5hh1cqzwi8ydnm658fmgyyjkzoqxd1ybso --checkout=latest web 4004 | |
| 201 | ``` | |
| 202 | ||
| 203 | --- | |
| 204 | ||
| 205 | ## Testing Checklist | |
| 206 | ||
| 207 | ### Before Testing Deployment | |
| 208 | ||
| 209 | - [ ] All unit tests pass | |
| 210 | - [ ] Bare mode works: `bare hyper-wallet.cjs web 4004` | |
| 211 | - [ ] Pear local mode works: `pear run -d . web 4004` | |
| 212 | - [ ] Wallet backup created | |
| 213 | - [ ] CHANGELOG.md updated | |
| 214 | ||
| 215 | ### Testing Verification | |
| 216 | ||
| 217 | - [ ] Web UI loads without errors | |
| 218 | - [ ] Password unlock works | |
| 219 | - [ ] Balance displays correctly | |
| 220 | - [ ] Send transaction works | |
| 221 | - [ ] Contact list works | |
| 222 | - [ ] Receive QR code displays | |
| 223 | - [ ] Transaction history loads | |
| 224 | - [ ] Settings work | |
| 225 | - [ ] No console errors | |
| 226 | - [ ] Network access works (test from ashatron) | |
| 227 | - [ ] Multi-device sync works (if applicable) | |
| 228 | ||
| 229 | ### Before Production Deployment | |
| 230 | ||
| 231 | - [ ] Testing verification complete | |
| 232 | - [ ] Multi-device testing complete (if applicable) | |
| 233 | - [ ] No critical bugs found | |
| 234 | - [ ] User approval obtained | |
| 235 | - [ ] Ready to announce | |
| 236 | ||
| 237 | ### After Production Deployment | |
| 238 | ||
| 239 | - [ ] Production seeder running (pear-seed:0) | |
| 240 | - [ ] Production pear:// key loads correctly | |
| 241 | - [ ] tmux-registry.json updated | |
| 242 | - [ ] CHANGELOG.md finalized | |
| 243 | - [ ] Users notified (if applicable) | |
| 244 | ||
| 245 | --- | |
| 246 | ||
| 247 | ## Troubleshooting | |
| 248 | ||
| 249 | ### Testing Channel Not Working | |
| 250 | ||
| 251 | ```bash | |
| 252 | # Recreate testing channel from scratch | |
| 253 | cd /storage/projects/code/hypercore-kb/hyper-fleeky/hyper-wallet | |
| 254 | pear stage hyper-wallet-test . | |
| 255 | pear release hyper-wallet-test | |
| 256 | ||
| 257 | # Start seeder manually in pear-seed:3 | |
| 258 | tmux send-keys -t pear-seed:3 "pear seed hyper-wallet-test ." Enter | |
| 259 | ``` | |
| 260 | ||
| 261 | ### Production Seeder Not Restarting | |
| 262 | ||
| 263 | ```bash | |
| 264 | # Manually restart production seeder | |
| 265 | tmux send-keys -t pear-seed:0 C-c | |
| 266 | sleep 2 | |
| 267 | tmux send-keys -t pear-seed:0 "pear seed pear://18x3enb54ttcr6uuhg5hh1cqzwi8ydnm658fmgyyjkzoqxd1ybso ." Enter | |
| 268 | ``` | |
| 269 | ||
| 270 | ### Cache Issues | |
| 271 | ||
| 272 | ```bash | |
| 273 | # Clear Pear cache (forces fresh download) | |
| 274 | rm -rf ~/.config/pear/app-storage/* | |
| 275 | ||
| 276 | # Run with --checkout=latest flag | |
| 277 | pear run hyper-wallet-test --checkout=latest web 4004 | |
| 278 | ``` | |
| 279 | ||
| 280 | --- | |
| 281 | ||
| 282 | ## Safety Rules | |
| 283 | ||
| 284 | ### NEVER | |
| 285 | ||
| 286 | - ❌ Deploy directly to production without testing | |
| 287 | - ❌ Skip testing verification steps | |
| 288 | - ❌ Deploy without user approval (when applicable) | |
| 289 | - ❌ Deploy without wallet backup | |
| 290 | - ❌ Push breaking changes without warning | |
| 291 | ||
| 292 | ### ALWAYS | |
| 293 | ||
| 294 | - ✅ Deploy to testing FIRST | |
| 295 | - ✅ Verify on multiple devices (tabertron + ashatron) | |
| 296 | - ✅ Create wallet backup before deploying | |
| 297 | - ✅ Test all critical features | |
| 298 | - ✅ Get approval before production push | |
| 299 | - ✅ Update documentation after deployment | |
| 300 | ||
| 301 | --- | |
| 302 | ||
| 303 | ## Version History | |
| 304 | ||
| 305 | - **2026-01-27**: Two-channel system established | |
| 306 | - Testing: `hyper-wallet-test` (pear-seed:3) | |
| 307 | - Production: `wdk-bare-wallet` (pear-seed:0) | |
| 308 | - Scripts updated: `scripts/pear-deploy.sh` | |
| 309 | - Documentation: This file + `.claude/skills/hyper-wallet/SKILL.md` | |
| 310 | ||
| 311 | --- | |
| 312 | ||
| 313 | ## Related Documentation | |
| 314 | ||
| 315 | - `.claude/skills/hyper-wallet/SKILL.md` - Complete skill documentation | |
| 316 | - `.claude/tmux-registry.json` - Tmux session tracking | |
| 317 | - `.claude/rules/08-tmux-sessions.md` - Tmux session management | |
| 318 | - `scripts/pear-deploy.sh` - Deployment automation script | |
| 319 | - `CHANGELOG.md` - Version history |
| … | … | @@ -5,9 +5,10 @@ |
| 5 | 5 | "windows": { |
| 6 | 6 | "0": { |
| 7 | 7 | "name": "hyper-wallet", |
| 8 | "purpose": "Seeding pear://18x3enb54ttcr6uuhg5hh1cqzwi8ydnm658fmgyyjkzoqxd1ybso", | |
| 8 | "purpose": "PRODUCTION: Seeding pear://18x3enb54ttcr6uuhg5hh1cqzwi8ydnm658fmgyyjkzoqxd1ybso (wdk-bare-wallet)", | |
| 9 | 9 | "command": "pear seed pear://18x3enb54ttcr6uuhg5hh1cqzwi8ydnm658fmgyyjkzoqxd1ybso .", |
| 10 | 10 | "persistent": true, |
| 11 | "channel": "wdk-bare-wallet", | |
| 11 | 12 | "latest_version": "11472", |
| 12 | 13 | "last_deployed": "2026-01-27", |
| 13 | 14 | "features": "Phase 2 COMPLETE: Auth + Encryption + Validation + Rate Limiting + CORS + Signed Invites + Password Unlock UI ✅" |
| … | … | @@ -23,9 +24,15 @@ |
| 23 | 24 | "persistent": true |
| 24 | 25 | }, |
| 25 | 26 | "3": { |
| 26 | "name": "hw-pear-", | |
| 27 | "purpose": "Experimental hyper-wallet seeding", | |
| 28 | "persistent": false | |
| 27 | "name": "hw-test", | |
| 28 | "purpose": "TESTING: Seeding hyper-wallet test channel (hyper-wallet-test)", | |
| 29 | "command": "pear seed hyper-wallet-test .", | |
| 30 | "persistent": true, | |
| 31 | "channel": "hyper-wallet-test", | |
| 32 | "latest_version": "TBD", | |
| 33 | "last_deployed": "TBD", | |
| 34 | "features": "Testing channel for pre-production verification", | |
| 35 | "notes": "Deploy here first with --testing flag, verify, then promote to production (window 0)" | |
| 29 | 36 | } |
| 30 | 37 | } |
| 31 | 38 | }, |
| … | … | @@ -1089,13 +1089,147 @@ async function deleteContact(id) { |
| 1089 | 1089 | |
| 1090 | 1090 | /** |
| 1091 | 1091 | * Find contact by address (helper for transaction display) |
| 1092 | * UPDATED: Supports both old (single address) and new (multiple addresses) format | |
| 1092 | 1093 | * @param {string} address - Blockchain address |
| 1093 | 1094 | * @param {string} chain - Chain name |
| 1094 | 1095 | * @returns {Promise<Object|null>} - Contact or null |
| 1095 | 1096 | */ |
| 1096 | 1097 | async function findContactByAddress(address, chain) { |
| 1097 | const contacts = await getContacts(chain) | |
| 1098 | return contacts.find(c => c.address.toLowerCase() === address.toLowerCase()) || null | |
| 1098 | const contacts = await getContacts() | |
| 1099 | ||
| 1100 | return contacts.find(c => { | |
| 1101 | // Old format: contact.address | |
| 1102 | if (c.address && c.address.toLowerCase() === address.toLowerCase() && c.chain === chain) { | |
| 1103 | return true | |
| 1104 | } | |
| 1105 | ||
| 1106 | // New format: contact.addresses[] | |
| 1107 | if (c.addresses && Array.isArray(c.addresses)) { | |
| 1108 | return c.addresses.some(addr => | |
| 1109 | addr.chain === chain && addr.address.toLowerCase() === address.toLowerCase() | |
| 1110 | ) | |
| 1111 | } | |
| 1112 | ||
| 1113 | return false | |
| 1114 | }) || null | |
| 1115 | } | |
| 1116 | ||
| 1117 | /** | |
| 1118 | * Add an address to an existing contact | |
| 1119 | * @param {string} contactId - Contact ID | |
| 1120 | * @param {Object} addressInfo - Address details | |
| 1121 | * @param {string} addressInfo.chain - Chain name (bitcoin, ethereum) | |
| 1122 | * @param {string} addressInfo.address - Blockchain address | |
| 1123 | * @param {string} addressInfo.network - Network (testnet, mainnet) | |
| 1124 | * @returns {Promise<Object>} - Updated contact | |
| 1125 | */ | |
| 1126 | async function addAddressToContact(contactId, { chain, address, network }) { | |
| 1127 | if (!autobase) { | |
| 1128 | throw new Error('Storage not initialized') | |
| 1129 | } | |
| 1130 | ||
| 1131 | const existing = await getContactById(contactId) | |
| 1132 | if (!existing) { | |
| 1133 | throw new Error('Contact not found') | |
| 1134 | } | |
| 1135 | ||
| 1136 | // Migrate old format to new format if needed | |
| 1137 | let addresses = [] | |
| 1138 | if (existing.addresses && Array.isArray(existing.addresses)) { | |
| 1139 | addresses = existing.addresses | |
| 1140 | } else if (existing.address && existing.chain) { | |
| 1141 | // Convert old single-address format | |
| 1142 | addresses = [{ | |
| 1143 | chain: existing.chain, | |
| 1144 | address: existing.address, | |
| 1145 | network: existing.network || network | |
| 1146 | }] | |
| 1147 | } | |
| 1148 | ||
| 1149 | // Check if address already exists for this chain | |
| 1150 | const existingAddr = addresses.find(a => | |
| 1151 | a.chain === chain && a.address.toLowerCase() === address.toLowerCase() | |
| 1152 | ) | |
| 1153 | if (existingAddr) { | |
| 1154 | throw new Error(`Address already exists for ${chain}`) | |
| 1155 | } | |
| 1156 | ||
| 1157 | // Add new address | |
| 1158 | addresses.push({ chain, address, network }) | |
| 1159 | ||
| 1160 | // Update contact with new addresses array | |
| 1161 | const updated = { | |
| 1162 | ...existing, | |
| 1163 | addresses, | |
| 1164 | // Remove old format fields | |
| 1165 | address: undefined, | |
| 1166 | chain: undefined, | |
| 1167 | modifiedAt: Date.now() | |
| 1168 | } | |
| 1169 | ||
| 1170 | const op = { | |
| 1171 | type: 'put-contact', | |
| 1172 | key: `contact:${contactId}`, | |
| 1173 | value: updated | |
| 1174 | } | |
| 1175 | ||
| 1176 | await autobase.append(JSON.stringify(op)) | |
| 1177 | ||
| 1178 | // Wait for view to update | |
| 1179 | await new Promise(resolve => setTimeout(resolve, 100)) | |
| 1180 | ||
| 1181 | return updated | |
| 1182 | } | |
| 1183 | ||
| 1184 | /** | |
| 1185 | * Remove an address from a contact | |
| 1186 | * @param {string} contactId - Contact ID | |
| 1187 | * @param {string} chain - Chain name to remove | |
| 1188 | * @returns {Promise<Object>} - Updated contact | |
| 1189 | */ | |
| 1190 | async function removeAddressFromContact(contactId, chain) { | |
| 1191 | if (!autobase) { | |
| 1192 | throw new Error('Storage not initialized') | |
| 1193 | } | |
| 1194 | ||
| 1195 | const existing = await getContactById(contactId) | |
| 1196 | if (!existing) { | |
| 1197 | throw new Error('Contact not found') | |
| 1198 | } | |
| 1199 | ||
| 1200 | if (!existing.addresses || !Array.isArray(existing.addresses)) { | |
| 1201 | throw new Error('Contact has no addresses array') | |
| 1202 | } | |
| 1203 | ||
| 1204 | // Filter out the address for this chain | |
| 1205 | const addresses = existing.addresses.filter(a => a.chain !== chain) | |
| 1206 | ||
| 1207 | if (addresses.length === existing.addresses.length) { | |
| 1208 | throw new Error(`No address found for chain: ${chain}`) | |
| 1209 | } | |
| 1210 | ||
| 1211 | if (addresses.length === 0) { | |
| 1212 | throw new Error('Cannot remove last address. Delete contact instead.') | |
| 1213 | } | |
| 1214 | ||
| 1215 | const updated = { | |
| 1216 | ...existing, | |
| 1217 | addresses, | |
| 1218 | modifiedAt: Date.now() | |
| 1219 | } | |
| 1220 | ||
| 1221 | const op = { | |
| 1222 | type: 'put-contact', | |
| 1223 | key: `contact:${contactId}`, | |
| 1224 | value: updated | |
| 1225 | } | |
| 1226 | ||
| 1227 | await autobase.append(JSON.stringify(op)) | |
| 1228 | ||
| 1229 | // Wait for view to update | |
| 1230 | await new Promise(resolve => setTimeout(resolve, 100)) | |
| 1231 | ||
| 1232 | return updated | |
| 1099 | 1233 | } |
| 1100 | 1234 | |
| 1101 | 1235 | /** |
| … | … | @@ -1827,5 +1961,8 @@ module.exports = { |
| 1827 | 1961 | updateContact, |
| 1828 | 1962 | deleteContact, |
| 1829 | 1963 | findContactByAddress, |
| 1964 | // NEW: Multi-address contact support | |
| 1965 | addAddressToContact, | |
| 1966 | removeAddressFromContact, | |
| 1830 | 1967 | closeStorage |
| 1831 | 1968 | } |
| … | … | @@ -1,14 +1,55 @@ |
| 1 | 1 | #!/bin/bash |
| 2 | # Pear Deployment Script | |
| 3 | # Usage: ./scripts/pear-deploy.sh "commit message" | |
| 2 | # Pear Deployment Script with Testing vs Production Channels | |
| 3 | # Usage: | |
| 4 | # ./scripts/pear-deploy.sh --testing "commit message" | |
| 5 | # ./scripts/pear-deploy.sh --production "commit message" | |
| 4 | 6 | |
| 5 | 7 | set -e # Exit on error |
| 6 | 8 | |
| 7 | PEAR_KEY="pear://18x3enb54ttcr6uuhg5hh1cqzwi8ydnm658fmgyyjkzoqxd1ybso" | |
| 9 | # Deployment channel configuration | |
| 10 | TESTING_KEY="hyper-wallet-test" | |
| 11 | PRODUCTION_KEY="wdk-bare-wallet" | |
| 8 | 12 | APP_DIR="/storage/projects/code/hypercore-kb/hyper-fleeky/hyper-wallet" |
| 9 | 13 | |
| 14 | # Parse arguments | |
| 15 | MODE="" | |
| 16 | MESSAGE="" | |
| 17 | ||
| 18 | if [ "$1" == "--testing" ] || [ "$1" == "-t" ]; then | |
| 19 | MODE="testing" | |
| 20 | MESSAGE="$2" | |
| 21 | PEAR_KEY="$TESTING_KEY" | |
| 22 | TMUX_WINDOW="pear-seed:3" # hw-test window | |
| 23 | elif [ "$1" == "--production" ] || [ "$1" == "-p" ]; then | |
| 24 | MODE="production" | |
| 25 | MESSAGE="$2" | |
| 26 | PEAR_KEY="$PRODUCTION_KEY" | |
| 27 | TMUX_WINDOW="pear-seed:0" # hyper-wallet production window | |
| 28 | else | |
| 29 | echo "❌ Invalid mode" | |
| 30 | echo "" | |
| 31 | echo "Usage:" | |
| 32 | echo " ./scripts/pear-deploy.sh --testing \"commit message\"" | |
| 33 | echo " ./scripts/pear-deploy.sh --production \"commit message\"" | |
| 34 | echo "" | |
| 35 | echo "Channels:" | |
| 36 | echo " --testing (-t) → $TESTING_KEY (tmux: pear-seed:3)" | |
| 37 | echo " --production (-p) → $PRODUCTION_KEY (tmux: pear-seed:0)" | |
| 38 | echo "" | |
| 39 | exit 1 | |
| 40 | fi | |
| 41 | ||
| 42 | if [ -z "$MESSAGE" ]; then | |
| 43 | echo "❌ Commit message required" | |
| 44 | echo "Usage: ./scripts/pear-deploy.sh --$MODE \"your commit message\"" | |
| 45 | exit 1 | |
| 46 | fi | |
| 47 | ||
| 10 | 48 | echo "🔧 Pear Deployment Workflow" |
| 11 | 49 | echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" |
| 50 | echo " Mode: $MODE" | |
| 51 | echo " Channel: $PEAR_KEY" | |
| 52 | echo " Tmux: $TMUX_WINDOW" | |
| 12 | 53 | echo "" |
| 13 | 54 | |
| 14 | 55 | # 1. Check we're in the right directory |
| … | … | @@ -21,12 +62,6 @@ fi |
| 21 | 62 | if [ -n "$(git status --porcelain)" ]; then |
| 22 | 63 | echo "📝 Step 1: Git Commit" |
| 23 | 64 | |
| 24 | if [ -z "$1" ]; then | |
| 25 | echo "❌ Commit message required" | |
| 26 | echo "Usage: ./scripts/pear-deploy.sh \"your commit message\"" | |
| 27 | exit 1 | |
| 28 | fi | |
| 29 | ||
| 30 | 65 | # Show what will be committed |
| 31 | 66 | echo "" |
| 32 | 67 | echo "Changes to commit:" |
| … | … | @@ -38,19 +73,21 @@ if [ -n "$(git status --porcelain)" ]; then |
| 38 | 73 | |
| 39 | 74 | # Commit with co-authorship |
| 40 | 75 | git commit -m "$(cat <<EOF |
| 41 | $1 | |
| 76 | $MESSAGE | |
| 77 | ||
| 78 | Deployment: $MODE ($PEAR_KEY) | |
| 42 | 79 | |
| 43 | 80 | Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> |
| 44 | 81 | EOF |
| 45 | 82 | )" |
| 46 | 83 | |
| 47 | echo "✅ Committed: $1" | |
| 84 | echo "✅ Committed: $MESSAGE" | |
| 48 | 85 | else |
| 49 | 86 | echo "✅ Step 1: No uncommitted changes" |
| 50 | 87 | fi |
| 51 | 88 | |
| 52 | 89 | echo "" |
| 53 | echo "📦 Step 2: Pear Stage" | |
| 90 | echo "📦 Step 2: Pear Stage ($MODE)" | |
| 54 | 91 | STAGE_OUTPUT=$(pear stage $PEAR_KEY . 2>&1) |
| 55 | 92 | echo "$STAGE_OUTPUT" |
| 56 | 93 | |
| … | … | @@ -58,27 +95,59 @@ echo "$STAGE_OUTPUT" |
| 58 | 95 | LATEST=$(echo "$STAGE_OUTPUT" | grep "Latest:" | awk '{print $2}') |
| 59 | 96 | RELEASE=$(echo "$STAGE_OUTPUT" | grep "Release:" | awk '{print $2}') |
| 60 | 97 | |
| 98 | # Get the actual pear:// key (only needed for testing on first run) | |
| 99 | PEAR_HASH=$(pear info $PEAR_KEY --json 2>/dev/null | grep -oP '"key":"pear://\K[^"]+' || echo "unknown") | |
| 100 | ||
| 61 | 101 | echo "" |
| 62 | echo "🚀 Step 3: Pear Release" | |
| 102 | echo "🚀 Step 3: Pear Release ($MODE)" | |
| 63 | 103 | pear release $PEAR_KEY |
| 64 | 104 | |
| 65 | 105 | echo "" |
| 66 | echo "🌱 Step 4: Update Seeder (tmux: pear-seed:0)" | |
| 67 | tmux send-keys -t pear-seed:0 C-c | |
| 68 | sleep 2 | |
| 69 | tmux send-keys -t pear-seed:0 "pear seed $PEAR_KEY ." Enter | |
| 106 | echo "🌱 Step 4: Update Seeder (tmux: $TMUX_WINDOW)" | |
| 107 | ||
| 108 | # Check if tmux window exists | |
| 109 | if tmux list-windows -t pear-seed 2>/dev/null | grep -q "^${TMUX_WINDOW##*:}:"; then | |
| 110 | tmux send-keys -t $TMUX_WINDOW C-c | |
| 111 | sleep 2 | |
| 112 | ||
| 113 | if [ "$MODE" == "testing" ]; then | |
| 114 | tmux send-keys -t $TMUX_WINDOW "pear seed $PEAR_KEY ." Enter | |
| 115 | else | |
| 116 | tmux send-keys -t $TMUX_WINDOW "pear seed pear://18x3enb54ttcr6uuhg5hh1cqzwi8ydnm658fmgyyjkzoqxd1ybso ." Enter | |
| 117 | fi | |
| 118 | ||
| 119 | echo "✅ Seeder updated in $TMUX_WINDOW" | |
| 120 | else | |
| 121 | echo "⚠️ Warning: tmux window $TMUX_WINDOW not found" | |
| 122 | echo " You may need to start the seeder manually" | |
| 123 | fi | |
| 70 | 124 | |
| 71 | 125 | echo "" |
| 72 | 126 | echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" |
| 73 | 127 | echo "✅ Deployment Complete!" |
| 74 | 128 | echo "" |
| 75 | 129 | echo "📊 Summary:" |
| 76 | echo " Commit: $1" | |
| 130 | echo " Mode: $MODE" | |
| 131 | echo " Channel: $PEAR_KEY" | |
| 132 | if [ "$PEAR_HASH" != "unknown" ]; then | |
| 133 | echo " Key: pear://$PEAR_HASH" | |
| 134 | fi | |
| 135 | echo " Commit: $MESSAGE" | |
| 77 | 136 | echo " Version: $LATEST" |
| 78 | echo " Seeding: Updated in tmux window pear-seed:0" | |
| 79 | echo "" | |
| 80 | echo "🧪 Next Steps:" | |
| 81 | echo " 1. Check tmux session 'pear-dev' for testing" | |
| 82 | echo " 2. Run: ./scripts/pear-test.sh" | |
| 83 | echo " 3. Or manually: tmux attach -t pear-dev" | |
| 137 | echo " Seeding: $TMUX_WINDOW" | |
| 84 | 138 | echo "" |
| 139 | ||
| 140 | if [ "$MODE" == "testing" ]; then | |
| 141 | echo "🧪 Testing Deployment - Next Steps:" | |
| 142 | echo " 1. Test on ashatron.local" | |
| 143 | echo " 2. Test all Phase 2 security features" | |
| 144 | echo " 3. Once verified, deploy to production:" | |
| 145 | echo " ./scripts/pear-deploy.sh --production \"Phase 2 complete\"" | |
| 146 | echo "" | |
| 147 | else | |
| 148 | echo "🚀 Production Deployment - Next Steps:" | |
| 149 | echo " 1. Announce to users" | |
| 150 | echo " 2. Monitor for issues" | |
| 151 | echo " 3. Update documentation with new version" | |
| 152 | echo "" | |
| 153 | fi |