Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ detect_platform() {
*) error "Unsupported OS: $OS" ;;
esac

if [ "$OS" = "darwin" ] && [ "$ARCH" = "x86_64" ] && command -v sysctl >/dev/null 2>&1; then
if [ "$(sysctl -in sysctl.proc_translated 2>/dev/null || true)" = "1" ]; then
ARCH="arm64"
fi
fi

case "$ARCH" in
x86_64|amd64) ARCH="x64" ;;
aarch64|arm64) ARCH="arm64" ;;
Expand Down
56 changes: 56 additions & 0 deletions src/platform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { execFileSync } from 'child_process';
import { arch, platform } from 'os';

export interface RuntimePlatform {
platform: NodeJS.Platform | string;
arch: string;
isTranslated?: boolean;
}

/**
* Rosetta reports the process as x64 even on Apple Silicon. For release
* binaries, choose the native machine architecture so macOS installs can
* replace a translated x64 binary with the arm64 build.
*/
export function resolvePlatformKey(runtime: RuntimePlatform): string {
const p = runtime.platform;
let a = runtime.arch;

if (p === 'darwin' && a === 'x64' && runtime.isTranslated) {
a = 'arm64';
}

if (p === 'darwin') {
return a === 'arm64' ? 'darwin-arm64' : 'darwin-x64';
} else if (p === 'linux') {
return a === 'arm64' ? 'linux-arm64' : 'linux-x64';
} else if (p === 'win32') {
return 'win32-x64';
}

return `${p}-${a}`;
}

function isRosettaTranslated(): boolean {
if (platform() !== 'darwin' || arch() !== 'x64') {
return false;
}

try {
const output = execFileSync('/usr/sbin/sysctl', ['-in', 'sysctl.proc_translated'], {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore'],
}).trim();
return output === '1';
} catch {
return false;
}
}

export function getPlatformKey(): string {
return resolvePlatformKey({
platform: platform(),
arch: arch(),
isTranslated: isRosettaTranslated(),
});
}
24 changes: 24 additions & 0 deletions src/updater.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { resolvePlatformKey } from './platform.ts';

test('resolvePlatformKey: uses arm64 artifact for translated Apple Silicon processes', () => {
assert.equal(
resolvePlatformKey({ platform: 'darwin', arch: 'x64', isTranslated: true }),
'darwin-arm64',
);
});

test('resolvePlatformKey: keeps native Intel macOS on x64 artifact', () => {
assert.equal(
resolvePlatformKey({ platform: 'darwin', arch: 'x64', isTranslated: false }),
'darwin-x64',
);
});

test('resolvePlatformKey: keeps non-macOS platform mapping unchanged', () => {
assert.equal(
resolvePlatformKey({ platform: 'linux', arch: 'arm64', isTranslated: true }),
'linux-arm64',
);
});
21 changes: 2 additions & 19 deletions src/updater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import { existsSync, createWriteStream, unlinkSync, chmodSync, renameSync } from 'fs';
import { join, dirname } from 'path';
import { homedir, platform, arch } from 'os';
import { homedir } from 'os';
import { pipeline } from 'stream/promises';
import { Readable } from 'stream';
import semver from 'semver';
import { VERSION, CYAN, GREEN, YELLOW, RED, RESET, DIM } from './constants.ts';
import { getPlatformKey } from './platform.ts';

const UPDATE_CHECK_FILE = join(homedir(), '.askill', 'last-update-check');
const UPDATE_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
Expand All @@ -28,24 +29,6 @@ export interface AvailableUpdate {
releaseUrl?: string;
}

/**
* Get platform key for download URL
*/
function getPlatformKey(): string {
const p = platform();
const a = arch();

if (p === 'darwin') {
return a === 'arm64' ? 'darwin-arm64' : 'darwin-x64';
} else if (p === 'linux') {
return a === 'arm64' ? 'linux-arm64' : 'linux-x64';
} else if (p === 'win32') {
return 'win32-x64';
}

return `${p}-${a}`;
}

/**
* Check if update check is needed
*/
Expand Down
Loading