Skip to content

Commit 19a780e

Browse files
committed
feat: enhance admin dashboard startup process and improve log file watching reliability
1 parent 90a43c6 commit 19a780e

File tree

4 files changed

+90
-44
lines changed

4 files changed

+90
-44
lines changed

bin/lib/admin.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -659,9 +659,14 @@ export async function startAdminDashboard(options = {}) {
659659

660660
// Auto-open browser if requested
661661
if (options.open !== false) {
662-
const openCmd = process.platform === 'darwin' ? 'open' :
663-
process.platform === 'win32' ? 'start' : 'xdg-open';
664-
spawn(openCmd, [`http://localhost:${port}`], { detached: true, stdio: 'ignore' });
662+
const url = `http://localhost:${port}`;
663+
if (process.platform === 'win32') {
664+
// Use cmd start to open default browser on Windows; needs shell invocation
665+
spawn('cmd', ['/c', 'start', '', url], { detached: true, stdio: 'ignore' });
666+
} else {
667+
const openCmd = process.platform === 'darwin' ? 'open' : 'xdg-open';
668+
spawn(openCmd, [url], { detached: true, stdio: 'ignore' });
669+
}
665670
}
666671
});
667672

bin/lib/dev.js

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,17 @@ import chalk from 'chalk';
44
import { spawn } from 'node:child_process';
55
import http from 'http';
66
import { initializeServiceLogs } from './logs.js';
7+
import { fileURLToPath } from 'url';
8+
9+
const __filename = fileURLToPath(import.meta.url);
10+
const __dirname = path.dirname(__filename);
11+
const cliEntry = path.resolve(__dirname, '..', 'index.js');
712

