()
| 169 | } |
| 170 | |
| 171 | async function main() { |
| 172 | const { port, host, dataDir, webDir, disableAccessPassword } = parseArgs(); |
| 173 | currentDataDir = dataDir; |
| 174 | installProcessErrorLogging(dataDir); |
| 175 | |
| 176 | // 确保数据目录存在 |
| 177 | if (!existsSync(dataDir)) { |
| 178 | mkdirSync(dataDir, { recursive: true }); |
| 179 | console.log(`Created data directory: ${dataDir}`); |
| 180 | } |
| 181 | |
| 182 | // 设置环境变量(必须在 import app 之前,因为 Prisma client 在模块加载时初始化) |
| 183 | const dbPath = path.join(dataDir, 'data.db'); |
| 184 | process.env.AGENT_TOWER_DATABASE_URL = `file:${dbPath}`; |
| 185 | process.env.AGENT_TOWER_DATA_DIR = dataDir; |
| 186 | process.env.AGENT_TOWER_WEB_DIR = webDir; |
| 187 | process.env.AGENT_TOWER_HOST = host; |
| 188 | process.env.AGENT_TOWER_PORT = String(port); |
| 189 | process.env.AGENT_TOWER_URL = `http://127.0.0.1:${port}`; |
| 190 | |
| 191 | // 初始化数据库 |
| 192 | const schemaPath = path.resolve(__dirname, '../prisma/schema.prisma'); |
| 193 | ensureDatabase(dataDir, dbPath, schemaPath); |
| 194 | process.env[INTERNAL_API_TOKEN_ENV] = getOrCreateInternalApiToken(dataDir); |
| 195 | |
| 196 | // 启动服务器 |
| 197 | const { buildApp } = await import('./app.js'); |
| 198 | if (disableAccessPassword) { |
| 199 | const { AccessAuthService } = await import('./services/access-auth.service.js'); |
| 200 | await AccessAuthService.disableForRecovery(); |
| 201 | console.log('Access password disabled.'); |
| 202 | } |
| 203 | const app = await buildApp(); |
| 204 | |
| 205 | let shuttingDown = false; |
| 206 | const shutdown = async (signal: string) => { |
| 207 | if (shuttingDown) { |
| 208 | console.log('\nForce exit.'); |
| 209 | process.exit(1); |
| 210 | } |
| 211 | shuttingDown = true; |
| 212 | console.log(`\n${signal} received, shutting down...`); |
| 213 | try { |
| 214 | await app.close(); |
| 215 | process.exit(0); |
| 216 | } catch (err) { |
| 217 | console.error('Shutdown error:', err); |
| 218 | process.exit(1); |
| 219 | } |
| 220 | }; |
| 221 | |
| 222 | process.on('SIGTERM', () => shutdown('SIGTERM')); |
| 223 | process.on('SIGINT', () => shutdown('SIGINT')); |
| 224 | |
| 225 | await app.listen({ port, host }); |
| 226 | |
| 227 | // 写入端口文件,供 MCP 等外部进程发现 |
| 228 | const portFile = path.join(dataDir, 'port'); |
no test coverage detected