-
Notifications
You must be signed in to change notification settings - Fork 3
CLI fixes #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
CLI fixes #8
Changes from 3 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
395c7eb
trip
batuhan 0579747
Update e2e-staging.ts
batuhan b5bb45d
wip
batuhan d68362b
wip
batuhan 8672798
Fix CLI binary release repository
batuhan 3faaa2c
Cap CLI binary download redirects
batuhan c8b07e6
Stream cloudflared downloads to disk
batuhan bb462ab
Stream installer downloads to disk
batuhan 90d74cf
Resolve publish package directories portably
batuhan c5b5d9b
Avoid redundant release package build
batuhan dcfbd0e
Require numeric bridge selection input
batuhan dcf2766
Escape README flag option pipes
batuhan c621fd4
Type chats start request payload
batuhan 46ac66e
Fix recovery key reset statement spacing
batuhan f814888
Persist remote setup after auth succeeds
batuhan df05cc9
Honor setup install channel flags
batuhan 325e8b1
Guard desktop Linux binary probing
batuhan 0e5e42b
Require complete local desktop readiness
batuhan ddd2945
Restrict restart coverage to server targets
batuhan e4d1226
Add command alias support to CLI generator
batuhan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| #!/usr/bin/env bun | ||
| import { execute } from '@oclif/core' | ||
| import { renderStartupLogo } from './logo.js' | ||
|
|
||
| void (async () => { | ||
| if (process.argv.slice(2).length === 0 && process.env.BEEPER_NO_LOGO !== '1') { | ||
| process.stdout.write(`${renderStartupLogo()}\n\n`) | ||
| } | ||
|
|
||
| await execute({ dir: import.meta.url }) | ||
| })() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,118 @@ | ||
| #!/usr/bin/env bun | ||
| import { execute } from '@oclif/core' | ||
| import { renderStartupLogo } from './logo.js' | ||
| #!/usr/bin/env node | ||
| import { createHash } from 'node:crypto' | ||
| import { createWriteStream, existsSync } from 'node:fs' | ||
| import { chmod, mkdir, readFile, rename, rm } from 'node:fs/promises' | ||
| import { get } from 'node:https' | ||
| import { homedir, tmpdir } from 'node:os' | ||
| import { basename, dirname, join } from 'node:path' | ||
| import { pipeline } from 'node:stream/promises' | ||
| import { fileURLToPath } from 'node:url' | ||
| import { spawn } from 'node:child_process' | ||
|
|
||
| void (async () => { | ||
| if (process.argv.slice(2).length === 0 && process.env.BEEPER_NO_LOGO !== '1') { | ||
| process.stdout.write(`${renderStartupLogo()}\n\n`) | ||
| const packageRoot = dirname(dirname(fileURLToPath(import.meta.url))) | ||
| const pkg = JSON.parse(await readFile(join(packageRoot, 'package.json'), 'utf8')) | ||
| const version = pkg.version | ||
| const platform = normalizePlatform(process.platform) | ||
| const arch = normalizeArch(process.arch) | ||
| const extension = platform === 'windows' ? '.exe' : '' | ||
| const executableName = `beeper-${platform}-${arch}${extension}` | ||
| const releaseTag = process.env.BEEPER_CLI_RELEASE_TAG || `v${version}` | ||
| const releaseBaseURL = (process.env.BEEPER_CLI_RELEASE_BASE_URL || `https://github.com/beeper/desktop-api-cli/releases/download/${releaseTag}`).replace(/\/$/, '') | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| const cacheRoot = process.env.BEEPER_CLI_BINARY_CACHE_DIR || join(homedir(), '.cache', 'beeper-cli') | ||
| const cacheDir = join(cacheRoot, version, `${platform}-${arch}`) | ||
| const cachedExecutable = join(cacheDir, platform === 'windows' ? 'beeper.exe' : 'beeper') | ||
|
|
||
| try { | ||
| const executable = await ensureExecutable() | ||
| const child = spawn(executable, process.argv.slice(2), { | ||
| env: process.env, | ||
| stdio: 'inherit', | ||
| }) | ||
| child.once('exit', (code, signal) => { | ||
| if (signal) process.kill(process.pid, signal) | ||
| process.exit(code ?? 1) | ||
| }) | ||
| child.once('error', error => { | ||
| console.error(`beeper-cli: failed to start downloaded binary: ${error.message}`) | ||
| process.exit(1) | ||
| }) | ||
| } catch (error) { | ||
| console.error(`beeper-cli: ${error instanceof Error ? error.message : String(error)}`) | ||
| process.exit(1) | ||
| } | ||
|
|
||
| async function ensureExecutable() { | ||
| if (existsSync(cachedExecutable)) return cachedExecutable | ||
|
|
||
| await mkdir(cacheDir, { recursive: true }) | ||
| const tmpPath = join(tmpdir(), `${executableName}.${process.pid}.${Date.now()}.download`) | ||
| const url = `${releaseBaseURL}/${executableName}` | ||
| console.error(`beeper-cli: downloading ${url}`) | ||
| await download(url, tmpPath) | ||
|
|
||
| const expectedHash = await fetchExpectedHash().catch(() => undefined) | ||
| if (expectedHash) { | ||
| const actualHash = await sha256(tmpPath) | ||
| if (actualHash !== expectedHash) { | ||
| await rm(tmpPath, { force: true }) | ||
| throw new Error(`downloaded binary checksum mismatch for ${executableName}`) | ||
| } | ||
| } else if (process.env.BEEPER_CLI_REQUIRE_CHECKSUM === '1') { | ||
| await rm(tmpPath, { force: true }) | ||
| throw new Error(`no checksum found for ${executableName}`) | ||
| } | ||
|
|
||
| if (platform !== 'windows') await chmod(tmpPath, 0o755) | ||
| await rename(tmpPath, cachedExecutable) | ||
| return cachedExecutable | ||
| } | ||
|
|
||
| function normalizePlatform(value) { | ||
| if (value === 'darwin') return 'darwin' | ||
| if (value === 'linux') return 'linux' | ||
| if (value === 'win32') return 'windows' | ||
| throw new Error(`unsupported platform: ${value}`) | ||
| } | ||
|
|
||
| function normalizeArch(value) { | ||
| if (value === 'x64') return 'x64' | ||
| if (value === 'arm64') return 'arm64' | ||
| throw new Error(`unsupported architecture: ${value}`) | ||
| } | ||
|
|
||
| async function fetchExpectedHash() { | ||
| const manifestURL = `${releaseBaseURL}/binaries.json` | ||
| const manifestPath = join(tmpdir(), `beeper-cli-binaries-${version}-${process.pid}-${Date.now()}.json`) | ||
| try { | ||
| await download(manifestURL, manifestPath, { quiet: true }) | ||
| const manifest = JSON.parse(await readFile(manifestPath, 'utf8')) | ||
| return manifest.artifacts?.find(artifact => artifact.file === executableName)?.sha256 | ||
| } finally { | ||
| await rm(manifestPath, { force: true }) | ||
| } | ||
| } | ||
|
|
||
| async function download(url, destination, options = {}) { | ||
| await mkdir(dirname(destination), { recursive: true }) | ||
| await new Promise((resolve, reject) => { | ||
| const request = get(url, response => { | ||
| if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) { | ||
| response.resume() | ||
| download(new URL(response.headers.location, url).toString(), destination, options).then(resolve, reject) | ||
| return | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| if (response.statusCode !== 200) { | ||
| response.resume() | ||
| reject(new Error(`download failed for ${basename(url)}: HTTP ${response.statusCode}`)) | ||
| return | ||
| } | ||
| pipeline(response, createWriteStream(destination)).then(resolve, reject) | ||
| }) | ||
| request.once('error', reject) | ||
| request.setTimeout(120_000, () => request.destroy(new Error(`download timed out: ${url}`))) | ||
| }) | ||
| } | ||
|
|
||
| await execute({ dir: import.meta.url }) | ||
| })() | ||
| async function sha256(path) { | ||
| return createHash('sha256').update(await readFile(path)).digest('hex') | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.