mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
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:
@@ -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 = {
|
||||
|
||||
@@ -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',
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user