| … | … | @@ -168,30 +168,56 @@ async function initPearRuntime () { |
| 168 | 168 | await runtime.applyUpdate() |
| 169 | 169 | |
| 170 | 170 | if (runtime.applied) { |
| 171 | | // Binary swap succeeded (by-arch). Now also update ALL other app files |
| 172 | | // from the Hyperdrive so index.js, daemon/, node_modules/ etc. stay current. |
| 173 | | // Without this, only the Godot binary+pck get OTA'd — launcher code changes |
| 174 | | // would require a full reinstall. |
| 171 | // Binary swap succeeded (by-arch). Sync only the app files that change |
| 172 | // between deploys — NOT all of node_modules (thousands of static files). |
| 173 | // pear-runtime only swaps by-arch/, so without this, launcher/daemon |
| 174 | // changes would require a full reinstall. |
| 175 | 175 | const appDir = getAppDir() |
| 176 | 176 | const co = runtime.drive.checkout(runtime.length) |
| 177 | 177 | let updated = 0 |
| 178 | 178 | |
| 179 | // Only sync files that actually change between deploys: |
| 180 | // - Top-level app files (index.js, package.json, version.txt) |
| 181 | // - daemon/ (our app code) |
| 182 | // - node_modules/keet-daemon/ (our modified daemon) |
| 183 | // - node_modules/pear-runtime/ (CI-patched) |
| 184 | const syncPrefixes = [ |
| 185 | '/index.js', |
| 186 | '/package.json', |
| 187 | '/version.txt', |
| 188 | '/daemon/', |
| 189 | '/node_modules/keet-daemon/', |
| 190 | '/node_modules/pear-runtime/' |
| 191 | ] |
| 192 | |
| 179 | 193 | try { |
| 180 | | for await (const entry of co.list('/')) { |
| 181 | | const key = entry.key || entry |
| 182 | | if (typeof key !== 'string') continue |
| 183 | | // Skip by-arch (already swapped atomically) and build/ (duplicate of by-arch) |
| 184 | | if (key.startsWith('/by-arch/') || key.startsWith('/build/')) continue |
| 185 | | |
| 186 | | const data = await co.get(key) |
| 187 | | if (data) { |
| 188 | | const dst = path.join(appDir, key) |
| 189 | | fs.mkdirSync(path.dirname(dst), { recursive: true }) |
| 190 | | fs.writeFileSync(dst, data) |
| 191 | | updated++ |
| 194 | for (const prefix of syncPrefixes) { |
| 195 | if (!prefix.endsWith('/')) { |
| 196 | // Single file |
| 197 | const data = await co.get(prefix) |
| 198 | if (data) { |
| 199 | const dst = path.join(appDir, prefix) |
| 200 | fs.writeFileSync(dst, data) |
| 201 | console.log(`[launcher] synced ${prefix}`) |
| 202 | updated++ |
| 203 | } |
| 204 | continue |
| 205 | } |
| 206 | // Directory — list entries under prefix |
| 207 | for await (const entry of co.list(prefix)) { |
| 208 | const key = entry.key || entry |
| 209 | if (typeof key !== 'string') continue |
| 210 | const data = await co.get(key) |
| 211 | if (data) { |
| 212 | const dst = path.join(appDir, key) |
| 213 | fs.mkdirSync(path.dirname(dst), { recursive: true }) |
| 214 | fs.writeFileSync(dst, data) |
| 215 | updated++ |
| 216 | } |
| 192 | 217 | } |
| 218 | if (updated > 0) console.log(`[launcher] synced ${prefix} (${updated} files so far)`) |
| 193 | 219 | } |
| 194 | | console.log(`[launcher] Updated ${updated} app files from Hyperdrive`) |
| 220 | console.log(`[launcher] Synced ${updated} app files from Hyperdrive`) |
| 195 | 221 | } catch (err) { |
| 196 | 222 | console.error('[launcher] App file sync partial:', err.message) |
| 197 | 223 | } |