Skip to content

Commit 2385412

Browse files
authored
Merge pull request #8 from tyom/fix-packaging
Add dev mode for bots and fix production bot spawning
2 parents 9547484 + d61b5f4 commit 2385412

File tree

2 files changed

+102
-15
lines changed

2 files changed

+102
-15
lines changed

apps/electron/electron.js

Lines changed: 99 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,7 @@ function getEmulatorConfig() {
203203
if (useDevServer) {
204204
// Dev mode: run the Slack plugin's server directly
205205
// The server/index.ts has `if (import.meta.main)` to run when executed directly
206-
const slackPackageDir = path.join(
207-
appRoot,
208-
'..',
209-
'..',
210-
'packages',
211-
'slack'
212-
)
206+
const slackPackageDir = path.join(appRoot, '..', '..', 'packages', 'slack')
213207
return {
214208
type: 'bun',
215209
bunPath: 'bun',
@@ -256,15 +250,98 @@ function readBotsManifest() {
256250
}
257251
}
258252

253+
/**
254+
* Read bots.json and resolve dev-mode configs (run from source via bun).
255+
* Mirrors the resolution logic in compile-bots.ts.
256+
*/
257+
function readBotsJsonDev() {
258+
const botsJsonPath = path.join(appRoot, 'bots.json')
259+
if (!fs.existsSync(botsJsonPath)) {
260+
electronLogger.info('No bots.json found for dev mode')
261+
return []
262+
}
263+
264+
let config
265+
try {
266+
config = JSON.parse(fs.readFileSync(botsJsonPath, 'utf-8'))
267+
} catch (err) {
268+
electronLogger.error({ err }, 'Failed to parse bots.json')
269+
return []
270+
}
271+
272+
const entries = config.bots ?? []
273+
const results = []
274+
275+
for (const entry of entries) {
276+
const source = typeof entry === 'string' ? entry : entry.source
277+
if (!source) {
278+
electronLogger.error({ entry }, 'Bot entry missing source path')
279+
continue
280+
}
281+
const sourcePath = path.resolve(appRoot, source)
282+
const entryFile =
283+
(typeof entry === 'object' ? entry.entry : undefined) ?? 'src/app.ts'
284+
285+
// Determine bot name: explicit override or from config.yaml simulator.id
286+
let name
287+
if (typeof entry === 'object' && entry.name) {
288+
name = entry.name
289+
} else {
290+
const configYamlPath = path.join(sourcePath, 'config.yaml')
291+
if (fs.existsSync(configYamlPath)) {
292+
const yamlContent = fs.readFileSync(configYamlPath, 'utf-8')
293+
const match = yamlContent.match(/^simulator:\s*\n\s+id:\s*(.+)/m)
294+
if (match) {
295+
name = match[1].trim()
296+
}
297+
}
298+
}
299+
300+
if (!name) {
301+
electronLogger.error(
302+
{ source },
303+
'Cannot determine bot name (no name override and no simulator.id in config.yaml)'
304+
)
305+
continue
306+
}
307+
308+
const script = path.join(sourcePath, entryFile)
309+
if (!fs.existsSync(script)) {
310+
electronLogger.error({ script }, 'Bot entry point not found')
311+
continue
312+
}
313+
314+
results.push({
315+
type: 'bun',
316+
bunPath: 'bun',
317+
script,
318+
cwd: sourcePath,
319+
name,
320+
})
321+
}
322+
323+
return results
324+
}
325+
259326
/**
260327
* Get bot configurations for starting
261-
* Reads from manifest.json generated by compile-bots.ts
262-
* Returns configs for compiled binaries
328+
* In dev mode: reads bots.json and runs from source via bun
329+
* In production: reads manifest.json for compiled binaries
263330
*/
264331
function getBotConfigs() {
265-
const botsManifest = readBotsManifest()
266332
const isPackaged = app.isPackaged
267333

334+
if (!isPackaged) {
335+
const devConfigs = readBotsJsonDev()
336+
electronLogger.info(
337+
{ count: devConfigs.length, isPackaged },
338+
'getBotConfigs called (dev mode)'
339+
)
340+
return devConfigs
341+
}
342+
343+
const botsManifest = readBotsManifest()
344+
268345
electronLogger.info({ botsManifest, isPackaged }, 'getBotConfigs called')
269346

270347
if (botsManifest.length === 0) {
@@ -273,9 +350,7 @@ function getBotConfigs() {
273350
}
274351

275352
// Use compiled binaries from manifest
276-
const botsDir = isPackaged
277-
? path.join(process.resourcesPath, 'bots')
278-
: path.join(appRoot, 'dist', 'bots')
353+
const botsDir = path.join(process.resourcesPath, 'bots')
279354

280355
return botsManifest
281356
.map((bot) => {
@@ -355,10 +430,19 @@ function settingsToEnv(settings) {
355430

356431
// Track all vars injected by the emulator (from UI settings, not user's .env file)
357432
// This allows bots to distinguish between UI-derived env vars and actual .env overrides
358-
const injectedVars = []
433+
const injectedVars = [
434+
'SLACK_BOT_TOKEN',
435+
'SLACK_APP_TOKEN',
436+
'SLACK_SIGNING_SECRET',
437+
]
359438

360439
const env = {
361440
SLACK_API_URL: `http://localhost:${EMULATOR_PORT}/api`,
441+
// Provide placeholder Slack tokens so bots pass env validation.
442+
// Real tokens aren't needed — bots always talk to the emulator.
443+
SLACK_BOT_TOKEN: 'xoxb-emulator',
444+
SLACK_APP_TOKEN: 'xapp-emulator',
445+
SLACK_SIGNING_SECRET: 'emulator',
362446
DATA_DIR: dataDir,
363447
}
364448

@@ -543,6 +627,7 @@ function spawnProcess(config, env, label, forwardLogs = false) {
543627
proc = spawn(config.path, [], {
544628
env: { ...childEnv, ...env },
545629
stdio: ['ignore', 'pipe', 'pipe'],
630+
cwd: app.getPath('userData'),
546631
})
547632
}
548633

apps/electron/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@
4343
{
4444
"from": "../ui/dist",
4545
"to": "dist",
46-
"filter": ["**/*"]
46+
"filter": [
47+
"**/*"
48+
]
4749
},
4850
"assets/**/*",
4951
"package.json"

0 commit comments

Comments
 (0)