|
1 | | -import { loadConfig, allProjects, findProjectConfig, type Config, type ProjectConfig, type WorkspaceConfig } from "./config.ts"; |
| 1 | +import { allProjects, findProjectConfig, type Config, type ProjectConfig, type WorkspaceConfig } from "./config.ts"; |
2 | 2 | import { IssueDB, ConfigDB, type IssueRow, type IssueStatus } from "./db.ts"; |
3 | 3 | import { PriorityQueue } from "./queue.ts"; |
4 | 4 | import { SentryAdapter } from "./sources/sentry.ts"; |
@@ -44,33 +44,19 @@ export class Daemon { |
44 | 44 | private queue!: PriorityQueue<PipelineItem>; |
45 | 45 | private workspaces: Map<string, WorkspaceRuntime> = new Map(); |
46 | 46 | private pollTimer: ReturnType<typeof setInterval> | null = null; |
47 | | - private configWatcher: ReturnType<typeof import("node:fs").watch> | null = null; |
48 | 47 | private stopping = false; |
49 | | - private configPath: string; |
| 48 | + private dbPath: string; |
50 | 49 | private dashboard!: DashboardServer; |
51 | | - private baseDir: string; |
52 | 50 |
|
53 | | - constructor(configPath: string) { |
54 | | - this.configPath = configPath; |
55 | | - this.baseDir = dirname(configPath); |
| 51 | + constructor(dbPath: string) { |
| 52 | + this.dbPath = dbPath; |
56 | 53 | } |
57 | 54 |
|
58 | 55 | async start() { |
59 | 56 | // Init DB |
60 | | - const dbPath = join(this.baseDir, "sqlite.db"); |
61 | | - this.db = new IssueDB(dbPath); |
| 57 | + this.db = new IssueDB(this.dbPath); |
62 | 58 | this.configDB = new ConfigDB(this.db.getDatabase()); |
63 | 59 |
|
64 | | - // Auto-import config.json if DB has no config |
65 | | - if (!this.configDB.hasConfig()) { |
66 | | - const configFile = Bun.file(this.configPath); |
67 | | - if (await configFile.exists()) { |
68 | | - const jsonConfig = await loadConfig(this.configPath); |
69 | | - this.configDB.importFromJson(jsonConfig); |
70 | | - logger.info("Auto-imported config.json into database"); |
71 | | - } |
72 | | - } |
73 | | - |
74 | 60 | // Start dashboard (always — even without config for setup wizard) |
75 | 61 | const isDev = process.env.DEV === "1"; |
76 | 62 | // Resolve dist/ relative to this source file so it works both in-repo and when |
@@ -129,9 +115,6 @@ export class Daemon { |
129 | 115 | // Start poll interval |
130 | 116 | this.pollTimer = setInterval(() => this.poll(), this.config.pollIntervalSeconds * 1000); |
131 | 117 |
|
132 | | - // Watch config.json for hot reload (legacy support) |
133 | | - this.watchConfig(); |
134 | | - |
135 | 118 | // Setup shutdown handlers |
136 | 119 | this.setupShutdownHandlers(); |
137 | 120 |
|
@@ -223,11 +206,6 @@ export class Daemon { |
223 | 206 | this.stopping = true; |
224 | 207 | logger.info("Shutting down..."); |
225 | 208 |
|
226 | | - if (this.configWatcher) { |
227 | | - this.configWatcher.close(); |
228 | | - this.configWatcher = null; |
229 | | - } |
230 | | - |
231 | 209 | if (this.pollTimer) { |
232 | 210 | clearInterval(this.pollTimer); |
233 | 211 | this.pollTimer = null; |
@@ -330,58 +308,6 @@ export class Daemon { |
330 | 308 | } |
331 | 309 | } |
332 | 310 |
|
333 | | - private watchConfig() { |
334 | | - const { watch } = require("node:fs") as typeof import("node:fs"); |
335 | | - let debounce: ReturnType<typeof setTimeout> | null = null; |
336 | | - |
337 | | - this.configWatcher = watch(this.configPath, () => { |
338 | | - if (debounce) clearTimeout(debounce); |
339 | | - debounce = setTimeout(() => this.reloadConfig(), 500); |
340 | | - }); |
341 | | - |
342 | | - logger.debug("Watching config for changes", { path: this.configPath }); |
343 | | - } |
344 | | - |
345 | | - private async reloadConfig() { |
346 | | - try { |
347 | | - const newConfig = await loadConfig(this.configPath); |
348 | | - |
349 | | - // Restart poll timer if interval changed |
350 | | - if (newConfig.pollIntervalSeconds !== this.config.pollIntervalSeconds) { |
351 | | - if (this.pollTimer) clearInterval(this.pollTimer); |
352 | | - this.pollTimer = setInterval(() => this.poll(), newConfig.pollIntervalSeconds * 1000); |
353 | | - logger.info("Poll interval updated", { seconds: newConfig.pollIntervalSeconds }); |
354 | | - } |
355 | | - |
356 | | - if (newConfig.logLevel !== this.config.logLevel) { |
357 | | - setLogLevel(newConfig.logLevel); |
358 | | - logger.info("Log level updated", { level: newConfig.logLevel }); |
359 | | - } |
360 | | - |
361 | | - // Reinit workspaces if workspace config changed |
362 | | - const oldWsJson = JSON.stringify(this.config.workspaces); |
363 | | - const newWsJson = JSON.stringify(newConfig.workspaces); |
364 | | - if (oldWsJson !== newWsJson) { |
365 | | - for (const ws of this.workspaces.values()) { |
366 | | - ws.telegram?.stopPolling(); |
367 | | - } |
368 | | - this.workspaces.clear(); |
369 | | - this.config = newConfig; |
370 | | - this.initWorkspaces(); |
371 | | - logger.info("Workspaces reinitialized"); |
372 | | - } else { |
373 | | - this.config = newConfig; |
374 | | - } |
375 | | - |
376 | | - logger.info("Config reloaded"); |
377 | | - |
378 | | - // Trigger immediate poll after reload |
379 | | - await this.poll(); |
380 | | - } catch (err) { |
381 | | - logger.error("Config reload failed, keeping current config", { error: String(err) }); |
382 | | - } |
383 | | - } |
384 | | - |
385 | 311 | private async poll() { |
386 | 312 | if (this.stopping) return; |
387 | 313 |
|
@@ -1090,7 +1016,7 @@ function buildPRBody(row: IssueRow): string { |
1090 | 1016 |
|
1091 | 1017 | // When run directly |
1092 | 1018 | if (import.meta.main) { |
1093 | | - const configPath = process.argv[2] || join(process.cwd(), "config.json"); |
1094 | | - const daemon = new Daemon(configPath); |
| 1019 | + const dbPath = process.argv[2] || join(process.env.HOME ?? "~", ".relay", "sqlite.db"); |
| 1020 | + const daemon = new Daemon(dbPath); |
1095 | 1021 | await daemon.start(); |
1096 | 1022 | } |
0 commit comments