813
// Start admin dashboard
914
function startAdminDashboard(cwd) {
1015
console.log(chalk.cyan('🎛️ Starting admin dashboard on http://localhost:9000'));
1116

12-
// Try to find create-polyglot command
13-
let adminCmd = 'npx';
14-
let adminArgs = ['create-polyglot', 'admin', '--port', '9000'];
15-
16-
// Try global command first
17-
try {
18-
const { execSync } = require('child_process');
19-
execSync('which create-polyglot', { stdio: 'ignore' });
20-
adminCmd = 'create-polyglot';
21-
adminArgs = ['admin', '--port', '9000'];
22-
} catch (e) {
23-
// Use npx as fallback
24-
}
25-
26-
const adminProcess = spawn(adminCmd, adminArgs, {
17+
const adminProcess = spawn(process.execPath, [cliEntry, 'admin', '--port', '9000', '--no-open'], {
2718
cwd,
2819
env: process.env,
2920
stdio: 'pipe'

bin/lib/logs.js

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,9 @@ export class LogFileWatcher {
612612
if (fs.existsSync(serviceDir)) {
613613
// Ensure .logs directory exists so watcher can subscribe immediately
614614
const logsDir = ensureLogsDir(serviceDir);
615-
watchPaths.push(path.join(logsDir, '*.log'));
615+
// Watch the directory itself, not glob pattern - more reliable
616+
const watchPath = logsDir.replace(/\\/g, '/');
617+
watchPaths.push(watchPath);
616618
}
617619
}
618620

@@ -621,21 +623,35 @@ export class LogFileWatcher {
621623
return;
622624
}
623625

626+
console.log(chalk.cyan('[LogWatcher] Watch paths:'), watchPaths);
627+
624628
// Initialize cache with current logs
625629
await this.loadInitialLogs(cfg.services);
626630

627-
// Start chokidar watcher
631+
// Start chokidar watcher - watch directories, filter for .log files in handlers
628632
this.watcher = chokidar.watch(watchPaths, {
629-
ignored: /(^|[\/\\])\../, // ignore dotfiles
633+
ignored: ['**/node_modules/**', '**/.git/**', '**/.DS_Store'],
630634
persistent: true,
631-
ignoreInitial: false
635+
ignoreInitial: false,
636+
usePolling: true, // Enable polling for more reliable file watching on Windows
637+
interval: 1000, // Poll every second
638+
depth: 0 // Only watch files in the immediate directory, not subdirectories
632639
});
633640

634641
this.watcher
635-
.on('add', (filePath) => this.handleFileChange('add', filePath))
636-
.on('change', (filePath) => this.handleFileChange('change', filePath))
637-
.on('unlink', (filePath) => this.handleFileChange('unlink', filePath))
638-
.on('error', (error) => console.error('Log watcher error:', error));
642+
.on('add', (filePath) => {
643+
if (!filePath.endsWith('.log')) return; // Only process .log files
644+
this.handleFileChange('add', filePath);
645+
})
646+
.on('change', (filePath) => {
647+
if (!filePath.endsWith('.log')) return; // Only process .log files
648+
this.handleFileChange('change', filePath);
649+
})
650+
.on('unlink', (filePath) => {
651+
if (!filePath.endsWith('.log')) return; // Only process .log files
652+
this.handleFileChange('unlink', filePath);
653+
})
654+
.on('error', (error) => console.error(chalk.red('Log watcher error:'), error));
639655

640656
this.isWatching = true;
641657
console.log(chalk.green('📁 Started watching log files with chokidar'));
@@ -678,7 +694,9 @@ export class LogFileWatcher {
678694
async handleFileChange(event, filePath) {
679695
try {
680696
const serviceName = this.getServiceNameFromLogPath(filePath);
681-
if (!serviceName) return;
697+
if (!serviceName) {
698+
return;
699+
}
682700

683701
if (event === 'unlink') {
684702
// File deleted - clear cache for this service

scripts/dev-basic.cjs

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { spawn } = require('node:child_process');
1+
const { spawn, spawnSync } = require('node:child_process');
22
const fs = require('fs');
33
const path = require('path');
44

@@ -81,28 +81,60 @@ export class Logger {
8181
}
8282

8383
// Start admin dashboard
84-
function startAdminDashboard() {
85-
console.log('🎛️ Starting admin dashboard...');
86-
87-
// Try to find create-polyglot globally or in node_modules
88-
let adminCmd = 'npx';
89-
let adminArgs = ['create-polyglot', 'admin', '--port', '9000'];
90-
91-
// Fallback: check if create-polyglot is available globally
84+
function resolveCliEntry() {
9285
try {
93-
const { execSync } = require('child_process');
94-
execSync('which create-polyglot', { stdio: 'ignore' });
95-
adminCmd = 'create-polyglot';
96-
adminArgs = ['admin', '--port', '9000'];
86+
return require.resolve('create-polyglot/bin/index.js', { paths: [root] });
9787
} catch (e) {
98-
// Use npx as fallback
88+
// ignore resolution failure
89+
}
90+
91+
const nodeModulesCli = path.join(root, 'node_modules', 'create-polyglot', 'bin', 'index.js');
92+
if (fs.existsSync(nodeModulesCli)) {
93+
return nodeModulesCli;
94+
}
95+
96+
const repoCli = path.resolve(__dirname, '../bin/index.js');
97+
if (fs.existsSync(repoCli)) {
98+
return repoCli;
9999
}
100+
101+
return null;
102+
}
103+
104+
function startAdminDashboard() {
105+
console.log('🎛️ Starting admin dashboard...');
100106

101-
const adminProcess = spawn(adminCmd, adminArgs, {
107+
const spawnOptions = {
102108
cwd: root,
103109
env: process.env,
104-
stdio: 'pipe'
105-
});
110+
stdio: 'pipe',
111+
shell: process.platform === 'win32'
112+
};
113+
114+
const localCli = resolveCliEntry();
115+
let adminCmd;
116+
let adminArgs;
117+
118+
if (localCli) {
119+
adminCmd = process.execPath;
120+
adminArgs = [localCli, 'admin', '--port', '9000', '--no-open'];
121+
spawnOptions.shell = false;
122+
} else {
123+
const check = spawnSync('create-polyglot', ['--version'], {
124+
stdio: 'ignore',
125+
shell: spawnOptions.shell
126+
});
127+
128+
if (check.status === 0 && !check.error) {
129+
adminCmd = 'create-polyglot';
130+
adminArgs = ['admin', '--port', '9000', '--no-open'];
131+
} else {
132+
adminCmd = 'npx';
133+
adminArgs = ['create-polyglot', 'admin', '--port', '9000', '--no-open'];
134+
}
135+
}
136+
137+
const adminProcess = spawn(adminCmd, adminArgs, spawnOptions);
106138

107139
adminProcess.stdout.on('data', d => process.stdout.write(`[admin] ${d}`));
108140
adminProcess.stderr.on('data', d => process.stderr.write(`[admin] ${d}`));

0 commit comments

Comments
 (0)