feat(browser, terminal): implement browser driver, password manager, terminal features (#6196)

* icon styling

* feat(desktop): isolate chat browser and terminal sessions

* feat(desktop): uncap browser and terminal tabs

* feat(desktop): polish browser and terminal resources

* improvement desktop

* fixes

* updates

* fixes

* fix

* update tests
This commit is contained in:
Siddharth Ganesan
2026-08-03 16:00:04 -07:00
committed by GitHub
parent 3de63c94e3
commit 5ab5f2c7ed
213 changed files with 27752 additions and 4081 deletions
+6 -15
View File
@@ -1,5 +1,6 @@
import { copyFileSync } from 'node:fs'
import { cpSync, rmSync } from 'node:fs'
import { build } from 'esbuild'
import { identityForOrigin } from './channels'
const watch = process.argv.includes('--watch')
@@ -23,20 +24,10 @@ if (bakedDefaultOrigin) {
console.log(`• Baking default server origin: ${bakedDefaultOrigin}`)
}
/** Selects the branded app icon that matches the build's baked environment. */
function iconForOrigin(origin: string): string {
if (!origin) return 'build/icon.icns'
const host = new URL(origin).hostname.toLowerCase()
if (host === 'localhost' || host === '127.0.0.1') return 'build/icon-local.icns'
if (host === 'dev.sim.ai' || host.endsWith('.dev.sim.ai')) return 'build/icon-dev.icns'
if (host === 'staging.sim.ai' || host.endsWith('.staging.sim.ai')) {
return 'build/icon-staging.icns'
}
return 'build/icon.icns'
}
const appIcon = iconForOrigin(bakedDefaultOrigin)
copyFileSync(appIcon, 'build/generated-icon.icns')
const appIcon = identityForOrigin(bakedDefaultOrigin).icon
const generatedIcon = 'build/generated-icon.icon'
rmSync(generatedIcon, { force: true, recursive: true })
cpSync(appIcon, generatedIcon, { recursive: true })
console.log(`• Selecting desktop icon: ${appIcon}`)
const common = {
+6
View File
@@ -23,6 +23,8 @@ export interface ChannelIdentity {
appId: string
/** Baked default origin + persisted settings origin. */
origin: string
/** Native Icon Composer source copied into the packager's generated path. */
icon: string
/**
* Artifact filename stem, and the per-channel scratch directory name.
* Space-free for the same reason electron-builder.yml's artifactName is:
@@ -36,24 +38,28 @@ export const PROD: ChannelIdentity = {
name: 'Sim',
appId: 'ai.sim.desktop',
origin: PROD_ORIGIN,
icon: 'build/icon.icon',
slug: 'sim',
}
export const STAGING: ChannelIdentity = {
name: 'Sim Staging',
appId: 'ai.sim.desktop.staging',
origin: STAGING_ORIGIN,
icon: 'build/icon-staging.icon',
slug: 'sim-staging',
}
export const DEV: ChannelIdentity = {
name: 'Sim Dev',
appId: 'ai.sim.desktop.dev',
origin: DEV_ORIGIN,
icon: 'build/icon-dev.icon',
slug: 'sim-dev',
}
export const LOCAL: ChannelIdentity = {
name: 'Sim Local',
appId: 'ai.sim.desktop.local',
origin: LOCAL_ORIGIN,
icon: 'build/icon-local.icon',
slug: 'sim-local',
}
+12
View File
@@ -59,6 +59,9 @@ const identity = channelFlags.length === 1 ? CHANNEL_FLAGS[channelFlags[0]] : DE
const APP_NAME = `${identity.name}.app`
const INSTALL_PATH = `/Applications/${APP_NAME}`
const RELEASE_DIRS = ['release/mac-universal', 'release/mac-arm64', 'release/mac']
const LOCAL_BUILD_VERSION = Math.floor(Date.now() / 1000).toString()
const LAUNCH_SERVICES_REGISTER =
'/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister'
/** Matches the app's userData path (app.setName(...) in src/main/index.ts). */
const SETTINGS_PATH = join(homedir(), `Library/Application Support/${identity.name}/settings.json`)
@@ -121,6 +124,13 @@ function applyOrigin(origin: string): void {
}
}
function refreshInstalledIcon(): void {
run('touch', [INSTALL_PATH])
if (existsSync(LAUNCH_SERVICES_REGISTER)) {
run(LAUNCH_SERVICES_REGISTER, ['-f', INSTALL_PATH])
}
}
console.log(`• Packaging ${identity.name} from the current checkout…`)
run(
'bun',
@@ -148,6 +158,7 @@ run('bunx', [
'-c.mac.timestamp=none',
`-c.productName=${identity.name}`,
`-c.appId=${identity.appId}`,
`-c.buildVersion=${LOCAL_BUILD_VERSION}`,
])
const builtApp = RELEASE_DIRS.map((dir) => join(dir, APP_NAME)).find(existsSync)
@@ -169,6 +180,7 @@ console.log(`• Installing ${builtApp} → ${INSTALL_PATH}`)
rmSync(INSTALL_PATH, { recursive: true, force: true })
// ditto preserves the code signature and extended attributes, unlike cp.
run('ditto', [builtApp, INSTALL_PATH])
refreshInstalledIcon()
if (identity.origin) {
applyOrigin(identity.origin)
+1 -1
View File
@@ -23,7 +23,7 @@
* naming itself "Sim Dev" at runtime.
*
* Channels build ONE AT A TIME on purpose. scripts/build.ts writes the bundle
* to dist/ and the app icon to build/generated-icon.icns, both fixed paths, so
* to dist/ and the app icon to build/generated-icon.icon, both fixed paths, so
* concurrent channels would overwrite each other's bundle mid-package and ship
* a dmg whose baked origin belongs to a different environment — invisible until
* someone signs in. Giving each channel its own bundle directory is what would