freebuff 0.0.196 → 0.0.198
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/index.js +1 -0
- package/launcher.js +72 -6
- package/package.json +9 -9
package/index.js
CHANGED
package/launcher.js
CHANGED
|
@@ -139,6 +139,9 @@ function createLauncher(productConfig) {
|
|
|
139
139
|
startupBanner = [],
|
|
140
140
|
telemetryEvent = 'cli.update_codebuff_failed',
|
|
141
141
|
telemetryProperties = {},
|
|
142
|
+
// Freebuff sessions remain open between turns. The launcher cannot know
|
|
143
|
+
// when a restart is safe, so keep the process alive until the user exits.
|
|
144
|
+
deferUpdatesUntilExit = false,
|
|
142
145
|
tempDownloadDirName = `.${packageName}-download-temp`,
|
|
143
146
|
// Tests only. os.homedir() ignores $HOME under `bun test`, so pointing HOME
|
|
144
147
|
// at a temp dir is not enough to keep a test off the real ~/.config.
|
|
@@ -267,7 +270,14 @@ function createLauncher(productConfig) {
|
|
|
267
270
|
binaryName,
|
|
268
271
|
binaryPath: path.join(configDir, binaryName),
|
|
269
272
|
metadataPath: path.join(configDir, `${packageName}-metadata.json`),
|
|
270
|
-
|
|
273
|
+
// A deferred download may wait here for an hour. Another invocation
|
|
274
|
+
// must not replace its staged binary (or delete it while downloading).
|
|
275
|
+
tempDownloadDir: path.join(
|
|
276
|
+
configDir,
|
|
277
|
+
deferUpdatesUntilExit
|
|
278
|
+
? `${tempDownloadDirName}-${process.pid}`
|
|
279
|
+
: tempDownloadDirName,
|
|
280
|
+
),
|
|
271
281
|
userAgent: `${packageName}-cli`,
|
|
272
282
|
requestTimeout: 20000,
|
|
273
283
|
downloadRequestTimeout: 120000,
|
|
@@ -276,6 +286,7 @@ function createLauncher(productConfig) {
|
|
|
276
286
|
}
|
|
277
287
|
|
|
278
288
|
const CONFIG = createConfig(packageName)
|
|
289
|
+
const pendingUpdates = new WeakMap()
|
|
279
290
|
const { downloadFile, httpGet, withRetries } = createReleaseHttpClient({
|
|
280
291
|
env: process.env,
|
|
281
292
|
userAgent: CONFIG.userAgent,
|
|
@@ -1085,7 +1096,10 @@ function createLauncher(productConfig) {
|
|
|
1085
1096
|
}
|
|
1086
1097
|
}
|
|
1087
1098
|
|
|
1088
|
-
function installStagedBinary(
|
|
1099
|
+
function installStagedBinary(
|
|
1100
|
+
{ tempBinaryPath, version, targetKey },
|
|
1101
|
+
{ quiet = false } = {},
|
|
1102
|
+
) {
|
|
1089
1103
|
const replacements = []
|
|
1090
1104
|
const metadataTempPath = `${CONFIG.metadataPath}.new.${process.pid}`
|
|
1091
1105
|
|
|
@@ -1133,8 +1147,10 @@ function createLauncher(productConfig) {
|
|
|
1133
1147
|
}
|
|
1134
1148
|
}
|
|
1135
1149
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1150
|
+
if (!quiet) {
|
|
1151
|
+
term.clearLine()
|
|
1152
|
+
console.log(`Download complete! Starting ${displayName}...`)
|
|
1153
|
+
}
|
|
1138
1154
|
}
|
|
1139
1155
|
|
|
1140
1156
|
async function downloadBinary(
|
|
@@ -1240,7 +1256,11 @@ function createLauncher(productConfig) {
|
|
|
1240
1256
|
})
|
|
1241
1257
|
}
|
|
1242
1258
|
|
|
1243
|
-
async function checkForUpdates(
|
|
1259
|
+
async function checkForUpdates(
|
|
1260
|
+
runningProcess,
|
|
1261
|
+
exitListener,
|
|
1262
|
+
fetchLatestRelease = getLatestRelease,
|
|
1263
|
+
) {
|
|
1244
1264
|
// main() schedules this 100ms after launch, so the binary it was handed can
|
|
1245
1265
|
// already be dead — a startup crash that handed off to the baseline
|
|
1246
1266
|
// fallback, most of all. Updating around a corpse would race that
|
|
@@ -1259,9 +1279,14 @@ function createLauncher(productConfig) {
|
|
|
1259
1279
|
try {
|
|
1260
1280
|
const currentVersion = getCurrentVersion()
|
|
1261
1281
|
|
|
1262
|
-
const latestRelease = await
|
|
1282
|
+
const latestRelease = await fetchLatestRelease()
|
|
1263
1283
|
const latestVersion = latestRelease?.version ?? null
|
|
1264
1284
|
if (!latestVersion) return
|
|
1285
|
+
if (
|
|
1286
|
+
runningProcess.exitCode !== null ||
|
|
1287
|
+
runningProcess.signalCode !== null
|
|
1288
|
+
)
|
|
1289
|
+
return
|
|
1265
1290
|
|
|
1266
1291
|
if (
|
|
1267
1292
|
// Download new version if current version is unknown or outdated.
|
|
@@ -1274,6 +1299,19 @@ function createLauncher(productConfig) {
|
|
|
1274
1299
|
{ quiet: true, binaryChecksums: latestRelease.binaryChecksums },
|
|
1275
1300
|
)
|
|
1276
1301
|
|
|
1302
|
+
if (deferUpdatesUntilExit) {
|
|
1303
|
+
// No signals, terminal output, or binary/WASM replacement while the
|
|
1304
|
+
// CLI owns the session. Even an idle model picker can admit a session
|
|
1305
|
+
// while the download is in flight. A download that loses the race
|
|
1306
|
+
// with exit must not install into a fallback child's running files.
|
|
1307
|
+
if (
|
|
1308
|
+
runningProcess.exitCode === null &&
|
|
1309
|
+
runningProcess.signalCode === null
|
|
1310
|
+
)
|
|
1311
|
+
pendingUpdates.set(runningProcess, stagedBinary)
|
|
1312
|
+
return
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1277
1315
|
term.clearLine()
|
|
1278
1316
|
|
|
1279
1317
|
runningProcess.removeListener('exit', exitListener)
|
|
@@ -1313,6 +1351,33 @@ function createLauncher(productConfig) {
|
|
|
1313
1351
|
}
|
|
1314
1352
|
}
|
|
1315
1353
|
|
|
1354
|
+
function installPendingUpdate(child) {
|
|
1355
|
+
const staged = pendingUpdates.get(child)
|
|
1356
|
+
pendingUpdates.delete(child)
|
|
1357
|
+
if (!staged) return
|
|
1358
|
+
|
|
1359
|
+
try {
|
|
1360
|
+
// A second launcher may have installed a newer release while this
|
|
1361
|
+
// session was open. Never roll its installation back on our exit.
|
|
1362
|
+
const currentVersion = getCurrentVersion()
|
|
1363
|
+
if (
|
|
1364
|
+
currentVersion &&
|
|
1365
|
+
compareVersions(currentVersion, staged.version) >= 0
|
|
1366
|
+
) {
|
|
1367
|
+
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true, force: true })
|
|
1368
|
+
return
|
|
1369
|
+
}
|
|
1370
|
+
installStagedBinary(staged, { quiet: true })
|
|
1371
|
+
console.log(
|
|
1372
|
+
`Updated ${displayName} to ${staged.version}. Ready for your next launch.`,
|
|
1373
|
+
)
|
|
1374
|
+
} catch (error) {
|
|
1375
|
+
// Installation rolls back on failure. Updating must not change the
|
|
1376
|
+
// user's exit code or resurrect a CLI they just closed.
|
|
1377
|
+
console.error(`Could not install ${displayName} update: ${error.message}`)
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1316
1381
|
/**
|
|
1317
1382
|
* Make captured output safe to print back to the terminal.
|
|
1318
1383
|
*
|
|
@@ -1693,6 +1758,7 @@ function createLauncher(productConfig) {
|
|
|
1693
1758
|
exitAlternateScreen: shouldExitAlternateScreen(code, signal),
|
|
1694
1759
|
})
|
|
1695
1760
|
printCrashDiagnostics(code, signal, { msAlive, stderrTail })
|
|
1761
|
+
installPendingUpdate(child)
|
|
1696
1762
|
process.exit(signal ? 1 : code || 0)
|
|
1697
1763
|
}
|
|
1698
1764
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "freebuff",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.198",
|
|
4
4
|
"description": "The world's strongest free coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
"provenance": false
|
|
42
42
|
},
|
|
43
43
|
"binaryChecksums": {
|
|
44
|
-
"linux-x64": "
|
|
45
|
-
"linux-x64-baseline": "
|
|
46
|
-
"linux-arm64": "
|
|
47
|
-
"darwin-x64": "
|
|
48
|
-
"darwin-x64-baseline": "
|
|
49
|
-
"darwin-arm64": "
|
|
50
|
-
"win32-x64": "
|
|
51
|
-
"win32-x64-baseline": "
|
|
44
|
+
"linux-x64": "ff8c4be2a49a89978650230783170a88e7a60bf718e009f475c5e5add3d9bd2c",
|
|
45
|
+
"linux-x64-baseline": "eac98aa596e18082c5b0e24846e3a22556e6e13f0ba8553a95ee294f8f443f0d",
|
|
46
|
+
"linux-arm64": "a1f1bfc3f67227109b2a3a9f1f5c3f6366482b70f0a18eafc7a344016c43ed04",
|
|
47
|
+
"darwin-x64": "f08a41139d778a2f569297bc9ad18202444f71a0a7cb567d86d52508cda68c47",
|
|
48
|
+
"darwin-x64-baseline": "f55359a8d94b0caad28d356a27f11178da2757bf927c2e8f99d7166f814f8246",
|
|
49
|
+
"darwin-arm64": "66dcabc9e0b094726fdcf8bfcd74f4c92066dbc372f5b0f352656c367315caff",
|
|
50
|
+
"win32-x64": "16779f47d82a482e224ab594ef91c062a999444777b26c57ae25cf3443c7aeda",
|
|
51
|
+
"win32-x64-baseline": "8866dc313c2fb6d60e14f04aad9885bf8346c2e384d4b756044475364fa186bc"
|
|
52
52
|
}
|
|
53
53
|
}
|