@openbuff/cli 1.9.30 → 1.9.31
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 +243 -172
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -213,11 +213,35 @@ function getPostHogConfig() {
|
|
|
213
213
|
return { apiKey, host }
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
const UPDATE_ERROR_CATEGORIES = new Set([
|
|
217
|
+
'platform_check',
|
|
218
|
+
'checksum_manifest',
|
|
219
|
+
'http_download',
|
|
220
|
+
'checksum_verify',
|
|
221
|
+
'extraction',
|
|
222
|
+
])
|
|
223
|
+
|
|
224
|
+
function getUpdateFailureProperties(version, context = {}) {
|
|
225
|
+
const category = UPDATE_ERROR_CATEGORIES.has(context.stage)
|
|
226
|
+
? context.stage
|
|
227
|
+
: 'unknown'
|
|
228
|
+
return {
|
|
229
|
+
distinct_id: 'anonymous-openbuff-release',
|
|
230
|
+
error: category,
|
|
231
|
+
version: version || 'unknown',
|
|
232
|
+
platform: process.platform,
|
|
233
|
+
arch: process.arch,
|
|
234
|
+
...(category === 'http_download' && Number.isInteger(context.statusCode)
|
|
235
|
+
? { statusCode: context.statusCode }
|
|
236
|
+
: {}),
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
216
240
|
/**
|
|
217
241
|
* Track update failure event to PostHog.
|
|
218
242
|
* Fire-and-forget - errors are silently ignored.
|
|
219
243
|
*/
|
|
220
|
-
function trackUpdateFailed(
|
|
244
|
+
function trackUpdateFailed(_errorMessage, version, context = {}) {
|
|
221
245
|
try {
|
|
222
246
|
const posthogConfig = getPostHogConfig()
|
|
223
247
|
if (!posthogConfig) {
|
|
@@ -227,14 +251,7 @@ function trackUpdateFailed(errorMessage, version, context = {}) {
|
|
|
227
251
|
const payload = JSON.stringify({
|
|
228
252
|
api_key: posthogConfig.apiKey,
|
|
229
253
|
event: 'cli.update_openbuff_failed',
|
|
230
|
-
properties:
|
|
231
|
-
distinct_id: `anonymous-${CONFIG.homeDir}`,
|
|
232
|
-
error: errorMessage,
|
|
233
|
-
version: version || 'unknown',
|
|
234
|
-
platform: process.platform,
|
|
235
|
-
arch: process.arch,
|
|
236
|
-
...context,
|
|
237
|
-
},
|
|
254
|
+
properties: getUpdateFailureProperties(version, context),
|
|
238
255
|
timestamp: new Date().toISOString(),
|
|
239
256
|
})
|
|
240
257
|
|
|
@@ -625,21 +642,24 @@ function compareVersions(v1, v2) {
|
|
|
625
642
|
i < Math.max(p1.prerelease.length, p2.prerelease.length);
|
|
626
643
|
i++
|
|
627
644
|
) {
|
|
628
|
-
|
|
629
|
-
|
|
645
|
+
if (i >= p1.prerelease.length) return -1
|
|
646
|
+
if (i >= p2.prerelease.length) return 1
|
|
647
|
+
|
|
648
|
+
const pr1 = p1.prerelease[i]
|
|
649
|
+
const pr2 = p2.prerelease[i]
|
|
630
650
|
|
|
631
|
-
const isNum1 =
|
|
632
|
-
const isNum2 =
|
|
651
|
+
const isNum1 = /^\d+$/.test(pr1)
|
|
652
|
+
const isNum2 = /^\d+$/.test(pr2)
|
|
633
653
|
|
|
634
654
|
if (isNum1 && isNum2) {
|
|
635
|
-
const num1 =
|
|
636
|
-
const num2 =
|
|
655
|
+
const num1 = Number(pr1)
|
|
656
|
+
const num2 = Number(pr2)
|
|
637
657
|
if (num1 < num2) return -1
|
|
638
658
|
if (num1 > num2) return 1
|
|
639
659
|
} else if (isNum1 && !isNum2) {
|
|
640
|
-
return 1
|
|
641
|
-
} else if (!isNum1 && isNum2) {
|
|
642
660
|
return -1
|
|
661
|
+
} else if (!isNum1 && isNum2) {
|
|
662
|
+
return 1
|
|
643
663
|
} else if (pr1 < pr2) {
|
|
644
664
|
return -1
|
|
645
665
|
} else if (pr1 > pr2) {
|
|
@@ -671,8 +691,8 @@ function getReleaseAssetBase(version) {
|
|
|
671
691
|
return `${downloadBase}/v${version}`
|
|
672
692
|
}
|
|
673
693
|
|
|
674
|
-
async function getExpectedChecksum(version, fileName) {
|
|
675
|
-
const checksumResponse = await
|
|
694
|
+
async function getExpectedChecksum(version, fileName, httpGetFn = httpGet) {
|
|
695
|
+
const checksumResponse = await httpGetFn(
|
|
676
696
|
`${getReleaseAssetBase(version)}/SHA256SUMS`,
|
|
677
697
|
)
|
|
678
698
|
if (checksumResponse.statusCode !== 200) {
|
|
@@ -733,8 +753,35 @@ function downloadResponseToFile(response, destination, totalSize) {
|
|
|
733
753
|
})
|
|
734
754
|
}
|
|
735
755
|
|
|
736
|
-
|
|
737
|
-
const
|
|
756
|
+
function assertExtractedRegularFile(extractionDir, filePath) {
|
|
757
|
+
const root = path.resolve(extractionDir)
|
|
758
|
+
const resolved = path.resolve(filePath)
|
|
759
|
+
if (resolved === root || !resolved.startsWith(`${root}${path.sep}`)) {
|
|
760
|
+
throw new Error(`Release archive entry escapes extraction directory: ${filePath}`)
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
let stat
|
|
764
|
+
try {
|
|
765
|
+
stat = fs.lstatSync(resolved)
|
|
766
|
+
} catch (error) {
|
|
767
|
+
if (error.code === 'ENOENT') return false
|
|
768
|
+
throw error
|
|
769
|
+
}
|
|
770
|
+
if (!stat.isFile()) {
|
|
771
|
+
throw new Error(
|
|
772
|
+
`Release archive entry must be a regular file: ${path.basename(filePath)}`,
|
|
773
|
+
)
|
|
774
|
+
}
|
|
775
|
+
return true
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
async function downloadBinary(version, options = {}) {
|
|
779
|
+
const config = options.config || CONFIG
|
|
780
|
+
const httpGetFn = options.httpGet || httpGet
|
|
781
|
+
const extractArchive =
|
|
782
|
+
options.extractArchive || ((tarOptions) => require('tar').x(tarOptions))
|
|
783
|
+
const rename = options.rename || fs.renameSync
|
|
784
|
+
const platformKey = options.platformKey || getPlatformKey()
|
|
738
785
|
const fileName = PLATFORM_TARGETS[platformKey]
|
|
739
786
|
|
|
740
787
|
if (!fileName) {
|
|
@@ -748,160 +795,186 @@ async function downloadBinary(version) {
|
|
|
748
795
|
throw error
|
|
749
796
|
}
|
|
750
797
|
|
|
751
|
-
// Binaries are hosted as GitHub Release assets on the public repo.
|
|
752
|
-
// Public repo → unauthenticated downloads; GitHub 302-redirects to a CDN,
|
|
753
|
-
// and the http.js client follows redirects. OPENBUFF_DOWNLOAD_BASE may
|
|
754
|
-
// override the base (e.g. for staging mirrors).
|
|
755
798
|
const downloadUrl = `${getReleaseAssetBase(version)}/${fileName}`
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
// Clean up any previous temp download directory
|
|
761
|
-
if (fs.existsSync(CONFIG.tempDownloadDir)) {
|
|
762
|
-
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
799
|
+
fs.mkdirSync(config.configDir, { recursive: true })
|
|
800
|
+
if (fs.existsSync(config.tempDownloadDir)) {
|
|
801
|
+
fs.rmSync(config.tempDownloadDir, { recursive: true })
|
|
763
802
|
}
|
|
764
|
-
fs.mkdirSync(
|
|
765
|
-
|
|
803
|
+
fs.mkdirSync(config.tempDownloadDir, { recursive: true })
|
|
766
804
|
term.write('Downloading...')
|
|
767
805
|
|
|
768
|
-
let expectedChecksum
|
|
769
806
|
try {
|
|
770
|
-
expectedChecksum
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
807
|
+
let expectedChecksum
|
|
808
|
+
try {
|
|
809
|
+
expectedChecksum = await getExpectedChecksum(
|
|
810
|
+
version,
|
|
811
|
+
fileName,
|
|
812
|
+
httpGetFn,
|
|
813
|
+
)
|
|
814
|
+
} catch (error) {
|
|
815
|
+
trackUpdateFailed(error.message, version, { stage: 'checksum_manifest' })
|
|
816
|
+
throw error
|
|
817
|
+
}
|
|
776
818
|
|
|
777
|
-
|
|
819
|
+
const res = await httpGetFn(downloadUrl)
|
|
820
|
+
if (res.statusCode !== 200) {
|
|
821
|
+
res.resume()
|
|
822
|
+
const error = new Error(`Download failed: HTTP ${res.statusCode}`)
|
|
823
|
+
trackUpdateFailed(error.message, version, {
|
|
824
|
+
stage: 'http_download',
|
|
825
|
+
statusCode: res.statusCode,
|
|
826
|
+
})
|
|
827
|
+
throw error
|
|
828
|
+
}
|
|
778
829
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
830
|
+
const totalSize = parseInt(res.headers['content-length'] || '0', 10)
|
|
831
|
+
const archivePath = path.join(config.tempDownloadDir, fileName)
|
|
832
|
+
await downloadResponseToFile(res, archivePath, totalSize)
|
|
833
|
+
|
|
834
|
+
const actualChecksum = await hashFile(archivePath)
|
|
835
|
+
if (actualChecksum !== expectedChecksum) {
|
|
836
|
+
const error = new Error(
|
|
837
|
+
`Checksum verification failed for ${fileName}: expected ${expectedChecksum}, received ${actualChecksum}`,
|
|
838
|
+
)
|
|
839
|
+
trackUpdateFailed(error.message, version, { stage: 'checksum_verify' })
|
|
840
|
+
throw error
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
await extractArchive({
|
|
844
|
+
cwd: config.tempDownloadDir,
|
|
845
|
+
file: archivePath,
|
|
846
|
+
preservePaths: false,
|
|
847
|
+
strict: true,
|
|
785
848
|
})
|
|
786
|
-
throw error
|
|
787
|
-
}
|
|
788
849
|
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
850
|
+
const tempBinaryPath = path.join(config.tempDownloadDir, config.binaryName)
|
|
851
|
+
if (!assertExtractedRegularFile(config.tempDownloadDir, tempBinaryPath)) {
|
|
852
|
+
const files = fs.readdirSync(config.tempDownloadDir)
|
|
853
|
+
const error = new Error(
|
|
854
|
+
`Binary not found after extraction. Expected: ${config.binaryName}, Available files: ${files.join(', ')}`,
|
|
855
|
+
)
|
|
856
|
+
trackUpdateFailed(error.message, version, { stage: 'extraction' })
|
|
857
|
+
throw error
|
|
858
|
+
}
|
|
792
859
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
860
|
+
const managedSiblings = getManagedSiblingNames(config.tempDownloadDir)
|
|
861
|
+
.map((name) => ({
|
|
862
|
+
name,
|
|
863
|
+
source: path.join(config.tempDownloadDir, name),
|
|
864
|
+
target: path.join(path.dirname(config.binaryPath), name),
|
|
865
|
+
}))
|
|
866
|
+
.filter(({ source }) =>
|
|
867
|
+
assertExtractedRegularFile(config.tempDownloadDir, source),
|
|
868
|
+
)
|
|
869
|
+
const tempMetadataPath = path.join(
|
|
870
|
+
config.tempDownloadDir,
|
|
871
|
+
path.basename(config.metadataPath),
|
|
798
872
|
)
|
|
799
|
-
|
|
800
|
-
throw error
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
// Extract only after the archive has passed integrity verification.
|
|
804
|
-
const tar = require('tar')
|
|
805
|
-
await tar.x({
|
|
806
|
-
cwd: CONFIG.tempDownloadDir,
|
|
807
|
-
file: archivePath,
|
|
808
|
-
preservePaths: false,
|
|
809
|
-
strict: true,
|
|
810
|
-
})
|
|
873
|
+
assertExtractedRegularFile(config.tempDownloadDir, tempMetadataPath)
|
|
811
874
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
)
|
|
815
|
-
if (extractedAssetProblems.length) {
|
|
816
|
-
throw new Error(
|
|
817
|
-
`Release archive has incomplete tree-sitter assets: ${extractedAssetProblems.join(', ')}`,
|
|
875
|
+
const extractedAssetProblems = getTreeSitterAssetProblems(
|
|
876
|
+
config.tempDownloadDir,
|
|
818
877
|
)
|
|
819
|
-
|
|
878
|
+
if (extractedAssetProblems.length) {
|
|
879
|
+
throw new Error(
|
|
880
|
+
`Release archive has incomplete tree-sitter assets: ${extractedAssetProblems.join(', ')}`,
|
|
881
|
+
)
|
|
882
|
+
}
|
|
820
883
|
|
|
821
|
-
|
|
884
|
+
if (process.platform !== 'win32') fs.chmodSync(tempBinaryPath, 0o755)
|
|
822
885
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
886
|
+
const installFiles = [
|
|
887
|
+
{ source: tempBinaryPath, target: config.binaryPath },
|
|
888
|
+
...managedSiblings,
|
|
889
|
+
]
|
|
890
|
+
fs.writeFileSync(
|
|
891
|
+
tempMetadataPath,
|
|
892
|
+
JSON.stringify({ version, platformKey }, null, 2),
|
|
829
893
|
)
|
|
830
|
-
|
|
831
|
-
throw error
|
|
832
|
-
}
|
|
894
|
+
installFiles.push({ source: tempMetadataPath, target: config.metadataPath })
|
|
833
895
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
896
|
+
for (const file of installFiles) {
|
|
897
|
+
if (process.platform !== 'win32' && file.name === 'rg') {
|
|
898
|
+
fs.chmodSync(file.source, 0o755)
|
|
899
|
+
}
|
|
900
|
+
}
|
|
838
901
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
fs.
|
|
844
|
-
|
|
845
|
-
// Fallback: try renaming the locked/undeletable binary (Windows)
|
|
846
|
-
const backupPath = CONFIG.binaryPath + `.old.${Date.now()}`
|
|
902
|
+
const committed = []
|
|
903
|
+
try {
|
|
904
|
+
for (const [index, file] of installFiles.entries()) {
|
|
905
|
+
const backup = `${file.target}.rollback-${process.pid}-${index}`
|
|
906
|
+
const hadExisting = fs.existsSync(file.target)
|
|
907
|
+
if (hadExisting) rename(file.target, backup)
|
|
847
908
|
try {
|
|
848
|
-
|
|
849
|
-
} catch (
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
`unlink error: ${err.code || err.message}, ` +
|
|
853
|
-
`rename error: ${renameErr.code || renameErr.message}`,
|
|
854
|
-
)
|
|
909
|
+
rename(file.source, file.target)
|
|
910
|
+
} catch (error) {
|
|
911
|
+
if (hadExisting && fs.existsSync(backup)) rename(backup, file.target)
|
|
912
|
+
throw error
|
|
855
913
|
}
|
|
914
|
+
committed.push({ ...file, backup: hadExisting ? backup : null })
|
|
856
915
|
}
|
|
916
|
+
} catch (error) {
|
|
917
|
+
for (const file of committed.reverse()) {
|
|
918
|
+
if (fs.existsSync(file.target)) fs.unlinkSync(file.target)
|
|
919
|
+
if (file.backup && fs.existsSync(file.backup)) {
|
|
920
|
+
fs.renameSync(file.backup, file.target)
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
throw error
|
|
857
924
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
// This includes the parser runtime, all language grammar WASMs, and
|
|
862
|
-
// legacy native/ripgrep assets. Deriving the grammar list from the
|
|
863
|
-
// archive keeps the installer aligned with the build manifest.
|
|
864
|
-
for (const siblingName of getManagedSiblingNames(CONFIG.tempDownloadDir)) {
|
|
865
|
-
const tempSiblingPath = path.join(CONFIG.tempDownloadDir, siblingName)
|
|
866
|
-
if (!fs.existsSync(tempSiblingPath)) continue
|
|
867
|
-
const targetSiblingPath = path.join(
|
|
868
|
-
path.dirname(CONFIG.binaryPath),
|
|
869
|
-
siblingName,
|
|
870
|
-
)
|
|
925
|
+
|
|
926
|
+
for (const file of committed) {
|
|
927
|
+
if (!file.backup) continue
|
|
871
928
|
try {
|
|
872
|
-
|
|
929
|
+
fs.unlinkSync(file.backup)
|
|
873
930
|
} catch {
|
|
874
|
-
//
|
|
875
|
-
}
|
|
876
|
-
fs.renameSync(tempSiblingPath, targetSiblingPath)
|
|
877
|
-
if (process.platform !== 'win32' && siblingName === 'rg') {
|
|
878
|
-
fs.chmodSync(targetSiblingPath, 0o755)
|
|
931
|
+
// A stale backup is harmless and can be removed on a later launch.
|
|
879
932
|
}
|
|
880
933
|
}
|
|
881
934
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
CONFIG.metadataPath,
|
|
885
|
-
JSON.stringify({ version, platformKey }, null, 2),
|
|
886
|
-
)
|
|
935
|
+
term.clearLine()
|
|
936
|
+
console.log('Download complete! Starting Openbuff...')
|
|
887
937
|
} finally {
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
938
|
+
if (fs.existsSync(config.tempDownloadDir)) {
|
|
939
|
+
fs.rmSync(config.tempDownloadDir, { recursive: true })
|
|
891
940
|
}
|
|
892
941
|
}
|
|
942
|
+
}
|
|
893
943
|
|
|
894
|
-
|
|
895
|
-
|
|
944
|
+
function printInstallFailureGuidance(resolveProxyUrl, logError) {
|
|
945
|
+
logError('Please check your internet connection and try again')
|
|
946
|
+
if (!resolveProxyUrl()) {
|
|
947
|
+
logError('If you are behind a proxy, set the HTTPS_PROXY environment variable')
|
|
948
|
+
}
|
|
896
949
|
}
|
|
897
950
|
|
|
898
|
-
async function ensureBinaryExists() {
|
|
899
|
-
const
|
|
951
|
+
async function ensureBinaryExists(options = {}) {
|
|
952
|
+
const config = options.config || CONFIG
|
|
953
|
+
const logError = options.consoleError || console.error
|
|
954
|
+
const resolveProxyUrl = options.getProxyUrl || getProxyUrl
|
|
955
|
+
const exit = options.exit || process.exit
|
|
956
|
+
const currentVersion =
|
|
957
|
+
options.currentVersion === undefined
|
|
958
|
+
? getCurrentVersion()
|
|
959
|
+
: options.currentVersion
|
|
900
960
|
const assetProblems = currentVersion
|
|
901
|
-
? getTreeSitterAssetProblems(
|
|
961
|
+
? getTreeSitterAssetProblems(config.configDir)
|
|
902
962
|
: []
|
|
903
|
-
|
|
904
|
-
|
|
963
|
+
let pendingVersion = options.pendingVersion
|
|
964
|
+
if (pendingVersion === undefined) {
|
|
965
|
+
try {
|
|
966
|
+
pendingVersion = fs.existsSync(config.metadataPath)
|
|
967
|
+
? JSON.parse(fs.readFileSync(config.metadataPath, 'utf8'))
|
|
968
|
+
.pendingVersion || null
|
|
969
|
+
: null
|
|
970
|
+
} catch {
|
|
971
|
+
pendingVersion = null
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
const packagedVersion =
|
|
975
|
+
options.packagedVersion === undefined
|
|
976
|
+
? getLocalPackageVersion()
|
|
977
|
+
: options.packagedVersion
|
|
905
978
|
const packagedUpdate =
|
|
906
979
|
packagedVersion &&
|
|
907
980
|
(currentVersion === null ||
|
|
@@ -913,60 +986,54 @@ async function ensureBinaryExists() {
|
|
|
913
986
|
packagedUpdate ||
|
|
914
987
|
(assetProblems.length ? currentVersion : null)
|
|
915
988
|
|
|
916
|
-
if (currentVersion !== null && !requestedVersion)
|
|
917
|
-
return
|
|
918
|
-
}
|
|
989
|
+
if (currentVersion !== null && !requestedVersion) return
|
|
919
990
|
|
|
920
991
|
if (assetProblems.length) {
|
|
921
|
-
|
|
992
|
+
logError(
|
|
922
993
|
`Repairing incomplete tree-sitter assets: ${assetProblems.join(', ')}`,
|
|
923
994
|
)
|
|
924
995
|
}
|
|
925
996
|
|
|
926
|
-
const version =
|
|
997
|
+
const version =
|
|
998
|
+
requestedVersion ||
|
|
999
|
+
(await (options.getLatestVersion || getLatestVersion)())
|
|
927
1000
|
if (!version) {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
console.error(
|
|
932
|
-
'If you are behind a proxy, set the HTTPS_PROXY environment variable',
|
|
933
|
-
)
|
|
934
|
-
}
|
|
935
|
-
process.exit(1)
|
|
1001
|
+
logError('❌ Failed to determine latest version')
|
|
1002
|
+
printInstallFailureGuidance(resolveProxyUrl, logError)
|
|
1003
|
+
exit(1)
|
|
936
1004
|
}
|
|
937
1005
|
|
|
1006
|
+
const download =
|
|
1007
|
+
options.downloadBinary ||
|
|
1008
|
+
((requestedVersion) => downloadBinary(requestedVersion, { config }))
|
|
938
1009
|
try {
|
|
939
|
-
await
|
|
1010
|
+
await download(version)
|
|
940
1011
|
} catch (error) {
|
|
941
1012
|
term.clearLine()
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
console.error(
|
|
946
|
-
'If you are behind a proxy, set the HTTPS_PROXY environment variable',
|
|
947
|
-
)
|
|
948
|
-
}
|
|
949
|
-
process.exit(1)
|
|
1013
|
+
logError('❌ Failed to download openbuff:', error.message)
|
|
1014
|
+
printInstallFailureGuidance(resolveProxyUrl, logError)
|
|
1015
|
+
exit(1)
|
|
950
1016
|
}
|
|
951
1017
|
}
|
|
952
1018
|
|
|
953
|
-
async function checkForUpdates() {
|
|
1019
|
+
async function checkForUpdates(options = {}) {
|
|
954
1020
|
try {
|
|
955
|
-
const currentVersion =
|
|
956
|
-
|
|
957
|
-
|
|
1021
|
+
const currentVersion =
|
|
1022
|
+
options.currentVersion === undefined
|
|
1023
|
+
? getCurrentVersion()
|
|
1024
|
+
: options.currentVersion
|
|
1025
|
+
const latestVersion = await (
|
|
1026
|
+
options.getLatestVersion || getLatestVersion
|
|
1027
|
+
)()
|
|
958
1028
|
if (!latestVersion) return
|
|
959
1029
|
|
|
960
1030
|
if (
|
|
961
|
-
// Download new version if current version is unknown or outdated.
|
|
962
1031
|
currentVersion === null ||
|
|
963
1032
|
compareVersions(currentVersion, latestVersion) < 0
|
|
964
1033
|
) {
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
)
|
|
969
|
-
writePendingUpdateVersion(latestVersion)
|
|
1034
|
+
const persistPending =
|
|
1035
|
+
options.writePendingUpdateVersion || writePendingUpdateVersion
|
|
1036
|
+
persistPending(latestVersion)
|
|
970
1037
|
}
|
|
971
1038
|
} catch (error) {
|
|
972
1039
|
trackUpdateFailed(error.message, null, { stage: 'background_check' })
|
|
@@ -1082,11 +1149,15 @@ if (require.main === module) {
|
|
|
1082
1149
|
}
|
|
1083
1150
|
|
|
1084
1151
|
module.exports = {
|
|
1152
|
+
checkForUpdates,
|
|
1085
1153
|
cleanupOldBinaryBackups,
|
|
1086
1154
|
compareVersions,
|
|
1155
|
+
downloadBinary,
|
|
1156
|
+
ensureBinaryExists,
|
|
1087
1157
|
getIllegalInstructionGuidance,
|
|
1088
1158
|
getManagedSiblingNames,
|
|
1089
1159
|
getTreeSitterAssetProblems,
|
|
1160
|
+
getUpdateFailureProperties,
|
|
1090
1161
|
parseExpectedChecksum,
|
|
1091
1162
|
parseLinuxCpuInfo,
|
|
1092
1163
|
resolveConfigDir,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openbuff/cli",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.31",
|
|
4
4
|
"description": "An AI coding agent that writes code for you. Run it from your project directory, tell it what to do, and it reads and writes files, runs commands, and iterates until the task is done. Supports sub-agents, custom tools, and Bring-Your-Own-Key providers.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|