182 lines
6.2 KiB
TypeScript
182 lines
6.2 KiB
TypeScript
import { defineConfig } from 'electron-vite'
|
|
import { sentryVitePlugin } from '@sentry/vite-plugin'
|
|
import react from '@vitejs/plugin-react'
|
|
import { readFileSync } from 'fs'
|
|
import { resolve } from 'path'
|
|
import type { Plugin } from 'vite'
|
|
|
|
// Read all production dependencies from package.json
|
|
// so they get bundled into the main process output.
|
|
// This avoids pnpm symlink issues with electron-builder's asar packaging.
|
|
const pkg = JSON.parse(readFileSync(resolve(__dirname, 'package.json'), 'utf-8'))
|
|
const prodDeps = Object.keys(pkg.dependencies || {})
|
|
|
|
// Fastify and its plugins rely on runtime module resolution that breaks when bundled.
|
|
const runtimeExternalDeps = new Set([
|
|
'node-pty',
|
|
'agent-teams-controller',
|
|
'fastify',
|
|
'@fastify/cors',
|
|
'@fastify/static',
|
|
])
|
|
|
|
// node-pty is a native addon that cannot be bundled by Rollup.
|
|
// It must remain external and be loaded at runtime via require().
|
|
const bundledDeps = prodDeps.filter(d => !runtimeExternalDeps.has(d))
|
|
|
|
// Rollup plugin: stub out native .node addon imports with empty modules.
|
|
// ssh2 and cpu-features use optional native bindings that can't be bundled,
|
|
// but they have pure JS fallbacks when the native module isn't available.
|
|
function nativeModuleStub(): Plugin {
|
|
const STUB_ID = '\0native-stub'
|
|
const NODE_MODULE_RE = /\.node(?:\?.*)?$/
|
|
return {
|
|
name: 'native-module-stub',
|
|
enforce: 'pre',
|
|
resolveId(source) {
|
|
if (NODE_MODULE_RE.test(source)) return `${STUB_ID}:${source}`
|
|
return null
|
|
},
|
|
load(id) {
|
|
if (id.startsWith(STUB_ID) || NODE_MODULE_RE.test(id)) return 'export default {}'
|
|
return null
|
|
}
|
|
}
|
|
}
|
|
|
|
const sentrySourceMapTargets = {
|
|
main: {
|
|
assets: ['./dist-electron/main/**/*.{js,cjs,mjs,map}'],
|
|
filesToDeleteAfterUpload: ['./dist-electron/main/**/*.map'],
|
|
},
|
|
renderer: {
|
|
assets: ['./out/renderer/**/*.{js,cjs,mjs,map}'],
|
|
filesToDeleteAfterUpload: ['./out/renderer/**/*.map'],
|
|
},
|
|
} as const
|
|
|
|
const sourceMapSetting = process.env.AGENT_TEAMS_DISABLE_SOURCEMAPS === '1' ? false : 'hidden'
|
|
|
|
// Sentry source map upload - only active in CI when SENTRY_AUTH_TOKEN is set.
|
|
function createSentryPlugins(target: keyof typeof sentrySourceMapTargets): Plugin[] {
|
|
if (!process.env.SENTRY_AUTH_TOKEN) return []
|
|
|
|
return [
|
|
sentryVitePlugin({
|
|
org: process.env.SENTRY_ORG ?? 'quant-jump-pro',
|
|
project: process.env.SENTRY_PROJECT ?? 'electron',
|
|
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
telemetry: false,
|
|
release: { name: `agent-teams-ai@${pkg.version}` },
|
|
sourcemaps: sentrySourceMapTargets[target],
|
|
}) as Plugin,
|
|
]
|
|
}
|
|
|
|
export default defineConfig({
|
|
main: {
|
|
plugins: [
|
|
nativeModuleStub(),
|
|
...createSentryPlugins('main'),
|
|
],
|
|
define: {
|
|
__APP_VERSION__: JSON.stringify(pkg.version),
|
|
// Inject DSN at compile time - process.env.SENTRY_DSN is NOT available
|
|
// at runtime in packaged Electron apps (only during CI build).
|
|
'process.env.SENTRY_DSN': JSON.stringify(process.env.SENTRY_DSN ?? ''),
|
|
},
|
|
resolve: {
|
|
alias: {
|
|
'@features': resolve(__dirname, 'src/features'),
|
|
'@main': resolve(__dirname, 'src/main'),
|
|
'@shared': resolve(__dirname, 'src/shared'),
|
|
'@preload': resolve(__dirname, 'src/preload')
|
|
}
|
|
},
|
|
build: {
|
|
externalizeDeps: {
|
|
exclude: bundledDeps
|
|
},
|
|
commonjsOptions: {
|
|
strictRequires: [/node_modules\/.*ssh2\//],
|
|
},
|
|
sourcemap: sourceMapSetting,
|
|
outDir: 'dist-electron/main',
|
|
rollupOptions: {
|
|
input: {
|
|
index: resolve(__dirname, 'src/main/index.ts'),
|
|
'team-fs-worker': resolve(__dirname, 'src/main/workers/team-fs-worker.ts'),
|
|
'task-change-worker': resolve(__dirname, 'src/main/workers/task-change-worker.ts'),
|
|
'team-data-worker': resolve(__dirname, 'src/main/workers/team-data-worker.ts')
|
|
},
|
|
output: {
|
|
// CJS format so bundled deps can use __dirname/require.
|
|
// Use .cjs extension since package.json has "type": "module".
|
|
format: 'cjs',
|
|
entryFileNames: '[name].cjs',
|
|
// Set UV_THREADPOOL_SIZE before any module code runs.
|
|
// Must be in the banner because ESM→CJS hoists imports above top-level code.
|
|
// On Windows, fs.watch({recursive:true}) occupies a UV pool thread per watcher;
|
|
// with 3+ watchers + concurrent fs/DNS/spawn, the default 4 threads deadlock.
|
|
banner: `if(!process.env.UV_THREADPOOL_SIZE){process.env.UV_THREADPOOL_SIZE='24'}`
|
|
}
|
|
}
|
|
}
|
|
},
|
|
preload: {
|
|
resolve: {
|
|
alias: {
|
|
'@features': resolve(__dirname, 'src/features'),
|
|
'@preload': resolve(__dirname, 'src/preload'),
|
|
'@shared': resolve(__dirname, 'src/shared'),
|
|
'@main': resolve(__dirname, 'src/main')
|
|
}
|
|
},
|
|
build: {
|
|
outDir: 'dist-electron/preload',
|
|
rollupOptions: {
|
|
input: {
|
|
index: resolve(__dirname, 'src/preload/index.ts')
|
|
},
|
|
output: {
|
|
format: 'cjs',
|
|
entryFileNames: '[name].js'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
renderer: {
|
|
cacheDir: resolve(__dirname, 'node_modules/.vite/electron-renderer'),
|
|
optimizeDeps: {
|
|
include: ['@codemirror/language-data'],
|
|
exclude: ['@claude-teams/agent-graph']
|
|
},
|
|
define: {
|
|
__APP_VERSION__: JSON.stringify(pkg.version),
|
|
// Pass SENTRY_DSN to renderer as VITE_SENTRY_DSN (Vite replaces at compile time)
|
|
'import.meta.env.VITE_SENTRY_DSN': JSON.stringify(process.env.SENTRY_DSN ?? ''),
|
|
},
|
|
resolve: {
|
|
alias: {
|
|
'@features': resolve(__dirname, 'src/features'),
|
|
'@renderer': resolve(__dirname, 'src/renderer'),
|
|
'@shared': resolve(__dirname, 'src/shared'),
|
|
'@main': resolve(__dirname, 'src/main'),
|
|
'@radix-ui/react-compose-refs': resolve(
|
|
__dirname,
|
|
'src/renderer/vendor/radixComposeRefs.ts'
|
|
),
|
|
'@claude-teams/agent-graph': resolve(__dirname, 'packages/agent-graph/src/index.ts')
|
|
}
|
|
},
|
|
plugins: [react(), ...createSentryPlugins('renderer')],
|
|
build: {
|
|
sourcemap: sourceMapSetting,
|
|
rollupOptions: {
|
|
input: {
|
|
index: resolve(__dirname, 'src/renderer/index.html')
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|