@babylonjsmarket/cli 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +290 -324
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/login-simple.ts","../src/utils/auth.ts","../src/config/constants.ts","../src/commands/logout.ts","../src/utils/theme-colors.ts","../src/commands/whoami.ts","../src/commands/download.ts","../src/commands/bbs.ts","../src/utils/buffered-bbs.ts","../src/utils/course-detail-viewer.ts","../src/utils/markdown-terminal.ts","../src/utils/code-highlighter.ts","../src/utils/course-detail/layout.ts","../src/utils/course-detail/windowing.ts","../src/utils/course-detail/reducer.ts","../src/utils/asset-downloader.ts","../src/utils/project-scanner.ts","../src/utils/component-catalog.ts","../src/commands/bbs/state.ts","../src/commands/bbs/keymap.ts","../src/commands/bbs/format.ts","../src/commands/bbs/layout.ts","../src/commands/bbs/viewmodel.ts","../src/commands/bbs/render.ts","../src/commands/inject.ts","../src/utils/version.ts","../src/lib/inject/engine.ts","../src/lib/inject/inject-options.ts","../src/lib/inject/detect-target.ts","../src/lib/inject/monorepo-root.ts","../src/commands/submissions.ts"],"sourcesContent":["import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { loginCommand } from './commands/login-simple.js';\nimport { logoutCommand } from './commands/logout.js';\nimport { whoamiCommand } from './commands/whoami.js';\nimport { downloadCommand } from './commands/download.js';\nimport { bbsCommand } from './commands/bbs.js';\nimport { injectCommand } from './commands/inject.js';\nimport { submissionsCommand } from './commands/submissions.js';\nimport { getVersion } from './utils/version.js';\n\nconst program = new Command();\n\nprogram\n .name('bjs')\n .description('BabylonJS Market CLI - BBS-style interface for courses and assets')\n .version(getVersion());\n\n// Add commands\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(whoamiCommand);\nprogram.addCommand(downloadCommand);\nprogram.addCommand(injectCommand);\nprogram.addCommand(submissionsCommand);\nprogram.addCommand(bbsCommand);\n\n// Error handling\nprogram.exitOverride();\n\ntry {\n await program.parseAsync(process.argv);\n} catch (error: any) {\n if (error.code === 'commander.executeSubCommandAsync') {\n // Normal exit from subcommand\n process.exit(error.exitCode);\n }\n console.error(chalk.red('Error:'), error.message);\n process.exit(1);\n}","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport open from 'open';\nimport ora from 'ora';\nimport fetch from 'node-fetch';\nimport { AuthManager } from '../utils/auth.js';\nimport { API_URL } from '../config/constants.js';\nimport { createServer } from 'https';\nimport { createServer as createHttpServer } from 'http';\nimport { URL } from 'url';\nimport { execSync } from 'child_process';\nimport fs from 'fs';\nimport path from 'path';\nimport os from 'os';\n\nexport const loginCommand = new Command('login')\n .description('Authenticate with BabylonJS Market')\n .option('--no-browser', 'Don\\'t open browser automatically')\n .action(async (options) => {\n const authManager = new AuthManager();\n \n // Check if already authenticated\n if (authManager.isAuthenticated()) {\n const user = authManager.getUser();\n console.log(chalk.yellow('You are already logged in as:'), chalk.cyan(user?.email || 'Unknown'));\n console.log(chalk.gray('Run \"bjs-cli logout\" to log out first.'));\n return;\n }\n\n console.log(chalk.blue('Starting authentication flow...'));\n \n try {\n // Start a local server to receive the callback\n const port = 8765;\n let token: string | null = null;\n \n // Create self-signed certificate for HTTPS\n const certDir = path.join(os.homedir(), '.bjs', 'certs');\n const keyPath = path.join(certDir, 'localhost-key.pem');\n const certPath = path.join(certDir, 'localhost-cert.pem');\n \n // Ensure cert directory exists\n if (!fs.existsSync(certDir)) {\n fs.mkdirSync(certDir, { recursive: true });\n }\n \n // Generate self-signed certificate if it doesn't exist\n if (!fs.existsSync(keyPath) || !fs.existsSync(certPath)) {\n console.log(chalk.gray('Generating self-signed certificate for HTTPS...'));\n try {\n execSync(\n `openssl req -x509 -newkey rsa:2048 -nodes -sha256 -days 365 ` +\n `-keyout \"${keyPath}\" -out \"${certPath}\" ` +\n `-subj \"/C=US/ST=State/L=City/O=BJS-CLI/CN=localhost\"`,\n { stdio: 'pipe' }\n );\n } catch (error) {\n console.log(chalk.yellow('Could not generate HTTPS certificate, falling back to HTTP'));\n }\n }\n \n // Try to use HTTPS, fall back to HTTP if certificates aren't available\n let server;\n let protocol = 'https';\n \n if (fs.existsSync(keyPath) && fs.existsSync(certPath)) {\n const serverOptions = {\n key: fs.readFileSync(keyPath),\n cert: fs.readFileSync(certPath)\n };\n server = createServer(serverOptions, (req, res) => {\n handleRequest(req, res);\n });\n } else {\n protocol = 'http';\n server = createHttpServer((req, res) => {\n handleRequest(req, res);\n });\n }\n \n const handleRequest = (req: any, res: any) => {\n const url = new URL(req.url!, `${protocol}://localhost:${port}`);\n token = url.searchParams.get('token');\n \n if (token) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(`\n <!DOCTYPE html>\n <html>\n <head>\n <title>Authentication Successful</title>\n <style>\n body { font-family: system-ui; padding: 40px; text-align: center; }\n .success { color: green; }\n .token { background: #f0f0f0; padding: 10px; margin: 20px; font-family: monospace; word-break: break-all; }\n </style>\n </head>\n <body>\n <h1 class=\"success\">✓ Authentication Successful!</h1>\n <p>You can close this window and return to your terminal.</p>\n <div class=\"token\">Token received: ${token.substring(0, 8)}...</div>\n <script>setTimeout(() => window.close(), 3000);</script>\n </body>\n </html>\n `);\n server.close();\n } else {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end('Missing token parameter');\n }\n };\n \n await new Promise<void>((resolve) => {\n server.listen(port, () => {\n console.log(chalk.gray(`Local callback server started on port ${port} (${protocol.toUpperCase()})`));\n resolve();\n });\n });\n \n // Open browser to auth page\n const callbackUrl = `${protocol}://localhost:${port}`;\n const authUrl = `${API_URL}/auth/cli?callback=${encodeURIComponent(callbackUrl)}`;\n console.log('\\n' + chalk.green('To authenticate, visit:'));\n console.log(chalk.cyan.bold(authUrl));\n \n if (options.browser !== false) {\n console.log('\\n' + chalk.gray('Opening browser...'));\n await open(authUrl);\n }\n \n // Wait for token\n console.log('\\n' + chalk.blue('Waiting for authentication...'));\n const spinner = ora('Waiting for browser authentication...').start();\n \n // Wait for server to receive token (with timeout)\n const timeout = setTimeout(() => {\n server.close();\n spinner.fail(chalk.red('Authentication timed out'));\n process.exit(1);\n }, 300000); // 5 minutes timeout\n \n await new Promise<void>((resolve) => {\n server.on('close', () => {\n clearTimeout(timeout);\n resolve();\n });\n });\n \n if (!token) {\n spinner.fail(chalk.red('No token received'));\n process.exit(1);\n }\n \n spinner.text = 'Exchanging token...';\n \n // Exchange the token for JWT\n const exchangeResponse = await fetch(`${API_URL}/api/auth/cli/exchange`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token })\n });\n \n if (!exchangeResponse.ok) {\n const error = await exchangeResponse.text();\n spinner.fail(chalk.red('Failed to exchange token'));\n console.error(chalk.red('Error:'), error);\n process.exit(1);\n }\n \n const tokenData = await exchangeResponse.json() as any;\n \n // Save tokens and user info\n authManager.saveTokens(\n tokenData.access_token,\n tokenData.refresh_token,\n tokenData.expires_in\n );\n \n authManager.saveUser(tokenData.user);\n \n spinner.succeed(chalk.green('Authentication successful!'));\n \n console.log(chalk.blue('\\nLogged in as:'), chalk.cyan(tokenData.user.email));\n console.log(chalk.gray(`\\nAuthentication data saved to ~/.bjs/config.json`));\n \n } catch (error: any) {\n console.error(chalk.red('Login failed:'), error.message);\n process.exit(1);\n }\n });","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';\nimport { join } from 'path';\nimport { CONFIG_DIR, CONFIG_FILE } from '../config/constants.js';\nimport fetch from 'node-fetch';\n\nconst LIBRARY_MANIFEST_FILE = join(CONFIG_DIR, 'library-manifest.json');\n\n// Tracks installed library files and their versions\nexport interface LibraryFileInfo {\n version: string; // File version hash/id from server\n installedAt: string; // ISO date when first installed\n updatedAt: string; // ISO date when last updated\n}\n\nexport interface LibraryManifest {\n files: Record<string, LibraryFileInfo>; // path -> info\n lastSyncAt?: string; // ISO date of last sync\n}\n\ninterface AuthConfig {\n accessToken?: string;\n refreshToken?: string;\n expiresAt?: number;\n user?: {\n id: string;\n email: string;\n name?: string;\n };\n preferences?: {\n theme?: string;\n animations?: boolean;\n mouse?: boolean;\n projectsDirectory?: string;\n libraryPath?: string;\n };\n}\n\nexport class AuthManager {\n private config: AuthConfig = {};\n\n constructor() {\n this.loadConfig();\n }\n\n private loadConfig(): void {\n try {\n if (existsSync(CONFIG_FILE)) {\n const data = readFileSync(CONFIG_FILE, 'utf-8');\n this.config = JSON.parse(data);\n }\n } catch (error) {\n console.error('Failed to load config:', error);\n this.config = {};\n }\n }\n\n private saveConfig(): void {\n try {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true });\n }\n writeFileSync(CONFIG_FILE, JSON.stringify(this.config, null, 2));\n } catch (error) {\n console.error('Failed to save config:', error);\n throw new Error('Failed to save authentication data');\n }\n }\n\n public saveTokens(accessToken: string, refreshToken?: string, expiresIn?: number): void {\n this.config.accessToken = accessToken;\n if (refreshToken) {\n this.config.refreshToken = refreshToken;\n }\n if (expiresIn) {\n this.config.expiresAt = Date.now() + (expiresIn * 1000);\n }\n this.saveConfig();\n }\n\n public saveUser(user: AuthConfig['user']): void {\n this.config.user = user;\n this.saveConfig();\n }\n\n public getAccessToken(): string | undefined {\n // Check if token is expired\n if (this.config.expiresAt && Date.now() > this.config.expiresAt) {\n // TODO: Implement token refresh\n return undefined;\n }\n return this.config.accessToken;\n }\n\n public getUser(): AuthConfig['user'] | undefined {\n return this.config.user;\n }\n\n public isAuthenticated(): boolean {\n return !!this.getAccessToken();\n }\n\n public clearAuth(): void {\n // Keep preferences when clearing auth\n const preferences = this.config.preferences;\n this.config = { preferences };\n this.saveConfig();\n }\n\n public savePreferences(preferences: Partial<AuthConfig['preferences']>): void {\n this.config.preferences = {\n ...this.config.preferences,\n ...preferences\n };\n this.saveConfig();\n }\n\n public getPreferences(): AuthConfig['preferences'] {\n return this.config.preferences || {};\n }\n\n public getProjectsDirectory(): string | undefined {\n return this.config.preferences?.projectsDirectory;\n }\n\n public setProjectsDirectory(directory: string): void {\n this.savePreferences({ projectsDirectory: directory });\n }\n\n public getLibraryPath(): string {\n // Return configured path or default to ~/.bjs/Library/\n return this.config.preferences?.libraryPath || join(CONFIG_DIR, 'Library');\n }\n\n public setLibraryPath(directory: string): void {\n this.savePreferences({ libraryPath: directory });\n }\n\n public async makeAuthenticatedRequest(url: string, options: any = {}): Promise<Response> {\n const token = this.getAccessToken();\n if (!token) {\n throw new Error('Not authenticated. Please run \"bjs login\" first.');\n }\n\n return fetch(url, {\n ...options,\n headers: {\n ...options.headers,\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n }) as any;\n }\n\n // Library manifest management\n public getLibraryManifest(): LibraryManifest {\n try {\n if (existsSync(LIBRARY_MANIFEST_FILE)) {\n const data = readFileSync(LIBRARY_MANIFEST_FILE, 'utf-8');\n return JSON.parse(data);\n }\n } catch {\n // Return empty manifest on error\n }\n return { files: {} };\n }\n\n public saveLibraryManifest(manifest: LibraryManifest): void {\n try {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true });\n }\n writeFileSync(LIBRARY_MANIFEST_FILE, JSON.stringify(manifest, null, 2));\n } catch (error) {\n console.error('Failed to save library manifest:', error);\n }\n }\n\n public updateLibraryFile(filePath: string, version: string): void {\n const manifest = this.getLibraryManifest();\n const now = new Date().toISOString();\n\n if (manifest.files[filePath]) {\n manifest.files[filePath].version = version;\n manifest.files[filePath].updatedAt = now;\n } else {\n manifest.files[filePath] = {\n version,\n installedAt: now,\n updatedAt: now\n };\n }\n\n this.saveLibraryManifest(manifest);\n }\n\n public getInstalledFileVersion(filePath: string): string | undefined {\n const manifest = this.getLibraryManifest();\n return manifest.files[filePath]?.version;\n }\n\n public markLibrarySynced(): void {\n const manifest = this.getLibraryManifest();\n manifest.lastSyncAt = new Date().toISOString();\n this.saveLibraryManifest(manifest);\n }\n}","import { homedir } from 'os';\nimport { join } from 'path';\n\n// API endpoints\nexport const API_BASE_URL = process.env.BJS_API_URL || 'https://babylonjsmarket.com';\nexport const DEV_API_URL = process.env.BJS_DEV_API_URL || 'https://dev.babylonjsmarket.com';\n\n// Default to production. Opt into the dev backend with BJS_ENV=development\n// (or override the host entirely with BJS_API_URL / BJS_DEV_API_URL).\nexport const USE_DEV = process.env.BJS_ENV === 'development';\nexport const API_URL = USE_DEV ? DEV_API_URL : API_BASE_URL;\n\n// Auth endpoints\nexport const AUTH_DEVICE_CODE_URL = `${API_URL}/api/auth/device/code`;\nexport const AUTH_DEVICE_TOKEN_URL = `${API_URL}/api/auth/device/token`;\nexport const AUTH_USER_INFO_URL = `${API_URL}/api/auth/user`;\nexport const AUTH_COURSES_URL = `${API_URL}/api/auth/courses`;\n\n// Storage\nexport const CONFIG_DIR = join(homedir(), '.bjs');\nexport const CONFIG_FILE = join(CONFIG_DIR, 'config.json');\nexport const TOKEN_SERVICE = 'bjs-cli';\nexport const TOKEN_ACCOUNT = 'bjsmarket';\n\n// OAuth Device Flow\nexport const CLIENT_ID = 'bjs-cli';\nexport const DEVICE_POLL_INTERVAL = 5000; // 5 seconds\nexport const DEVICE_TIMEOUT = 900000; // 15 minutes","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { AuthManager } from '../utils/auth.js';\nimport { applyTheme } from '../utils/theme-colors.js';\n\nexport const logoutCommand = new Command('logout')\n .description('Log out from BabylonJS Market')\n .action(async () => {\n const authManager = new AuthManager();\n const theme = applyTheme();\n \n if (!authManager.isAuthenticated()) {\n console.log(theme.warning('You are not logged in.'));\n return;\n }\n \n const user = authManager.getUser();\n authManager.clearAuth();\n \n console.log(theme.success('Successfully logged out'));\n if (user?.email) {\n console.log(theme.dim(`Was logged in as: ${user.email}`));\n }\n });","import chalk from 'chalk';\nimport { AuthManager } from './auth.js';\n\nexport type ThemeName = 'classic' | 'desert' | 'matrix' | 'commando' | 'sandiego' | 'ed209';\n\ninterface ThemeColors {\n primary: (text: string) => string;\n secondary: (text: string) => string;\n accent: (text: string) => string;\n success: (text: string) => string;\n error: (text: string) => string;\n warning: (text: string) => string;\n info: (text: string) => string;\n dim: (text: string) => string;\n}\n\nconst themes: Record<ThemeName, ThemeColors> = {\n classic: {\n primary: (text) => chalk.cyan(text),\n secondary: (text) => chalk.yellow(text),\n accent: (text) => chalk.magenta(text),\n success: (text) => chalk.green(text),\n error: (text) => chalk.red(text),\n warning: (text) => chalk.yellow(text),\n info: (text) => chalk.blue(text),\n dim: (text) => chalk.gray(text)\n },\n desert: {\n primary: (text) => chalk.yellow(text),\n secondary: (text) => chalk.red(text),\n accent: (text) => chalk.green(text),\n success: (text) => chalk.green(text),\n error: (text) => chalk.red(text),\n warning: (text) => chalk.yellow(text),\n info: (text) => chalk.cyan(text),\n dim: (text) => chalk.gray(text)\n },\n matrix: {\n primary: (text) => chalk.green(text),\n secondary: (text) => chalk.greenBright(text),\n accent: (text) => chalk.cyan(text),\n success: (text) => chalk.greenBright(text),\n error: (text) => chalk.red(text),\n warning: (text) => chalk.yellow(text),\n info: (text) => chalk.green(text),\n dim: (text) => chalk.gray(text)\n },\n commando: {\n primary: (text) => chalk.rgb(107, 142, 35)(text), // Olive green\n secondary: (text) => chalk.rgb(139, 90, 43)(text), // Brown\n accent: (text) => chalk.rgb(47, 79, 47)(text), // Dark green\n success: (text) => chalk.green(text),\n error: (text) => chalk.rgb(139, 0, 0)(text), // Dark red\n warning: (text) => chalk.rgb(189, 183, 107)(text), // Khaki\n info: (text) => chalk.rgb(85, 107, 47)(text), // Dark olive green\n dim: (text) => chalk.gray(text)\n },\n sandiego: {\n primary: (text) => chalk.red(text),\n secondary: (text) => chalk.yellow(text),\n accent: (text) => chalk.white(text),\n success: (text) => chalk.green(text),\n error: (text) => chalk.redBright(text),\n warning: (text) => chalk.yellowBright(text),\n info: (text) => chalk.blue(text),\n dim: (text) => chalk.gray(text)\n },\n ed209: {\n primary: (text) => chalk.rgb(192, 192, 192)(text), // Silver\n secondary: (text) => chalk.rgb(135, 206, 235)(text), // Sky blue\n accent: (text) => chalk.rgb(105, 105, 105)(text), // Dim gray\n success: (text) => chalk.greenBright(text),\n error: (text) => chalk.redBright(text),\n warning: (text) => chalk.rgb(255, 140, 0)(text), // Dark orange\n info: (text) => chalk.cyanBright(text),\n dim: (text) => chalk.gray(text)\n }\n};\n\nexport function getThemeColors(themeName?: ThemeName): ThemeColors {\n // Try to get theme from preferences if not specified\n if (!themeName) {\n const authManager = new AuthManager();\n const prefs = authManager.getPreferences();\n themeName = (prefs?.theme as ThemeName) || 'classic';\n }\n \n return themes[themeName] || themes.classic;\n}\n\nexport function applyTheme(themeName?: ThemeName) {\n const theme = getThemeColors(themeName);\n \n return {\n ...theme,\n // Add some convenience methods\n header: (text: string) => theme.primary(chalk.bold(text)),\n subheader: (text: string) => theme.secondary(chalk.bold(text)),\n highlight: (text: string) => theme.accent(chalk.bold(text)),\n code: (text: string) => theme.dim(`\\`${text}\\``),\n link: (text: string) => theme.info(chalk.underline(text))\n };\n}","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { AuthManager } from '../utils/auth.js';\nimport { applyTheme } from '../utils/theme-colors.js';\n\nexport const whoamiCommand = new Command('whoami')\n .description('Display current authenticated user')\n .action(async () => {\n const authManager = new AuthManager();\n const theme = applyTheme();\n \n if (!authManager.isAuthenticated()) {\n console.log(theme.warning('Not logged in.'));\n console.log(theme.dim('Run \"bjs login\" to authenticate.'));\n return;\n }\n \n const user = authManager.getUser();\n if (user) {\n console.log(theme.info('Logged in as:'));\n console.log(theme.primary(` Email: ${user.email}`));\n if (user.name) {\n console.log(theme.primary(` Name: ${user.name}`));\n }\n if (user.id) {\n console.log(theme.dim(` ID: ${user.id}`));\n }\n } else {\n console.log(theme.warning('Logged in but user information not available.'));\n }\n });","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { AuthManager } from '../utils/auth.js';\nimport { applyTheme } from '../utils/theme-colors.js';\nimport { API_URL } from '../config/constants.js';\nimport { createWriteStream, existsSync, mkdirSync } from 'fs';\nimport { pipeline } from 'stream/promises';\nimport fetch from 'node-fetch';\nimport path from 'path';\n\nexport const downloadCommand = new Command('download')\n .description('Download assets from BabylonJS Market')\n .argument('<asset-key>', 'Asset key to download')\n .option('-o, --output <path>', 'Output directory (default: current directory)')\n .action(async (assetKey: string, options) => {\n const authManager = new AuthManager();\n const theme = applyTheme();\n \n if (!authManager.isAuthenticated()) {\n console.log(theme.error('You must be logged in to download assets.'));\n console.log(theme.dim('Run \"bjs login\" to authenticate.'));\n process.exit(1);\n }\n \n const spinner = ora('Requesting download token...').start();\n \n try {\n // Step 1: Request download token from the correct endpoint\n const tokenResponse = await authManager.makeAuthenticatedRequest(\n `${API_URL}/api/assets/download?key=${encodeURIComponent(assetKey)}`\n );\n \n if (!tokenResponse.ok) {\n if (tokenResponse.status === 429) {\n const errorData = await tokenResponse.json() as any;\n spinner.fail(theme.warning(`Rate limited: ${errorData.error}`));\n console.log(theme.dim('Please wait before trying again.'));\n process.exit(1);\n }\n \n const error = await tokenResponse.text();\n throw new Error(`Failed to get download token: ${error}`);\n }\n \n const tokenData = await tokenResponse.json() as any;\n \n if (!tokenData.success) {\n throw new Error(tokenData.error || 'Failed to get download URL');\n }\n \n const { fileName, downloadUrl, expiresInSeconds } = tokenData.data;\n spinner.text = `Downloading ${fileName} (token expires in ${expiresInSeconds} seconds)...`;\n\n // Step 2: Download the file immediately using the token URL\n // Handle different URL formats from the server\n let fullDownloadUrl = downloadUrl;\n\n if (downloadUrl.includes('localhost:3333')) {\n // Replace localhost URL with actual API URL\n // The server returns /assets/retrieve but it should be /api/assets/retrieve\n fullDownloadUrl = downloadUrl\n .replace('http://localhost:3333/assets/retrieve', `${API_URL}/api/assets/retrieve`)\n .replace('https://localhost:3333/assets/retrieve', `${API_URL}/api/assets/retrieve`)\n .replace('http://localhost:3333', API_URL)\n .replace('https://localhost:3333', API_URL);\n } else if (downloadUrl.startsWith('http://') || downloadUrl.startsWith('https://')) {\n // It's already a full URL, use as-is\n fullDownloadUrl = downloadUrl;\n } else if (downloadUrl.startsWith('/')) {\n // Relative path - prepend base URL\n fullDownloadUrl = `${API_URL}${downloadUrl}`;\n } else {\n // Assume it's a relative path without leading slash\n fullDownloadUrl = `${API_URL}/${downloadUrl}`;\n }\n\n const fileResponse = await fetch(fullDownloadUrl);\n \n if (!fileResponse.ok) {\n throw new Error(`Failed to download file: ${fileResponse.status}`);\n }\n \n // Determine output path\n const outputDir = options.output || process.cwd();\n\n // Create output directory if it doesn't exist\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n }\n\n const outputPath = path.join(outputDir, fileName);\n\n // Save to file with progress tracking\n const contentLength = fileResponse.headers.get('content-length');\n const total = contentLength ? parseInt(contentLength, 10) : 0;\n let loaded = 0;\n \n const fileStream = createWriteStream(outputPath);\n \n if (total > 0) {\n // Track progress if we have content length\n const reader = fileResponse.body;\n reader?.on('data', (chunk: Buffer) => {\n loaded += chunk.length;\n const percentage = Math.round((loaded / total) * 100);\n spinner.text = `Downloading ${fileName}: ${percentage}%`;\n });\n }\n \n await pipeline(fileResponse.body as any, fileStream);\n \n spinner.succeed(theme.success(`Downloaded ${fileName} to ${outputPath}`));\n \n } catch (error: any) {\n spinner.fail(theme.error('Download failed'));\n console.error(theme.error('Error:'), error.message);\n process.exit(1);\n }\n });","import { Command } from 'commander';\nimport terminalKit from 'terminal-kit';\nimport { AuthManager } from '../utils/auth.js';\nimport {\n API_URL,\n AUTH_DEVICE_CODE_URL,\n AUTH_DEVICE_TOKEN_URL,\n AUTH_USER_INFO_URL,\n CLIENT_ID,\n DEVICE_TIMEOUT\n} from '../config/constants.js';\nimport { BufferedBBS, Theme } from '../utils/buffered-bbs.js';\nimport { CourseDetailViewer } from '../utils/course-detail-viewer.js';\nimport type { CourseDetail } from '../utils/course-detail/types.js';\nimport fs from 'fs';\nimport path from 'path';\nimport { homedir } from 'os';\nimport process from 'process';\nimport { AssetDownloader } from '../utils/asset-downloader.js';\nimport { scanForProjects, Project } from '../utils/project-scanner.js';\nimport {\n getAvailableComponents, installComponent, ComponentInfo, COMPONENT_CATALOG,\n getAvailableGameModes, installGameMode, GameModeInfo, getGameModeCatalog,\n getInstalledGameModes, getProjectScenes, createScene,\n initializeLibrary, isLibraryInitialized, migrateFromArcadeRef,\n fetchLibraryManifest, syncLibrary, compareManifests, getLibrarySyncStatus,\n ServerManifest\n} from '../utils/component-catalog.js';\nimport open from 'open';\nimport fetch from 'node-fetch';\nimport {\n BbsState,\n Action,\n Course,\n Toy,\n Download,\n ProjectLike,\n THEMES,\n createInitialState,\n reduce,\n} from './bbs/state.js';\nimport { keyToAction, Effect } from './bbs/keymap.js';\nimport {\n buildHome,\n buildCourses,\n buildToys,\n buildDownloads,\n buildProjects,\n buildSettings,\n markedCount,\n type Dimensions,\n} from './bbs/viewmodel.js';\nimport {\n renderHome,\n renderCourses,\n renderToys,\n renderDownloads,\n renderProjects,\n renderSettings,\n renderFooter,\n type RenderContext,\n} from './bbs/render.js';\n\nconst term = terminalKit.terminal;\nconst { ScreenBuffer } = terminalKit;\n\ninterface DeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n}\n\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n token_type: string;\n}\n\n// Cleanup function to restore terminal state\nfunction cleanupTerminal() {\n try {\n term.clear();\n term.hideCursor(false);\n term.grabInput(false);\n } catch (e) {\n // Ignore cleanup errors\n }\n}\n\n// Fatal error handler - cleans up terminal and prints error\nfunction fatalError(error: Error | string, context?: string) {\n cleanupTerminal();\n console.error('\\n\\x1b[31m═══ BBS FATAL ERROR ═══\\x1b[0m');\n if (context) {\n console.error(`\\x1b[33mContext:\\x1b[0m ${context}`);\n }\n console.error(`\\x1b[33mError:\\x1b[0m ${typeof error === 'string' ? error : error.message}`);\n if (typeof error === 'object' && error.stack) {\n console.error(`\\x1b[90m${error.stack}\\x1b[0m`);\n }\n process.exit(1);\n}\n\nexport const bbsCommand = new Command('bbs')\n .description('BabylonJS Market BBS - Browse courses and assets in retro style')\n .option('-t, --theme <theme>', 'Color theme (classic, desert, matrix, commando, sandiego, ed209)', 'classic')\n .option('--no-animations', 'Disable animations')\n .option('--no-mouse', 'Disable mouse support')\n .option('--no-browser', 'Don\\'t open browser automatically during authentication')\n .option('--saveTo <path>', 'Directory to save downloaded files (default: current directory)')\n .action(async (options) => {\n // Global error handlers to catch unhandled errors and clean up terminal\n process.on('uncaughtException', (error) => {\n fatalError(error, 'Uncaught Exception');\n });\n process.on('unhandledRejection', (reason) => {\n fatalError(reason instanceof Error ? reason : new Error(String(reason)), 'Unhandled Promise Rejection');\n });\n\n const authManager = new AuthManager();\n\n // Capture the initial working directory for downloads\n const downloadDirectory = options.saveTo ? path.resolve(options.saveTo) : process.cwd();\n\n // Load saved preferences even if not authenticated\n const savedPrefs = authManager.getPreferences();\n if (savedPrefs && savedPrefs.theme && THEMES.includes(savedPrefs.theme as Theme)) {\n options.theme = savedPrefs.theme;\n }\n if (savedPrefs && savedPrefs.animations !== undefined) {\n options.animations = savedPrefs.animations;\n }\n if (savedPrefs && savedPrefs.mouse !== undefined) {\n options.mouse = savedPrefs.mouse;\n }\n\n // Setup terminal\n term.clear();\n term.hideCursor();\n term.grabInput({ mouse: options.mouse ? 'button' : undefined });\n\n // Create main screen buffer with delta optimization\n const termWidth = Math.min(term.width || 80, 500); // Cap at reasonable max\n const termHeight = Math.min(term.height || 24, 100);\n\n let screenBuffer = new ScreenBuffer({\n dst: term,\n width: termWidth,\n height: termHeight,\n x: 1,\n y: 1,\n noFill: true\n });\n\n // Create back buffer for double buffering\n let backBuffer = new ScreenBuffer({\n width: termWidth,\n height: termHeight,\n dst: term,\n noFill: true\n });\n\n // Clear both buffers initially\n backBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n screenBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n screenBuffer.draw();\n\n // Create BBS component with back buffer\n let bbs = new BufferedBBS(backBuffer, options.theme as Theme, options.animations);\n\n // Store original console.error\n const originalConsoleError = console.error;\n\n // Redirect console.error to prevent terminal corruption\n const errorLogs: string[] = [];\n console.error = (...args: any[]) => {\n // Store errors but don't print to stderr\n errorLogs.push(args.map(a => String(a)).join(' '));\n };\n\n // Check authentication - if not authenticated, show auth flow with BBS UI\n if (!authManager.isAuthenticated()) {\n try {\n // Show initial loading animation\n if (options.animations) {\n await bbs.showLoadingAnimation('Connecting to BabylonJS Market BBS...', 1000);\n }\n\n // Clear screen for auth popup\n backBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n\n // Draw BBS header even during auth\n bbs.drawBBSHeader('GUEST', 'AUTHENTICATION', 0);\n\n // Step 1: Request device code\n bbs.showPollingStatus('checking', 'Requesting authentication code...');\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n\n const deviceCodeResponse = await fetch(AUTH_DEVICE_CODE_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ client_id: CLIENT_ID })\n });\n\n if (!deviceCodeResponse.ok) {\n const error = await deviceCodeResponse.text();\n throw new Error(`Failed to get device code: ${error}`);\n }\n\n const deviceData = await deviceCodeResponse.json() as DeviceCodeResponse;\n\n // Step 2: Display device code in BBS-style popup\n backBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n bbs.drawBBSHeader('GUEST', 'AUTHENTICATION', 0);\n bbs.showAuthPopup(deviceData.user_code, deviceData.verification_uri);\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n\n // Step 3: Open browser if enabled\n if (options.browser !== false) {\n const urlToOpen = deviceData.verification_uri_complete || deviceData.verification_uri;\n await open(urlToOpen);\n }\n\n // Step 4: Poll for token with BBS-style status updates\n const startTime = Date.now();\n const pollInterval = (deviceData.interval || 5) * 1000;\n let authenticated = false;\n\n while (Date.now() - startTime < DEVICE_TIMEOUT && !authenticated) {\n await new Promise(resolve => setTimeout(resolve, pollInterval));\n\n // Update polling status\n bbs.showPollingStatus('checking', 'Checking authentication status...');\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n\n const tokenResponse = await fetch(AUTH_DEVICE_TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n client_id: CLIENT_ID,\n device_code: deviceData.device_code,\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code'\n })\n });\n\n if (tokenResponse.ok) {\n const tokenData = await tokenResponse.json() as TokenResponse;\n\n // Save tokens\n authManager.saveTokens(\n tokenData.access_token,\n tokenData.refresh_token,\n tokenData.expires_in\n );\n\n // Get user info\n const userResponse = await authManager.makeAuthenticatedRequest(AUTH_USER_INFO_URL);\n if (userResponse.ok) {\n const userData = await userResponse.json() as any;\n authManager.saveUser({\n id: userData.id,\n email: userData.email,\n name: userData.name\n });\n }\n\n // Show success\n bbs.showPollingStatus('success', 'Authentication successful!');\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n\n authenticated = true;\n\n // Brief pause to show success message\n await new Promise(resolve => setTimeout(resolve, 1500));\n\n // Transition animation\n if (options.animations) {\n const theme = bbs.getTheme();\n await bbs.transition(theme.animation);\n }\n\n break;\n }\n\n const errorData = await tokenResponse.json() as any;\n\n if (errorData.error === 'authorization_pending') {\n // Still waiting for user to authorize\n bbs.showPollingStatus('waiting', 'Waiting for authorization...');\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n } else if (errorData.error === 'slow_down') {\n // Too many requests, slow down\n await new Promise(resolve => setTimeout(resolve, 5000));\n } else if (errorData.error === 'expired_token') {\n throw new Error('Authentication timed out. Please try again.');\n } else if (errorData.error === 'access_denied') {\n throw new Error('Authentication was denied.');\n } else {\n throw new Error(`Authentication failed: ${errorData.error}`);\n }\n }\n\n if (!authenticated) {\n throw new Error('Authentication timed out. Please try again.');\n }\n\n } catch (error: any) {\n // Show error in BBS style\n bbs.showErrorPopup(error, 'Authentication Failed');\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n\n // Wait for user to press a key\n await new Promise<void>((resolve) => {\n term.once('key', () => resolve());\n });\n\n // Cleanup and exit\n console.error = originalConsoleError;\n term.clear();\n term.hideCursor(false);\n term.grabInput(false);\n term.processExit(1);\n return;\n }\n }\n\n const user = authManager.getUser();\n\n try {\n // Terminal, buffers, and BBS component are already set up above\n\n fs.appendFileSync('/tmp/bbs-debug.log', `${new Date().toISOString()} BBS starting - animations: ${options.animations}\\n`);\n // Show loading animation with theme-specific transition\n if (options.animations) {\n await bbs.showLoadingAnimation('Dialing BabylonJS Market BBS...', 1500);\n const theme = bbs.getTheme();\n await bbs.transition(theme.animation);\n } else {\n // Show static loading message\n bbs.put(2, 2, 'Connecting to BabylonJS Market BBS...', bbs.getTheme().primary, true);\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n }\n\n // Fetch ALL courses (both owned and unowned) from authenticated endpoint\n fs.appendFileSync('/tmp/bbs-debug.log', `${new Date().toISOString()} Fetching courses from ${API_URL}\\n`);\n let allCoursesResponse;\n try {\n allCoursesResponse = await authManager.makeAuthenticatedRequest(`${API_URL}/api/auth/courses/all`);\n fs.appendFileSync('/tmp/bbs-debug.log', `${new Date().toISOString()} Courses fetched OK\\n`);\n } catch (fetchError: any) {\n throw new Error(`Network error: ${fetchError.message}`);\n }\n\n if (!allCoursesResponse.ok) {\n const errorText = await allCoursesResponse.text();\n throw new Error(`Failed to fetch courses (${allCoursesResponse.status}): ${errorText}`);\n }\n\n const allCoursesData = await allCoursesResponse.json() as any;\n // The /api/auth/courses/all endpoint already includes ownership status\n const courses: Course[] = allCoursesData.courses || [];\n\n // Fetch downloads (course assets)\n let downloads: Download[] = [];\n try {\n const downloadsResponse = await authManager.makeAuthenticatedRequest(`${API_URL}/api/auth/downloads`);\n if (downloadsResponse.ok) {\n const downloadsData = await downloadsResponse.json() as any;\n downloads = downloadsData.downloads || [];\n }\n } catch (fetchError: any) {\n console.error(\"Failed to fetch downloads:\", fetchError.message);\n }\n\n // Scan for projects in the configured projects directory (with timeout)\n let scannedProjects: Project[] = [];\n const configuredProjectsDir = authManager.getProjectsDirectory();\n\n if (configuredProjectsDir && fs.existsSync(configuredProjectsDir)) {\n try {\n // Add 3 second timeout to prevent hangs\n const scanPromise = scanForProjects(configuredProjectsDir, 2);\n const timeoutPromise = new Promise<Project[]>((_, reject) =>\n setTimeout(() => reject(new Error('Project scan timed out')), 3000)\n );\n scannedProjects = await Promise.race([scanPromise, timeoutPromise]);\n } catch (scanError: any) {\n // Silently fail - projects will just be empty\n }\n }\n // If no projects directory is configured, projects will be empty\n\n // Dummy toys data with asset keys for testing\n const toys: Toy[] = [\n { id: 1, name: 'Spaceship Fighter', size: '2.4 MB', downloads: 1234, filetype: '.glb', modeltype: 'Arcade', assetKey: 'spaceship-fighter' },\n { id: 2, name: 'Robot Walker', size: '3.1 MB', downloads: 892, filetype: '.glb', modeltype: 'Rigged', assetKey: 'robot-walker' },\n { id: 3, name: 'City Buildings Pack', size: '15.2 MB', downloads: 3421, filetype: '.zip', modeltype: 'Static', assetKey: 'city-buildings' },\n { id: 4, name: 'Vehicle Collection', size: '8.7 MB', downloads: 2103, filetype: '.zip', modeltype: 'Static', assetKey: 'vehicle-collection' },\n { id: 5, name: 'Character Animations', size: '5.5 MB', downloads: 1567, filetype: '.glb', modeltype: 'Animated', assetKey: 'character-anims' }\n ];\n\n // ── Single source of truth: the pure BBS state. ──\n let state: BbsState = createInitialState({\n courses,\n toys,\n downloads,\n projects: scannedProjects as ProjectLike[],\n theme: options.theme as Theme,\n animations: !!options.animations,\n mouse: !!options.mouse,\n });\n\n // Impure handles that live alongside (but outside) the pure state.\n let courseDetailViewer: CourseDetailViewer | null = null;\n let currentCourseDetail: CourseDetail | null = null;\n let actionInProgress = false; // Prevent multiple actions\n let lastActionTime = 0; // Track last action time\n let currentError: Error | null = null; // Store current error\n let serverManifest: ServerManifest | null = null;\n\n // Dispatch a pure action into the state (does not render).\n const dispatch = (action: Action) => {\n state = reduce(state, action);\n };\n\n // Status display helper function (moved to outer scope)\n const statusY = term.height - 2;\n const showStatus = (msg: string, color: string = 'gray') => {\n term.moveTo(1, statusY);\n term.eraseLine();\n (term as any)[color](msg);\n };\n\n // Debug log file for tracking hangs\n const debugLog = (msg: string) => {\n fs.appendFileSync('/tmp/bbs-debug.log', `${new Date().toISOString()} ${msg}\\n`);\n };\n\n // Build the render context from the (impure) AuthManager + catalogs.\n const buildRenderContext = (): RenderContext => {\n const selectedProject = state.projects[state.projectsSelectedIndex];\n let syncUpdates: number | undefined;\n if (serverManifest) {\n const localManifest = authManager.getLibraryManifest();\n const comparison = compareManifests(serverManifest, localManifest);\n syncUpdates = comparison.toInstall.length + comparison.toUpdate.length;\n }\n return {\n componentCatalogLength: COMPONENT_CATALOG.length,\n gameModeCatalogLength: getGameModeCatalog().length,\n projectScenesCount: selectedProject ? getProjectScenes(selectedProject.path).length : 0,\n syncUpdates,\n serverManifest: serverManifest\n ? { unlockedFiles: serverManifest.unlockedFiles, totalFiles: serverManifest.totalFiles }\n : null,\n };\n };\n\n // Main render function using double buffering\n const render = async () => {\n try {\n debugLog(`render() start - currentView: ${state.currentView}`);\n // If in course detail view, let the viewer handle rendering\n if (state.currentView === 'courseDetail' && courseDetailViewer) {\n return;\n }\n\n // Clear back buffer\n backBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n\n const dim: Dimensions = { width: term.width, height: term.height };\n\n // Draw header with marked count\n bbs.drawBBSHeader(user?.email || user?.name || 'Guest', state.currentView.toUpperCase(), markedCount(state));\n\n // Keep the projects library data fresh for the selected project (the\n // original render() recomputed these inline each frame).\n if (state.currentView === 'projects' && state.projects.length > 0) {\n const selectedProject = state.projects[state.projectsSelectedIndex];\n if (selectedProject) {\n state = reduce(state, {\n type: 'SetLibraryData',\n components: getAvailableComponents(selectedProject.path),\n gameModes: getAvailableGameModes(selectedProject.path),\n installed: getInstalledGameModes(selectedProject.path),\n });\n }\n }\n\n const ctx = buildRenderContext();\n\n if (state.currentView === 'home') {\n renderHome(bbs, buildHome(state, dim));\n } else if (state.currentView === 'courses') {\n renderCourses(bbs, buildCourses(state, dim));\n } else if (state.currentView === 'toys') {\n renderToys(bbs, buildToys(state, dim));\n } else if (state.currentView === 'projects') {\n const projDir = authManager.getProjectsDirectory();\n renderProjects(bbs, buildProjects(state, dim, { projectsDir: projDir }), state, dim, ctx);\n } else if (state.currentView === 'downloads') {\n renderDownloads(bbs, buildDownloads(state, dim), dim);\n } else if (state.currentView === 'settings') {\n const settingsModel = buildSettings(state, {\n projectsDir: authManager.getProjectsDirectory(),\n libraryPath: authManager.getLibraryPath(),\n libraryInitialized: isLibraryInitialized(),\n lastSyncAt: (() => {\n const localStatus = getLibrarySyncStatus();\n return localStatus.lastSyncAt ? new Date(localStatus.lastSyncAt) : null;\n })(),\n });\n renderSettings(bbs, settingsModel, dim, ctx);\n } else if (state.currentView === 'courseDetail') {\n // Course detail view handles its own navigation display\n return;\n }\n\n // Navigation footer\n renderFooter(bbs, state, dim);\n\n // CRITICAL: Draw back buffer to screen buffer, then to terminal\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true }); // Only update changed cells\n\n // If there's an error popup, draw it on top\n if (state.errorPopupVisible && currentError) {\n bbs.showErrorPopup(currentError, 'BBS Error');\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n }\n } catch (renderError: any) {\n // Handle render errors without printing to stderr\n errorLogs.push(`Render error: ${renderError.message}`);\n currentError = renderError;\n state = reduce(state, { type: 'ShowError' });\n }\n };\n\n // Initial render\n debugLog('About to call initial render()');\n await render();\n debugLog('Initial render() complete');\n\n // Update the display every second to keep the timer fresh\n const timerInterval = setInterval(async () => {\n await render();\n }, 1000);\n\n // Handle terminal resize\n term.on('resize', async (width: number, height: number) => {\n // Recreate buffers with new size - cap at reasonable max\n const newWidth = Math.min(width || term.width || 80, 500);\n const newHeight = Math.min(height || term.height || 24, 100);\n\n screenBuffer = new ScreenBuffer({\n dst: term,\n width: newWidth,\n height: newHeight,\n x: 1,\n y: 1,\n noFill: true\n });\n\n backBuffer = new ScreenBuffer({\n width: newWidth,\n height: newHeight,\n dst: term,\n noFill: true\n });\n\n // Update course detail viewer if it exists\n if (courseDetailViewer) {\n courseDetailViewer.resize(newWidth, newHeight);\n }\n\n // Update BBS with new buffer\n bbs = new BufferedBBS(backBuffer, state.theme, state.animations);\n\n await render();\n });\n\n // Asset downloader instance\n const assetDownloader = new AssetDownloader(authManager);\n\n // Download function - shows status without blocking\n const downloadAsset = async (item: Course | Toy | Download, type: 'course' | 'toy' | 'download') => {\n let name: string;\n let assetKey: string;\n let fileName: string;\n\n if (type === 'download') {\n const dl = item as Download;\n name = dl.fileName;\n assetKey = dl.assetKey;\n fileName = dl.fileName;\n } else if (type === 'course') {\n const course = item as Course;\n name = course.title;\n assetKey = course.assetKey || `course-${course.slug}`;\n fileName = assetKey + '.zip';\n } else {\n const toy = item as Toy;\n name = toy.name;\n assetKey = toy.assetKey || toy.name.toLowerCase().replace(/\\s+/g, '-');\n fileName = assetKey + '.glb';\n }\n\n const outputPath = path.join(downloadDirectory, fileName);\n\n try {\n // Ensure download directory exists\n if (!fs.existsSync(downloadDirectory)) {\n fs.mkdirSync(downloadDirectory, { recursive: true });\n }\n\n showStatus(`Downloading ${name}...`, 'yellow');\n\n const success = await assetDownloader.downloadAsset(\n assetKey,\n outputPath,\n (progress) => {\n showStatus(`Downloading ${name}: ${progress.percentage}%`, 'yellow');\n }\n );\n\n if (success) {\n showStatus(`✓ Downloaded ${name} to ${outputPath}`, 'green');\n } else {\n showStatus(`✗ Failed to download ${name}`, 'red');\n }\n } catch (error: any) {\n showStatus(`✗ Error: ${error.message}`, 'red');\n }\n\n // Clear status after 3 seconds\n setTimeout(() => {\n term.moveTo(1, statusY);\n term.eraseLine();\n }, 3000);\n };\n\n // ── Path autocomplete (shared by projectsDir + libraryPath editing). ──\n const autocompletePath = (input: string): string => {\n try {\n if (!input || input.trim() === '') {\n return homedir() + '/';\n }\n const dir = path.dirname(input);\n const base = path.basename(input);\n if (dir && fs.existsSync(dir)) {\n const entries = fs.readdirSync(dir);\n const matches = entries\n .filter(e => e.toLowerCase().startsWith(base.toLowerCase()))\n .filter(e => {\n try {\n return fs.statSync(path.join(dir, e)).isDirectory();\n } catch {\n return false;\n }\n });\n if (matches.length === 1) {\n return path.join(dir, matches[0]) + '/';\n } else if (matches.length > 1) {\n const commonPrefix = matches.reduce((prefix, match) => {\n let i = 0;\n while (i < prefix.length && i < match.length && prefix[i].toLowerCase() === match[i].toLowerCase()) {\n i++;\n }\n return match.slice(0, i);\n });\n if (commonPrefix.length > base.length) {\n return path.join(dir, commonPrefix);\n }\n }\n } else if (input.startsWith('~')) {\n return homedir() + input.slice(1);\n }\n } catch (err) {\n // Ignore autocomplete errors\n }\n return input;\n };\n\n // ── Effect runner: executes the side-effecting intents from keymap. ──\n const runEffect = async (effect: Effect): Promise<void> => {\n switch (effect.type) {\n case 'CommitProjectsDir': {\n if (state.projectsDirInput.trim()) {\n const resolvedPath = path.resolve(state.projectsDirInput.trim());\n if (fs.existsSync(resolvedPath)) {\n authManager.setProjectsDirectory(resolvedPath);\n dispatch({ type: 'SetProjectsDirResult', success: '✓ Saved! Scanning...' });\n await render();\n\n const newProjects = await scanForProjects(resolvedPath, 2);\n state = { ...state, projects: newProjects as ProjectLike[], projectsSelectedIndex: 0, editingProjectsDir: false, projectsDirInput: '' };\n dispatch({\n type: 'SetProjectsDirResult',\n success: `✓ Found ${state.projects.length} project${state.projects.length === 1 ? '' : 's'}`,\n });\n\n setTimeout(async () => {\n dispatch({ type: 'SetProjectsDirResult', success: '' });\n await render();\n }, 2000);\n } else {\n dispatch({ type: 'SetProjectsDirResult', error: '✗ Directory not found' });\n }\n }\n await render();\n break;\n }\n\n case 'AutocompleteProjectsDir':\n dispatch({ type: 'InputSet', value: autocompletePath(state.projectsDirInput) });\n await render();\n break;\n\n case 'CommitLibraryPath': {\n if (state.libraryPathInput.trim()) {\n const resolvedPath = path.resolve(state.libraryPathInput.trim());\n authManager.setLibraryPath(resolvedPath);\n\n if (!fs.existsSync(path.join(resolvedPath, 'Components'))) {\n const result = await initializeLibrary(resolvedPath);\n state = { ...state, libraryPathSuccess: result.success ? '✓ Library initialized!' : result.message };\n } else {\n state = { ...state, libraryPathSuccess: '✓ Saved!' };\n }\n state = { ...state, libraryPathError: '', editingLibraryPath: false, libraryPathInput: '' };\n\n setTimeout(async () => {\n dispatch({ type: 'SetLibraryPathResult', success: '' });\n await render();\n }, 2000);\n }\n await render();\n break;\n }\n\n case 'AutocompleteLibraryPath':\n dispatch({ type: 'InputSet', value: autocompletePath(state.libraryPathInput) });\n await render();\n break;\n\n case 'InstallComponent': {\n const comp = state.availableComponents[state.componentSelectedIndex];\n const project = state.projects[state.projectsSelectedIndex];\n if (comp && project) {\n const result = await installComponent(comp.name, project.path);\n dispatch({ type: 'SetComponentInstallResult', message: result.message, success: result.success });\n if (result.success) {\n const projDir = authManager.getProjectsDirectory();\n if (projDir) {\n state = { ...state, projects: (await scanForProjects(projDir, 2)) as ProjectLike[] };\n }\n dispatch({ type: 'SetAvailableComponents', components: getAvailableComponents(project.path) });\n }\n await render();\n }\n break;\n }\n\n case 'InstallGameMode': {\n const mode = state.availableGameModes[state.gameModeSelectedIndex];\n const project = state.projects[state.projectsSelectedIndex];\n if (mode && project) {\n const result = await installGameMode(mode.name, project.path);\n dispatch({ type: 'SetGameModeInstallResult', message: result.message, success: result.success });\n if (result.success) {\n dispatch({ type: 'SetAvailableGameModes', gameModes: getAvailableGameModes(project.path) });\n dispatch({ type: 'SetInstalledGameModes', gameModes: getInstalledGameModes(project.path) });\n }\n await render();\n }\n break;\n }\n\n case 'CreateScene': {\n const project = state.projects[state.projectsSelectedIndex];\n if (state.sceneNameInput.trim() && state.installedGameModes.length > 0 && project) {\n const gameMode = state.installedGameModes[state.sceneGameModeIndex] || state.installedGameModes[0];\n const result = await createScene(project.path, gameMode, state.sceneNameInput.trim());\n dispatch({ type: 'SetSceneCreatorResult', message: result.message, success: result.success });\n if (result.success) {\n dispatch({ type: 'ClearSceneNameInput' });\n setTimeout(async () => {\n if (result.path) {\n const editor = process.env.EDITOR || 'code';\n const { spawn } = await import('child_process');\n const editorProcess = spawn(editor, [result.path], { detached: true, stdio: 'ignore' });\n editorProcess.unref();\n }\n }, 500);\n }\n await render();\n } else if (!state.sceneNameInput.trim()) {\n dispatch({ type: 'SetSceneCreatorResult', message: 'Please enter a scene name', success: false });\n await render();\n }\n break;\n }\n\n case 'ActivateSettings': {\n // Debounce only applies to the ENTER path historically; SPACE path\n // had no debounce. Preserve that distinction.\n const idx = effect.index;\n if (!effect.viaSpace) {\n const now = Date.now();\n if (actionInProgress || (now - lastActionTime) < 500) break;\n lastActionTime = now;\n }\n\n if (effect.viaSpace) {\n // Space only handles theme/anim/mouse rows (0..7).\n if (idx < 6) {\n const theme = THEMES[idx];\n dispatch({ type: 'SetTheme', theme });\n bbs.setTheme(theme);\n options.theme = theme;\n authManager.savePreferences({ theme });\n } else if (idx === 6) {\n dispatch({ type: 'ToggleAnimations' });\n options.animations = state.animations;\n authManager.savePreferences({ animations: state.animations });\n } else if (idx === 7) {\n dispatch({ type: 'ToggleMouse' });\n options.mouse = state.mouse;\n authManager.savePreferences({ mouse: state.mouse });\n term.grabInput({ mouse: state.mouse ? 'button' : undefined });\n }\n await render();\n break;\n }\n\n // ENTER path: full settings activation.\n if (idx < 6) {\n const theme = THEMES[idx];\n dispatch({ type: 'SetTheme', theme });\n bbs.setTheme(theme);\n options.theme = theme;\n authManager.savePreferences({ theme });\n } else if (idx === 6) {\n dispatch({ type: 'ToggleAnimations' });\n options.animations = state.animations;\n authManager.savePreferences({ animations: state.animations });\n } else if (idx === 7) {\n dispatch({ type: 'ToggleMouse' });\n options.mouse = state.mouse;\n authManager.savePreferences({ mouse: state.mouse });\n term.grabInput({ mouse: state.mouse ? 'button' : undefined });\n } else if (idx === 8) {\n const currentDir = authManager.getProjectsDirectory();\n dispatch({ type: 'StartEditProjectsDir', value: currentDir || '' });\n } else if (idx === 9) {\n if (!isLibraryInitialized()) {\n const result = await initializeLibrary();\n if (result.success) {\n dispatch({ type: 'SetLibraryPathResult', success: '✓ Library initialized!' });\n setTimeout(async () => {\n dispatch({ type: 'SetLibraryPathResult', success: '' });\n await render();\n }, 2000);\n } else {\n dispatch({ type: 'SetLibraryPathResult', error: result.message });\n }\n } else {\n dispatch({ type: 'StartEditLibraryPath', value: authManager.getLibraryPath() });\n }\n } else if (idx === 10) {\n if (!state.syncingLibrary) {\n dispatch({ type: 'SetSyncState', syncing: true, message: '', error: '', progress: '' });\n await render();\n\n const result = await syncLibrary((current, total, fileName) => {\n // Best-effort progress (can't await render in callback).\n state = reduce(state, { type: 'SetSyncState', progress: `${current}/${total}: ${fileName}` });\n });\n\n dispatch({ type: 'SetSyncState', syncing: false, progress: '' });\n\n if (result.success) {\n dispatch({ type: 'SetSyncState', message: result.message });\n const manifestResult = await fetchLibraryManifest();\n if (manifestResult.success && manifestResult.manifest) {\n serverManifest = manifestResult.manifest;\n }\n } else {\n dispatch({ type: 'SetSyncState', error: result.message });\n }\n\n setTimeout(async () => {\n dispatch({ type: 'SetSyncState', message: '', error: '' });\n await render();\n }, 3000);\n }\n } else if (idx === 11) {\n dispatch({ type: 'SetLibraryPathResult', success: 'Migrating from arcade-ref...' });\n await render();\n\n const result = await migrateFromArcadeRef();\n if (result.success) {\n dispatch({ type: 'SetLibraryPathResult', success: `✓ ${result.message}` });\n } else {\n dispatch({ type: 'SetLibraryPathResult', error: result.message });\n }\n\n setTimeout(async () => {\n dispatch({ type: 'SetLibraryPathResult', success: '', error: '' });\n await render();\n }, 3000);\n }\n await render();\n break;\n }\n\n case 'OpenCourse': {\n const now = Date.now();\n if (actionInProgress || (now - lastActionTime) < 500) break;\n lastActionTime = now;\n\n const course = state.courses[state.selectedIndex];\n if (!course) break;\n\n if (!actionInProgress) {\n actionInProgress = true;\n try {\n if (course.isOwned) {\n showStatus(`Loading course details for ${course.title}...`, 'yellow');\n\n const detailsResponse = await authManager.makeAuthenticatedRequest(\n `${API_URL}/api/auth/courses/${course.slug}`\n );\n\n if (detailsResponse.ok) {\n const detailData = await detailsResponse.json() as any;\n\n currentCourseDetail = {\n ...detailData.course,\n articles: detailData.articles || []\n };\n\n courseDetailViewer = new CourseDetailViewer(\n backBuffer,\n screenBuffer,\n state.theme,\n state.animations\n );\n courseDetailViewer.setUserInfo(user?.email || user?.name || 'Guest');\n\n try {\n if (!currentCourseDetail) {\n throw new Error('Course detail unavailable');\n }\n courseDetailViewer.loadCourse(currentCourseDetail);\n } catch (loadError: any) {\n errorLogs.push(`Error loading course details: ${loadError.message}`);\n currentError = loadError;\n dispatch({ type: 'ShowError' });\n courseDetailViewer = null;\n currentCourseDetail = null;\n await render();\n break;\n }\n\n courseDetailViewer.once('exit', () => {\n courseDetailViewer = null;\n currentCourseDetail = null;\n state = { ...state, currentView: 'courses' };\n render();\n });\n\n courseDetailViewer.on('error', (error: Error) => {\n currentError = error;\n dispatch({ type: 'ShowError' });\n render();\n });\n\n // Switch to detail view (push history like the monolith).\n state = { ...state, navigationHistory: [...state.navigationHistory, 'courses'], currentView: 'courseDetail' };\n\n term.moveTo(1, statusY);\n term.eraseLine();\n } else {\n showStatus(`Failed to load course details`, 'red');\n }\n } else {\n showStatus(`Opening browser to purchase: ${course.title}...`, 'yellow');\n const category = course.category || 'foundations';\n await open(`https://dev.babylonjsmarket.com/products/${category}/${course.slug}/`);\n showStatus(`Opened browser for course purchase`, 'green');\n setTimeout(() => {\n term.moveTo(1, statusY);\n term.eraseLine();\n render();\n }, 2000);\n }\n } catch (error: any) {\n showStatus(`Error loading course: ${error.message}`, 'red');\n } finally {\n actionInProgress = false;\n }\n }\n break;\n }\n\n case 'ShowToyInfo': {\n const toy = state.toys[state.toysSelectedIndex];\n if (toy) {\n term.moveTo(1, statusY);\n term.eraseLine();\n term.gray(`${toy.name} - ${toy.size} - ${toy.modeltype} model`);\n setTimeout(() => {\n term.moveTo(1, statusY);\n term.eraseLine();\n }, 3000);\n }\n break;\n }\n\n case 'OpenProjectInEditor': {\n const project = state.projects[state.projectsSelectedIndex];\n if (project) {\n const editor = process.env.EDITOR || 'code';\n const editorName = path.basename(editor);\n showStatus(`Opening ${project.name} in ${editorName}...`, 'yellow');\n const { spawn } = await import('child_process');\n const editorProcess = spawn(editor, [project.path], { detached: true, stdio: 'ignore' });\n editorProcess.unref();\n showStatus(`✓ Opened ${project.name} in ${editorName}`, 'green');\n setTimeout(() => {\n showStatus('', 'gray');\n }, 3000);\n }\n break;\n }\n\n case 'Download': {\n if (state.currentView === 'courses' && state.courses[state.selectedIndex]) {\n downloadAsset(state.courses[state.selectedIndex], 'course');\n } else if (state.currentView === 'toys' && state.toys[state.toysSelectedIndex]) {\n downloadAsset(state.toys[state.toysSelectedIndex], 'toy');\n } else if (state.currentView === 'downloads' && state.downloads[state.downloadsSelectedIndex]) {\n downloadAsset(state.downloads[state.downloadsSelectedIndex], 'download');\n }\n break;\n }\n\n case 'DevServer': {\n const project = state.projects[state.projectsSelectedIndex];\n if (project) {\n if (project.hasPackageJson) {\n showStatus(`Starting dev server for ${project.name}...`, 'yellow');\n const { exec } = await import('child_process');\n const script = `cd \"${project.path}\" && npm run dev`;\n exec(`osascript -e 'tell app \"Terminal\" to do script \"${script.replace(/\"/g, '\\\\\"')}\"'`);\n showStatus(`✓ Opened terminal for dev server`, 'green');\n setTimeout(() => {\n showStatus('', 'gray');\n }, 3000);\n } else {\n showStatus(`✗ No package.json found in ${project.name}`, 'red');\n }\n }\n break;\n }\n\n case 'DownloadAllMarked': {\n if (state.currentView === 'downloads' && state.markedDownloads.size > 0) {\n showStatus(`Starting batch download of ${state.markedDownloads.size} files...`, 'yellow');\n let downloadedCount = 0;\n const total = state.markedDownloads.size;\n for (const index of state.markedDownloads) {\n if (state.downloads[index]) {\n await downloadAsset(state.downloads[index], 'download');\n downloadedCount++;\n if (downloadedCount < total) {\n await new Promise(resolve => setTimeout(resolve, 31000)); // avoid rate limit\n }\n }\n }\n state = { ...state, markedDownloads: new Set<number>() };\n showStatus(`✓ Batch download complete: ${downloadedCount} files`, 'green');\n await render();\n }\n break;\n }\n\n case 'BuyInBrowser': {\n const now = Date.now();\n if (actionInProgress || (now - lastActionTime) < 500) break;\n lastActionTime = now;\n actionInProgress = true;\n try {\n if (state.currentView === 'courses' && state.courses[state.selectedIndex]) {\n const openFn = (await import('open')).default;\n const course = state.courses[state.selectedIndex];\n const category = course.category || 'foundations';\n await openFn(`${API_URL}/products/${category}/${course.slug}/`);\n await new Promise(resolve => setTimeout(resolve, 1000));\n } else if (state.currentView === 'toys' && state.toys[state.toysSelectedIndex]) {\n const openFn = (await import('open')).default;\n await openFn(`${API_URL}/toys`);\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n } finally {\n actionInProgress = false;\n }\n break;\n }\n\n case 'NewProject': {\n const projDir = authManager.getProjectsDirectory();\n if (!projDir) {\n showStatus('✗ Set projects directory in Settings first', 'red');\n } else {\n showStatus('Creating new project with create-arcade...', 'yellow');\n const { exec } = await import('child_process');\n const createArcadePath = '/Users/law/Programming/Web/BJSM/tools/create-arcade/dist/index.mjs';\n const script = `cd \"${projDir}\" && node \"${createArcadePath}\"`;\n exec(`osascript -e 'tell app \"Terminal\" to do script \"${script.replace(/\"/g, '\\\\\"')}\"'`);\n showStatus('✓ Opened terminal for create-arcade wizard', 'green');\n setTimeout(async () => {\n showStatus('Press R to rescan projects when done', 'gray');\n }, 3000);\n }\n break;\n }\n\n case 'RescanProjects': {\n const projDir = authManager.getProjectsDirectory();\n if (projDir) {\n showStatus('Rescanning projects...', 'yellow');\n state = { ...state, projects: (await scanForProjects(projDir, 2)) as ProjectLike[], projectsSelectedIndex: 0 };\n showStatus(`✓ Found ${state.projects.length} project${state.projects.length === 1 ? '' : 's'}`, 'green');\n await render();\n setTimeout(() => {\n showStatus('', 'gray');\n }, 3000);\n }\n break;\n }\n\n case 'InstallLibraryDeps': {\n const project = state.projects[state.projectsSelectedIndex];\n if (project) {\n if (!project.hasPackageJson) {\n showStatus(`✗ No package.json in ${project.name}`, 'red');\n } else {\n showStatus(`Running npm install in ${project.name}...`, 'yellow');\n const { exec } = await import('child_process');\n const script = `cd \"${project.path}\" && npm install; echo \"\"; echo \"Press any key to close...\"; read -n 1`;\n exec(`osascript -e 'tell app \"Terminal\" to do script \"${script.replace(/\"/g, '\\\\\"')}\"'`);\n showStatus(`✓ Opened terminal for npm install`, 'green');\n setTimeout(() => {\n showStatus('', 'gray');\n }, 3000);\n }\n }\n break;\n }\n\n case 'TestError':\n if (process.env.DEBUG) {\n throw new Error('This is a test error to demonstrate the error popup functionality. The error message can be quite long and will wrap appropriately in the popup dialog.');\n }\n break;\n\n case 'Quit': {\n clearInterval(timerInterval);\n\n if (state.animations) {\n const theme = bbs.getTheme();\n await bbs.transition(theme.animation);\n }\n\n term.clear();\n term.hideCursor(false);\n term.grabInput(false);\n\n term.moveTo(1, 2);\n term.cyan(`\n ╔══════════════════════════════════════════╗\n ║ ║\n ║ Thank you for using BJ's BBS! ║\n ║ ║\n ║ NO CARRIER ║\n ║ ║\n ╚══════════════════════════════════════════╝\n `);\n\n console.error = originalConsoleError;\n term.processExit(0);\n break;\n }\n }\n };\n\n // ── Main key handler: key → keyToAction → reduce/effect → render. ──\n const mainKeyHandler = async (name: string) => {\n try {\n // Gate order mirrors the original monolith exactly:\n // 1. error-popup ESC (full-screen redraw) 2. error-popup swallow\n // 3. inline editing gates 4. scene-creator text input\n // 5. actionInProgress block 6. courseDetail input 7. main switch.\n // keyToAction() resolves gates 1–4 purely, so we only need to special-\n // case the error-popup redraw, then enforce gates 5 & 6 here.\n\n // Gate 1: error popup full-screen redraw on dismiss.\n if (state.errorPopupVisible && name === 'ESCAPE') {\n dispatch({ type: 'DismissError' });\n currentError = null;\n backBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n screenBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n screenBuffer.draw();\n await render();\n return;\n }\n // Gate 2: error popup swallows everything else.\n if (state.errorPopupVisible) {\n return;\n }\n\n // Gates 3 & 4 are pure: route them through keyToAction immediately so\n // they run *before* the actionInProgress block (matching original).\n const inEditingMode =\n state.editingProjectsDir ||\n state.editingLibraryPath ||\n (state.sceneCreatorActive && state.currentView === 'projects');\n if (inEditingMode) {\n const intent = keyToAction(name, state);\n // Scene-creator falls through for ENTER/ESC/LEFT/RIGHT — those are\n // handled below by the normal path, so only short-circuit when the\n // editing gate actually produced an intent for a consumed key.\n if (intent && (state.editingProjectsDir || state.editingLibraryPath)) {\n if (intent.kind === 'action') {\n dispatch(intent.action);\n await render();\n } else {\n await runEffect(intent.effect);\n }\n return;\n }\n if (intent && state.sceneCreatorActive) {\n // Only consume if it's the scene-name text input (InputChar / Backspace).\n if (\n intent.kind === 'action' &&\n (intent.action.type === 'InputChar' || intent.action.type === 'InputBackspace')\n ) {\n dispatch(intent.action);\n await render();\n return;\n }\n // otherwise fall through to the normal path below\n }\n }\n\n // Gate 5: block ordinary keys while an action is in progress.\n if (actionInProgress) {\n return;\n }\n\n // Gate 6: course detail view handles its own input.\n if (state.currentView === 'courseDetail' && courseDetailViewer) {\n const handled = courseDetailViewer.handleInput(name);\n if (handled) return;\n }\n\n // Gate 7: main switch.\n const intent = keyToAction(name, state);\n if (!intent) {\n return;\n }\n\n if (intent.kind === 'action') {\n dispatch(intent.action);\n await render();\n } else {\n await runEffect(intent.effect);\n }\n } catch (keyError: any) {\n errorLogs.push(`Key handler error: ${keyError.message}`);\n currentError = keyError;\n dispatch({ type: 'ShowError' });\n await render();\n }\n };\n\n // Register the main key handler\n debugLog('Registering key handler');\n term.on('key', mainKeyHandler);\n debugLog('Key handler registered - BBS ready for input');\n\n } catch (error: any) {\n // Restore console.error before exiting\n if (typeof originalConsoleError !== 'undefined') {\n console.error = originalConsoleError;\n }\n\n term.clear();\n term.red.bold('ERROR: ');\n term.white(error.message || 'Failed to connect to BBS\\n');\n term.hideCursor(false);\n term.grabInput(false);\n term.processExit(1);\n }\n });\n","import terminalKit from 'terminal-kit';\nimport { EventEmitter } from 'events';\n\nconst { ScreenBuffer, TextBuffer } = terminalKit;\n\nexport type Theme = 'classic' | 'desert' | 'matrix' | 'commando' | 'sandiego' | 'ed209';\n\ninterface ThemeColors {\n primary: string;\n secondary: string;\n accent: string;\n text: string;\n dim: string;\n animation: 'fade' | 'wipe' | 'matrix' | 'sweep';\n}\n\nexport class BufferedBBS extends EventEmitter {\n private buffer: any;\n private term: any;\n private theme: Theme;\n private themes: Record<Theme, ThemeColors> = {\n classic: {\n primary: 'cyan',\n secondary: 'yellow', \n accent: 'magenta',\n text: 'white',\n dim: 'gray',\n animation: 'fade'\n },\n desert: {\n primary: 'yellow',\n secondary: 'red',\n accent: 'green',\n text: 'white', \n dim: 'gray',\n animation: 'wipe'\n },\n matrix: {\n primary: 'green',\n secondary: 'brightGreen',\n accent: 'cyan',\n text: 'green',\n dim: 'darkGray',\n animation: 'matrix'\n },\n commando: {\n primary: 'green',\n secondary: 'yellow',\n accent: 'darkGray',\n text: 'white',\n dim: 'darkGray',\n animation: 'sweep'\n },\n sandiego: {\n primary: 'red',\n secondary: 'yellow',\n accent: 'brightWhite',\n text: 'white',\n dim: 'gray',\n animation: 'fade'\n },\n ed209: {\n primary: 'cyan',\n secondary: 'brightBlue',\n accent: 'gray',\n text: 'brightWhite',\n dim: 'darkGray',\n animation: 'wipe'\n }\n };\n \n private nodeNumber: number;\n public connectStartTime: number;\n private transferProtocol: 'Xmodem' | 'Ymodem' | 'Zmodem' = 'Zmodem';\n public animations: boolean;\n\n constructor(buffer: any, theme: Theme = 'classic', animations = true) {\n super();\n this.buffer = buffer;\n this.term = terminalKit.terminal;\n this.theme = theme;\n this.animations = animations;\n this.nodeNumber = Math.floor(Math.random() * 8) + 1;\n this.connectStartTime = Date.now();\n }\n\n getTheme(): ThemeColors {\n return this.themes[this.theme];\n }\n\n setTheme(theme: Theme) {\n this.theme = theme;\n this.emit('themeChanged', theme);\n }\n\n // Convert color name to terminal-kit attribute\n private getColorAttr(colorName: string): any {\n const colorMap: Record<string, any> = {\n 'black': { color: 0 },\n 'red': { color: 1 },\n 'green': { color: 2 },\n 'yellow': { color: 3 },\n 'blue': { color: 4 },\n 'magenta': { color: 5 },\n 'cyan': { color: 6 },\n 'white': { color: 7 },\n 'gray': { color: 8 },\n 'darkGray': { color: 8 },\n 'brightRed': { color: 9 },\n 'brightGreen': { color: 10 },\n 'brightYellow': { color: 11 },\n 'brightBlue': { color: 12 },\n 'brightMagenta': { color: 13 },\n 'brightCyan': { color: 14 },\n 'brightWhite': { color: 15 }\n };\n return colorMap[colorName] || { color: 7 };\n }\n\n // Draw text to buffer at position\n put(x: number, y: number, text: string | number | boolean | undefined | null, colorName?: string, bold: boolean = false) {\n // Ensure text is a string\n const textStr = text === undefined || text === null ? '' : String(text);\n \n const attr = colorName ? this.getColorAttr(colorName) : { color: 7 };\n if (bold) attr.bold = true;\n \n this.buffer.put({ \n x: x - 1, // Convert to 0-based\n y: y - 1, \n attr,\n wrap: false\n }, textStr);\n }\n\n // Draw a box to buffer\n drawBox(x: number, y: number, width: number, height: number, title?: string, focused: boolean = false) {\n const theme = this.getTheme();\n const color = theme.secondary;\n \n const chars = {\n topLeft: '╔', topRight: '╗', bottomLeft: '╚', bottomRight: '╝',\n horizontal: '═', vertical: '║'\n };\n\n // Top border\n this.put(x, y, chars.topLeft, color);\n for (let i = 1; i < width - 1; i++) {\n this.put(x + i, y, chars.horizontal, color);\n }\n this.put(x + width - 1, y, chars.topRight, color);\n\n // Title if provided\n if (title) {\n if (focused) {\n // Draw shadow/highlight effect for focused window\n const titlePadding = 3;\n const titleWidth = title.length + (titlePadding * 2);\n const titleX = x + Math.floor((width - titleWidth) / 2);\n \n // Draw shadow background\n this.put(titleX, y, '╔', theme.accent);\n for (let i = 1; i < titleWidth - 1; i++) {\n this.put(titleX + i, y, '═', theme.accent);\n }\n this.put(titleX + titleWidth - 1, y, '╗', theme.accent);\n \n // Draw title with padding\n const paddedTitle = ' '.repeat(titlePadding) + title + ' '.repeat(titlePadding);\n this.put(titleX + 1, y, paddedTitle.substring(1, paddedTitle.length - 1), theme.primary, true);\n } else {\n const titleX = x + Math.floor((width - title.length - 2) / 2);\n this.put(titleX, y, ' ', color);\n this.put(titleX + 1, y, title, theme.primary, true);\n this.put(titleX + title.length + 1, y, ' ', color);\n }\n }\n\n // Sides\n for (let i = 1; i < height - 1; i++) {\n this.put(x, y + i, chars.vertical, color);\n // Clear inside of box\n for (let j = 1; j < width - 1; j++) {\n this.put(x + j, y + i, ' ');\n }\n this.put(x + width - 1, y + i, chars.vertical, color);\n }\n\n // Bottom border\n this.put(x, y + height - 1, chars.bottomLeft, color);\n for (let i = 1; i < width - 1; i++) {\n this.put(x + i, y + height - 1, chars.horizontal, color);\n }\n this.put(x + width - 1, y + height - 1, chars.bottomRight, color);\n }\n\n // Draw BBS header to buffer\n drawBBSHeader(username: string, currentPage: string = 'MAIN', markedCount: number = 0) {\n const width = this.buffer.width;\n const theme = this.getTheme();\n \n // Top border\n for (let i = 0; i < width; i++) {\n this.put(i + 1, 1, '═', theme.secondary);\n }\n \n // Title and info line\n this.put(2, 2, \"BJ's BBS\", theme.primary, true);\n \n // Node info\n const nodeText = `Node ${this.nodeNumber}`;\n this.put(15, 2, nodeText, theme.accent);\n \n // Current page\n const pageX = Math.floor((width - currentPage.length) / 2);\n this.put(pageX, 2, currentPage, theme.primary, true);\n \n // Protocol on the right\n this.put(width - 10, 2, this.transferProtocol, theme.accent);\n \n // Connection info line\n const connectTime = Math.floor((Date.now() - this.connectStartTime) / 1000 / 60);\n const baud = '2400 BAUD';\n const protocol = 'ANSI';\n const timeStr = `${connectTime}:${String(new Date().getSeconds()).padStart(2, '0')}`;\n \n this.put(2, 3, baud, theme.dim);\n this.put(15, 3, protocol, theme.dim);\n this.put(30, 3, timeStr, theme.dim);\n \n // Show marked count if any\n if (markedCount > 0) {\n const markedText = `Marked: ${markedCount}`;\n this.put(width - 20, 3, markedText, theme.accent, true);\n }\n \n // Bottom border\n for (let i = 0; i < width; i++) {\n this.put(i + 1, 4, '═', theme.secondary);\n }\n }\n\n // Draw a table to buffer\n drawTable(x: number, y: number, options: {\n data: any[];\n columns: Array<{ key: string; label: string; width?: number }>;\n selectedIndex?: number;\n width?: number;\n }) {\n const theme = this.getTheme();\n const width = options.width || this.buffer.width - x;\n \n // Calculate column widths\n const numCols = options.columns.length;\n const borderWidth = numCols + 1;\n const paddingWidth = numCols * 2;\n const availableWidth = width - borderWidth - paddingWidth;\n \n const colWidths: number[] = [];\n let assignedWidth = 0;\n \n options.columns.forEach((col, i) => {\n if (col.width) {\n colWidths[i] = col.width;\n assignedWidth += col.width;\n } else {\n colWidths[i] = 0;\n }\n });\n \n // Distribute remaining width\n const flexCols = options.columns.filter((_, i) => colWidths[i] === 0).length;\n if (flexCols > 0) {\n const flexWidth = Math.floor((availableWidth - assignedWidth) / flexCols);\n options.columns.forEach((_, i) => {\n if (colWidths[i] === 0) {\n colWidths[i] = flexWidth;\n }\n });\n }\n \n // Draw top border\n this.put(x, y, '╔', theme.secondary);\n let xPos = x + 1;\n colWidths.forEach((w, i) => {\n for (let j = 0; j < w + 2; j++) {\n this.put(xPos++, y, '═', theme.secondary);\n }\n if (i < colWidths.length - 1) {\n this.put(xPos++, y, '╦', theme.secondary);\n }\n });\n this.put(xPos, y, '╗', theme.secondary);\n \n // Draw header\n y++;\n this.put(x, y, '║', theme.secondary);\n xPos = x + 1;\n options.columns.forEach((col, i) => {\n this.put(xPos++, y, ' ');\n const text = this.truncate(col.label, colWidths[i]);\n this.put(xPos, y, text, theme.primary, true);\n xPos += colWidths[i];\n this.put(xPos++, y, ' ');\n this.put(xPos++, y, '║', theme.secondary);\n });\n \n // Draw separator\n y++;\n this.put(x, y, '╠', theme.secondary);\n xPos = x + 1;\n colWidths.forEach((w, i) => {\n for (let j = 0; j < w + 2; j++) {\n this.put(xPos++, y, '═', theme.secondary);\n }\n if (i < colWidths.length - 1) {\n this.put(xPos++, y, '╬', theme.secondary);\n }\n });\n this.put(xPos, y, '╣', theme.secondary);\n \n // Draw data rows\n options.data.forEach((row, rowIndex) => {\n y++;\n const isSelected = rowIndex === options.selectedIndex;\n \n this.put(x, y, '║', theme.secondary);\n xPos = x + 1;\n \n options.columns.forEach((col, i) => {\n this.put(xPos++, y, ' ');\n const value = String(row[col.key] || '');\n const text = this.truncate(value, colWidths[i]);\n const color = isSelected ? \n (this.theme === 'desert' ? 'brightYellow' : \n this.theme === 'matrix' ? 'brightGreen' : 'brightCyan') : \n 'white';\n this.put(xPos, y, text, color, isSelected);\n xPos += colWidths[i];\n this.put(xPos++, y, ' ');\n this.put(xPos++, y, '║', theme.secondary);\n });\n });\n \n // Draw bottom border\n y++;\n this.put(x, y, '╚', theme.secondary);\n xPos = x + 1;\n colWidths.forEach((w, i) => {\n for (let j = 0; j < w + 2; j++) {\n this.put(xPos++, y, '═', theme.secondary);\n }\n if (i < colWidths.length - 1) {\n this.put(xPos++, y, '╩', theme.secondary);\n }\n });\n this.put(xPos, y, '╝', theme.secondary);\n \n return y - options.data.length - 3; // Return starting Y position\n }\n \n private truncate(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text.padEnd(maxLength);\n return text.substring(0, maxLength - 3) + '...';\n }\n\n // Show notification (draw to a temporary position)\n showNotification(message: string, type: 'info' | 'success' | 'error') {\n const theme = this.getTheme();\n const color = type === 'error' ? 'red' : type === 'success' ? 'green' : theme.primary;\n const y = this.buffer.height - 2;\n const x = 2;\n \n // Clear line\n for (let i = 0; i < this.buffer.width; i++) {\n this.put(i + 1, y, ' ');\n }\n \n // Draw message\n this.put(x, y, message, color, true);\n }\n \n // Loading animation\n async showLoadingAnimation(message: string, duration: number = 1500) {\n const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n const startTime = Date.now();\n let frameIndex = 0;\n \n while (Date.now() - startTime < duration) {\n this.term.moveTo(2, 2);\n this.term[this.getTheme().primary](frames[frameIndex] + ' ' + message);\n frameIndex = (frameIndex + 1) % frames.length;\n await new Promise(resolve => setTimeout(resolve, 80));\n }\n }\n\n // Show error in a popup dialog\n showErrorPopup(error: Error | string, title: string = 'Error') {\n const theme = this.getTheme();\n const errorMessage = typeof error === 'string' ? error : error.message;\n const errorStack = typeof error === 'object' && error.stack ? error.stack : '';\n\n // Calculate popup dimensions\n const maxWidth = Math.min(70, this.term.width - 10);\n const lines = this.wrapText(errorMessage, maxWidth - 4);\n\n // Add stack trace lines if available (limit to 5 lines)\n const stackLines: string[] = [];\n if (errorStack && process.env.DEBUG) {\n const stack = errorStack.split('\\n').slice(1, 6); // Skip first line (it's the message)\n stackLines.push('', '--- Stack Trace ---');\n stack.forEach(line => {\n const wrapped = this.wrapText(line.trim(), maxWidth - 4);\n stackLines.push(...wrapped);\n });\n }\n\n const allLines = [...lines, ...stackLines];\n const popupHeight = Math.min(allLines.length + 6, this.term.height - 4);\n const popupWidth = maxWidth;\n\n const x = Math.floor((this.term.width - popupWidth) / 2);\n const y = Math.floor((this.term.height - popupHeight) / 2);\n\n // Draw error popup box with red border\n this.drawBox(x, y, popupWidth, popupHeight, `⚠ ${title}`);\n\n // Override border color to red for error\n const chars = {\n topLeft: '╔', topRight: '╗', bottomLeft: '╚', bottomRight: '╝',\n horizontal: '═', vertical: '║'\n };\n\n // Redraw borders in red\n for (let i = 0; i < popupWidth; i++) {\n this.put(x + i, y, i === 0 ? chars.topLeft : i === popupWidth - 1 ? chars.topRight : chars.horizontal, 'red');\n this.put(x + i, y + popupHeight - 1, i === 0 ? chars.bottomLeft : i === popupWidth - 1 ? chars.bottomRight : chars.horizontal, 'red');\n }\n for (let i = 1; i < popupHeight - 1; i++) {\n this.put(x, y + i, chars.vertical, 'red');\n this.put(x + popupWidth - 1, y + i, chars.vertical, 'red');\n }\n\n // Draw title with warning icon\n const titleText = `⚠ ${title}`;\n const titleX = x + Math.floor((popupWidth - titleText.length - 2) / 2);\n this.put(titleX, y, ' ', 'red');\n this.put(titleX + 1, y, titleText, 'brightRed', true);\n this.put(titleX + titleText.length + 1, y, ' ', 'red');\n\n // Draw error message\n let lineY = y + 2;\n allLines.forEach((line, idx) => {\n if (lineY < y + popupHeight - 2) {\n const isStackTrace = idx >= lines.length;\n const color = isStackTrace ? 'gray' : 'white';\n this.put(x + 2, lineY, line, color);\n lineY++;\n }\n });\n\n // Draw instructions at bottom\n const instruction = '[ESC] to close';\n const instrX = x + Math.floor((popupWidth - instruction.length) / 2);\n this.put(instrX, y + popupHeight - 2, instruction, theme.accent);\n\n return { x, y, width: popupWidth, height: popupHeight };\n }\n\n // Show authentication device code popup\n showAuthPopup(deviceCode: string, verificationUri: string) {\n const theme = this.getTheme();\n const popupWidth = 60;\n const popupHeight = 14;\n\n const x = Math.floor((this.buffer.width - popupWidth) / 2);\n const y = Math.floor((this.buffer.height - popupHeight) / 2);\n\n // Draw authentication popup box\n this.drawBox(x, y, popupWidth, popupHeight, '🔐 AUTHENTICATION REQUIRED');\n\n // Override border color to theme accent\n const chars = {\n topLeft: '╔', topRight: '╗', bottomLeft: '╚', bottomRight: '╝',\n horizontal: '═', vertical: '║'\n };\n\n // Redraw borders in accent color\n for (let i = 0; i < popupWidth; i++) {\n this.put(x + i, y, i === 0 ? chars.topLeft : i === popupWidth - 1 ? chars.topRight : chars.horizontal, theme.secondary);\n this.put(x + i, y + popupHeight - 1, i === 0 ? chars.bottomLeft : i === popupWidth - 1 ? chars.bottomRight : chars.horizontal, theme.secondary);\n }\n for (let i = 1; i < popupHeight - 1; i++) {\n this.put(x, y + i, chars.vertical, theme.secondary);\n this.put(x + popupWidth - 1, y + i, chars.vertical, theme.secondary);\n }\n\n // Draw title\n const titleText = '🔐 AUTHENTICATION REQUIRED';\n const titleX = x + Math.floor((popupWidth - titleText.length - 2) / 2);\n this.put(titleX, y, ' ', theme.secondary);\n this.put(titleX + 1, y, titleText, theme.primary, true);\n this.put(titleX + titleText.length + 1, y, ' ', theme.secondary);\n\n // Instructions\n let lineY = y + 2;\n const instructions = [\n 'To connect to BabylonJS Market BBS, enter this code:',\n '',\n ];\n\n instructions.forEach(line => {\n const lineX = x + Math.floor((popupWidth - line.length) / 2);\n this.put(lineX, lineY, line, theme.text);\n lineY++;\n });\n\n // Device code in a box\n const codeBoxWidth = deviceCode.length + 6;\n const codeBoxX = x + Math.floor((popupWidth - codeBoxWidth) / 2);\n\n // Draw code box\n this.put(codeBoxX, lineY, '┌', theme.accent);\n for (let i = 1; i < codeBoxWidth - 1; i++) {\n this.put(codeBoxX + i, lineY, '─', theme.accent);\n }\n this.put(codeBoxX + codeBoxWidth - 1, lineY, '┐', theme.accent);\n\n lineY++;\n this.put(codeBoxX, lineY, '│', theme.accent);\n this.put(codeBoxX + 2, lineY, ' ', theme.text);\n this.put(codeBoxX + 3, lineY, deviceCode, 'yellow', true);\n this.put(codeBoxX + 3 + deviceCode.length, lineY, ' ', theme.text);\n this.put(codeBoxX + codeBoxWidth - 1, lineY, '│', theme.accent);\n\n lineY++;\n this.put(codeBoxX, lineY, '└', theme.accent);\n for (let i = 1; i < codeBoxWidth - 1; i++) {\n this.put(codeBoxX + i, lineY, '─', theme.accent);\n }\n this.put(codeBoxX + codeBoxWidth - 1, lineY, '┘', theme.accent);\n\n // URL\n lineY += 2;\n const urlText = 'On this page:';\n const urlX = x + Math.floor((popupWidth - urlText.length) / 2);\n this.put(urlX, lineY, urlText, theme.text);\n\n lineY++;\n const urlLinkX = x + Math.floor((popupWidth - verificationUri.length) / 2);\n this.put(urlLinkX, lineY, verificationUri, 'cyan', true);\n\n // Status line\n lineY = y + popupHeight - 2;\n const statusText = 'Opening browser automatically...';\n const statusX = x + Math.floor((popupWidth - statusText.length) / 2);\n this.put(statusX, lineY, statusText, theme.dim);\n\n return { x, y, width: popupWidth, height: popupHeight };\n }\n\n // Show polling status\n showPollingStatus(status: 'waiting' | 'checking' | 'success' | 'error', message?: string) {\n const theme = this.getTheme();\n const y = this.buffer.height - 3;\n const x = 2;\n\n // Clear the status line\n for (let i = 0; i < this.buffer.width - 4; i++) {\n this.put(x + i, y, ' ');\n }\n\n // Status icons and colors\n const statusConfig = {\n waiting: { icon: '⏳', color: theme.accent, text: message || 'Waiting for authentication...' },\n checking: { icon: '🔄', color: 'yellow', text: message || 'Checking authentication status...' },\n success: { icon: '✓', color: 'green', text: message || 'Authentication successful!' },\n error: { icon: '✗', color: 'red', text: message || 'Authentication failed' }\n };\n\n const config = statusConfig[status];\n const fullText = `${config.icon} ${config.text}`;\n\n // Center the status text\n const textX = Math.floor((this.buffer.width - fullText.length) / 2);\n this.put(textX, y, config.icon, config.color);\n this.put(textX + 2, y, config.text, config.color, status === 'success');\n }\n \n // Helper function to wrap text\n private wrapText(text: string, maxWidth: number): string[] {\n const words = text.split(' ');\n const lines: string[] = [];\n let currentLine = '';\n \n for (const word of words) {\n if (currentLine.length + word.length + 1 <= maxWidth) {\n currentLine += (currentLine ? ' ' : '') + word;\n } else {\n if (currentLine) lines.push(currentLine);\n currentLine = word;\n \n // Handle very long words\n while (currentLine.length > maxWidth) {\n lines.push(currentLine.substring(0, maxWidth));\n currentLine = currentLine.substring(maxWidth);\n }\n }\n }\n \n if (currentLine) lines.push(currentLine);\n return lines.length > 0 ? lines : [''];\n }\n \n // Page transition animations (preserve header - only animate content area)\n async transition(type: 'fade' | 'wipe' | 'matrix' | 'sweep' = 'fade') {\n if (!this.animations) return;\n \n const width = this.term.width;\n const height = this.term.height;\n const contentStartY = 5; // Start transitions below the header\n \n switch(type) {\n case 'fade':\n // Fade out effect (only content area)\n for (let i = 0; i < 3; i++) {\n for (let y = contentStartY; y < height; y++) {\n this.term.moveTo(1, y);\n for (let x = 0; x < width; x++) {\n this.term.gray(String.fromCharCode(9617)); // Light shade\n }\n }\n await new Promise(resolve => setTimeout(resolve, 50));\n }\n // Clear only content area\n for (let y = contentStartY; y <= height; y++) {\n this.term.moveTo(1, y);\n this.term.eraseLine();\n }\n break;\n \n case 'wipe':\n // Wipe from left to right (only content area)\n for (let x = 0; x < width; x += 2) {\n for (let y = contentStartY; y <= height; y++) {\n this.term.moveTo(x, y);\n this.term(' ');\n if (x + 1 < width) {\n this.term.moveTo(x + 1, y);\n this.term(' ');\n }\n }\n await new Promise(resolve => setTimeout(resolve, 10));\n }\n break;\n \n case 'matrix':\n // Matrix rain effect (only in content area)\n const columns = Math.floor(width / 2);\n const drops: number[] = [];\n const contentHeight = height - contentStartY;\n \n for (let i = 0; i < columns; i++) {\n drops[i] = Math.floor(Math.random() * -contentHeight);\n }\n \n for (let frame = 0; frame < 20; frame++) {\n for (let i = 0; i < columns; i++) {\n const x = i * 2;\n const y = drops[i] + contentStartY;\n \n if (y >= contentStartY && y <= height) {\n this.term.moveTo(x + 1, y);\n this.term.brightGreen(String.fromCharCode(33 + Math.floor(Math.random() * 94)));\n }\n \n if (y > contentStartY + 3 && y - 3 >= contentStartY) {\n this.term.moveTo(x + 1, y - 3);\n this.term.green(String.fromCharCode(33 + Math.floor(Math.random() * 94)));\n }\n \n if (y > contentStartY + 6 && y - 6 >= contentStartY) {\n this.term.moveTo(x + 1, y - 6);\n this.term.dim.green(String.fromCharCode(33 + Math.floor(Math.random() * 94)));\n }\n \n if (y > contentStartY + 9 && y - 9 >= contentStartY) {\n this.term.moveTo(x + 1, y - 9);\n this.term(' ');\n }\n \n drops[i]++;\n if (drops[i] > contentHeight + 10) {\n drops[i] = Math.floor(Math.random() * -10);\n }\n }\n await new Promise(resolve => setTimeout(resolve, 50));\n }\n // Clear only content area\n for (let y = contentStartY; y <= height; y++) {\n this.term.moveTo(1, y);\n this.term.eraseLine();\n }\n break;\n \n case 'sweep':\n // Diagonal sweep animation (only content area)\n for (let i = 0; i < width + (height - contentStartY); i++) {\n for (let y = contentStartY; y <= height; y++) {\n const x = i - (y - contentStartY);\n if (x >= 0 && x < width) {\n this.term.moveTo(x + 1, y);\n this.term(' ');\n }\n }\n await new Promise(resolve => setTimeout(resolve, 15));\n }\n break;\n }\n }\n}","import terminalKit from 'terminal-kit';\nimport chalk from 'chalk';\nimport { BufferedBBS, Theme } from './buffered-bbs.js';\nimport { MarkdownTerminalRenderer } from './markdown-terminal.js';\nimport { CodeHighlighter } from './code-highlighter.js';\nimport { EventEmitter } from 'events';\nimport { execSync } from 'child_process';\nimport asciify from 'asciify-image';\nimport fetch from 'node-fetch';\nimport open from 'open';\nimport { API_URL } from '../config/constants.js';\n\n// Pure modules – no terminal-kit\nimport {\n computeTocWidth,\n computeContentStartX,\n computeContentHeight,\n computeWrapWidth,\n computeCodeBlockWidth,\n maxContentScrollOffset,\n maxTocScrollOffset,\n isCodeBlockVisible,\n isImageVisible,\n isCopiedLine as _isCopiedLine,\n reduce,\n makeInitialState,\n} from './course-detail/index.js';\nimport type {\n Article,\n CourseDetail,\n TOCEntry,\n TrackedImage,\n CodeBlock,\n ViewerState,\n} from './course-detail/index.js';\n\nconst { ScreenBuffer } = terminalKit;\n\nexport class CourseDetailViewer extends EventEmitter {\n private backBuffer: any;\n private screenBuffer: any;\n private term: any;\n private bbs: BufferedBBS;\n private renderer: MarkdownTerminalRenderer;\n\n // ── Pure viewer state (all navigation / dimension data) ──────────────────\n private vs: ViewerState;\n\n // ── Content arrays (produced by content-generation, consumed by renderer) ─\n private contentLines: string[] = [];\n private tocEntries: TOCEntry[] = [];\n private codeBlocks: CodeBlock[] = [];\n private trackedImages: TrackedImage[] = [];\n\n // Fixed header/footer heights (unchanged from original)\n private readonly headerHeight: number = 5;\n private readonly footerHeight: number = 3;\n\n constructor(\n backBuffer: any,\n screenBuffer: any,\n theme: Theme = 'classic',\n animations: boolean = true\n ) {\n super();\n this.backBuffer = backBuffer;\n this.screenBuffer = screenBuffer;\n this.term = terminalKit.terminal;\n this.bbs = new BufferedBBS(backBuffer, theme, animations);\n\n const w = this.term.width as number;\n const h = this.term.height as number;\n const tocW = computeTocWidth(w);\n const startX = computeContentStartX(tocW);\n\n this.vs = makeInitialState(w, h, this.headerHeight, this.footerHeight, tocW, startX);\n\n this.renderer = new MarkdownTerminalRenderer(theme, w - startX - 2);\n\n // Update layout based on initial terminal width\n this._updateLayout();\n }\n\n // ── Accessors used by rendering helpers (keep backward-compat references) ─\n\n private get width() { return this.vs.width; }\n private get height() { return this.vs.height; }\n private get contentHeight() { return this.vs.contentHeight; }\n private get tocWidth() { return this.vs.tocWidth; }\n private get contentStartX() { return this.vs.contentStartX; }\n private get scrollOffset() { return this.vs.scrollOffset; }\n private get tocScrollOffset() { return this.vs.tocScrollOffset; }\n private get selectedTocIndex() { return this.vs.selectedTocIndex; }\n private get viewMode() { return this.vs.viewMode; }\n private get focusPanel() { return this.vs.focusPanel; }\n private get copiedBlockIndex() { return this.vs.copiedBlockIndex; }\n private get copiedTimestamp() { return this.vs.copiedTimestamp; }\n private get courseTitle() { return this.vs.courseTitle; }\n private get username() { return this.vs.username; }\n\n /**\n * Update layout calculations based on terminal width (delegates to pure helpers).\n */\n private _updateLayout() {\n const tocW = computeTocWidth(this.vs.width);\n const startX = computeContentStartX(tocW);\n this.vs = { ...this.vs, tocWidth: tocW, contentStartX: startX };\n }\n\n /** @deprecated internal alias kept so that resize() still works */\n private updateLayout() { this._updateLayout(); }\n\n /**\n * Handle terminal resize\n */\n resize(width: number, height: number) {\n this.vs = {\n ...this.vs,\n width,\n height,\n contentHeight: computeContentHeight(height, this.headerHeight, this.footerHeight),\n };\n\n // Update layout calculations (tocWidth + contentStartX)\n this._updateLayout();\n\n // Update renderer width\n const contentWidth = this.viewMode === 'content' ? this.width - 6 : this.width - this.contentStartX - 2;\n this.renderer = new MarkdownTerminalRenderer(\n (this.bbs as any).theme || 'classic',\n contentWidth\n );\n\n // Re-wrap content for new width if needed\n if (this.contentLines.length > 0) {\n // Store current course data to re-process with new width\n const currentCourse = (this as any).currentCourse;\n if (currentCourse) {\n // Regenerate content with new width\n const { lines, tocEntries } = this.generateCourseContent(currentCourse);\n this.contentLines = lines.filter(line => line !== undefined && line !== null);\n this.tocEntries = tocEntries;\n }\n }\n\n // Re-render with new dimensions\n this.render();\n }\n\n /**\n * Set user information for header\n */\n setUserInfo(username: string) {\n this.vs = { ...this.vs, username };\n }\n\n /**\n * Load course data and prepare content\n */\n loadCourse(course: CourseDetail) {\n // Store course for resize reprocessing\n (this as any).currentCourse = course;\n\n // Reset navigation state while preserving dimension fields\n this.vs = {\n ...this.vs,\n courseTitle: course.title || 'COURSE',\n scrollOffset: 0,\n tocScrollOffset: 0,\n selectedTocIndex: 0,\n };\n\n // Clear existing content\n this.contentLines = [];\n this.tocEntries = [];\n\n // Validate course data\n if (!course || !course.articles) {\n this.contentLines = ['Error: Invalid course data'];\n this.render();\n return;\n }\n\n // Generate content and TOC\n const { lines, tocEntries } = this.generateCourseContent(course);\n // Filter out any undefined or null lines\n this.contentLines = lines.filter(line => line !== undefined && line !== null);\n this.tocEntries = tocEntries;\n\n // Initial render\n this.render();\n }\n\n /**\n * Generate course content with articles\n */\n private generateCourseContent(course: CourseDetail): {\n lines: string[];\n tocEntries: TOCEntry[];\n } {\n const allLines: string[] = [];\n const tocEntries: TOCEntry[] = [];\n const theme = this.bbs.getTheme();\n\n // Clear code blocks and images tracking\n this.codeBlocks = [];\n this.trackedImages = [];\n\n // Add course header\n allLines.push('');\n this.addColoredLine(allLines, `═══ ${course.title.toUpperCase()} ═══`, theme.primary);\n if (course.category) {\n this.addColoredLine(allLines, `Category: ${course.category}`, theme.secondary);\n }\n if (course.description) {\n allLines.push('');\n const wrappedDesc = this.wrapText(course.description, this.width - this.contentStartX - 4);\n // Push description lines directly without color metadata\n wrappedDesc.forEach(line => allLines.push(line));\n }\n allLines.push('');\n this.addColoredLine(allLines, '─'.repeat(60), theme.dim);\n allLines.push('');\n\n // Sort articles by order (with safety check)\n const sortedArticles = course.articles ?\n [...course.articles].sort((a, b) => (a.order || 0) - (b.order || 0)) :\n [];\n\n // Process each article\n sortedArticles.forEach((article, index) => {\n // Skip invalid articles\n if (!article || !article.title) return;\n const articleStartLine = allLines.length;\n\n // Add article to TOC as a section header\n tocEntries.push({\n title: `Article ${article.order}: ${article.title}`,\n line: articleStartLine,\n type: 'article'\n });\n\n // Article separator\n if (index > 0) {\n allLines.push('');\n this.addColoredLine(allLines, '═'.repeat(70), theme.primary);\n allLines.push('');\n }\n\n // Article header\n this.addColoredLine(\n allLines,\n `ARTICLE ${article.order}: ${article.title.toUpperCase()}`,\n theme.primary,\n true\n );\n this.addColoredLine(allLines, '─'.repeat(70), theme.dim);\n allLines.push('');\n\n if (course.isOwned && article.markdown) {\n // Extract headings for TOC\n const headings = this.extractHeadings(article.markdown);\n\n // Process markdown with proper code block handling\n // Pass the current position in allLines as the base line number\n const currentLinePosition = allLines.length;\n const renderedContent = this.renderMarkdownWithCodeBlocks(\n article.markdown,\n theme,\n currentLinePosition\n );\n\n // Add headings to TOC under this article\n headings.forEach(heading => {\n // Find the line number where this heading appears\n let lineNum = articleStartLine;\n for (let i = 0; i < renderedContent.length; i++) {\n // For H2 headings, search for uppercase version since they're rendered that way\n const searchText = heading.level === 2 ? heading.text.toUpperCase() : heading.text;\n if (renderedContent[i].includes(searchText)) {\n lineNum = allLines.length + i; // Use current position in allLines, not articleStartLine\n break;\n }\n }\n\n tocEntries.push({\n title: heading.text,\n line: lineNum,\n type: 'heading',\n level: heading.level\n });\n });\n\n allLines.push(...renderedContent);\n } else {\n // Show preview for unowned content\n this.addColoredLine(allLines, '⚠ Premium Content', theme.accent);\n allLines.push('');\n if (article.description) {\n const wrapped = this.wrapText(article.description, this.width - this.contentStartX - 4);\n wrapped.forEach(line => this.addColoredLine(allLines, line, theme.dim));\n } else {\n this.addColoredLine(\n allLines,\n 'This article is part of the premium course.',\n theme.dim\n );\n this.addColoredLine(\n allLines,\n 'Purchase the course to access full content.',\n theme.dim\n );\n }\n }\n\n allLines.push('');\n allLines.push('');\n });\n\n return { lines: allLines, tocEntries };\n }\n\n /**\n * Extract headings from markdown\n */\n private extractHeadings(markdown: string): Array<{ level: number; text: string }> {\n const headings: Array<{ level: number; text: string }> = [];\n const lines = markdown.split('\\n');\n\n lines.forEach(line => {\n // Match headings that might be in numbered lists or at start of line\n // This handles cases like \"1. ### Heading\" or \"### Heading\"\n const match = line.match(/(?:^\\d+\\.\\s+)?(#{2,3})\\s+(.+)$/);\n if (match) {\n headings.push({\n level: match[1].length,\n text: match[2].trim()\n });\n }\n });\n\n return headings;\n }\n\n /**\n * Render markdown with proper code block handling\n */\n private renderMarkdownWithCodeBlocks(\n markdown: string,\n theme: any,\n startLine: number\n ): string[] {\n const result: string[] = [];\n const lines = markdown.split('\\n');\n let inCodeBlock = false;\n let codeBlockLines: string[] = [];\n let codeBlockLanguage = '';\n let inFrontmatter = false;\n let skipNextTitle = false;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // Handle frontmatter\n if (line === '---') {\n if (i === 0 || (i > 0 && lines[i-1] === '')) {\n // Start of frontmatter\n inFrontmatter = true;\n skipNextTitle = true; // Skip the title that follows frontmatter\n continue;\n } else if (inFrontmatter) {\n // End of frontmatter\n inFrontmatter = false;\n continue;\n }\n }\n\n // Skip lines inside frontmatter\n if (inFrontmatter) {\n continue;\n }\n\n // Skip the first # header after frontmatter (it's redundant with article title)\n if (skipNextTitle && line.startsWith('# ')) {\n skipNextTitle = false;\n continue;\n }\n\n // Handle code blocks\n if (line.startsWith('```')) {\n if (!inCodeBlock) {\n // Starting a code block - parse language and metadata\n inCodeBlock = true;\n const fenceInfo = line.substring(3).trim();\n\n // Parse metadata like: ts FILENAME=\"SRC/COMPONENTS/LOGGING.TS\" LINENUMSTART=\"75\"\n let language = 'javascript';\n let filename = '';\n let lineNumStart = 1;\n\n if (fenceInfo) {\n // Extract language (first word)\n const parts = fenceInfo.split(/\\s+/);\n if (parts[0] && !parts[0].includes('=')) {\n language = parts[0];\n }\n\n // Extract metadata\n const filenameMatch = fenceInfo.match(/FILENAME=[\"']([^\"']+)[\"']/i);\n if (filenameMatch) {\n filename = filenameMatch[1];\n }\n\n const lineNumMatch = fenceInfo.match(/LINENUMSTART=[\"']?(\\d+)[\"']?/i);\n if (lineNumMatch) {\n lineNumStart = parseInt(lineNumMatch[1], 10);\n }\n }\n\n codeBlockLanguage = language;\n codeBlockLines = [];\n\n // Store metadata for use when rendering\n (codeBlockLines as any).filename = filename;\n (codeBlockLines as any).lineNumStart = lineNumStart;\n } else {\n // Ending a code block - render with highlighting\n inCodeBlock = false;\n const codeContent = codeBlockLines.join('\\n');\n const filename = (codeBlockLines as any).filename || '';\n const lineNumStart = (codeBlockLines as any).lineNumStart || 1;\n\n // Track code block position relative to the overall content\n // startLine is the base line number for this article in the full content\n // result.length is current position in the article's rendered content\n const codeBlockStartLine = startLine + result.length; // Absolute position in contentLines\n\n\n // Format code block with syntax highlighting\n // Get the actual theme name from the bbs instance\n const themeName = (this.bbs as any).theme || 'classic';\n\n // Use full width for code blocks in full mode, appropriate width in split mode\n // In split mode, content starts at contentStartX and needs padding\n // In full mode, content starts at 4 and uses most of the width\n const isFullMode = this.viewMode === 'content';\n const codeBlockWidth = isFullMode ? this.width - 10 : this.width - this.contentStartX - 6;\n\n const formattedBlock = CodeHighlighter.formatCodeBlock(\n codeContent,\n codeBlockLanguage,\n codeBlockWidth,\n themeName,\n filename,\n lineNumStart\n );\n\n // Add formatted lines without additional color metadata\n formattedBlock.forEach(line => {\n // The formatCodeBlock already returns colored strings, just add them\n result.push(line);\n });\n\n // Track this code block for copy functionality\n this.codeBlocks.push({\n startLine: codeBlockStartLine,\n endLine: codeBlockStartLine + formattedBlock.length - 1, // -1 for zero-based end\n code: codeContent,\n language: codeBlockLanguage\n });\n\n result.push(''); // Add spacing after code block\n }\n continue;\n }\n\n if (inCodeBlock) {\n codeBlockLines.push(line);\n continue;\n }\n\n // Render non-code-block lines\n const rendered = this.renderMarkdownLine(line, theme);\n result.push(...rendered);\n }\n\n return result;\n }\n\n /**\n * Render a single markdown line (non-code-block)\n */\n private renderMarkdownLine(line: string, theme: any): string[] {\n const result: string[] = [];\n \n // Calculate proper wrap width based on view mode\n const isFullMode = this.viewMode === 'content';\n const wrapWidth = isFullMode ? this.width - 8 : this.width - this.contentStartX - 6;\n\n // Skip any remaining frontmatter markers that weren't caught\n if (line === '---') {\n return result;\n }\n\n // Headers - skip # headers as they're shown as article titles\n if (line.startsWith('# ')) {\n // Skip top-level headers as they duplicate the article title\n return result;\n }\n\n // Check for H2 headings (including in numbered lists)\n const h2Match = line.match(/^(?:\\d+\\.\\s+)?(##)\\s+(.+)$/);\n if (h2Match) {\n result.push('');\n this.addColoredLine(result, h2Match[2].toUpperCase(), theme.secondary, true);\n return result;\n }\n\n // Check for H3 headings (including in numbered lists)\n const h3Match = line.match(/^(?:\\d+\\.\\s+)?(###)\\s+(.+)$/);\n if (h3Match) {\n result.push('');\n this.addColoredLine(result, h3Match[2], theme.accent);\n return result;\n }\n\n // Lists\n if (line.match(/^[-*+]\\s+/)) {\n const content = line.replace(/^[-*+]\\s+/, '');\n // Wrap list content properly\n const wrapped = this.wrapText('- ' + content, wrapWidth);\n wrapped.forEach((wl, idx) => {\n // Indent continuation lines\n if (idx > 0) {\n result.push(' ' + wl);\n } else {\n result.push(wl);\n }\n });\n return result;\n }\n\n // Blockquotes\n if (line.startsWith('>')) {\n this.addColoredLine(result, '│ ' + line.substring(1).trim(), theme.dim);\n return result;\n }\n\n // Image handling\n if (line.includes('![')) {\n const imageMatch = line.match(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/);\n if (imageMatch) {\n const alt = imageMatch[1] || 'Image';\n let url = imageMatch[2];\n \n // Prepend API_URL if the URL is relative\n if (!url.startsWith('http')) {\n url = `${API_URL}${url.startsWith('/') ? '' : '/'}${url}`;\n }\n \n // Simple, clean image indicator\n const imageStartLine = result.length;\n result.push('');\n result.push(chalk.cyan('[IMAGE] ') + chalk.white(alt || 'Image'));\n result.push(chalk.yellow('Press [I] to view in browser'));\n \n // Track the image with its line range for [I] key handling\n const imageEndLine = result.length;\n this.trackedImages.push({ url, alt, lineNumber: imageStartLine, endLine: imageEndLine });\n result.push('');\n \n // Process any text before or after the image on the same line\n const beforeImage = line.substring(0, line.indexOf('!['));\n const afterImage = line.substring(line.indexOf(')') + 1);\n \n if (beforeImage.trim()) {\n const wrapped = this.wrapText(beforeImage, wrapWidth);\n wrapped.forEach(wl => result.unshift(wl));\n }\n \n if (afterImage.trim()) {\n const wrapped = this.wrapText(afterImage, wrapWidth);\n wrapped.forEach(wl => result.push(wl));\n }\n \n return result;\n }\n }\n \n // Inline code handling\n if (line.includes('`')) {\n const formatted = this.formatInlineCode(line, theme);\n // Push formatted line directly without adding color metadata\n result.push(formatted);\n return result;\n }\n\n // Regular text - check for inline color markers\n if (line.trim()) {\n // Check if line starts with a color marker like \"green:text\" or \"green: text\"\n const colorMatch = line.match(/^(red|green|blue|yellow|cyan|magenta|white|gray|brightRed|brightGreen|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n if (colorMatch) {\n const color = colorMatch[1].toLowerCase();\n const text = colorMatch[2] || '';\n // If there's text after the color, use it WITHOUT the color prefix\n if (text.trim()) {\n const cleanText = text.trim();\n const wrapped = this.wrapText(cleanText, wrapWidth);\n // Push directly with color metadata, don't let theme add more\n wrapped.forEach(wl => {\n result.push(`${color}:${wl}`);\n });\n } else {\n // No text after color marker, treat as regular text\n const wrapped = this.wrapText(line, wrapWidth);\n wrapped.forEach(wl => result.push(wl));\n }\n } else {\n // For non-colored lines, just add the plain text without color metadata\n const wrapped = this.wrapText(line, wrapWidth);\n wrapped.forEach(wl => result.push(wl));\n }\n } else {\n result.push('');\n }\n\n return result;\n }\n\n /**\n * Format inline code in text\n */\n private formatInlineCode(text: string, theme: any): string {\n // Replace inline code with formatted version\n const themeName = (this.bbs as any).theme || 'classic';\n return text.replace(/`([^`]+)`/g, (_, code) => {\n return CodeHighlighter.formatInlineCode(code, themeName);\n });\n }\n\n /**\n * Add a colored line to the content array\n */\n private addColoredLine(\n lines: string[],\n text: string,\n color: string,\n bold: boolean = false\n ) {\n // Check if text already has a color tag - if so, don't add another\n const hasColorTag = /^(red|green|blue|yellow|cyan|magenta|white|gray|brightRed|brightGreen|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):/i.test(text);\n\n if (hasColorTag) {\n // Text already has color specified, push as-is\n lines.push(text);\n } else if (color === 'white' || color === 'text') {\n // For default text color, don't add metadata - just push the plain text\n lines.push(text);\n } else {\n // Store the line with color metadata for non-default colors\n lines.push(`${color}${bold ? ':BOLD' : ''}:${text}`);\n }\n }\n\n /**\n * Parse ANSI escape codes and render text with terminal-kit colors\n */\n private parseAndRenderANSI(line: string, x: number, y: number) {\n // Common ANSI color codes mapping\n const ansiToColor: Record<string, string> = {\n '30': 'black',\n '31': 'red',\n '32': 'green',\n '33': 'yellow',\n '34': 'blue',\n '35': 'magenta',\n '36': 'cyan',\n '37': 'white',\n '90': 'gray',\n '91': 'brightRed',\n '92': 'brightGreen',\n '93': 'brightYellow',\n '94': 'brightBlue',\n '95': 'brightMagenta',\n '96': 'brightCyan',\n '97': 'brightWhite',\n '38;5;250': 'gray', // Common gray shade\n '39': 'white' // Default color\n };\n\n // Split the line by ANSI escape sequences\n const parts = line.split(/\\x1b\\[([0-9;]+)m/);\n let currentX = x;\n let currentColor = 'white';\n let isBold = false;\n let isDim = false;\n\n for (let i = 0; i < parts.length; i++) {\n if (i % 2 === 0) {\n // This is text content\n const text = parts[i];\n if (text) {\n // Apply current formatting\n let color = currentColor;\n if (isDim && color === 'white') {\n color = 'gray';\n }\n this.bbs.put(currentX, y, text, color, isBold);\n currentX += text.length;\n }\n } else {\n // This is an ANSI code\n const codes = parts[i].split(';');\n for (const code of codes) {\n if (code === '0') {\n // Reset\n currentColor = 'white';\n isBold = false;\n isDim = false;\n } else if (code === '1') {\n isBold = true;\n } else if (code === '2') {\n isDim = true;\n } else if (code === '22') {\n isBold = false;\n isDim = false;\n } else if (code === '23') {\n // Not italic (we don't support italic in terminal)\n } else if (ansiToColor[code]) {\n currentColor = ansiToColor[code];\n } else if (parts[i] in ansiToColor) {\n // Handle compound codes like '38;5;250'\n currentColor = ansiToColor[parts[i]];\n }\n }\n }\n }\n }\n\n /**\n * Render the current view to buffers\n */\n render() {\n try {\n // Clear back buffer\n this.backBuffer.fill({\n char: ' ',\n attr: { color: 'white', bgColor: 'black' }\n });\n\n const theme = this.bbs.getTheme();\n\n // Draw header\n this.drawHeader();\n\n // Draw content area based on view mode\n switch (this.viewMode) {\n case 'split':\n this.drawTOC();\n this.drawContent();\n break;\n case 'toc':\n this.drawTOCFullScreen();\n break;\n case 'content':\n this.drawContentFullScreen();\n break;\n }\n\n // Draw footer with navigation hints\n this.drawFooter();\n\n // Copy back buffer to screen buffer\n this.backBuffer.draw({ dst: this.screenBuffer });\n this.screenBuffer.draw({ delta: true });\n } catch (error: any) {\n // Emit error to parent for handling without logging to stderr\n this.emit('error', error);\n }\n }\n\n /**\n * Draw the header\n */\n private drawHeader() {\n // Use the BBS header with course title - truncate if needed\n const maxTitleLength = 30;\n const displayTitle = this.courseTitle.length > maxTitleLength ?\n this.courseTitle.substring(0, maxTitleLength - 3) + '...' :\n this.courseTitle.toUpperCase();\n this.bbs.drawBBSHeader(this.username, displayTitle, 0);\n }\n\n /**\n * Draw table of contents panel\n */\n private drawTOC() {\n const theme = this.bbs.getTheme();\n\n // TOC box - highlight if focused in split view\n const isFocused = this.viewMode === 'split' && this.focusPanel === 'toc';\n this.bbs.drawBox(0, this.headerHeight, this.tocWidth, this.contentHeight, 'JUMP TO', isFocused);\n\n // Render TOC entries\n const visibleTocItems = Math.min(\n this.tocEntries.length - this.tocScrollOffset,\n this.contentHeight - 2\n );\n\n let currentArticle = '';\n for (let i = 0; i < visibleTocItems; i++) {\n const entry = this.tocEntries[this.tocScrollOffset + i];\n const y = this.headerHeight + 1 + i;\n const isSelected = this.tocScrollOffset + i === this.selectedTocIndex;\n\n // Clear line first\n for (let x = 1; x < this.tocWidth - 1; x++) {\n this.bbs.put(x, y, ' ');\n }\n\n // Check if we're starting a new article section\n if (entry.type === 'article') {\n currentArticle = entry.title;\n // Draw article separator if not the first item\n if (i > 0) {\n // Draw a subtle separator line above the article\n for (let x = 2; x < this.tocWidth - 2; x++) {\n this.bbs.put(x, y - 1, '─', theme.dim);\n }\n }\n // Draw article title in a distinct style\n const maxLength = this.tocWidth - 4;\n const displayText = entry.title.length > maxLength ?\n entry.title.substring(0, maxLength - 3) + '...' :\n entry.title;\n \n if (isSelected) {\n this.bbs.put(1, y, '>', theme.accent);\n }\n this.bbs.put(2, y, displayText, theme.primary, true);\n } else if (entry.type === 'heading') {\n // Indentation and color based on heading level\n let indent = 4;\n let color = theme.secondary;\n \n if (entry.level === 2) {\n // H2 headings - less indented\n indent = 4;\n color = theme.secondary;\n } else if (entry.level === 3) {\n // H3 headings - more indented, same color as H2\n indent = 6;\n color = theme.secondary;\n }\n\n // Selection indicator\n if (isSelected) {\n this.bbs.put(indent - 2, y, '>', theme.accent);\n }\n\n // Truncate text if needed\n const maxLength = this.tocWidth - indent - 2;\n let displayText = entry.title;\n \n // Don't uppercase in TOC - keep original case\n if (displayText.length > maxLength) {\n displayText = displayText.substring(0, maxLength - 3) + '...';\n }\n\n this.bbs.put(indent, y, displayText, color, false);\n }\n }\n\n // Scroll indicators on the right side of the TOC window\n if (this.tocScrollOffset > 0) {\n this.bbs.put(this.tocWidth - 2, this.headerHeight, '▲', theme.accent);\n }\n if (this.tocScrollOffset + visibleTocItems < this.tocEntries.length) {\n this.bbs.put(this.tocWidth - 2, this.headerHeight + this.contentHeight - 1, '▼', theme.accent);\n }\n }\n\n /**\n * Draw content panel\n */\n private drawContent() {\n const theme = this.bbs.getTheme();\n const contentWidth = this.width - this.contentStartX;\n\n // Content box - highlight if focused in split view\n const isFocused = this.viewMode === 'split' && this.focusPanel === 'content';\n this.bbs.drawBox(this.contentStartX, this.headerHeight, contentWidth, this.contentHeight, 'ARTICLE', isFocused);\n\n // Render visible content lines\n const visibleLines = Math.min(\n this.contentLines.length - this.scrollOffset,\n this.contentHeight - 2\n );\n\n for (let i = 0; i < visibleLines; i++) {\n const line = this.contentLines[this.scrollOffset + i];\n const y = this.headerHeight + 1 + i;\n\n // Clear line first\n for (let x = this.contentStartX + 1; x < this.width - 1; x++) {\n this.bbs.put(x, y, ' ');\n }\n\n // Check if the line contains ANSI codes (from syntax highlighting)\n if (line && line.includes('\\x1b[')) {\n // Check if this line is part of a copied code block\n const lineNum = this.scrollOffset + i;\n const isCopiedLine = this.copiedBlockIndex >= 0 &&\n Date.now() - this.copiedTimestamp < 3000 &&\n this.codeBlocks[this.copiedBlockIndex] &&\n lineNum >= this.codeBlocks[this.copiedBlockIndex].startLine &&\n lineNum <= this.codeBlocks[this.copiedBlockIndex].endLine;\n\n // Parse and render with proper colors\n this.parseAndRenderANSI(line, this.contentStartX + 2, y);\n \n // Show success message at the bottom line of the code block\n if (isCopiedLine && lineNum === this.codeBlocks[this.copiedBlockIndex].endLine) {\n // Show success message at the bottom of the code block\n const msg = ' ✓ COPIED TO CLIPBOARD!';\n this.bbs.put(this.contentStartX + 2, y, msg, 'brightGreen', true);\n }\n }\n // Parse color metadata from line (original format) - check for specific pattern first\n else if (line && line.match(/^([a-zA-Z]+)((?::BOLD)?):(.*)$/)) {\n const match = line.match(/^([a-zA-Z]+)((?::BOLD)?):(.*)$/);\n if (match) {\n const color = match[1].toLowerCase();\n const isBold = match[2] === ':BOLD';\n let text = match[3] || '';\n\n\n // Check if the text itself starts with another color tag (double-tagged)\n // This can happen when theme adds a color and content has color:\n const doubleTagMatch = text.match(/^(red|green|blue|yellow|cyan|magenta|white|gray|brightRed|brightGreen|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n if (doubleTagMatch) {\n // Use the inner color and text\n const innerColor = doubleTagMatch[1].toLowerCase();\n let innerText = doubleTagMatch[2] || '';\n // Strip any additional color tags that might have slipped through\n innerText = innerText.replace(/^(green|red|blue|yellow|cyan|magenta|white|gray|brightGreen|brightRed|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*/i, '');\n // Only display if there's text after the inner color tag\n if (innerText.trim()) {\n this.bbs.put(this.contentStartX + 2, y, innerText.trim(), innerColor, isBold);\n }\n } else if (text) {\n // Check one more time if text starts with a color tag\n const cleanText = text.replace(/^(green|red|blue|yellow|cyan|magenta|white|gray|brightGreen|brightRed|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*/i, '');\n // Normal case - display with the metadata color\n this.bbs.put(this.contentStartX + 2, y, cleanText || text, color, isBold);\n }\n }\n } else if (line) {\n // Check if this might be a line that starts with a color tag in the content\n const inlineColorMatch = line.match(/^(red|green|blue|yellow|cyan|magenta|white|gray|brightRed|brightGreen|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n if (inlineColorMatch) {\n // This is a color-tagged line that wasn't caught by metadata parsing\n const color = inlineColorMatch[1].toLowerCase();\n const text = inlineColorMatch[2] || line;\n this.bbs.put(this.contentStartX + 2, y, text, color);\n } else {\n // Check if this line is part of a copied code block\n const lineNum = this.scrollOffset + i;\n const isCopiedLine = this.copiedBlockIndex >= 0 &&\n Date.now() - this.copiedTimestamp < 3000 &&\n this.codeBlocks[this.copiedBlockIndex] &&\n lineNum >= this.codeBlocks[this.copiedBlockIndex].startLine &&\n lineNum <= this.codeBlocks[this.copiedBlockIndex].endLine;\n\n // Plain text - no truncation for regular text\n const displayText = line;\n\n // Check if this line looks like it's from a code block (has frame characters)\n const isCodeBlockFrame = displayText.includes('╭─') || displayText.includes('│') ||\n displayText.includes('╰─') || displayText.includes('─╮') ||\n displayText.includes('─╯');\n\n // Ensure we have a valid string\n if (displayText) {\n // Check if this line itself starts with a color tag that wasn't caught\n const lineColorMatch = displayText.match(/^(green|red|blue|yellow|cyan|magenta|white|gray|brightGreen|brightRed|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n\n // Show success message at the bottom line of the code block\n if (isCopiedLine && lineNum === this.codeBlocks[this.copiedBlockIndex].endLine) {\n // Show copied message at bottom of code block\n this.bbs.put(this.contentStartX + 2, y, ' ✓ COPIED TO CLIPBOARD!', 'brightGreen', true);\n } else if (isCopiedLine && isCodeBlockFrame) {\n // Highlight the code block frame\n this.bbs.put(this.contentStartX + 2, y, displayText, 'brightGreen');\n } else if (lineColorMatch) {\n // This line has an inline color tag - display with that color\n const inlineColor = lineColorMatch[1].toLowerCase();\n const inlineText = lineColorMatch[2] || '';\n // Only display if there's actual text after the color tag\n if (inlineText.trim()) {\n this.bbs.put(this.contentStartX + 2, y, inlineText, inlineColor);\n } else {\n // Just a color tag with no text - skip or show the original\n this.bbs.put(this.contentStartX + 2, y, displayText, theme.text);\n }\n } else {\n // Normal rendering\n const color = isCodeBlockFrame ? 'gray' : theme.text;\n this.bbs.put(this.contentStartX + 2, y, displayText, color);\n }\n }\n }\n }\n }\n\n // Scroll indicators on the right side of the content window\n if (this.scrollOffset > 0) {\n this.bbs.put(this.width - 2, this.headerHeight, '▲', theme.accent);\n }\n if (this.scrollOffset + visibleLines < this.contentLines.length) {\n this.bbs.put(this.width - 2, this.headerHeight + this.contentHeight - 1, '▼', theme.accent);\n }\n\n // Line counter\n const lineInfo = `${this.scrollOffset + 1}-${Math.min(\n this.scrollOffset + visibleLines,\n this.contentLines.length\n )}/${this.contentLines.length}`;\n this.bbs.put(this.width - lineInfo.length - 2, this.headerHeight, lineInfo, theme.dim);\n }\n\n /**\n * Draw TOC in full screen mode\n */\n private drawTOCFullScreen() {\n // Similar to drawTOC but uses full width\n const theme = this.bbs.getTheme();\n\n this.bbs.drawBox(0, this.headerHeight, this.width, this.contentHeight, 'JUMP TO');\n\n const visibleTocItems = Math.min(\n this.tocEntries.length - this.tocScrollOffset,\n this.contentHeight - 2\n );\n\n let currentArticle = '';\n for (let i = 0; i < visibleTocItems; i++) {\n const entry = this.tocEntries[this.tocScrollOffset + i];\n const y = this.headerHeight + 1 + i;\n const isSelected = this.tocScrollOffset + i === this.selectedTocIndex;\n\n // Clear line\n for (let x = 1; x < this.width - 1; x++) {\n this.bbs.put(x, y, ' ');\n }\n\n // Check if we're starting a new article section\n if (entry.type === 'article') {\n currentArticle = entry.title;\n // Draw article separator if not the first item\n if (i > 0) {\n // Draw a subtle separator line above the article\n for (let x = 4; x < this.width - 4; x++) {\n this.bbs.put(x, y - 1, '─', theme.dim);\n }\n }\n // Draw article title in a distinct style\n if (isSelected) {\n this.bbs.put(2, y, '>', theme.accent);\n }\n this.bbs.put(4, y, entry.title, theme.primary, true);\n } else if (entry.type === 'heading') {\n // Indentation and color based on heading level\n let indent = 6;\n let color = theme.secondary;\n \n if (entry.level === 2) {\n // H2 headings - less indented\n indent = 6;\n color = theme.secondary;\n } else if (entry.level === 3) {\n // H3 headings - more indented, same color as H2\n indent = 10;\n color = theme.secondary;\n }\n\n // Selection indicator\n if (isSelected) {\n this.bbs.put(indent - 2, y, '>', theme.accent);\n }\n\n // Display text - keep original case in TOC\n let displayText = entry.title;\n\n this.bbs.put(indent, y, displayText, color, false);\n }\n }\n \n // Scroll indicators on the right side\n if (this.tocScrollOffset > 0) {\n this.bbs.put(this.width - 2, this.headerHeight, '▲', theme.accent);\n }\n if (this.tocScrollOffset + visibleTocItems < this.tocEntries.length) {\n this.bbs.put(this.width - 2, this.headerHeight + this.contentHeight - 1, '▼', theme.accent);\n }\n }\n\n /**\n * Draw content in full screen mode\n */\n private drawContentFullScreen() {\n // Similar to drawContent but uses full width\n const theme = this.bbs.getTheme();\n\n this.bbs.drawBox(0, this.headerHeight, this.width, this.contentHeight, 'ARTICLE');\n\n const visibleLines = Math.min(\n this.contentLines.length - this.scrollOffset,\n this.contentHeight - 2\n );\n\n for (let i = 0; i < visibleLines; i++) {\n const line = this.contentLines[this.scrollOffset + i];\n const y = this.headerHeight + 1 + i;\n\n // Clear line\n for (let x = 1; x < this.width - 1; x++) {\n this.bbs.put(x, y, ' ');\n }\n\n // Check if the line contains ANSI codes (from syntax highlighting)\n if (line && line.includes('\\x1b[')) {\n // Check if this line is part of a copied code block\n const lineNum = this.scrollOffset + i;\n const isCopiedLine = this.copiedBlockIndex >= 0 &&\n Date.now() - this.copiedTimestamp < 3000 &&\n this.codeBlocks[this.copiedBlockIndex] &&\n lineNum >= this.codeBlocks[this.copiedBlockIndex].startLine &&\n lineNum <= this.codeBlocks[this.copiedBlockIndex].endLine;\n\n // Parse and render with proper colors\n this.parseAndRenderANSI(line, 4, y);\n \n // Show success message at the bottom line of the code block\n if (isCopiedLine && lineNum === this.codeBlocks[this.copiedBlockIndex].endLine) {\n // Show success message at the bottom of the code block\n const msg = ' ✓ COPIED TO CLIPBOARD!';\n this.bbs.put(4, y, msg, 'brightGreen', true);\n }\n }\n // Parse color metadata from line (original format) - check for specific pattern first\n else if (line && line.match(/^([a-zA-Z]+)((?::BOLD)?):(.*)$/)) {\n // More flexible pattern to match color metadata\n const match = line.match(/^([a-zA-Z]+)((?::BOLD)?):(.*)$/);\n if (match) {\n const color = match[1].toLowerCase();\n const isBold = match[2] === ':BOLD';\n let text = match[3] || '';\n\n // Check if the text itself starts with another color tag (double-tagged)\n // This can happen when theme adds a color and content has color:\n const doubleTagMatch = text.match(/^(red|green|blue|yellow|cyan|magenta|white|gray|brightRed|brightGreen|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n if (doubleTagMatch) {\n // Use the inner color and text\n const innerColor = doubleTagMatch[1].toLowerCase();\n let innerText = doubleTagMatch[2] || '';\n // Strip any additional color tags that might have slipped through\n innerText = innerText.replace(/^(green|red|blue|yellow|cyan|magenta|white|gray|brightGreen|brightRed|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*/i, '');\n // Only display if there's text after the inner color tag\n if (innerText.trim()) {\n this.bbs.put(4, y, innerText.trim(), innerColor, isBold);\n }\n } else if (text) {\n // Check one more time if text starts with a color tag\n const cleanText = text.replace(/^(green|red|blue|yellow|cyan|magenta|white|gray|brightGreen|brightRed|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*/i, '');\n // Normal case - display with the metadata color\n this.bbs.put(4, y, cleanText || text, color, isBold);\n }\n } else {\n // Not a color-coded line, treat as plain text\n const displayText = line;\n\n if (displayText) {\n this.bbs.put(4, y, displayText, theme.text);\n }\n }\n } else if (line) {\n // Check if this might be a line that starts with a color tag in the content\n const inlineColorMatch = line.match(/^(red|green|blue|yellow|cyan|magenta|white|gray|brightRed|brightGreen|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n if (inlineColorMatch) {\n // This is a color-tagged line that wasn't caught by metadata parsing\n const color = inlineColorMatch[1].toLowerCase();\n const text = inlineColorMatch[2] || line;\n this.bbs.put(4, y, text, color);\n } else {\n // Check if this line is part of a copied code block\n const lineNum = this.scrollOffset + i;\n const isCopiedLine = this.copiedBlockIndex >= 0 &&\n Date.now() - this.copiedTimestamp < 3000 &&\n this.codeBlocks[this.copiedBlockIndex] &&\n lineNum >= this.codeBlocks[this.copiedBlockIndex].startLine &&\n lineNum <= this.codeBlocks[this.copiedBlockIndex].endLine;\n\n // In full mode, use the full width\n const displayText = line;\n\n // Check if this line looks like it's from a code block (has frame characters)\n const isCodeBlockFrame = displayText.includes('╭─') || displayText.includes('│') ||\n displayText.includes('╰─') || displayText.includes('─╮') ||\n displayText.includes('─╯');\n\n if (displayText) {\n // Check if this line itself starts with a color tag that wasn't caught\n const lineColorMatch = displayText.match(/^(green|red|blue|yellow|cyan|magenta|white|gray|brightGreen|brightRed|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n\n // Show success message at the bottom line of the code block\n if (isCopiedLine && lineNum === this.codeBlocks[this.copiedBlockIndex].endLine) {\n // Show copied message at bottom of code block\n this.bbs.put(4, y, ' ✓ COPIED TO CLIPBOARD!', 'brightGreen', true);\n } else if (isCopiedLine && isCodeBlockFrame) {\n // Highlight the code block frame\n this.bbs.put(4, y, displayText, 'brightGreen');\n } else if (lineColorMatch) {\n // This line has an inline color tag - display with that color\n const inlineColor = lineColorMatch[1].toLowerCase();\n const inlineText = lineColorMatch[2] || displayText;\n this.bbs.put(4, y, inlineText, inlineColor);\n } else {\n this.bbs.put(4, y, displayText, theme.text);\n }\n }\n }\n }\n }\n \n // Scroll indicators on the right side\n if (this.scrollOffset > 0) {\n this.bbs.put(this.width - 2, this.headerHeight, '▲', theme.accent);\n }\n if (this.scrollOffset + visibleLines < this.contentLines.length) {\n this.bbs.put(this.width - 2, this.headerHeight + this.contentHeight - 1, '▼', theme.accent);\n }\n }\n\n /**\n * Draw footer with navigation hints\n */\n private drawFooter() {\n const theme = this.bbs.getTheme();\n const y = this.height - 2;\n\n // Footer border\n this.bbs.drawBox(0, y - 1, this.width, this.footerHeight, '');\n\n // Navigation hints based on current mode\n let hints: string[] = [];\n if (this.viewMode === 'split') {\n hints = [\n '[↑↓] Scroll',\n '[←→] Focus',\n '[Tab] Switch',\n '[Enter] Jump',\n '[C] Copy Code',\n '[F] Full',\n '[Q] Back'\n ];\n // Add focus indicator\n const focusText = `[Focus: ${this.focusPanel.toUpperCase()}]`;\n this.bbs.put(this.width - focusText.length - 2, y - 2, focusText, theme.accent);\n } else {\n hints = [\n '[↑↓] Scroll',\n '[Tab] Mode',\n '[Enter] Jump',\n '[C] Copy Code',\n '[T] TOC',\n '[F] Full',\n '[Q] Back'\n ];\n }\n\n let x = 2;\n hints.forEach(hint => {\n if (x + hint.length < this.width - 2) {\n this.bbs.put(x, y, hint, theme.dim);\n x += hint.length + 2;\n }\n });\n }\n\n /**\n * Copy code block to clipboard\n */\n private openImageAtCurrentPosition(): boolean {\n // Find if current viewport contains any part of an image\n const viewportStart = this.scrollOffset;\n const viewportEnd = this.scrollOffset + this.contentHeight - 2;\n\n // Find any image that overlaps with the current viewport\n for (const image of this.trackedImages) {\n // Check if any part of the image is visible in the current viewport\n const imageVisible = (\n // Image starts within viewport\n (image.lineNumber >= viewportStart && image.lineNumber <= viewportEnd) ||\n // Image ends within viewport (if endLine is set)\n (image.endLine && image.endLine >= viewportStart && image.endLine <= viewportEnd) ||\n // Image spans entire viewport\n (image.lineNumber <= viewportStart && image.endLine && image.endLine >= viewportEnd)\n );\n\n if (imageVisible) {\n // Open the image URL in browser\n open(image.url);\n \n // Show status message (if we have a status message system)\n // For now, just return true to indicate success\n return true;\n }\n }\n\n return false;\n }\n\n private copyCodeBlockAtCurrentPosition(): boolean {\n // Find if current viewport contains any part of a code block\n const viewportStart = this.scrollOffset;\n const viewportEnd = this.scrollOffset + this.contentHeight - 2;\n\n // Debug: Check what code blocks we have\n // console.error(`Viewport: ${viewportStart}-${viewportEnd}, Code blocks:`, this.codeBlocks.map(b => `${b.startLine}-${b.endLine}`));\n\n // Find any code block that overlaps with the current viewport\n for (const block of this.codeBlocks) {\n // Check if any part of the code block is visible in the current viewport\n const blockVisible = (\n // Block starts within viewport\n (block.startLine >= viewportStart && block.startLine <= viewportEnd) ||\n // Block ends within viewport\n (block.endLine >= viewportStart && block.endLine <= viewportEnd) ||\n // Block spans entire viewport\n (block.startLine <= viewportStart && block.endLine >= viewportEnd)\n );\n\n if (blockVisible) {\n try {\n // Try to copy to clipboard using platform-specific commands\n const platform = process.platform;\n let command: string;\n\n if (platform === 'darwin') {\n // macOS\n command = 'pbcopy';\n } else if (platform === 'win32') {\n // Windows\n command = 'clip';\n } else {\n // Linux/Unix - try xclip first, then xsel\n try {\n execSync('which xclip', { stdio: 'ignore' });\n command = 'xclip -selection clipboard';\n } catch {\n command = 'xsel --clipboard --input';\n }\n }\n\n execSync(command, { input: block.code });\n\n // Track which block was copied (update pure state)\n const nowMs = Date.now();\n this.vs = {\n ...this.vs,\n copiedBlockIndex: this.codeBlocks.indexOf(block),\n copiedTimestamp: nowMs,\n };\n\n // Show feedback with language info\n const theme = this.bbs.getTheme();\n const langInfo = block.language ? ` (${block.language})` : '';\n const lineCount = block.code.split('\\n').length;\n this.showNotification(`✓ Copied ${lineCount} lines${langInfo}!`, 'green');\n\n // Re-render to show the highlight\n this.render();\n\n // Clear the highlight after 3 seconds\n setTimeout(() => {\n if (Date.now() - this.vs.copiedTimestamp >= 2900) {\n this.vs = { ...this.vs, copiedBlockIndex: -1 };\n this.render();\n }\n }, 3000);\n\n return true;\n } catch (error) {\n this.showNotification('✗ Failed to copy. Install xclip (Linux) or try manual selection.', 'red');\n return false;\n }\n }\n }\n\n // Debug message\n const debugMsg = this.codeBlocks.length === 0 ?\n '⚠ No code blocks found in this article' :\n '⚠ No code block visible. Scroll to a code block and try again.';\n this.showNotification(debugMsg, 'yellow');\n return false;\n }\n\n /**\n * Show a temporary notification\n */\n private showNotification(message: string, color: string) {\n const y = Math.floor(this.height / 2); // Center vertically\n const boxWidth = message.length + 6;\n const x = Math.floor((this.width - boxWidth) / 2);\n\n // Draw a box around the message for prominence\n const theme = this.bbs.getTheme();\n\n // Clear area for the notification box\n for (let row = y - 1; row <= y + 1; row++) {\n for (let col = x; col < x + boxWidth; col++) {\n this.bbs.put(col, row, ' ', 'black');\n }\n }\n\n // Draw box border\n this.bbs.put(x, y - 1, '╭' + '─'.repeat(boxWidth - 2) + '╮', color);\n this.bbs.put(x, y, '│', color);\n this.bbs.put(x + boxWidth - 1, y, '│', color);\n this.bbs.put(x, y + 1, '╰' + '─'.repeat(boxWidth - 2) + '╯', color);\n\n // Show the message in the center\n this.bbs.put(x + 3, y, message, color, true);\n\n // Update screen immediately\n this.backBuffer.draw({ dst: this.screenBuffer });\n this.screenBuffer.draw({ delta: true });\n\n // Clear after 2 seconds\n setTimeout(() => {\n // Just re-render to clear the notification\n this.render();\n }, 2000);\n }\n\n /**\n * Handle keyboard input.\n *\n * Navigation logic is delegated to the pure `reduce()` function; only\n * side effects (copy to clipboard, open image, emit exit) live here.\n */\n handleInput(key: string): boolean {\n try {\n const tocLines = this.tocEntries.map(e => e.line);\n const result = reduce(\n this.vs,\n key,\n this.contentLines.length,\n this.tocEntries.length,\n tocLines\n );\n\n // Update state (always safe — reducer returns the same object on no-op)\n this.vs = result.state;\n\n // Dispatch side effects\n if (result.effect === 'copy_code') {\n this.copyCodeBlockAtCurrentPosition();\n } else if (result.effect === 'open_image') {\n this.openImageAtCurrentPosition();\n } else if (result.effect === 'exit') {\n this.emit('exit');\n }\n\n // Re-render whenever the key was handled (except pure side-effect keys\n // that already call render() themselves via copy/notification helpers)\n if (result.handled && result.effect === 'none') {\n this.render();\n }\n\n return result.handled;\n } catch (error: any) {\n // Emit error to parent for handling without logging to stderr\n this.emit('error', error);\n return false;\n }\n }\n\n /**\n * Wrap text to fit width\n */\n private wrapText(text: string, maxWidth: number): string[] {\n if (text.length <= maxWidth) {\n return [text];\n }\n\n const words = text.split(' ');\n const lines: string[] = [];\n let currentLine = '';\n\n for (const word of words) {\n if (currentLine.length + word.length + 1 > maxWidth) {\n if (currentLine) {\n lines.push(currentLine);\n currentLine = word;\n } else {\n lines.push(word);\n }\n } else {\n currentLine = currentLine ? currentLine + ' ' + word : word;\n }\n }\n\n if (currentLine) {\n lines.push(currentLine);\n }\n\n return lines;\n }\n}\n","import chalk from 'chalk';\nimport { marked } from 'marked';\nimport stripAnsi from 'strip-ansi';\nimport { applyTheme, ThemeName } from './theme-colors.js';\nimport { CodeHighlighter } from './code-highlighter.js';\nimport { API_URL } from '../config/constants.js';\nimport asciify from 'asciify-image';\nimport fetch from 'node-fetch';\n\ninterface Heading {\n level: number;\n text: string;\n id: string;\n line: number;\n}\n\ninterface Article {\n id: number;\n title: string;\n markdown?: string;\n description?: string;\n order: number;\n}\n\nexport interface ImageInfo {\n url: string;\n alt: string;\n lineNumber: number;\n}\n\nexport class MarkdownTerminalRenderer {\n private theme: ReturnType<typeof applyTheme>;\n private width: number;\n private themeName: ThemeName;\n public trackedImages: ImageInfo[] = [];\n private pendingImages: Array<{alt: string, url: string}> = [];\n \n constructor(themeName?: ThemeName, width: number = 80) {\n this.themeName = themeName || 'classic';\n this.theme = applyTheme(this.themeName);\n this.width = width;\n }\n \n /**\n * Extract H2 and H3 headings from markdown to create a table of contents\n */\n extractHeadings(markdown: string): Heading[] {\n const headings: Heading[] = [];\n const lines = markdown.split('\\n');\n \n lines.forEach((line, index) => {\n // Match H2 (##) and H3 (###) headings\n const match = line.match(/^(#{2,3})\\s+(.+)$/);\n if (match) {\n const level = match[1].length;\n const text = match[2].trim();\n const id = text.toLowerCase().replace(/[^a-z0-9]+/g, '-');\n \n if (level === 2 || level === 3) {\n headings.push({\n level,\n text,\n id,\n line: index\n });\n }\n }\n });\n \n return headings;\n }\n \n /**\n * Render markdown content for terminal display\n */\n renderMarkdown(markdown: string): string[] {\n const lines = markdown.split('\\n');\n const rendered: string[] = [];\n let inCodeBlock = false;\n let inList = false;\n let codeBlockLines: string[] = [];\n let codeBlockLanguage = '';\n \n for (const line of lines) {\n // Code blocks with syntax highlighting\n if (line.startsWith('```')) {\n if (!inCodeBlock) {\n // Starting a code block\n inCodeBlock = true;\n codeBlockLanguage = line.substring(3).trim() || 'javascript';\n codeBlockLines = [];\n } else {\n // Ending a code block - render with highlighting\n inCodeBlock = false;\n const codeContent = codeBlockLines.join('\\n');\n const highlightedBlock = CodeHighlighter.formatCodeBlock(\n codeContent,\n codeBlockLanguage,\n this.width,\n this.themeName\n );\n rendered.push(...highlightedBlock);\n rendered.push(''); // Add spacing after code block\n }\n continue;\n }\n \n if (inCodeBlock) {\n codeBlockLines.push(line);\n continue;\n }\n \n // Headers\n if (line.startsWith('# ')) {\n rendered.push('');\n rendered.push('═'.repeat(Math.min(this.width, 60)));\n rendered.push(line.substring(2).toUpperCase());\n rendered.push('═'.repeat(Math.min(this.width, 60)));\n rendered.push('');\n continue;\n }\n \n if (line.startsWith('## ')) {\n rendered.push('');\n rendered.push(line.substring(3).toUpperCase());\n rendered.push('');\n continue;\n }\n \n if (line.startsWith('### ')) {\n rendered.push('');\n rendered.push(line.substring(4));\n continue;\n }\n \n if (line.startsWith('#### ')) {\n rendered.push(line.substring(5));\n continue;\n }\n \n // Lists\n if (line.match(/^[\\s]*[-*+]\\s+/)) {\n const indent = line.search(/\\S/);\n const bullet = indent > 0 ? '-' : '-';\n const content = line.replace(/^[\\s]*[-*+]\\s+/, '');\n rendered.push(' '.repeat(indent) + bullet + ' ' + this.processInlineFormatting(content));\n inList = true;\n continue;\n }\n \n // Numbered lists\n if (line.match(/^[\\s]*\\d+\\.\\s+/)) {\n const match = line.match(/^([\\s]*)(\\d+)\\.\\s+(.*)$/);\n if (match) {\n const [, indent, num, content] = match;\n rendered.push(indent + num + '. ' + this.processInlineFormatting(content));\n inList = true;\n }\n continue;\n }\n \n // Blockquotes\n if (line.startsWith('>')) {\n const content = line.substring(1).trim();\n rendered.push('> ' + content);\n continue;\n }\n \n // Horizontal rules\n if (line.match(/^[-*_]{3,}$/)) {\n rendered.push('');\n rendered.push('─'.repeat(Math.min(this.width, 60)));\n rendered.push('');\n continue;\n }\n \n // Empty lines\n if (line.trim() === '') {\n if (inList) {\n inList = false;\n }\n rendered.push('');\n continue;\n }\n \n // Regular paragraphs - process and check for images\n const processed = this.processInlineFormatting(line);\n \n // Check if line contains image placeholders\n if (processed.includes('\\x00IMAGE')) {\n // Process images asynchronously\n const parts = processed.split(/(\\x00IMAGE\\d+\\x00)/);\n for (const part of parts) {\n const imageMatch = part.match(/\\x00IMAGE(\\d+)\\x00/);\n if (imageMatch) {\n const index = parseInt(imageMatch[1]);\n if (this.pendingImages && this.pendingImages[index]) {\n const image = this.pendingImages[index];\n // Track image for [I] key handling; async rendering done separately\n this.trackedImages.push({ url: image.url, alt: image.alt, lineNumber: rendered.length });\n rendered.push(`[Image: ${image.alt}]`);\n }\n } else if (part) {\n const wrappedLines = this.wrapText(part, this.width - 4);\n rendered.push(...wrappedLines);\n }\n }\n } else {\n const wrappedLines = this.wrapText(processed, this.width - 4);\n rendered.push(...wrappedLines);\n }\n }\n \n return rendered.flat();\n }\n \n /**\n * Process inline markdown formatting (bold, italic, code, links, images)\n * Using a simpler, more reliable approach\n */\n private processInlineFormatting(text: string): string {\n let result = text;\n \n // Store code blocks, links, and images to protect them from formatting\n const codeBlocks: string[] = [];\n const links: Array<{text: string, url: string}> = [];\n \n // Clear pending images for this processing run\n this.pendingImages = [];\n \n // Extract and replace images FIRST (before regular links)\n result = result.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, (_, alt, url) => {\n const index = this.pendingImages.length;\n // Prepend API_URL if the URL is relative\n const fullUrl = url.startsWith('http') ? url : `${API_URL}${url.startsWith('/') ? '' : '/'}${url}`;\n this.pendingImages.push({ alt: alt || 'Image', url: fullUrl });\n return `\\x00IMAGE${index}\\x00`;\n });\n \n // Extract and replace inline code\n result = result.replace(/`([^`]+)`/g, (_, content) => {\n const index = codeBlocks.length;\n codeBlocks.push(CodeHighlighter.formatInlineCode(content, this.themeName));\n return `\\x00CODE${index}\\x00`;\n });\n \n // Extract and replace links\n result = result.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_, linkText, url) => {\n const index = links.length;\n links.push({ text: linkText, url });\n return `\\x00LINK${index}\\x00`;\n });\n \n // Apply formatting in the correct order to handle nesting\n // Handle triple asterisk/underscore (bold + italic) first\n result = result.replace(/\\*\\*\\*(.+?)\\*\\*\\*/g, (_, content) => {\n return chalk.bold(chalk.italic(content));\n });\n result = result.replace(/___(.+?)___/g, (_, content) => {\n return chalk.bold(chalk.italic(content));\n });\n \n // Handle double asterisk/underscore (bold)\n result = result.replace(/\\*\\*(.+?)\\*\\*/g, (_, content) => {\n // Check for nested italic\n const withItalic = content.replace(/\\*(.+?)\\*/g, (_: string, text: string) => chalk.italic(text));\n return chalk.bold(withItalic);\n });\n result = result.replace(/__(.+?)__/g, (_, content) => {\n // Check for nested italic\n const withItalic = content.replace(/_(.+?)_/g, (_: string, text: string) => chalk.italic(text));\n return chalk.bold(withItalic);\n });\n \n // Handle single asterisk/underscore (italic)\n result = result.replace(/(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)/g, (_, content) => {\n return chalk.italic(content);\n });\n result = result.replace(/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g, (_, content) => {\n return chalk.italic(content);\n });\n \n // Handle strikethrough\n result = result.replace(/~~(.+?)~~/g, (_, content) => {\n return chalk.strikethrough(content);\n });\n \n // Restore code blocks\n result = result.replace(/\\x00CODE(\\d+)\\x00/g, (_, index) => {\n return codeBlocks[parseInt(index)];\n });\n \n // Restore links with formatted text\n result = result.replace(/\\x00LINK(\\d+)\\x00/g, (_, index) => {\n const link = links[parseInt(index)];\n // Apply formatting to link text\n let formattedText = link.text;\n formattedText = formattedText.replace(/\\*\\*(.+?)\\*\\*/g, (_: string, text: string) => chalk.bold(text));\n formattedText = formattedText.replace(/\\*(.+?)\\*/g, (_: string, text: string) => chalk.italic(text));\n return chalk.underline(chalk.blue(formattedText)) + chalk.gray(` (${link.url})`);\n });\n \n // Note: Image placeholders will be processed later in renderMarkdownContent\n // Keep the placeholders for now\n \n return result;\n }\n \n /**\n * Create ASCII art representation of an image\n */\n private async createAsciiImage(alt: string, url: string, lineNumber: number): Promise<string> {\n const width = Math.min(70, this.width - 4);\n const border = '─'.repeat(width);\n \n // Track this image for [I] key handling\n this.trackedImages.push({ url, alt, lineNumber });\n const imageIndex = this.trackedImages.length;\n \n // Create ASCII art frame\n const lines: string[] = [];\n lines.push('');\n lines.push(chalk.gray('┌' + border + '┐'));\n \n try {\n // Try to fetch and convert the image to ASCII\n const response = await fetch(url);\n if (response.ok) {\n const buffer = await response.buffer();\n const asciiArt = await asciify(buffer, {\n fit: 'box',\n width: width - 4,\n height: 25,\n color: false,\n format: 'string'\n });\n \n // Add the ASCII art (asciify returns string | string[] depending on `format`)\n const asciiLines = Array.isArray(asciiArt) ? asciiArt : asciiArt.split('\\n');\n for (const line of asciiLines) {\n if (line) {\n const padding = Math.max(0, width - line.length);\n lines.push(chalk.gray('│ ') + chalk.cyan(line) + ' '.repeat(padding) + chalk.gray('│'));\n }\n }\n } else {\n // Fallback if image can't be loaded\n lines.push(chalk.gray('│') + chalk.yellow(' 🖼 Image could not be loaded ') + ' '.repeat(Math.max(0, width - 32)) + chalk.gray('│'));\n }\n } catch (error) {\n // Fallback on error - but still trackable\n lines.push(chalk.gray('│') + chalk.yellow(' 🖼 Image (local/offline) ') + ' '.repeat(Math.max(0, width - 28)) + chalk.gray('│'));\n }\n \n if (lines.length === 2) {\n // No image content was added, add a placeholder\n lines.push(chalk.gray('│') + chalk.dim(' [Image] ') + ' '.repeat(Math.max(0, width - 10)) + chalk.gray('│'));\n }\n \n lines.push(chalk.gray('├' + border + '┤'));\n \n // Add alt text if present\n if (alt && alt.trim()) {\n const altLines = this.wrapText(alt, width - 2);\n for (const line of altLines) {\n const padding = Math.max(0, width - stripAnsi(line).length);\n lines.push(chalk.gray('│ ') + chalk.white(line) + ' '.repeat(padding) + chalk.gray('│'));\n }\n lines.push(chalk.gray('├' + border + '┤'));\n }\n \n // Add instruction\n const instruction = `Press [I] to open image ${imageIndex} in browser`;\n const padding = Math.max(0, width - instruction.length);\n lines.push(chalk.gray('│ ') + chalk.yellow(instruction) + ' '.repeat(padding) + chalk.gray('│'));\n \n lines.push(chalk.gray('└' + border + '┘'));\n lines.push('');\n \n return lines.join('\\n');\n }\n \n /**\n * Wrap text to fit within specified width\n * Improved to handle ANSI codes better\n */\n private wrapText(text: string, maxWidth: number): string[] {\n // Use stripAnsi for accurate length calculation\n const plainText = stripAnsi(text);\n \n if (plainText.length <= maxWidth) {\n return [text];\n }\n \n const words = text.split(' ');\n const lines: string[] = [];\n let currentLine = '';\n \n for (const word of words) {\n const plainWord = stripAnsi(word);\n const plainLine = stripAnsi(currentLine);\n \n if (plainLine.length + plainWord.length + 1 > maxWidth) {\n if (currentLine) {\n lines.push(currentLine);\n currentLine = word;\n } else {\n // Word is longer than max width, force break\n lines.push(word);\n }\n } else {\n currentLine = currentLine ? currentLine + ' ' + word : word;\n }\n }\n \n if (currentLine) {\n lines.push(currentLine);\n }\n \n return lines;\n }\n \n /**\n * Render a table of contents from headings\n */\n renderTableOfContents(headings: Heading[]): string[] {\n const lines: string[] = [];\n \n lines.push('TABLE OF CONTENTS');\n lines.push('─'.repeat(40));\n lines.push('');\n \n let h2Count = 0;\n headings.forEach((heading) => {\n const indent = heading.level === 2 ? '' : ' ';\n let number = '';\n \n if (heading.level === 2) {\n h2Count++;\n number = `${h2Count}.`;\n } else {\n number = '•';\n }\n \n lines.push(\n indent + number + ' ' + heading.text\n );\n });\n \n lines.push('');\n lines.push('─'.repeat(40));\n \n return lines;\n }\n \n /**\n * Render article preview (for unowned courses)\n */\n renderArticlePreview(article: Article): string[] {\n const lines: string[] = [];\n \n lines.push(`Article ${article.order}: ${article.title}`);\n lines.push('─'.repeat(50));\n lines.push('');\n lines.push('⚠ Premium Content');\n \n if (article.description) {\n lines.push('');\n lines.push(...this.wrapText(article.description, this.width - 4));\n lines.push('');\n } else {\n lines.push('');\n lines.push('This article is part of the premium course.');\n lines.push('Purchase the course to access full content.');\n lines.push('');\n }\n \n return lines;\n }\n \n /**\n * Create a scrollable view data structure\n */\n createScrollableContent(articles: Article[], isOwned: boolean): {\n lines: string[];\n tocEntries: Array<{ title: string; line: number; type: 'article' | 'heading' }>;\n } {\n const allLines: string[] = [];\n const tocEntries: Array<{ title: string; line: number; type: 'article' | 'heading' }> = [];\n \n articles.sort((a, b) => a.order - b.order);\n \n articles.forEach((article, articleIndex) => {\n const startLine = allLines.length;\n \n // Add article to TOC\n tocEntries.push({\n title: `Article ${article.order}: ${article.title}`,\n line: startLine,\n type: 'article'\n });\n \n // Add article separator\n if (articleIndex > 0) {\n allLines.push('');\n allLines.push('═'.repeat(Math.min(this.width, 70)));\n allLines.push('');\n }\n \n // Add article header\n allLines.push(`ARTICLE ${article.order}: ${article.title.toUpperCase()}`);\n allLines.push('─'.repeat(Math.min(this.width, 70)));\n allLines.push('');\n \n if (isOwned && article.markdown) {\n // Render full markdown content\n const rendered = this.renderMarkdown(article.markdown);\n \n // Extract and add headings to TOC\n const headings = this.extractHeadings(article.markdown);\n headings.forEach(heading => {\n // Find the actual line number in rendered content\n const headingLine = startLine + allLines.length + \n rendered.findIndex(line => \n line.includes(heading.text)\n );\n \n tocEntries.push({\n title: (heading.level === 2 ? ' ' : ' ') + heading.text,\n line: headingLine,\n type: 'heading'\n });\n });\n \n allLines.push(...rendered);\n } else {\n // Show preview for unowned courses\n allLines.push(...this.renderArticlePreview(article));\n }\n \n allLines.push('');\n });\n \n return { lines: allLines, tocEntries };\n }\n}","import chalk from 'chalk';\nimport { highlight, supportsLanguage } from 'cli-highlight';\n\ninterface CodeBlockInfo {\n language: string;\n code: string;\n startLine: number;\n}\n\nexport class CodeHighlighter {\n private static readonly SUPPORTED_LANGUAGES = [\n 'javascript', 'js', 'typescript', 'ts', 'jsx', 'tsx',\n 'python', 'py', 'java', 'c', 'cpp', 'c++', 'csharp', 'cs',\n 'html', 'css', 'scss', 'sass', 'less',\n 'json', 'xml', 'yaml', 'yml',\n 'bash', 'sh', 'shell', 'powershell',\n 'sql', 'graphql', 'markdown', 'md',\n 'rust', 'go', 'php', 'ruby', 'swift', 'kotlin'\n ];\n\n /**\n * Extract code blocks from markdown with their language\n */\n static extractCodeBlocks(markdown: string): CodeBlockInfo[] {\n const codeBlocks: CodeBlockInfo[] = [];\n const lines = markdown.split('\\n');\n let inCodeBlock = false;\n let currentBlock: string[] = [];\n let currentLanguage = '';\n let blockStartLine = 0;\n\n lines.forEach((line, index) => {\n if (line.startsWith('```')) {\n if (!inCodeBlock) {\n // Starting a code block\n inCodeBlock = true;\n currentLanguage = line.substring(3).trim().toLowerCase() || 'text';\n blockStartLine = index;\n currentBlock = [];\n } else {\n // Ending a code block\n inCodeBlock = false;\n codeBlocks.push({\n language: currentLanguage,\n code: currentBlock.join('\\n'),\n startLine: blockStartLine\n });\n currentBlock = [];\n }\n } else if (inCodeBlock) {\n currentBlock.push(line);\n }\n });\n\n return codeBlocks;\n }\n\n /**\n * Highlight code with syntax highlighting\n */\n static highlightCode(code: string, language: string): string[] {\n try {\n // Map common aliases to cli-highlight language names\n const languageMap: Record<string, string> = {\n 'js': 'javascript',\n 'ts': 'typescript',\n 'py': 'python',\n 'yml': 'yaml',\n 'sh': 'bash',\n 'shell': 'bash',\n 'c++': 'cpp',\n 'cs': 'csharp',\n 'md': 'markdown'\n };\n\n const mappedLang = languageMap[language] || language;\n\n // Check if the language is supported\n if (supportsLanguage(mappedLang)) {\n const highlighted = highlight(code, { language: mappedLang });\n return highlighted.split('\\n');\n }\n } catch (error) {\n // Fall through to basic highlighting\n }\n\n // Fallback: Basic syntax highlighting using chalk\n return code.split('\\n').map(line => {\n // Basic JavaScript/TypeScript highlighting\n const lang = language.toLowerCase();\n if (lang === 'javascript' || lang === 'typescript' || lang === 'js' || lang === 'ts') {\n return line\n // Keywords\n .replace(/\\b(const|let|var|function|class|interface|type|return|if|else|for|while|import|export|from|extends|implements|new|this|super|async|await|try|catch|throw|switch|case|break|continue|default)\\b/g, chalk.blue('$1'))\n // Strings\n .replace(/([\"'])(?:(?=(\\\\?))\\2.)*?\\1/g, chalk.green('$&'))\n // Numbers\n .replace(/\\b(\\d+)\\b/g, chalk.cyan('$1'))\n // Comments\n .replace(/(\\/\\/.*$)/g, chalk.gray('$1'))\n // Functions\n .replace(/(\\w+)(?=\\()/g, chalk.yellow('$1'))\n // Properties\n .replace(/\\.(\\w+)/g, '.' + chalk.cyan('$1'));\n }\n \n // Default: return with minimal styling\n return chalk.white(line);\n });\n }\n\n /**\n * Format code block for terminal display with frame\n */\n static formatCodeBlock(\n code: string, \n language: string, \n width: number = 80,\n theme: 'classic' | 'desert' | 'matrix' | 'commando' | 'sandiego' | 'ed209' = 'classic',\n filename: string = '',\n lineNumStart: number = 1\n ): string[] {\n const lines: string[] = [];\n const maxWidth = width - 4; // Use the full provided width\n \n // Theme-based colors\n const frameColors = {\n classic: chalk.cyan,\n desert: chalk.yellow,\n matrix: chalk.green,\n commando: chalk.rgb(107, 142, 35), // Olive green\n sandiego: chalk.red,\n ed209: chalk.rgb(192, 192, 192) // Silver\n };\n \n const frameColor = frameColors[theme] || chalk.cyan;\n \n // Map language aliases\n const languageAliases: Record<string, string> = {\n 'ts': 'typescript',\n 'js': 'javascript',\n 'sh': 'bash',\n 'shell': 'bash',\n 'py': 'python',\n 'yml': 'yaml',\n 'c++': 'cpp',\n 'cs': 'csharp',\n 'md': 'markdown'\n };\n \n const displayLang = languageAliases[language.toLowerCase()] || language;\n const langDisplay = displayLang.toUpperCase();\n \n // Create header text with filename if provided\n let headerText = langDisplay;\n if (filename) {\n // Show filename with language\n headerText = `${filename} ─ ${langDisplay}`;\n // Truncate if too long\n if (headerText.length > maxWidth - 6) {\n headerText = '...' + headerText.substring(headerText.length - (maxWidth - 9));\n }\n }\n \n // Top frame with language/filename indicator\n const padding = Math.max(2, maxWidth - 2 - headerText.length - 2);\n const topBorder = '╭' + '─'.repeat(padding) + ` ${headerText} ` + '─╮';\n lines.push(frameColor(topBorder));\n \n // Highlight the code - use displayLang for better language detection\n const highlightedLines = this.highlightCode(code, displayLang);\n \n // Add line numbers and code\n highlightedLines.forEach((line, index) => {\n const lineNum = String(lineNumStart + index).padStart(3, ' ');\n const lineNumFormatted = chalk.dim.gray(`${lineNum} │`);\n \n // Don't truncate code lines - let them use full width\n let codeLine = line;\n const maxLineLength = maxWidth - 8;\n // Only truncate if extremely long (over 200 chars) to prevent terminal issues\n if (codeLine.length > 200) {\n codeLine = codeLine.substring(0, 197) + chalk.dim('...');\n }\n \n lines.push(`${frameColor('│')} ${lineNumFormatted} ${codeLine}`);\n });\n \n // Bottom frame with copy hint\n const bottomBorder = '╰' + '─'.repeat(maxWidth - 2) + '╯';\n lines.push(frameColor(bottomBorder));\n \n return lines;\n }\n\n /**\n * Create a selectable code block (stores position for interaction)\n */\n static createSelectableCodeBlock(\n code: string,\n language: string,\n startY: number,\n width: number = 80\n ): {\n lines: string[];\n bounds: { startY: number; endY: number; code: string; language: string };\n } {\n const formattedLines = this.formatCodeBlock(code, language, width);\n \n return {\n lines: formattedLines,\n bounds: {\n startY,\n endY: startY + formattedLines.length,\n code,\n language\n }\n };\n }\n\n /**\n * Format inline code\n */\n static formatInlineCode(code: string, theme: string = 'classic'): string {\n const themeColors = {\n classic: chalk.bgGray.white,\n desert: chalk.bgYellow.black,\n matrix: chalk.bgGreen.black,\n commando: chalk.bgRgb(107, 142, 35).white,\n sandiego: chalk.bgRed.white,\n ed209: chalk.bgRgb(105, 105, 105).white\n };\n \n const colorFn = themeColors[theme as keyof typeof themeColors] || chalk.bgGray.white;\n return ` ${colorFn(code)} `;\n }\n\n /**\n * Detect language from code content (heuristic)\n */\n static detectLanguage(code: string): string {\n // Simple heuristics for language detection\n const patterns = [\n { pattern: /\\bfunction\\s+\\w+\\s*\\(|const\\s+\\w+\\s*=|let\\s+\\w+\\s*=|var\\s+\\w+\\s*=/, lang: 'javascript' },\n { pattern: /\\bclass\\s+\\w+\\s*{|\\binterface\\s+\\w+\\s*{|\\btype\\s+\\w+\\s*=/, lang: 'typescript' },\n { pattern: /\\bdef\\s+\\w+\\s*\\(|\\bimport\\s+\\w+|\\bfrom\\s+\\w+\\s+import/, lang: 'python' },\n { pattern: /\\bpublic\\s+class\\s+\\w+|\\bprivate\\s+\\w+\\s+\\w+\\s*\\(/, lang: 'java' },\n { pattern: /<\\w+>.*<\\/\\w+>|<\\w+\\s+.*\\/>/, lang: 'html' },\n { pattern: /\\{\\s*\"[\\w-]+\"\\s*:/, lang: 'json' },\n { pattern: /^\\s*#include\\s+<\\w+>|int\\s+main\\s*\\(/, lang: 'c' },\n { pattern: /\\bfn\\s+\\w+\\s*\\(|\\blet\\s+mut\\s+\\w+/, lang: 'rust' },\n { pattern: /\\bfunc\\s+\\w+\\s*\\(|\\bpackage\\s+\\w+/, lang: 'go' },\n { pattern: /^\\s*\\$\\w+\\s*=|\\becho\\s+/, lang: 'bash' }\n ];\n\n for (const { pattern, lang } of patterns) {\n if (pattern.test(code)) {\n return lang;\n }\n }\n\n return 'text';\n }\n}","/**\n * Pure layout calculations — no terminal-kit, no side effects.\n */\n\n/**\n * Compute the TOC panel width based on terminal width.\n * Mirrors the logic in CourseDetailViewer.updateLayout().\n */\nexport function computeTocWidth(terminalWidth: number): number {\n if (terminalWidth < 80) {\n return Math.min(25, Math.floor(terminalWidth * 0.35));\n } else if (terminalWidth < 120) {\n return 30;\n } else if (terminalWidth < 160) {\n return 35;\n } else {\n return Math.min(45, Math.floor(terminalWidth * 0.25));\n }\n}\n\n/**\n * Compute the x-column where content starts (one past the TOC divider).\n */\nexport function computeContentStartX(tocWidth: number): number {\n return tocWidth + 1;\n}\n\n/**\n * Compute the usable content area height (rows between header and footer).\n */\nexport function computeContentHeight(\n terminalHeight: number,\n headerHeight: number,\n footerHeight: number\n): number {\n return terminalHeight - headerHeight - footerHeight;\n}\n\n/**\n * Compute the wrap width for content text based on view mode.\n *\n * @param viewMode - 'content' | 'split' | 'toc'\n * @param termWidth - full terminal width\n * @param contentStartX - column where the content panel starts (split mode)\n */\nexport function computeWrapWidth(\n viewMode: 'split' | 'content' | 'toc',\n termWidth: number,\n contentStartX: number\n): number {\n if (viewMode === 'content') {\n return termWidth - 8;\n }\n return termWidth - contentStartX - 6;\n}\n\n/**\n * Compute the code block display width.\n */\nexport function computeCodeBlockWidth(\n viewMode: 'split' | 'content' | 'toc',\n termWidth: number,\n contentStartX: number\n): number {\n if (viewMode === 'content') {\n return termWidth - 10;\n }\n return termWidth - contentStartX - 6;\n}\n","/**\n * Pure windowing calculations — which lines/entries are visible for a given\n * scroll offset and viewport height. No terminal-kit, no side effects.\n */\n\nimport type { TOCEntry, CodeBlock, TrackedImage } from './types.js';\n\n/**\n * Maximum scroll offset for the main content.\n * Clamps to 0 so we never return a negative number.\n */\nexport function maxContentScrollOffset(\n totalLines: number,\n contentHeight: number\n): number {\n return Math.max(0, totalLines - contentHeight + 2);\n}\n\n/**\n * Maximum scroll offset for the TOC panel.\n */\nexport function maxTocScrollOffset(\n totalEntries: number,\n contentHeight: number\n): number {\n return Math.max(0, totalEntries - contentHeight + 2);\n}\n\n/**\n * Number of TOC entries visible in a given viewport.\n */\nexport function visibleTocCount(\n totalEntries: number,\n tocScrollOffset: number,\n contentHeight: number\n): number {\n return Math.min(totalEntries - tocScrollOffset, contentHeight - 2);\n}\n\n/**\n * Number of content lines visible in a given viewport.\n */\nexport function visibleContentCount(\n totalLines: number,\n scrollOffset: number,\n contentHeight: number\n): number {\n return Math.min(totalLines - scrollOffset, contentHeight - 2);\n}\n\n/**\n * Returns `true` if any part of a code block overlaps the current viewport.\n */\nexport function isCodeBlockVisible(\n block: CodeBlock,\n viewportStart: number,\n viewportEnd: number\n): boolean {\n return (\n (block.startLine >= viewportStart && block.startLine <= viewportEnd) ||\n (block.endLine >= viewportStart && block.endLine <= viewportEnd) ||\n (block.startLine <= viewportStart && block.endLine >= viewportEnd)\n );\n}\n\n/**\n * Returns `true` if any part of a tracked image overlaps the current viewport.\n */\nexport function isImageVisible(\n image: TrackedImage,\n viewportStart: number,\n viewportEnd: number\n): boolean {\n return (\n (image.lineNumber >= viewportStart && image.lineNumber <= viewportEnd) ||\n (image.endLine !== undefined &&\n image.endLine >= viewportStart &&\n image.endLine <= viewportEnd) ||\n (image.lineNumber <= viewportStart &&\n image.endLine !== undefined &&\n image.endLine >= viewportEnd)\n );\n}\n\n/**\n * Given a viewport and a set of code blocks, find the first visible block.\n * Returns `undefined` when none is visible.\n */\nexport function findVisibleCodeBlock(\n blocks: readonly CodeBlock[],\n viewportStart: number,\n viewportEnd: number\n): CodeBlock | undefined {\n return blocks.find(b => isCodeBlockVisible(b, viewportStart, viewportEnd));\n}\n\n/**\n * Given a viewport and a set of tracked images, find the first visible image.\n */\nexport function findVisibleImage(\n images: readonly TrackedImage[],\n viewportStart: number,\n viewportEnd: number\n): TrackedImage | undefined {\n return images.find(img => isImageVisible(img, viewportStart, viewportEnd));\n}\n\n/**\n * Returns `true` if the `copiedBlock` highlight is still active (within 3 s)\n * and the given `lineNum` falls inside that block's range.\n */\nexport function isCopiedLine(\n lineNum: number,\n copiedBlockIndex: number,\n copiedTimestamp: number,\n blocks: readonly CodeBlock[],\n nowMs: number\n): boolean {\n if (copiedBlockIndex < 0) return false;\n if (nowMs - copiedTimestamp >= 3000) return false;\n const block = blocks[copiedBlockIndex];\n if (!block) return false;\n return lineNum >= block.startLine && lineNum <= block.endLine;\n}\n","/**\n * Pure navigation reducer for CourseDetailViewer.\n *\n * Takes the current ViewerState + a key name, returns a new (or the same)\n * ViewerState. Has zero terminal-kit / side-effect dependencies.\n *\n * Keys that trigger side effects (C – copy, I – open image, q/Q/ESCAPE – exit)\n * are represented by action tags that the caller interprets; the reducer still\n * returns the resulting state so the caller only needs to apply the side effects.\n */\n\nimport type { ViewerState } from './types.js';\nimport {\n maxContentScrollOffset,\n maxTocScrollOffset,\n} from './windowing.js';\n\nexport type ReducerEffect =\n | 'none'\n | 'exit'\n | 'copy_code'\n | 'open_image';\n\nexport interface ReducerResult {\n state: ViewerState;\n /**\n * Side-effect the renderer/controller must carry out (clipboard, browser,\n * EventEmitter.emit('exit'), …).\n */\n effect: ReducerEffect;\n /**\n * `true` when the key was consumed (same semantics as the original\n * handleInput return value).\n */\n handled: boolean;\n}\n\n// ─── helpers ────────────────────────────────────────────────────────────────\n\nfunction scrollTocUp(s: ViewerState): ViewerState {\n if (s.selectedTocIndex <= 0) return s;\n const next = s.selectedTocIndex - 1;\n return {\n ...s,\n selectedTocIndex: next,\n tocScrollOffset: Math.min(s.tocScrollOffset, next),\n };\n}\n\nfunction scrollTocDown(s: ViewerState, totalEntries: number): ViewerState {\n if (s.selectedTocIndex >= totalEntries - 1) return s;\n const next = s.selectedTocIndex + 1;\n const visibleItems = s.contentHeight - 2;\n const newOffset =\n next >= s.tocScrollOffset + visibleItems\n ? next - visibleItems + 1\n : s.tocScrollOffset;\n return { ...s, selectedTocIndex: next, tocScrollOffset: newOffset };\n}\n\nfunction scrollContentUp(s: ViewerState): ViewerState {\n if (s.scrollOffset <= 0) return s;\n return { ...s, scrollOffset: Math.max(0, s.scrollOffset - 1) };\n}\n\nfunction scrollContentDown(s: ViewerState, totalLines: number): ViewerState {\n const maxScroll = maxContentScrollOffset(totalLines, s.contentHeight);\n if (s.scrollOffset >= maxScroll) return s;\n return { ...s, scrollOffset: Math.min(maxScroll, s.scrollOffset + 1) };\n}\n\n// ─── reducer ────────────────────────────────────────────────────────────────\n\nexport function reduce(\n state: ViewerState,\n key: string,\n totalContentLines: number,\n totalTocEntries: number,\n tocEntryLines: readonly number[] // line numbers of each TOC entry\n): ReducerResult {\n const s = state;\n\n // Helper to return a \"handled, no side-effect\" result\n const ok = (next: ViewerState): ReducerResult => ({\n state: next,\n effect: 'none',\n handled: true,\n });\n\n switch (key) {\n // ── UP ───────────────────────────────────────────────────────────────\n case 'UP': {\n if (s.viewMode === 'split') {\n if (s.focusPanel === 'toc') {\n return ok(scrollTocUp(s));\n }\n return ok(scrollContentUp(s));\n }\n if (s.viewMode === 'toc') {\n return ok(scrollTocUp(s));\n }\n // content\n return ok(scrollContentUp(s));\n }\n\n // ── DOWN ─────────────────────────────────────────────────────────────\n case 'DOWN': {\n if (s.viewMode === 'split') {\n if (s.focusPanel === 'toc') {\n return ok(scrollTocDown(s, totalTocEntries));\n }\n return ok(scrollContentDown(s, totalContentLines));\n }\n if (s.viewMode === 'toc') {\n return ok(scrollTocDown(s, totalTocEntries));\n }\n return ok(scrollContentDown(s, totalContentLines));\n }\n\n // ── PAGE_UP ───────────────────────────────────────────────────────────\n case 'PAGE_UP': {\n const pageSize = s.contentHeight - 2;\n if (s.viewMode === 'split') {\n if (s.focusPanel === 'toc') {\n return ok({\n ...s,\n tocScrollOffset: Math.max(0, s.tocScrollOffset - pageSize),\n selectedTocIndex: Math.max(0, s.selectedTocIndex - pageSize),\n });\n }\n return ok({ ...s, scrollOffset: Math.max(0, s.scrollOffset - pageSize) });\n }\n if (s.viewMode === 'toc') {\n return ok({\n ...s,\n tocScrollOffset: Math.max(0, s.tocScrollOffset - pageSize),\n selectedTocIndex: Math.max(0, s.selectedTocIndex - pageSize),\n });\n }\n return ok({ ...s, scrollOffset: Math.max(0, s.scrollOffset - pageSize) });\n }\n\n // ── PAGE_DOWN ─────────────────────────────────────────────────────────\n case 'PAGE_DOWN': {\n const pageSize = s.contentHeight - 2;\n if (s.viewMode === 'split') {\n if (s.focusPanel === 'toc') {\n const maxToc = maxTocScrollOffset(totalTocEntries, s.contentHeight);\n return ok({\n ...s,\n tocScrollOffset: Math.min(maxToc, s.tocScrollOffset + pageSize),\n selectedTocIndex: Math.min(\n totalTocEntries - 1,\n s.selectedTocIndex + pageSize\n ),\n });\n }\n const maxScroll = maxContentScrollOffset(totalContentLines, s.contentHeight);\n return ok({\n ...s,\n scrollOffset: Math.min(maxScroll, s.scrollOffset + pageSize),\n });\n }\n if (s.viewMode === 'toc') {\n const maxToc = maxTocScrollOffset(totalTocEntries, s.contentHeight);\n return ok({\n ...s,\n tocScrollOffset: Math.min(maxToc, s.tocScrollOffset + pageSize),\n selectedTocIndex: Math.min(\n totalTocEntries - 1,\n s.selectedTocIndex + pageSize\n ),\n });\n }\n const maxScroll = maxContentScrollOffset(totalContentLines, s.contentHeight);\n return ok({\n ...s,\n scrollOffset: Math.min(maxScroll, s.scrollOffset + pageSize),\n });\n }\n\n // ── ENTER ─────────────────────────────────────────────────────────────\n case 'ENTER': {\n if (\n (s.viewMode === 'split' || s.viewMode === 'toc') &&\n s.selectedTocIndex < tocEntryLines.length\n ) {\n // Scroll so the heading appears with 1 blank line above it (matches original)\n const targetLine = Math.max(0, tocEntryLines[s.selectedTocIndex] + 2);\n let next: ViewerState = { ...s, scrollOffset: targetLine };\n if (s.viewMode === 'toc') {\n next = { ...next, viewMode: 'content' };\n } else {\n next = { ...next, focusPanel: 'content' };\n }\n return ok(next);\n }\n return ok(s);\n }\n\n // ── TAB ───────────────────────────────────────────────────────────────\n case 'TAB': {\n if (s.viewMode === 'split') {\n return ok({\n ...s,\n focusPanel: s.focusPanel === 'toc' ? 'content' : 'toc',\n });\n }\n // cycle toc → content → split\n if (s.viewMode === 'toc') {\n return ok({ ...s, viewMode: 'content' });\n }\n return ok({ ...s, viewMode: 'split' });\n }\n\n // ── LEFT ──────────────────────────────────────────────────────────────\n case 'LEFT': {\n if (s.viewMode === 'split') {\n return ok({ ...s, focusPanel: 'toc' });\n }\n return ok(s);\n }\n\n // ── RIGHT ─────────────────────────────────────────────────────────────\n case 'RIGHT': {\n if (s.viewMode === 'split') {\n return ok({ ...s, focusPanel: 'content' });\n }\n return ok(s);\n }\n\n // ── T / t ─────────────────────────────────────────────────────────────\n case 't':\n case 'T': {\n return ok({\n ...s,\n viewMode: s.viewMode === 'toc' ? 'split' : 'toc',\n });\n }\n\n // ── F / f ─────────────────────────────────────────────────────────────\n case 'f':\n case 'F': {\n return ok({\n ...s,\n viewMode: s.viewMode === 'content' ? 'split' : 'content',\n });\n }\n\n // ── C / c ─── copy code (side effect handled by caller) ───────────────\n case 'c':\n case 'C': {\n return { state: s, effect: 'copy_code', handled: true };\n }\n\n // ── I / i ─── open image (side effect handled by caller) ──────────────\n case 'i':\n case 'I': {\n return { state: s, effect: 'open_image', handled: true };\n }\n\n // ── q / Q / ESCAPE ────────────────────────────────────────────────────\n case 'q':\n case 'Q':\n case 'ESCAPE': {\n return { state: s, effect: 'exit', handled: true };\n }\n\n default:\n return { state: s, effect: 'none', handled: false };\n }\n}\n\n// ─── state factory ────────────────────────────────────────────────────────────\n\nexport function makeInitialState(\n width: number,\n height: number,\n headerHeight: number,\n footerHeight: number,\n tocWidth: number,\n contentStartX: number\n): ViewerState {\n return {\n scrollOffset: 0,\n tocScrollOffset: 0,\n selectedTocIndex: 0,\n viewMode: 'split',\n focusPanel: 'content',\n copiedBlockIndex: -1,\n copiedTimestamp: 0,\n width,\n height,\n contentHeight: height - headerHeight - footerHeight,\n headerHeight,\n footerHeight,\n tocWidth,\n contentStartX,\n courseTitle: 'COURSE',\n username: 'Guest',\n };\n}\n","import fetch from 'node-fetch';\nimport fs from 'fs';\nimport { pipeline } from 'stream/promises';\nimport { AuthManager } from './auth.js';\nimport { API_URL } from '../config/constants.js';\n\nexport interface DownloadProgress {\n loaded: number;\n total: number;\n percentage: number;\n}\n\nexport interface AssetDownloadResponse {\n success: boolean;\n data?: {\n fileName: string;\n downloadUrl: string;\n mimeType: string;\n expiresAt: string;\n expiresInSeconds: number;\n };\n error?: string;\n}\n\nexport class AssetDownloader {\n private authManager: AuthManager;\n private baseUrl: string;\n\n constructor(authManager: AuthManager) {\n this.authManager = authManager;\n this.baseUrl = API_URL;\n }\n\n async downloadAsset(\n assetKey: string, \n outputPath: string,\n onProgress?: (progress: DownloadProgress) => void\n ): Promise<boolean> {\n try {\n // Step 1: Request download token\n const tokenResponse = await this.authManager.makeAuthenticatedRequest(\n `${this.baseUrl}/api/assets/download?key=${assetKey}`\n );\n\n if (!tokenResponse.ok) {\n const error = await tokenResponse.json() as any;\n \n // Handle rate limiting\n if (tokenResponse.status === 429) {\n const waitTime = this.extractWaitTime(error.error || '');\n throw new Error(`Rate limited. Please wait ${waitTime} seconds before downloading again.`);\n }\n \n if (tokenResponse.status === 403) {\n throw new Error('Access denied. This asset requires a purchase.');\n }\n \n if (tokenResponse.status === 404) {\n throw new Error('Asset not found.');\n }\n \n throw new Error(error.error || `Failed to get download token: ${tokenResponse.status}`);\n }\n\n const tokenData = await tokenResponse.json() as AssetDownloadResponse;\n \n if (!tokenData.success || !tokenData.data) {\n throw new Error(tokenData.error || 'Failed to get download URL');\n }\n\n // Step 2: Download the file immediately (token expires in 30 seconds)\n // Note: The retrieve endpoint doesn't require auth, just the token\n let downloadUrl = tokenData.data.downloadUrl;\n\n // Handle different URL formats from the server\n if (downloadUrl.includes('localhost:3333')) {\n // Replace localhost URL with actual API URL\n // The server returns /assets/retrieve but it should be /api/assets/retrieve\n downloadUrl = downloadUrl\n .replace('http://localhost:3333/assets/retrieve', `${this.baseUrl}/api/assets/retrieve`)\n .replace('https://localhost:3333/assets/retrieve', `${this.baseUrl}/api/assets/retrieve`)\n .replace('http://localhost:3333', this.baseUrl)\n .replace('https://localhost:3333', this.baseUrl);\n } else if (downloadUrl.startsWith('http://') || downloadUrl.startsWith('https://')) {\n // It's already a full URL, use as-is\n downloadUrl = downloadUrl;\n } else if (downloadUrl.startsWith('/')) {\n // Relative path - prepend base URL\n downloadUrl = `${this.baseUrl}${downloadUrl}`;\n } else {\n // Assume it's a relative path without leading slash\n downloadUrl = `${this.baseUrl}/${downloadUrl}`;\n }\n\n const fileResponse = await fetch(downloadUrl);\n\n if (!fileResponse.ok) {\n if (fileResponse.status === 401) {\n throw new Error('Download token expired. Please try again.');\n }\n throw new Error(`Failed to download file: ${fileResponse.status}`);\n }\n\n // Step 3: Save to disk with progress tracking if available\n if (onProgress && fileResponse.body) {\n const contentLength = fileResponse.headers.get('content-length');\n const total = parseInt(contentLength || '0', 10);\n let loaded = 0;\n\n // Use Node.js stream handling\n const writer = fs.createWriteStream(outputPath);\n \n // Handle progress with stream events\n fileResponse.body.on('data', (chunk: Buffer) => {\n loaded += chunk.length;\n writer.write(chunk);\n \n if (onProgress && total > 0) {\n onProgress({\n loaded,\n total,\n percentage: Math.round((loaded / total) * 100)\n });\n }\n });\n \n // Wait for download to complete\n await pipeline(fileResponse.body as any, writer);\n } else {\n // Simple download without progress\n const fileStream = fs.createWriteStream(outputPath);\n await pipeline(fileResponse.body as any, fileStream);\n }\n \n return true;\n\n } catch (error: any) {\n throw error;\n }\n }\n\n private extractWaitTime(errorMessage: string): number {\n // Try to extract wait time from error message\n const match = errorMessage.match(/(\\d+)\\s*seconds?/i);\n return match ? parseInt(match[1], 10) : 30;\n }\n\n async getAssetInfo(assetKey: string): Promise<AssetDownloadResponse> {\n const response = await this.authManager.makeAuthenticatedRequest(\n `${this.baseUrl}/api/assets/download?key=${assetKey}`\n );\n\n if (!response.ok) {\n const error = await response.json() as any;\n return {\n success: false,\n error: error.error || `Failed to get asset info: ${response.status}`\n };\n }\n\n return await response.json() as AssetDownloadResponse;\n }\n}","import fs from 'fs';\nimport path from 'path';\n\nexport interface Project {\n id: number;\n name: string;\n path: string;\n engine: 'BabylonJS' | 'ThreeJS' | 'Unknown';\n genre: string; // FPS, ThirdPerson, BulletHell, Fighter, Platformer, Custom, etc.\n components: string[]; // List of component names found in src/Components/\n hasPackageJson: boolean;\n}\n\n/**\n * Scans a directory for game projects\n */\nexport async function scanForProjects(baseDir: string, maxDepth: number = 2): Promise<Project[]> {\n const projects: Project[] = [];\n let projectId = 1;\n\n async function scanDirectory(dir: string, depth: number): Promise<void> {\n if (depth > maxDepth) return;\n\n try {\n const entries = await fs.promises.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n // Skip node_modules, .git, and other common ignore patterns\n if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'dist' || entry.name === '.next') {\n continue;\n }\n\n // Skip symlinks to avoid circular references\n if (entry.isSymbolicLink()) {\n continue;\n }\n\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n // Check if this directory is a project\n const isProject = await isProjectDirectory(fullPath);\n\n if (isProject) {\n const project = await analyzeProject(fullPath, projectId++);\n projects.push(project);\n // Don't scan inside projects\n continue;\n }\n\n // Recursively scan subdirectories\n await scanDirectory(fullPath, depth + 1);\n }\n }\n } catch (error) {\n // Ignore directories we can't read\n }\n }\n\n await scanDirectory(baseDir, 0);\n return projects;\n}\n\n/**\n * Check if a directory is a project directory\n */\nasync function isProjectDirectory(dir: string): Promise<boolean> {\n try {\n const entries = await fs.promises.readdir(dir);\n\n // Check for package.json\n if (entries.includes('package.json')) {\n const packageJsonPath = path.join(dir, 'package.json');\n const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, 'utf-8'));\n\n // Check for babylonjs or threejs dependencies\n const allDeps = {\n ...packageJson.dependencies || {},\n ...packageJson.devDependencies || {}\n };\n\n const hasBabylonJS = Object.keys(allDeps).some(dep =>\n dep.includes('babylon') || dep.includes('@babylonjs')\n );\n const hasThreeJS = Object.keys(allDeps).some(dep =>\n dep === 'three' || dep.includes('@three')\n );\n\n if (hasBabylonJS || hasThreeJS) {\n return true;\n }\n }\n\n return false;\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Detect the game genre from project files\n */\nasync function detectGenre(dir: string): Promise<string> {\n // Check for .arcade or arcade.json config file\n const configFiles = ['arcade.json', '.arcade', '.arcade.json'];\n for (const configFile of configFiles) {\n const configPath = path.join(dir, configFile);\n if (fs.existsSync(configPath)) {\n try {\n const config = JSON.parse(await fs.promises.readFile(configPath, 'utf-8'));\n if (config.genre || config.template) {\n return config.genre || config.template;\n }\n } catch {\n // Ignore parse errors\n }\n }\n }\n\n // Check package.json for template info\n const packageJsonPath = path.join(dir, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n try {\n const pkg = JSON.parse(await fs.promises.readFile(packageJsonPath, 'utf-8'));\n if (pkg.arcade?.genre) return pkg.arcade.genre;\n if (pkg.arcade?.template) return pkg.arcade.template;\n if (pkg.gameType) return pkg.gameType;\n } catch {\n // Ignore parse errors\n }\n }\n\n // Try to detect from directory structure or component names\n const componentsDir = path.join(dir, 'src', 'Components');\n if (fs.existsSync(componentsDir)) {\n try {\n const components = await fs.promises.readdir(componentsDir);\n const componentNames = components.map(c => c.toLowerCase());\n\n if (componentNames.some(c => c.includes('fps') || c.includes('firstperson'))) {\n return 'FPS';\n }\n if (componentNames.some(c => c.includes('thirdperson') || c.includes('followcamera'))) {\n return 'ThirdPerson';\n }\n if (componentNames.some(c => c.includes('bullet') || c.includes('projectile') || c.includes('shooter'))) {\n return 'BulletHell';\n }\n if (componentNames.some(c => c.includes('fighter') || c.includes('combo') || c.includes('hitbox'))) {\n return 'Fighter';\n }\n if (componentNames.some(c => c.includes('platformer') || c.includes('jump'))) {\n return 'Platformer';\n }\n } catch {\n // Ignore errors\n }\n }\n\n // Check data directory for game modes\n const dataDir = path.join(dir, 'data');\n if (fs.existsSync(dataDir)) {\n try {\n const dataDirs = await fs.promises.readdir(dataDir);\n for (const d of dataDirs) {\n const lowerName = d.toLowerCase();\n if (lowerName === 'thirdperson') return 'ThirdPerson';\n if (lowerName === 'firstperson' || lowerName === 'fps') return 'FPS';\n if (lowerName === 'arcade') return 'Arcade';\n if (lowerName === 'platformer') return 'Platformer';\n }\n } catch {\n // Ignore errors\n }\n }\n\n return 'Custom';\n}\n\n/**\n * Scan for components in the project\n */\nasync function scanComponents(dir: string): Promise<string[]> {\n const components: string[] = [];\n const componentsDir = path.join(dir, 'src', 'Components');\n\n if (!fs.existsSync(componentsDir)) {\n return components;\n }\n\n try {\n const files = await fs.promises.readdir(componentsDir);\n for (const file of files) {\n if (file.endsWith('.ts') || file.endsWith('.js')) {\n // Remove extension and add to list\n const componentName = file.replace(/\\.(ts|js)$/, '');\n // Skip index files\n if (componentName.toLowerCase() !== 'index') {\n components.push(componentName);\n }\n }\n }\n } catch {\n // Ignore errors\n }\n\n return components.sort();\n}\n\n/**\n * Analyze a project directory to get details\n */\nasync function analyzeProject(dir: string, id: number): Promise<Project> {\n const name = path.basename(dir);\n\n let hasPackageJson = false;\n let engine: 'BabylonJS' | 'ThreeJS' | 'Unknown' = 'Unknown';\n\n try {\n const packageJsonPath = path.join(dir, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n hasPackageJson = true;\n const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, 'utf-8'));\n\n const allDeps = {\n ...packageJson.dependencies || {},\n ...packageJson.devDependencies || {}\n };\n\n const depNames = Object.keys(allDeps);\n\n // Detect engine\n if (depNames.some(d => d.includes('@babylonjs') || d.includes('babylonjs'))) {\n engine = 'BabylonJS';\n } else if (depNames.some(d => d === 'three' || d.includes('@three'))) {\n engine = 'ThreeJS';\n }\n }\n } catch {\n // Ignore errors reading package.json\n }\n\n const genre = await detectGenre(dir);\n const components = await scanComponents(dir);\n\n return {\n id,\n name,\n path: dir,\n engine,\n genre,\n components,\n hasPackageJson\n };\n}\n\n/**\n * Get a single project by path\n */\nexport async function getProjectByPath(projectPath: string): Promise<Project | null> {\n const isProject = await isProjectDirectory(projectPath);\n if (!isProject) return null;\n\n return analyzeProject(projectPath, 1);\n}\n","import fs from 'fs';\nimport path from 'path';\nimport { AuthManager, LibraryManifest } from './auth.js';\nimport { API_URL } from '../config/constants.js';\n\n// ============================================\n// Library Path Management\n// ============================================\n\nexport function getLibraryPath(): string {\n const auth = new AuthManager();\n return auth.getLibraryPath();\n}\n\nexport function isLibraryInitialized(): boolean {\n const libraryPath = getLibraryPath();\n return fs.existsSync(path.join(libraryPath, 'Components'));\n}\n\nexport async function initializeLibrary(libraryPath?: string): Promise<{ success: boolean; message: string }> {\n const targetPath = libraryPath || getLibraryPath();\n\n const dirs = [\n '',\n 'Components',\n 'Systems',\n 'Data',\n 'Tests',\n 'GameModes'\n ];\n\n try {\n for (const dir of dirs) {\n const fullPath = path.join(targetPath, dir);\n if (!fs.existsSync(fullPath)) {\n fs.mkdirSync(fullPath, { recursive: true });\n }\n }\n\n // Create README\n const readmePath = path.join(targetPath, 'README.md');\n if (!fs.existsSync(readmePath)) {\n const readme = `# BJS Library\n\nYour personal library of BabylonJS components, systems, and game mode presets.\n\n## Structure\n\n- \\`Components/\\` - Reusable component .ts files\n- \\`Systems/\\` - System .ts files\n- \\`Data/\\` - Shared data definition .ts files\n- \\`Tests/\\` - Component test files\n- \\`GameModes/\\` - Game mode presets with gamemode.json schemas\n\n## GameMode Schema (gamemode.json)\n\n\\`\\`\\`json\n{\n \"name\": \"ThirdPerson\",\n \"description\": \"Third-person camera game mode\",\n \"components\": [\"Movement\", \"FollowCamera\", \"PlayerInput\"],\n \"data\": [\"Light\", \"FollowCamera\"],\n \"scenes\": [\"Main.ts\"]\n}\n\\`\\`\\`\n\nContent from babylonjsmarket.com will be downloaded here automatically.\n`;\n fs.writeFileSync(readmePath, readme);\n }\n\n return { success: true, message: `Library initialized at ${targetPath}` };\n } catch (error: any) {\n return { success: false, message: `Failed to initialize library: ${error.message}` };\n }\n}\n\n// ============================================\n// GameMode Schema\n// ============================================\n\nexport interface GameModeSchema {\n name: string;\n description: string;\n version?: string;\n components: string[];\n systems?: string[];\n data?: string[];\n includeShared?: boolean;\n scenes?: string[];\n screens?: string[];\n metadata?: {\n author?: string;\n category?: string;\n tags?: string[];\n };\n}\n\nexport function getGameModeSchema(modeName: string): GameModeSchema | null {\n const libraryPath = getLibraryPath();\n const schemaPath = path.join(libraryPath, 'GameModes', modeName, 'gamemode.json');\n\n if (!fs.existsSync(schemaPath)) {\n return null;\n }\n\n try {\n const content = fs.readFileSync(schemaPath, 'utf-8');\n return JSON.parse(content) as GameModeSchema;\n } catch {\n return null;\n }\n}\n\n// ============================================\n// Component Catalog\n// ============================================\n\nexport interface ComponentInfo {\n name: string;\n description: string;\n category: 'Core' | 'Input' | 'Camera' | 'Physics' | 'Visual' | 'AI' | 'UI' | 'Debug';\n hasDataFile: boolean;\n dependencies?: string[]; // Other components this depends on\n}\n\n// Component catalog with descriptions\nexport const COMPONENT_CATALOG: ComponentInfo[] = [\n // Core\n { name: 'Mesh', description: 'Load and display 3D models (GLB/GLTF)', category: 'Core', hasDataFile: false },\n { name: 'MeshPrimitive', description: 'Create basic shapes (box, sphere, cylinder)', category: 'Core', hasDataFile: false },\n { name: 'Position', description: 'Set entity position in 3D space', category: 'Core', hasDataFile: false },\n { name: 'Rotation', description: 'Control entity rotation', category: 'Core', hasDataFile: false },\n { name: 'Animation', description: 'Play skeletal animations from models', category: 'Core', hasDataFile: false },\n { name: 'GameMode', description: 'Manage game states and mode switching', category: 'Core', hasDataFile: false },\n\n // Input\n { name: 'KeyboardControl', description: 'Basic WASD keyboard input', category: 'Input', hasDataFile: false },\n { name: 'SimpleKeyboard', description: 'Simplified keyboard controls', category: 'Input', hasDataFile: false },\n { name: 'GamepadInput', description: 'Gamepad/controller support', category: 'Input', hasDataFile: false },\n { name: 'GamepadControl', description: 'Map gamepad to game actions', category: 'Input', hasDataFile: false },\n { name: 'DeviceInput', description: 'Unified input from any device', category: 'Input', hasDataFile: false },\n { name: 'InputAction', description: 'Action-based input mapping', category: 'Input', hasDataFile: false },\n { name: 'PlayerInput', description: 'Full player input handling', category: 'Input', hasDataFile: false },\n { name: 'PlayerInputMore', description: 'Extended player input options', category: 'Input', hasDataFile: false },\n { name: 'ComboKeys', description: 'Detect key combinations/combos', category: 'Input', hasDataFile: false },\n { name: 'KeyboardTiming', description: 'Timed input detection', category: 'Input', hasDataFile: false },\n { name: 'Actions', description: 'Define and trigger game actions', category: 'Input', hasDataFile: true },\n\n // Camera\n { name: 'Camera', description: 'Basic camera setup and control', category: 'Camera', hasDataFile: false },\n { name: 'FollowCamera', description: 'Camera that follows a target', category: 'Camera', hasDataFile: false },\n { name: 'SimpleCamera', description: 'Quick camera setup', category: 'Camera', hasDataFile: false },\n { name: 'MultiCamera', description: 'Multiple camera support', category: 'Camera', hasDataFile: false },\n { name: 'VRCamera', description: 'Virtual reality camera', category: 'Camera', hasDataFile: false },\n\n // Physics\n { name: 'Physics', description: 'Havok physics integration', category: 'Physics', hasDataFile: false },\n { name: 'SimplePhysics', description: 'Basic physics without Havok', category: 'Physics', hasDataFile: false },\n { name: 'Movement', description: 'Character movement with physics', category: 'Physics', hasDataFile: false },\n { name: 'SimpleMovement', description: 'Basic movement without physics', category: 'Physics', hasDataFile: false },\n { name: 'MovementImproved', description: 'Enhanced movement system', category: 'Physics', hasDataFile: false },\n { name: 'MovementRefactored', description: 'Clean movement implementation', category: 'Physics', hasDataFile: false },\n { name: 'MovementPhysicsController', description: 'Physics-based character controller', category: 'Physics', hasDataFile: false },\n { name: 'RampMovement', description: 'Handle slopes and ramps', category: 'Physics', hasDataFile: false },\n { name: 'Intersection', description: 'Collision detection and triggers', category: 'Physics', hasDataFile: false },\n { name: 'Collectible', description: 'Pickups and collectible items', category: 'Physics', hasDataFile: false },\n { name: 'Obstacle', description: 'Obstacles and hazards', category: 'Physics', hasDataFile: false },\n { name: 'PushableBlocks', description: 'Pushable physics objects', category: 'Physics', hasDataFile: false },\n { name: 'Ragdoll', description: 'Ragdoll physics on death', category: 'Physics', hasDataFile: false },\n\n // Visual\n { name: 'Lighting', description: 'Scene lighting setup', category: 'Visual', hasDataFile: false },\n { name: 'Light', description: 'Individual light sources', category: 'Visual', hasDataFile: false },\n { name: 'SimpleLight', description: 'Quick lighting setup', category: 'Visual', hasDataFile: false },\n { name: 'Shadow', description: 'Dynamic shadows', category: 'Visual', hasDataFile: false },\n { name: 'SkyBox', description: 'Skybox/environment background', category: 'Visual', hasDataFile: false },\n { name: 'Background', description: '2D background images', category: 'Visual', hasDataFile: false },\n { name: 'Ground', description: 'Ground plane/terrain', category: 'Visual', hasDataFile: true },\n { name: 'FootDust', description: 'Dust particles when walking', category: 'Visual', hasDataFile: false },\n { name: 'VideoTexture', description: 'Video as texture', category: 'Visual', hasDataFile: false },\n\n // AI\n { name: 'AI', description: 'Enemy AI behavior', category: 'AI', hasDataFile: false },\n\n // UI\n { name: 'GamesMenuGUI', description: 'In-game menu system', category: 'UI', hasDataFile: false },\n { name: 'Pause', description: 'Pause menu functionality', category: 'UI', hasDataFile: false },\n\n // Debug\n { name: 'Debug', description: 'Debug overlays and tools', category: 'Debug', hasDataFile: false },\n { name: 'Inspector', description: 'BabylonJS Inspector integration', category: 'Debug', hasDataFile: false },\n];\n\n// Get components grouped by category\nexport function getComponentsByCategory(): Map<string, ComponentInfo[]> {\n const grouped = new Map<string, ComponentInfo[]>();\n for (const comp of COMPONENT_CATALOG) {\n if (!grouped.has(comp.category)) {\n grouped.set(comp.category, []);\n }\n grouped.get(comp.category)!.push(comp);\n }\n return grouped;\n}\n\n// Get a flat list of all components\nexport function getAllComponents(): ComponentInfo[] {\n return COMPONENT_CATALOG;\n}\n\n// Find component by name\nexport function getComponentInfo(name: string): ComponentInfo | undefined {\n return COMPONENT_CATALOG.find(c => c.name === name);\n}\n\n// Install a component to a project from Library\n// New folder-based structure: Library/Components/Movement/{Movement.ts, Movement.test.ts}\nexport async function installComponent(\n componentName: string,\n targetProjectPath: string\n): Promise<{ success: boolean; message: string; files: string[] }> {\n const libraryPath = getLibraryPath();\n const componentDir = path.join(libraryPath, 'Components', componentName);\n const componentFile = path.join(componentDir, `${componentName}.ts`);\n const files: string[] = [];\n\n // Check if component folder exists with main .ts file\n if (!fs.existsSync(componentFile)) {\n // Fallback to legacy flat file structure\n const legacyPath = path.join(libraryPath, 'Components', `${componentName}.ts`);\n if (fs.existsSync(legacyPath)) {\n // Legacy mode - single file\n const targetComponentDir = path.join(targetProjectPath, 'src', 'Components');\n if (!fs.existsSync(targetComponentDir)) {\n fs.mkdirSync(targetComponentDir, { recursive: true });\n }\n const targetComponentPath = path.join(targetComponentDir, `${componentName}.ts`);\n if (fs.existsSync(targetComponentPath)) {\n return { success: false, message: `${componentName}.ts already exists`, files };\n }\n fs.copyFileSync(legacyPath, targetComponentPath);\n files.push(`src/Components/${componentName}.ts`);\n return { success: true, message: `Installed ${componentName} (${files.length} files)`, files };\n }\n return { success: false, message: `Component ${componentName} not found in Library`, files };\n }\n\n // Create target directories if needed\n const targetComponentDir = path.join(targetProjectPath, 'src', 'Components');\n if (!fs.existsSync(targetComponentDir)) {\n fs.mkdirSync(targetComponentDir, { recursive: true });\n }\n\n // Copy main component file\n const targetComponentPath = path.join(targetComponentDir, `${componentName}.ts`);\n if (fs.existsSync(targetComponentPath)) {\n return { success: false, message: `${componentName}.ts already exists`, files };\n }\n\n fs.copyFileSync(componentFile, targetComponentPath);\n files.push(`src/Components/${componentName}.ts`);\n\n // Check for test file in component folder\n const testPath = path.join(componentDir, `${componentName}.test.ts`);\n if (fs.existsSync(testPath)) {\n const targetTestDir = path.join(targetProjectPath, 'tests', 'Components');\n if (!fs.existsSync(targetTestDir)) {\n fs.mkdirSync(targetTestDir, { recursive: true });\n }\n const targetTestPath = path.join(targetTestDir, `${componentName}.test.ts`);\n if (!fs.existsSync(targetTestPath)) {\n fs.copyFileSync(testPath, targetTestPath);\n files.push(`tests/Components/${componentName}.test.ts`);\n }\n }\n\n return {\n success: true,\n message: `Installed ${componentName} (${files.length} files)`,\n files\n };\n}\n\n// Get list of components not yet in target project (scans Library)\n// Supports both folder-based (Components/Movement/) and legacy flat file structure\nexport function getAvailableComponents(targetProjectPath: string): ComponentInfo[] {\n const libraryPath = getLibraryPath();\n const libraryComponentsDir = path.join(libraryPath, 'Components');\n const targetComponentDir = path.join(targetProjectPath, 'src', 'Components');\n\n const installedComponents = new Set<string>();\n const availableComponents: ComponentInfo[] = [];\n\n // Get installed components in target project\n if (fs.existsSync(targetComponentDir)) {\n const files = fs.readdirSync(targetComponentDir);\n for (const file of files) {\n if (file.endsWith('.ts')) {\n installedComponents.add(file.replace('.ts', ''));\n }\n }\n }\n\n // Scan Library for available components\n if (fs.existsSync(libraryComponentsDir)) {\n const entries = fs.readdirSync(libraryComponentsDir, { withFileTypes: true });\n for (const entry of entries) {\n let name: string;\n\n if (entry.isDirectory()) {\n // New folder structure: Components/Movement/Movement.ts\n name = entry.name;\n const mainFile = path.join(libraryComponentsDir, name, `${name}.ts`);\n if (!fs.existsSync(mainFile)) {\n continue; // Skip folders without main .ts file\n }\n } else if (entry.isFile() && entry.name.endsWith('.ts')) {\n // Legacy flat structure: Components/Movement.ts\n name = entry.name.replace('.ts', '');\n } else {\n continue;\n }\n\n if (!installedComponents.has(name)) {\n // Check catalog for metadata, otherwise create basic entry\n const catalogInfo = COMPONENT_CATALOG.find(c => c.name === name);\n availableComponents.push(catalogInfo || {\n name,\n description: `${name} component`,\n category: 'Core' as const,\n hasDataFile: false\n });\n }\n }\n }\n\n return availableComponents;\n}\n\n// ============================================\n// Game Mode / Data Directory Management\n// ============================================\n\nexport interface GameModeInfo {\n name: string;\n description: string;\n hasScenes: boolean;\n hasScreens: boolean;\n hasShared: boolean;\n}\n\n// Static fallback catalog (used when Library is empty)\nexport const GAME_MODE_CATALOG: GameModeInfo[] = [];\n\n// Get game mode catalog dynamically from Library\nexport function getGameModeCatalog(): GameModeInfo[] {\n const libraryPath = getLibraryPath();\n const gameModesDir = path.join(libraryPath, 'GameModes');\n const modes: GameModeInfo[] = [];\n\n if (!fs.existsSync(gameModesDir)) {\n return modes;\n }\n\n try {\n const dirs = fs.readdirSync(gameModesDir, { withFileTypes: true });\n for (const dir of dirs) {\n if (!dir.isDirectory()) continue;\n\n const schema = getGameModeSchema(dir.name);\n if (schema) {\n modes.push({\n name: schema.name,\n description: schema.description,\n hasScenes: (schema.scenes?.length || 0) > 0,\n hasScreens: (schema.screens?.length || 0) > 0,\n hasShared: schema.includeShared || false\n });\n } else {\n // Legacy mode without schema - check folder structure\n const modePath = path.join(gameModesDir, dir.name);\n modes.push({\n name: dir.name,\n description: `${dir.name} game mode`,\n hasScenes: fs.existsSync(path.join(modePath, 'Scenes')),\n hasScreens: fs.existsSync(path.join(modePath, 'Screens')),\n hasShared: fs.existsSync(path.join(modePath, 'Data'))\n });\n }\n }\n } catch {\n // Return empty if can't read directory\n }\n\n return modes;\n}\n\n// Get game modes not yet in target project\nexport function getAvailableGameModes(targetProjectPath: string): GameModeInfo[] {\n const targetDataDir = path.join(targetProjectPath, 'data');\n const installedModes = new Set<string>();\n\n if (fs.existsSync(targetDataDir)) {\n const dirs = fs.readdirSync(targetDataDir);\n for (const dir of dirs) {\n const stat = fs.statSync(path.join(targetDataDir, dir));\n if (stat.isDirectory()) {\n installedModes.add(dir);\n }\n }\n }\n\n return getGameModeCatalog().filter(m => !installedModes.has(m.name));\n}\n\n// Get installed game modes in target project\nexport function getInstalledGameModes(targetProjectPath: string): string[] {\n const targetDataDir = path.join(targetProjectPath, 'data');\n const modes: string[] = [];\n\n if (fs.existsSync(targetDataDir)) {\n const dirs = fs.readdirSync(targetDataDir);\n for (const dir of dirs) {\n const stat = fs.statSync(path.join(targetDataDir, dir));\n if (stat.isDirectory() && dir !== 'Shared') {\n modes.push(dir);\n }\n }\n }\n\n return modes;\n}\n\n// Helper for recursive directory copy\nfunction copyDir(src: string, dest: string, files: string[], baseRelPath: string) {\n fs.mkdirSync(dest, { recursive: true });\n const entries = fs.readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n const relPath = path.join(baseRelPath, entry.name);\n\n if (entry.isDirectory()) {\n copyDir(srcPath, destPath, files, relPath);\n } else if (entry.name !== 'gamemode.json') { // Skip schema file\n fs.copyFileSync(srcPath, destPath);\n files.push(relPath);\n }\n }\n}\n\n// Install a game mode to a project (schema-based)\nexport async function installGameMode(\n modeName: string,\n targetProjectPath: string\n): Promise<{ success: boolean; message: string; files: string[] }> {\n const libraryPath = getLibraryPath();\n const gameModeDir = path.join(libraryPath, 'GameModes', modeName);\n const files: string[] = [];\n\n if (!fs.existsSync(gameModeDir)) {\n return { success: false, message: `Game mode ${modeName} not found in Library`, files };\n }\n\n const targetDataDir = path.join(targetProjectPath, 'data', modeName);\n if (fs.existsSync(targetDataDir)) {\n return { success: false, message: `${modeName} already exists`, files };\n }\n\n // Check for schema (new approach)\n const schema = getGameModeSchema(modeName);\n\n try {\n if (schema) {\n // Schema-based installation: install components first\n for (const compName of schema.components) {\n const result = await installComponent(compName, targetProjectPath);\n if (result.success) {\n files.push(...result.files);\n }\n // Continue even if component already exists\n }\n\n // Install systems if specified\n if (schema.systems) {\n for (const sysName of schema.systems) {\n const sysPath = path.join(libraryPath, 'Systems', `${sysName}.ts`);\n if (fs.existsSync(sysPath)) {\n const targetSysDir = path.join(targetProjectPath, 'src', 'Systems');\n if (!fs.existsSync(targetSysDir)) {\n fs.mkdirSync(targetSysDir, { recursive: true });\n }\n const targetSysPath = path.join(targetSysDir, `${sysName}.ts`);\n if (!fs.existsSync(targetSysPath)) {\n fs.copyFileSync(sysPath, targetSysPath);\n files.push(`src/Systems/${sysName}.ts`);\n }\n }\n }\n }\n\n // Create target data directory\n fs.mkdirSync(targetDataDir, { recursive: true });\n\n // Copy Data/ subdirectory if exists\n const modeDataDir = path.join(gameModeDir, 'Data');\n if (fs.existsSync(modeDataDir)) {\n const targetSharedDir = path.join(targetDataDir, 'Shared');\n copyDir(modeDataDir, targetSharedDir, files, `data/${modeName}/Shared`);\n }\n\n // Copy Scenes/ subdirectory if exists\n const modeScenesDir = path.join(gameModeDir, 'Scenes');\n if (fs.existsSync(modeScenesDir)) {\n const targetScenesDir = path.join(targetDataDir, 'Scenes');\n copyDir(modeScenesDir, targetScenesDir, files, `data/${modeName}/Scenes`);\n }\n\n // Copy Screens/ subdirectory if exists\n const modeScreensDir = path.join(gameModeDir, 'Screens');\n if (fs.existsSync(modeScreensDir)) {\n const targetScreensDir = path.join(targetDataDir, 'Screens');\n copyDir(modeScreensDir, targetScreensDir, files, `data/${modeName}/Screens`);\n }\n\n } else {\n // Legacy: copy entire directory\n copyDir(gameModeDir, targetDataDir, files, `data/${modeName}`);\n }\n\n return {\n success: true,\n message: `Installed ${modeName} preset (${files.length} files)`,\n files\n };\n } catch (error: any) {\n return { success: false, message: error.message, files };\n }\n}\n\n// ============================================\n// Scene Management\n// ============================================\n\nexport interface SceneInfo {\n name: string;\n path: string;\n gameMode: string;\n}\n\n// Get existing scenes in a project\nexport function getProjectScenes(targetProjectPath: string): SceneInfo[] {\n const scenes: SceneInfo[] = [];\n const dataDir = path.join(targetProjectPath, 'data');\n\n if (!fs.existsSync(dataDir)) return scenes;\n\n const modes = fs.readdirSync(dataDir);\n for (const mode of modes) {\n const scenesDir = path.join(dataDir, mode, 'Scenes');\n if (fs.existsSync(scenesDir)) {\n const sceneFiles = fs.readdirSync(scenesDir);\n for (const file of sceneFiles) {\n if (file.endsWith('.ts')) {\n scenes.push({\n name: file.replace('.ts', ''),\n path: path.join(scenesDir, file),\n gameMode: mode\n });\n }\n }\n }\n }\n\n return scenes;\n}\n\n// Create a new scene file\nexport async function createScene(\n targetProjectPath: string,\n gameMode: string,\n sceneName: string\n): Promise<{ success: boolean; message: string; path: string }> {\n const scenesDir = path.join(targetProjectPath, 'data', gameMode, 'Scenes');\n\n if (!fs.existsSync(scenesDir)) {\n fs.mkdirSync(scenesDir, { recursive: true });\n }\n\n const scenePath = path.join(scenesDir, `${sceneName}.ts`);\n if (fs.existsSync(scenePath)) {\n return { success: false, message: `Scene ${sceneName} already exists`, path: '' };\n }\n\n const template = `import Basics from \"../../Shared/Basics\";\nimport Light from \"../../Shared/Light\";\n\nexport default {\n gameTitle: \"${gameMode}\",\n sceneTitle: \"${sceneName}\",\n worldEntity: \"World\",\n entities: {\n World: {\n components: {\n Position: {\n startingPosition: [0, 0, 0],\n },\n Background: {\n color: [0.53, 0.81, 0.92],\n },\n Mesh: {\n name: \"Ground\",\n src: \"/Assets/Ground/sandbox.glb\",\n },\n },\n },\n ...Light,\n },\n};\n`;\n\n try {\n fs.writeFileSync(scenePath, template);\n return {\n success: true,\n message: `Created scene ${sceneName}`,\n path: scenePath\n };\n } catch (error: any) {\n return { success: false, message: error.message, path: '' };\n }\n}\n\n// ============================================\n// Migration from arcade-ref\n// ============================================\n\nconst ARCADE_REF_PATH = '/Users/law/Programming/Web/BJSM/arcades/arcade-ref';\n\nexport async function migrateFromArcadeRef(): Promise<{ success: boolean; message: string; files: string[] }> {\n const libraryPath = getLibraryPath();\n const files: string[] = [];\n\n // Ensure Library is initialized\n if (!isLibraryInitialized()) {\n const initResult = await initializeLibrary(libraryPath);\n if (!initResult.success) {\n return { success: false, message: initResult.message, files };\n }\n }\n\n try {\n // Copy Components\n const srcComponents = path.join(ARCADE_REF_PATH, 'src', 'Components');\n if (fs.existsSync(srcComponents)) {\n const targetComponents = path.join(libraryPath, 'Components');\n const componentFiles = fs.readdirSync(srcComponents);\n for (const file of componentFiles) {\n if (file.endsWith('.ts')) {\n const srcPath = path.join(srcComponents, file);\n const destPath = path.join(targetComponents, file);\n if (!fs.existsSync(destPath)) {\n fs.copyFileSync(srcPath, destPath);\n files.push(`Components/${file}`);\n }\n }\n }\n }\n\n // Copy Tests\n const srcTests = path.join(ARCADE_REF_PATH, 'tests', 'Components');\n if (fs.existsSync(srcTests)) {\n const targetTests = path.join(libraryPath, 'Tests');\n const testFiles = fs.readdirSync(srcTests);\n for (const file of testFiles) {\n if (file.endsWith('.test.ts')) {\n const srcPath = path.join(srcTests, file);\n const destPath = path.join(targetTests, file);\n if (!fs.existsSync(destPath)) {\n fs.copyFileSync(srcPath, destPath);\n files.push(`Tests/${file}`);\n }\n }\n }\n }\n\n // Copy Shared data\n const srcData = path.join(ARCADE_REF_PATH, 'data', 'Shared');\n if (fs.existsSync(srcData)) {\n const targetData = path.join(libraryPath, 'Data');\n const dataFiles = fs.readdirSync(srcData);\n for (const file of dataFiles) {\n if (file.endsWith('.ts')) {\n const srcPath = path.join(srcData, file);\n const destPath = path.join(targetData, file);\n if (!fs.existsSync(destPath)) {\n fs.copyFileSync(srcPath, destPath);\n files.push(`Data/${file}`);\n }\n }\n }\n }\n\n // Copy Game Modes with schemas\n const gameModes = ['ThirdPerson', 'Arcade'];\n for (const mode of gameModes) {\n const srcMode = path.join(ARCADE_REF_PATH, 'data', mode);\n if (fs.existsSync(srcMode)) {\n const targetMode = path.join(libraryPath, 'GameModes', mode);\n if (!fs.existsSync(targetMode)) {\n fs.mkdirSync(targetMode, { recursive: true });\n\n // Copy subdirectories (Scenes, Screens, Shared)\n const subdirs = ['Scenes', 'Screens', 'Shared'];\n for (const subdir of subdirs) {\n const srcSubdir = path.join(srcMode, subdir);\n if (fs.existsSync(srcSubdir)) {\n const targetSubdir = subdir === 'Shared'\n ? path.join(targetMode, 'Data')\n : path.join(targetMode, subdir);\n fs.mkdirSync(targetSubdir, { recursive: true });\n\n const subFiles = fs.readdirSync(srcSubdir);\n for (const file of subFiles) {\n const srcPath = path.join(srcSubdir, file);\n const destPath = path.join(targetSubdir, file);\n const stat = fs.statSync(srcPath);\n if (stat.isFile()) {\n fs.copyFileSync(srcPath, destPath);\n files.push(`GameModes/${mode}/${subdir === 'Shared' ? 'Data' : subdir}/${file}`);\n }\n }\n }\n }\n\n // Generate gamemode.json\n const schema: GameModeSchema = {\n name: mode,\n description: mode === 'ThirdPerson'\n ? 'Third-person camera game mode with player, terrain, and follow camera'\n : 'Classic arcade-style game mode with start screens and sandbox scenes',\n components: mode === 'ThirdPerson'\n ? ['Movement', 'FollowCamera', 'PlayerInput', 'Animation', 'Physics', 'KeyboardTiming']\n : ['Movement', 'SimpleCamera', 'PlayerInput', 'SimplePhysics'],\n data: ['Light', 'Basics'],\n includeShared: true,\n scenes: fs.existsSync(path.join(srcMode, 'Scenes'))\n ? fs.readdirSync(path.join(srcMode, 'Scenes')).filter(f => f.endsWith('.ts'))\n : [],\n screens: fs.existsSync(path.join(srcMode, 'Screens'))\n ? fs.readdirSync(path.join(srcMode, 'Screens')).filter(f => f.endsWith('.ts'))\n : []\n };\n\n fs.writeFileSync(\n path.join(targetMode, 'gamemode.json'),\n JSON.stringify(schema, null, 2)\n );\n files.push(`GameModes/${mode}/gamemode.json`);\n }\n }\n }\n\n return {\n success: true,\n message: `Migrated ${files.length} files from arcade-ref`,\n files\n };\n } catch (error: any) {\n return { success: false, message: error.message, files };\n }\n}\n\n// ============================================\n// API-Based Library Management\n// ============================================\n\n// Server manifest file info\nexport interface ServerFileInfo {\n path: string; // e.g., \"Components/Movement\" (folder path)\n version: string; // Version hash\n category: 'Components' | 'Systems' | 'Data' | 'Tests' | 'GameModes';\n hasAccess: boolean; // Whether user has access to this file\n price?: number; // Price if not owned (undefined if free or owned)\n description?: string; // File description\n updatedAt: string; // ISO date when file was last updated on server\n files: string[]; // Files within this component folder (e.g., [\"Movement.ts\", \"Movement.test.ts\"])\n dependencies?: string[]; // Other components this depends on\n}\n\nexport interface ServerManifest {\n files: ServerFileInfo[];\n totalFiles: number;\n unlockedFiles: number;\n}\n\nexport interface LibrarySyncStatus {\n totalFiles: number; // Total files in server library\n unlockedFiles: number; // Files user has access to\n installedFiles: number; // Files installed locally\n updatesAvailable: number; // Files with newer versions\n lastSyncAt?: string; // ISO date of last sync\n}\n\n// Fetch the library manifest from the server\nexport async function fetchLibraryManifest(): Promise<{\n success: boolean;\n manifest?: ServerManifest;\n error?: string;\n}> {\n const auth = new AuthManager();\n\n try {\n const response = await auth.makeAuthenticatedRequest(`${API_URL}/api/library/manifest`);\n\n if (!response.ok) {\n if (response.status === 401) {\n return { success: false, error: 'Not authenticated' };\n }\n return { success: false, error: `Server error: ${response.status}` };\n }\n\n const data = await response.json() as any;\n return { success: true, manifest: data };\n } catch (error: any) {\n return { success: false, error: error.message };\n }\n}\n\n// Download a single file from the library\nexport async function downloadLibraryFile(filePath: string): Promise<{\n success: boolean;\n content?: string;\n version?: string;\n error?: string;\n}> {\n const auth = new AuthManager();\n\n try {\n const response = await auth.makeAuthenticatedRequest(\n `${API_URL}/api/library/file/${encodeURIComponent(filePath)}`\n );\n\n if (!response.ok) {\n if (response.status === 401) {\n return { success: false, error: 'Not authenticated' };\n }\n if (response.status === 403) {\n return { success: false, error: 'No access to this file' };\n }\n if (response.status === 404) {\n return { success: false, error: 'File not found' };\n }\n return { success: false, error: `Server error: ${response.status}` };\n }\n\n const data = await response.json() as any;\n return {\n success: true,\n content: data.content,\n version: data.version\n };\n } catch (error: any) {\n return { success: false, error: error.message };\n }\n}\n\n// Get sync status (compare local vs server)\nexport function getLibrarySyncStatus(): LibrarySyncStatus {\n const auth = new AuthManager();\n const manifest = auth.getLibraryManifest();\n const installedFiles = Object.keys(manifest.files).length;\n\n return {\n totalFiles: 0, // Will be updated after fetching server manifest\n unlockedFiles: 0,\n installedFiles,\n updatesAvailable: 0,\n lastSyncAt: manifest.lastSyncAt\n };\n}\n\n// Compare local and server manifests to find updates\nexport function compareManifests(\n serverManifest: ServerManifest,\n localManifest: LibraryManifest\n): {\n toInstall: ServerFileInfo[]; // New files to download\n toUpdate: ServerFileInfo[]; // Files with newer versions\n upToDate: ServerFileInfo[]; // Files already current\n locked: ServerFileInfo[]; // Files user doesn't have access to\n} {\n const toInstall: ServerFileInfo[] = [];\n const toUpdate: ServerFileInfo[] = [];\n const upToDate: ServerFileInfo[] = [];\n const locked: ServerFileInfo[] = [];\n\n for (const file of serverManifest.files) {\n if (!file.hasAccess) {\n locked.push(file);\n continue;\n }\n\n const localFile = localManifest.files[file.path];\n\n if (!localFile) {\n toInstall.push(file);\n } else if (localFile.version !== file.version) {\n toUpdate.push(file);\n } else {\n upToDate.push(file);\n }\n }\n\n return { toInstall, toUpdate, upToDate, locked };\n}\n\n// Sync library - download/update all accessible components\nexport async function syncLibrary(\n onProgress?: (current: number, total: number, fileName: string) => void\n): Promise<{\n success: boolean;\n message: string;\n installed: number;\n updated: number;\n errors: string[];\n}> {\n const auth = new AuthManager();\n const libraryPath = getLibraryPath();\n const errors: string[] = [];\n let installed = 0;\n let updated = 0;\n\n // Ensure library directory exists\n if (!isLibraryInitialized()) {\n await initializeLibrary();\n }\n\n // Fetch server manifest\n const manifestResult = await fetchLibraryManifest();\n if (!manifestResult.success || !manifestResult.manifest) {\n return {\n success: false,\n message: manifestResult.error || 'Failed to fetch manifest',\n installed: 0,\n updated: 0,\n errors: [manifestResult.error || 'Unknown error']\n };\n }\n\n const serverManifest = manifestResult.manifest;\n const localManifest = auth.getLibraryManifest();\n const { toInstall, toUpdate } = compareManifests(serverManifest, localManifest);\n\n const componentsToSync = [...toInstall, ...toUpdate];\n const totalComponents = componentsToSync.length;\n\n if (totalComponents === 0) {\n auth.markLibrarySynced();\n return {\n success: true,\n message: 'Already up to date',\n installed: 0,\n updated: 0,\n errors: []\n };\n }\n\n // Count total files for progress\n let totalFiles = 0;\n for (const comp of componentsToSync) {\n totalFiles += comp.files.length || 1;\n }\n\n let currentFile = 0;\n\n // Download each component's files\n for (const component of componentsToSync) {\n const isInstall = toInstall.includes(component);\n const componentName = component.path.split('/').pop() || component.path;\n\n // Each component has multiple files (e.g., Movement.ts, Movement.test.ts)\n const filesToDownload = component.files.length > 0\n ? component.files\n : [`${componentName}.ts`]; // Fallback if files array is empty\n\n let componentSuccess = true;\n\n for (const fileName of filesToDownload) {\n currentFile++;\n\n // Full path like \"Components/Movement/Movement.ts\"\n const filePath = `${component.path}/${fileName}`;\n\n if (onProgress) {\n onProgress(currentFile, totalFiles, filePath);\n }\n\n const result = await downloadLibraryFile(filePath);\n\n if (!result.success) {\n errors.push(`${filePath}: ${result.error}`);\n componentSuccess = false;\n continue;\n }\n\n // Write file to library - maintain folder structure\n const fullPath = path.join(libraryPath, filePath);\n const dir = path.dirname(fullPath);\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n fs.writeFileSync(fullPath, result.content!);\n }\n\n // Update local manifest with component version (not individual files)\n if (componentSuccess) {\n auth.updateLibraryFile(component.path, component.version);\n\n if (isInstall) {\n installed++;\n } else {\n updated++;\n }\n }\n }\n\n auth.markLibrarySynced();\n\n const totalSynced = installed + updated;\n const message = errors.length > 0\n ? `Synced ${totalSynced} components with ${errors.length} errors`\n : `Synced ${totalSynced} components (${installed} new, ${updated} updated)`;\n\n return {\n success: errors.length === 0,\n message,\n installed,\n updated,\n errors\n };\n}\n","/**\n * Pure, renderer-agnostic BBS state + reducer (Elm/Redux pattern).\n *\n * This module holds every piece of state the old `term.on('key')` closure\n * mutated inline, plus a pure `reduce(state, action)` that performs all the\n * selection / marking / view-transition logic. No terminal I/O, no fs, no\n * network — those side effects stay in the orchestrator (bbs.ts), which\n * dispatches *intents* (Actions) here and runs effects separately.\n *\n * Behavior is preserved exactly from the original monolith.\n */\n\nexport type View =\n | 'home'\n | 'courses'\n | 'toys'\n | 'downloads'\n | 'settings'\n | 'projects'\n | 'courseDetail';\n\nexport type Theme =\n | 'classic'\n | 'desert'\n | 'matrix'\n | 'commando'\n | 'sandiego'\n | 'ed209';\n\nexport const THEMES: Theme[] = [\n 'classic',\n 'desert',\n 'matrix',\n 'commando',\n 'sandiego',\n 'ed209',\n];\n\n// ── Domain data shapes (mirrors of the interfaces in bbs.ts) ─────────────────\n\nexport interface Course {\n id: number;\n title: string;\n slug: string;\n description?: string;\n category?: string;\n progress?: number;\n completedArticles?: number;\n totalArticles?: number;\n assetKey?: string;\n isOwned?: boolean;\n price?: string;\n image?: string;\n banner?: string;\n}\n\nexport interface Toy {\n id: number;\n name: string;\n size: string;\n downloads: number;\n filetype: string;\n modeltype: 'Static' | 'Animated' | 'Rigged' | 'Arcade';\n downloadUrl?: string;\n assetKey?: string;\n}\n\nexport interface Download {\n id: string;\n assetKey: string;\n fileName: string;\n fileSize: string;\n fileSizeBytes: number;\n fileType: string;\n mimeType?: string;\n description: string;\n productTitle: string;\n productSlug: string;\n productCategory?: string;\n totalDownloads: number;\n lastDownloaded?: string;\n createdAt: string;\n}\n\n/** A scanned project (mirror of project-scanner's Project, fields the UI reads). */\nexport interface ProjectLike {\n name: string;\n path: string;\n engine: string;\n genre: string;\n components: string[];\n hasPackageJson?: boolean;\n}\n\n/** Component catalog entry the library browser lists. */\nexport interface ComponentLike {\n name: string;\n category: string;\n description: string;\n hasDataFile?: boolean;\n}\n\n/** Game mode catalog entry the library browser lists. */\nexport interface GameModeLike {\n name: string;\n description: string;\n hasScenes?: boolean;\n hasScreens?: boolean;\n hasShared?: boolean;\n}\n\n// ── State ────────────────────────────────────────────────────────────────────\n\nexport interface BbsState {\n // Navigation\n currentView: View;\n navigationHistory: View[];\n\n // Per-view selection indices\n selectedIndex: number; // courses\n toysSelectedIndex: number;\n downloadsSelectedIndex: number;\n settingsSelectedIndex: number;\n projectsSelectedIndex: number;\n componentSelectedIndex: number;\n gameModeSelectedIndex: number;\n sceneGameModeIndex: number;\n\n // Marked sets (indices into the respective data arrays)\n markedCourses: Set<number>;\n markedToys: Set<number>;\n markedDownloads: Set<number>;\n markedProjects: Set<number>;\n\n // Data\n courses: Course[];\n toys: Toy[];\n downloads: Download[];\n projects: ProjectLike[];\n availableComponents: ComponentLike[];\n availableGameModes: GameModeLike[];\n installedGameModes: string[];\n\n // Settings / preferences\n theme: Theme;\n animations: boolean;\n mouse: boolean;\n\n // Library browser sub-panels (projects view)\n componentBrowserActive: boolean;\n gameModeBrowserActive: boolean;\n sceneCreatorActive: boolean;\n\n // Inline text input: projects directory editing (settings)\n editingProjectsDir: boolean;\n projectsDirInput: string;\n projectsDirError: string;\n projectsDirSuccess: string;\n\n // Inline text input: library path editing (settings)\n editingLibraryPath: boolean;\n libraryPathInput: string;\n libraryPathError: string;\n libraryPathSuccess: string;\n\n // Library sync (settings)\n syncingLibrary: boolean;\n librarySyncMessage: string;\n librarySyncError: string;\n librarySyncProgress: string;\n\n // Scene creator text input (projects)\n sceneNameInput: string;\n sceneCreatorMessage: string;\n sceneCreatorSuccess: boolean;\n\n // Library browser install messages (projects)\n componentInstallMessage: string;\n componentInstallSuccess: boolean;\n gameModeInstallMessage: string;\n gameModeInstallSuccess: boolean;\n\n // Error popup\n errorPopupVisible: boolean;\n}\n\n/** A factory producing the initial state (parametrized by the data loaded at startup). */\nexport function createInitialState(init: {\n courses: Course[];\n toys: Toy[];\n downloads: Download[];\n projects: ProjectLike[];\n theme: Theme;\n animations: boolean;\n mouse: boolean;\n}): BbsState {\n return {\n currentView: 'home',\n navigationHistory: [],\n\n selectedIndex: 0,\n toysSelectedIndex: 0,\n downloadsSelectedIndex: 0,\n settingsSelectedIndex: 0,\n projectsSelectedIndex: 0,\n componentSelectedIndex: 0,\n gameModeSelectedIndex: 0,\n sceneGameModeIndex: 0,\n\n markedCourses: new Set<number>(),\n markedToys: new Set<number>(),\n markedDownloads: new Set<number>(),\n markedProjects: new Set<number>(),\n\n courses: init.courses,\n toys: init.toys,\n downloads: init.downloads,\n projects: init.projects,\n availableComponents: [],\n availableGameModes: [],\n installedGameModes: [],\n\n theme: init.theme,\n animations: init.animations,\n mouse: init.mouse,\n\n componentBrowserActive: false,\n gameModeBrowserActive: false,\n sceneCreatorActive: false,\n\n editingProjectsDir: false,\n projectsDirInput: '',\n projectsDirError: '',\n projectsDirSuccess: '',\n\n editingLibraryPath: false,\n libraryPathInput: '',\n libraryPathError: '',\n libraryPathSuccess: '',\n\n syncingLibrary: false,\n librarySyncMessage: '',\n librarySyncError: '',\n librarySyncProgress: '',\n\n sceneNameInput: '',\n sceneCreatorMessage: '',\n sceneCreatorSuccess: false,\n\n componentInstallMessage: '',\n componentInstallSuccess: false,\n gameModeInstallMessage: '',\n gameModeInstallSuccess: false,\n\n errorPopupVisible: false,\n };\n}\n\n// ── Actions (input intents) ───────────────────────────────────────────────────\n\n/** The highest settings list index (Migrate from arcade-ref). */\nexport const SETTINGS_MAX_INDEX = 11;\n/** Number of theme rows at the top of the settings list (indices 0..5). */\nexport const SETTINGS_THEME_COUNT = 6;\n\nexport type Action =\n // Navigation within lists\n | { type: 'MoveUp' }\n | { type: 'MoveDown' }\n | { type: 'MoveLeft' } // scene-creator game-mode selector\n | { type: 'MoveRight' }\n // View changes\n | { type: 'ChangeView'; view: View }\n | { type: 'Back' }\n // Marking\n | { type: 'ToggleMark' }\n // Settings toggles (the pure part — persistence is an effect)\n | { type: 'SettingsActivate' } // ENTER/SPACE on the currently-selected settings row\n // Library browser panels (projects view)\n | { type: 'ToggleComponentBrowser' }\n | { type: 'ToggleGameModeBrowser' }\n | { type: 'ToggleSceneCreator' }\n | { type: 'CloseLibraryPanels' }\n // Inline text input\n | { type: 'InputChar'; char: string }\n | { type: 'InputBackspace' }\n | { type: 'InputSet'; value: string } // used by TAB autocomplete (effect computes value)\n | { type: 'StartEditProjectsDir'; value: string }\n | { type: 'StartEditLibraryPath'; value: string }\n | { type: 'CancelEdit' }\n // Data setters (effects fetch, then dispatch these)\n | { type: 'SetCourses'; courses: Course[] }\n | { type: 'SetDownloads'; downloads: Download[] }\n | { type: 'SetProjects'; projects: ProjectLike[] }\n | { type: 'SetAvailableComponents'; components: ComponentLike[] }\n | { type: 'SetAvailableGameModes'; gameModes: GameModeLike[] }\n | { type: 'SetInstalledGameModes'; gameModes: string[] }\n | { type: 'SetLibraryData'; components: ComponentLike[]; gameModes: GameModeLike[]; installed: string[] }\n // Theme / settings (direct sets, used by the settings ENTER effect)\n | { type: 'SetTheme'; theme: Theme }\n | { type: 'ToggleAnimations' }\n | { type: 'ToggleMouse' }\n // Messages (effects set these after async ops)\n | { type: 'SetProjectsDirResult'; error?: string; success?: string }\n | { type: 'SetLibraryPathResult'; error?: string; success?: string }\n | { type: 'SetSyncState'; syncing?: boolean; message?: string; error?: string; progress?: string }\n | { type: 'SetSceneCreatorResult'; message: string; success: boolean }\n | { type: 'SetComponentInstallResult'; message: string; success: boolean }\n | { type: 'SetGameModeInstallResult'; message: string; success: boolean }\n | { type: 'ClearSceneNameInput' }\n // Error popup\n | { type: 'ShowError' }\n | { type: 'DismissError' };\n\n// ── Helpers ────────────────────────────────────────────────────────────────────\n\nfunction toggle(set: Set<number>, index: number): Set<number> {\n const next = new Set(set);\n if (next.has(index)) next.delete(index);\n else next.add(index);\n return next;\n}\n\n/** True when any library sub-panel is open in the projects view. */\nfunction anyLibraryPanelActive(s: BbsState): boolean {\n return s.componentBrowserActive || s.gameModeBrowserActive || s.sceneCreatorActive;\n}\n\n// ── Reducer ────────────────────────────────────────────────────────────────────\n\nexport function reduce(state: BbsState, action: Action): BbsState {\n switch (action.type) {\n // ── Up / Down navigation ──────────────────────────────────────────────\n case 'MoveUp': {\n const s = state;\n if (s.currentView === 'projects' && s.componentBrowserActive) {\n if (s.componentSelectedIndex > 0) {\n return { ...s, componentSelectedIndex: s.componentSelectedIndex - 1, componentInstallMessage: '' };\n }\n return s;\n }\n if (s.currentView === 'projects' && s.gameModeBrowserActive) {\n if (s.gameModeSelectedIndex > 0) {\n return { ...s, gameModeSelectedIndex: s.gameModeSelectedIndex - 1, gameModeInstallMessage: '' };\n }\n return s;\n }\n if (s.currentView === 'courses' && s.selectedIndex > 0) {\n return { ...s, selectedIndex: s.selectedIndex - 1 };\n }\n if (s.currentView === 'toys' && s.toysSelectedIndex > 0) {\n return { ...s, toysSelectedIndex: s.toysSelectedIndex - 1 };\n }\n if (s.currentView === 'projects' && s.projectsSelectedIndex > 0) {\n return { ...s, projectsSelectedIndex: s.projectsSelectedIndex - 1 };\n }\n if (s.currentView === 'downloads' && s.downloadsSelectedIndex > 0) {\n return { ...s, downloadsSelectedIndex: s.downloadsSelectedIndex - 1 };\n }\n if (s.currentView === 'settings' && s.settingsSelectedIndex > 0) {\n return { ...s, settingsSelectedIndex: s.settingsSelectedIndex - 1 };\n }\n return s;\n }\n\n case 'MoveDown': {\n const s = state;\n if (s.currentView === 'projects' && s.componentBrowserActive) {\n if (s.componentSelectedIndex < s.availableComponents.length - 1) {\n return { ...s, componentSelectedIndex: s.componentSelectedIndex + 1, componentInstallMessage: '' };\n }\n return s;\n }\n if (s.currentView === 'projects' && s.gameModeBrowserActive) {\n if (s.gameModeSelectedIndex < s.availableGameModes.length - 1) {\n return { ...s, gameModeSelectedIndex: s.gameModeSelectedIndex + 1, gameModeInstallMessage: '' };\n }\n return s;\n }\n if (s.currentView === 'courses' && s.selectedIndex < s.courses.length - 1) {\n return { ...s, selectedIndex: s.selectedIndex + 1 };\n }\n if (s.currentView === 'toys' && s.toysSelectedIndex < s.toys.length - 1) {\n return { ...s, toysSelectedIndex: s.toysSelectedIndex + 1 };\n }\n if (s.currentView === 'projects' && s.projectsSelectedIndex < s.projects.length - 1) {\n return { ...s, projectsSelectedIndex: s.projectsSelectedIndex + 1 };\n }\n if (s.currentView === 'downloads' && s.downloadsSelectedIndex < s.downloads.length - 1) {\n return { ...s, downloadsSelectedIndex: s.downloadsSelectedIndex + 1 };\n }\n if (s.currentView === 'settings' && s.settingsSelectedIndex < SETTINGS_MAX_INDEX) {\n return { ...s, settingsSelectedIndex: s.settingsSelectedIndex + 1 };\n }\n return s;\n }\n\n case 'MoveLeft': {\n const s = state;\n if (s.currentView === 'projects' && s.sceneCreatorActive && s.sceneGameModeIndex > 0) {\n return { ...s, sceneGameModeIndex: s.sceneGameModeIndex - 1, sceneCreatorMessage: '' };\n }\n return s;\n }\n\n case 'MoveRight': {\n const s = state;\n if (\n s.currentView === 'projects' &&\n s.sceneCreatorActive &&\n s.sceneGameModeIndex < s.installedGameModes.length - 1\n ) {\n return { ...s, sceneGameModeIndex: s.sceneGameModeIndex + 1, sceneCreatorMessage: '' };\n }\n return s;\n }\n\n // ── View changes ──────────────────────────────────────────────────────\n case 'ChangeView': {\n const s = state;\n if (s.currentView === action.view) return s;\n const next: BbsState = {\n ...s,\n navigationHistory: [...s.navigationHistory, s.currentView],\n currentView: action.view,\n };\n // The monolith resets selection on switching to projects/downloads/settings.\n if (action.view === 'projects') next.projectsSelectedIndex = 0;\n if (action.view === 'downloads') next.downloadsSelectedIndex = 0;\n if (action.view === 'settings') next.settingsSelectedIndex = 0;\n return next;\n }\n\n case 'Back': {\n const s = state;\n // In projects, ESC first closes any open library sub-panel.\n if (s.currentView === 'projects' && anyLibraryPanelActive(s)) {\n return {\n ...s,\n componentBrowserActive: false,\n gameModeBrowserActive: false,\n sceneCreatorActive: false,\n componentSelectedIndex: 0,\n gameModeSelectedIndex: 0,\n componentInstallMessage: '',\n gameModeInstallMessage: '',\n sceneNameInput: '',\n sceneCreatorMessage: '',\n };\n }\n if (s.navigationHistory.length > 0) {\n const history = [...s.navigationHistory];\n const view = history.pop() as View;\n return { ...s, navigationHistory: history, currentView: view };\n }\n if (s.currentView !== 'home') {\n return { ...s, currentView: 'home' };\n }\n return s;\n }\n\n // ── Marking ─────────────────────────────────────────────────────────────\n case 'ToggleMark': {\n const s = state;\n if (s.currentView === 'courses' && s.courses[s.selectedIndex]) {\n return { ...s, markedCourses: toggle(s.markedCourses, s.selectedIndex) };\n }\n if (s.currentView === 'toys' && s.toys[s.toysSelectedIndex]) {\n return { ...s, markedToys: toggle(s.markedToys, s.toysSelectedIndex) };\n }\n if (s.currentView === 'downloads' && s.downloads[s.downloadsSelectedIndex]) {\n return { ...s, markedDownloads: toggle(s.markedDownloads, s.downloadsSelectedIndex) };\n }\n return s;\n }\n\n // ── Library browser panels ────────────────────────────────────────────\n case 'ToggleComponentBrowser': {\n const s = state;\n if (s.componentBrowserActive) {\n return { ...s, componentBrowserActive: false, componentSelectedIndex: 0, componentInstallMessage: '' };\n }\n return {\n ...s,\n componentBrowserActive: true,\n gameModeBrowserActive: false,\n sceneCreatorActive: false,\n componentSelectedIndex: 0,\n componentInstallMessage: '',\n };\n }\n\n case 'ToggleGameModeBrowser': {\n const s = state;\n if (s.gameModeBrowserActive) {\n return { ...s, gameModeBrowserActive: false, gameModeSelectedIndex: 0, gameModeInstallMessage: '' };\n }\n return {\n ...s,\n gameModeBrowserActive: true,\n componentBrowserActive: false,\n sceneCreatorActive: false,\n gameModeSelectedIndex: 0,\n gameModeInstallMessage: '',\n };\n }\n\n case 'ToggleSceneCreator': {\n const s = state;\n if (s.sceneCreatorActive) {\n return { ...s, sceneCreatorActive: false, sceneNameInput: '', sceneCreatorMessage: '' };\n }\n return {\n ...s,\n sceneCreatorActive: true,\n componentBrowserActive: false,\n gameModeBrowserActive: false,\n sceneNameInput: '',\n sceneCreatorMessage: '',\n sceneGameModeIndex: 0,\n };\n }\n\n case 'CloseLibraryPanels':\n return {\n ...state,\n componentBrowserActive: false,\n gameModeBrowserActive: false,\n sceneCreatorActive: false,\n componentSelectedIndex: 0,\n gameModeSelectedIndex: 0,\n componentInstallMessage: '',\n gameModeInstallMessage: '',\n sceneNameInput: '',\n sceneCreatorMessage: '',\n };\n\n // ── Inline text input ──────────────────────────────────────────────────\n case 'InputChar': {\n const s = state;\n if (s.editingProjectsDir) {\n return { ...s, projectsDirInput: s.projectsDirInput + action.char, projectsDirError: '' };\n }\n if (s.editingLibraryPath) {\n return { ...s, libraryPathInput: s.libraryPathInput + action.char, libraryPathError: '' };\n }\n if (s.sceneCreatorActive && s.currentView === 'projects' && /[a-zA-Z0-9_-]/.test(action.char)) {\n return { ...s, sceneNameInput: s.sceneNameInput + action.char, sceneCreatorMessage: '' };\n }\n return s;\n }\n\n case 'InputBackspace': {\n const s = state;\n if (s.editingProjectsDir) {\n return { ...s, projectsDirInput: s.projectsDirInput.slice(0, -1), projectsDirError: '' };\n }\n if (s.editingLibraryPath) {\n return { ...s, libraryPathInput: s.libraryPathInput.slice(0, -1), libraryPathError: '' };\n }\n if (s.sceneCreatorActive && s.currentView === 'projects') {\n return { ...s, sceneNameInput: s.sceneNameInput.slice(0, -1), sceneCreatorMessage: '' };\n }\n return s;\n }\n\n case 'InputSet': {\n const s = state;\n if (s.editingProjectsDir) {\n return { ...s, projectsDirInput: action.value, projectsDirError: '' };\n }\n if (s.editingLibraryPath) {\n return { ...s, libraryPathInput: action.value, libraryPathError: '' };\n }\n return s;\n }\n\n case 'StartEditProjectsDir':\n return {\n ...state,\n editingProjectsDir: true,\n projectsDirInput: action.value,\n projectsDirError: '',\n projectsDirSuccess: '',\n };\n\n case 'StartEditLibraryPath':\n return {\n ...state,\n editingLibraryPath: true,\n libraryPathInput: action.value,\n libraryPathError: '',\n libraryPathSuccess: '',\n };\n\n case 'CancelEdit': {\n const s = state;\n if (s.editingProjectsDir) {\n return {\n ...s,\n editingProjectsDir: false,\n projectsDirInput: '',\n projectsDirError: '',\n projectsDirSuccess: '',\n };\n }\n if (s.editingLibraryPath) {\n return {\n ...s,\n editingLibraryPath: false,\n libraryPathInput: '',\n libraryPathError: '',\n libraryPathSuccess: '',\n };\n }\n return s;\n }\n\n // ── Data setters ─────────────────────────────────────────────────────────\n case 'SetCourses':\n return { ...state, courses: action.courses };\n\n case 'SetDownloads':\n return { ...state, downloads: action.downloads };\n\n case 'SetProjects':\n return { ...state, projects: action.projects, projectsSelectedIndex: 0 };\n\n case 'SetAvailableComponents': {\n const s = state;\n // Keep the selected index in range after a refresh (install path).\n let idx = s.componentSelectedIndex;\n if (idx >= action.components.length) idx = Math.max(0, action.components.length - 1);\n return { ...s, availableComponents: action.components, componentSelectedIndex: idx };\n }\n\n case 'SetAvailableGameModes': {\n const s = state;\n let idx = s.gameModeSelectedIndex;\n if (idx >= action.gameModes.length) idx = Math.max(0, action.gameModes.length - 1);\n return { ...s, availableGameModes: action.gameModes, gameModeSelectedIndex: idx };\n }\n\n case 'SetInstalledGameModes':\n return { ...state, installedGameModes: action.gameModes };\n\n case 'SetLibraryData':\n return {\n ...state,\n availableComponents: action.components,\n availableGameModes: action.gameModes,\n installedGameModes: action.installed,\n };\n\n // ── Theme / settings ───────────────────────────────────────────────────\n case 'SetTheme':\n return { ...state, theme: action.theme };\n\n case 'ToggleAnimations':\n return { ...state, animations: !state.animations };\n\n case 'ToggleMouse':\n return { ...state, mouse: !state.mouse };\n\n // ── Result messages ────────────────────────────────────────────────────\n case 'SetProjectsDirResult':\n return {\n ...state,\n projectsDirError: action.error ?? '',\n projectsDirSuccess: action.success ?? '',\n };\n\n case 'SetLibraryPathResult':\n return {\n ...state,\n libraryPathError: action.error ?? '',\n libraryPathSuccess: action.success ?? '',\n };\n\n case 'SetSyncState':\n return {\n ...state,\n ...(action.syncing !== undefined ? { syncingLibrary: action.syncing } : {}),\n ...(action.message !== undefined ? { librarySyncMessage: action.message } : {}),\n ...(action.error !== undefined ? { librarySyncError: action.error } : {}),\n ...(action.progress !== undefined ? { librarySyncProgress: action.progress } : {}),\n };\n\n case 'SetSceneCreatorResult':\n return { ...state, sceneCreatorMessage: action.message, sceneCreatorSuccess: action.success };\n\n case 'SetComponentInstallResult':\n return { ...state, componentInstallMessage: action.message, componentInstallSuccess: action.success };\n\n case 'SetGameModeInstallResult':\n return { ...state, gameModeInstallMessage: action.message, gameModeInstallSuccess: action.success };\n\n case 'ClearSceneNameInput':\n return { ...state, sceneNameInput: '' };\n\n // ── Error popup ────────────────────────────────────────────────────────\n case 'ShowError':\n return { ...state, errorPopupVisible: true };\n\n case 'DismissError':\n return { ...state, errorPopupVisible: false };\n\n // SettingsActivate is handled as an effect in the orchestrator (it needs\n // AuthManager / library calls), so the pure reducer leaves state unchanged.\n case 'SettingsActivate':\n return state;\n\n default:\n return state;\n }\n}\n","/**\n * Pure key → intent mapping for the BBS.\n *\n * Translates a terminal-kit key name (plus current state) into either:\n * - a pure `Action` (handled by the reducer), or\n * - an `Effect` intent (a side-effecting command the orchestrator runs:\n * downloads, browser opens, spawning editors, async fetches, persistence).\n *\n * No terminal I/O, no fs, no network — entirely deterministic, so the whole\n * key-routing table is unit-testable. The original monolith interleaved state\n * mutation and effects inside one giant `switch`; here the routing is pure and\n * the effects are named, leaving execution to bbs.ts.\n */\n\nimport type { Action, BbsState, View } from './state.js';\nimport { SETTINGS_THEME_COUNT } from './state.js';\n\n/** Side-effecting commands the orchestrator must execute (kept out of the reducer). */\nexport type Effect =\n // Settings row activation (ENTER/SPACE): theme/anim/mouse/dir/lib/sync/migrate.\n | { type: 'ActivateSettings'; index: number; viaSpace: boolean }\n // Inline-edit commits + autocomplete.\n | { type: 'CommitProjectsDir' }\n | { type: 'CommitLibraryPath' }\n | { type: 'AutocompleteProjectsDir' }\n | { type: 'AutocompleteLibraryPath' }\n // Library browser ENTER actions.\n | { type: 'InstallComponent' }\n | { type: 'InstallGameMode' }\n | { type: 'CreateScene' }\n // Courses/toys/projects ENTER.\n | { type: 'OpenCourse' } // owned → detail view; unowned → browser purchase\n | { type: 'ShowToyInfo' }\n | { type: 'OpenProjectInEditor' }\n // Downloads / D key.\n | { type: 'Download' } // current item in courses/toys/downloads\n | { type: 'DevServer' } // D in projects\n | { type: 'DownloadAllMarked' } // A in downloads\n // Browser open (B).\n | { type: 'BuyInBrowser' }\n // Project lifecycle.\n | { type: 'NewProject' } // N\n | { type: 'RescanProjects' } // R\n | { type: 'InstallLibraryDeps' } // I\n // Quit / debug.\n | { type: 'Quit' }\n | { type: 'TestError' }; // E (DEBUG only)\n\nexport type Intent =\n | { kind: 'action'; action: Action }\n | { kind: 'effect'; effect: Effect };\n\nconst act = (action: Action): Intent => ({ kind: 'action', action });\nconst eff = (effect: Effect): Intent => ({ kind: 'effect', effect });\n\n/**\n * Map a key to an intent. Returns null when the key is a no-op in the current\n * context (mirrors the monolith's `break` with no work done).\n *\n * NOTE: The original handler had several *pre-switch* gates (error popup,\n * inline editing modes, scene-creator text input, course-detail input,\n * action-in-progress debounce). Those gates are honored here in the same order\n * so the routing is faithful. Debounce timing and course-detail delegation are\n * handled in the orchestrator (they need wall-clock time / the viewer), so this\n * function assumes it is only called when input should be routed normally —\n * except for the editing/error/scene-input gates, which it resolves because\n * they are pure given the key name.\n */\nexport function keyToAction(name: string, state: BbsState): Intent | null {\n const s = state;\n\n // ── Gate 0: error popup. ESC dismisses; everything else is swallowed. ──\n if (s.errorPopupVisible) {\n if (name === 'ESCAPE') return act({ type: 'DismissError' });\n return null;\n }\n\n // ── Gate 1: inline projects-directory editing. ──\n if (s.editingProjectsDir) {\n if (name === 'ESCAPE') return act({ type: 'CancelEdit' });\n if (name === 'ENTER') return eff({ type: 'CommitProjectsDir' });\n if (name === 'BACKSPACE') return act({ type: 'InputBackspace' });\n if (name === 'TAB') return eff({ type: 'AutocompleteProjectsDir' });\n if (name.length === 1) return act({ type: 'InputChar', char: name });\n return null;\n }\n\n // ── Gate 2: inline library-path editing. ──\n if (s.editingLibraryPath) {\n if (name === 'ESCAPE') return act({ type: 'CancelEdit' });\n if (name === 'ENTER') return eff({ type: 'CommitLibraryPath' });\n if (name === 'BACKSPACE') return act({ type: 'InputBackspace' });\n if (name === 'TAB') return eff({ type: 'AutocompleteLibraryPath' });\n if (name.length === 1) return act({ type: 'InputChar', char: name });\n return null;\n }\n\n // ── Gate 3: scene-creator text input. BACKSPACE + valid chars are consumed\n // here; ENTER/ESC/LEFT/RIGHT fall through to the main switch below. ──\n if (s.sceneCreatorActive && s.currentView === 'projects') {\n if (name === 'BACKSPACE') return act({ type: 'InputBackspace' });\n if (name.length === 1 && /[a-zA-Z0-9_-]/.test(name)) {\n return act({ type: 'InputChar', char: name });\n }\n // else fall through\n }\n\n // ── Main key switch ──\n switch (name) {\n case 'ESCAPE':\n return act({ type: 'Back' });\n\n case 'UP':\n case 'k':\n return act({ type: 'MoveUp' });\n\n case 'DOWN':\n case 'j':\n return act({ type: 'MoveDown' });\n\n case 'LEFT':\n return act({ type: 'MoveLeft' });\n\n case 'RIGHT':\n return act({ type: 'MoveRight' });\n\n case 'ENTER':\n return enterIntent(s);\n\n case 'd':\n case 'D':\n if (s.currentView === 'projects' && s.projects[s.projectsSelectedIndex]) {\n return eff({ type: 'DevServer' });\n }\n if (\n (s.currentView === 'courses' && s.courses[s.selectedIndex]) ||\n (s.currentView === 'toys' && s.toys[s.toysSelectedIndex]) ||\n (s.currentView === 'downloads' && s.downloads[s.downloadsSelectedIndex])\n ) {\n return eff({ type: 'Download' });\n }\n return null;\n\n case 'a':\n case 'A':\n if (s.currentView === 'downloads' && s.markedDownloads.size > 0) {\n return eff({ type: 'DownloadAllMarked' });\n }\n return null;\n\n case 'm':\n case 'M':\n case ' ':\n // Space/M mark in list views; Space additionally activates settings rows.\n if (s.currentView === 'settings') {\n return eff({ type: 'ActivateSettings', index: s.settingsSelectedIndex, viaSpace: true });\n }\n return act({ type: 'ToggleMark' });\n\n case 'n':\n case 'N':\n if (s.currentView === 'projects') return eff({ type: 'NewProject' });\n return null;\n\n case 'r':\n case 'R':\n if (s.currentView === 'projects') return eff({ type: 'RescanProjects' });\n return null;\n\n case 'i':\n case 'I':\n if (s.currentView === 'projects' && s.projects[s.projectsSelectedIndex]) {\n return eff({ type: 'InstallLibraryDeps' });\n }\n return null;\n\n case 'b':\n case 'B':\n if (\n (s.currentView === 'courses' && s.courses[s.selectedIndex]) ||\n (s.currentView === 'toys' && s.toys[s.toysSelectedIndex])\n ) {\n return eff({ type: 'BuyInBrowser' });\n }\n // Debounce still applies in the orchestrator, but with nothing to open\n // the monolith just consumed the key. Returning the effect is harmless\n // since the effect re-checks; preserve original by returning null.\n return null;\n\n case 'c':\n case 'C':\n if (s.currentView === 'projects' && s.projects[s.projectsSelectedIndex]) {\n return act({ type: 'ToggleComponentBrowser' });\n }\n if (s.currentView !== 'courses') {\n return act({ type: 'ChangeView', view: 'courses' });\n }\n return null;\n\n case 'g':\n case 'G':\n if (s.currentView === 'projects' && s.projects[s.projectsSelectedIndex]) {\n return act({ type: 'ToggleGameModeBrowser' });\n }\n return null;\n\n case '+':\n case '=':\n if (s.currentView === 'projects' && s.projects[s.projectsSelectedIndex]) {\n return act({ type: 'ToggleSceneCreator' });\n }\n return null;\n\n case 't':\n case 'T':\n if (s.currentView !== 'toys') return act({ type: 'ChangeView', view: 'toys' });\n return null;\n\n case 'p':\n case 'P':\n if (s.currentView !== 'projects') return act({ type: 'ChangeView', view: 'projects' });\n return null;\n\n case 'f':\n case 'F':\n if (s.currentView !== 'downloads') return act({ type: 'ChangeView', view: 'downloads' });\n return null;\n\n case 's':\n case 'S':\n if (s.currentView !== 'settings') return act({ type: 'ChangeView', view: 'settings' });\n return null;\n\n case 'e':\n case 'E':\n if (process.env.DEBUG) return eff({ type: 'TestError' });\n return null;\n\n case 'q':\n case 'Q':\n case 'CTRL_C':\n return eff({ type: 'Quit' });\n\n default:\n return null;\n }\n}\n\n/** ENTER routing — depends on view + active sub-panel. */\nfunction enterIntent(s: BbsState): Intent | null {\n if (s.currentView === 'projects' && s.componentBrowserActive) {\n return eff({ type: 'InstallComponent' });\n }\n if (s.currentView === 'projects' && s.gameModeBrowserActive) {\n return eff({ type: 'InstallGameMode' });\n }\n if (s.currentView === 'projects' && s.sceneCreatorActive) {\n return eff({ type: 'CreateScene' });\n }\n if (s.currentView === 'settings') {\n return eff({ type: 'ActivateSettings', index: s.settingsSelectedIndex, viaSpace: false });\n }\n if (s.currentView === 'courses' && s.courses[s.selectedIndex]) {\n return eff({ type: 'OpenCourse' });\n }\n if (s.currentView === 'toys' && s.toys[s.toysSelectedIndex]) {\n return eff({ type: 'ShowToyInfo' });\n }\n if (s.currentView === 'projects' && s.projects[s.projectsSelectedIndex]) {\n return eff({ type: 'OpenProjectInEditor' });\n }\n return null;\n}\n\n/** Whether a settings index toggles a theme (0..5) vs another row. */\nexport function isThemeIndex(index: number): boolean {\n return index < SETTINGS_THEME_COUNT;\n}\n","/**\n * Pure formatting helpers for the BBS — string/data transforms with no terminal\n * I/O, so they're unit-testable in isolation. Extracted from the bbs.ts monolith\n * as the first step toward a renderer-agnostic BBS core.\n */\n\n/** Relative time label, e.g. \"just now\", \"5m ago\", \"3h ago\", \"2d ago\", or a date. */\nexport function getTimeAgo(date: Date, now: number = Date.now()): string {\n const seconds = Math.floor((now - date.getTime()) / 1000)\n if (seconds < 60) return 'just now'\n if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`\n if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`\n if (seconds < 604800) return `${Math.floor(seconds / 86400)}d ago`\n return date.toLocaleDateString()\n}\n\nexport interface CourseStatusInput {\n isOwned?: boolean\n /** Completion percentage (0–100) for owned courses. */\n progress?: number\n /** Display price for unowned courses, e.g. \"$29.99\". */\n price?: string\n}\n\nexport interface CourseStatus {\n status: 'IN PROGRESS' | 'OWNED' | 'AVAILABLE'\n /** Progress % for owned courses, price for unowned. */\n value: string\n}\n\n/** Ownership/status label + value column for a course row. */\nexport function courseStatus(course: CourseStatusInput): CourseStatus {\n if (course.isOwned) {\n if (course.progress && course.progress > 0) {\n return { status: 'IN PROGRESS', value: `${course.progress}%` }\n }\n return { status: 'OWNED', value: '0%' }\n }\n return { status: 'AVAILABLE', value: course.price || '$29.99' }\n}\n\n/** Truncate a title to `max` chars, with an ellipsis when clipped. */\nexport function truncateTitle(title: string, max = 40): string {\n return title.length > max ? `${title.substring(0, max - 3)}...` : title\n}\n","/**\n * Pure layout/scroll math for the BBS list views — no terminal I/O. Extracted\n * from the repeated windowing logic in bbs.ts (courses, projects, components,\n * game-modes all used the same `Math.max(0, selected - maxVisible + 1)` slice).\n */\n\nexport interface RowWindow<T> {\n /** Index of the first visible row within `rows`. */\n offset: number\n /** The slice of rows currently on screen. */\n visible: T[]\n /** True if there are rows scrolled off the top (show a ↑ indicator). */\n hasAbove: boolean\n /** True if there are rows scrolled off the bottom (show a ↓ indicator). */\n hasBelow: boolean\n}\n\n/**\n * Window a list to `maxVisible` rows, keeping `selectedIndex` in view by pinning\n * it to the bottom of the window once it scrolls past the fold (preserves the\n * original BBS behavior). `selectedIndex` within the window is `selected - offset`.\n */\nexport function windowRows<T>(rows: T[], selectedIndex: number, maxVisible: number): RowWindow<T> {\n const offset = Math.max(0, selectedIndex - maxVisible + 1)\n const visible = rows.slice(offset, offset + maxVisible)\n return {\n offset,\n visible,\n hasAbove: offset > 0,\n hasBelow: offset + maxVisible < rows.length,\n }\n}\n","/**\n * Pure view-model selectors for the BBS.\n *\n * Each `build*` turns `(state, { width, height })` into a plain-data render\n * model — rows, columns, cursor index, marked flags, scroll indicators, status\n * lines — with no terminal coupling. The terminal renderer (render.ts) consumes\n * these; tests assert on them directly (no TTY needed).\n *\n * Reuses the already-tested pure utils:\n * - getTimeAgo / courseStatus / truncateTitle from ./format\n * - windowRows from ./layout\n */\n\nimport type { BbsState, Course, Download, ProjectLike } from './state.js';\nimport { courseStatus, truncateTitle, getTimeAgo } from './format.js';\nimport { windowRows } from './layout.js';\n\nexport interface Dimensions {\n width: number;\n height: number;\n}\n\n// ── Home ─────────────────────────────────────────────────────────────────────\n\nexport interface MenuItem {\n key: string;\n label: string;\n desc: string;\n}\n\nexport interface HomeModel {\n view: 'home';\n items: MenuItem[];\n /** Centered menu box geometry. */\n box: { x: number; y: number; width: number; height: number };\n}\n\nconst HOME_ITEMS: MenuItem[] = [\n { key: 'C', label: 'Courses', desc: 'Browse available courses' },\n { key: 'T', label: 'Toys', desc: '3D models and assets' },\n { key: 'P', label: 'Projects', desc: 'Manage game projects' },\n { key: 'F', label: 'Files', desc: 'Course downloads' },\n { key: 'S', label: 'Settings', desc: 'Configure BBS' },\n { key: 'Q', label: 'Quit', desc: 'Disconnect from BBS' },\n];\n\nexport function buildHome(_state: BbsState, dim: Dimensions): HomeModel {\n const width = 50;\n const height = 14;\n return {\n view: 'home',\n items: HOME_ITEMS,\n box: {\n x: Math.floor((dim.width - width) / 2),\n y: Math.floor((dim.height - height) / 2),\n width,\n height,\n },\n };\n}\n\n// ── Courses ──────────────────────────────────────────────────────────────────\n\nexport interface CourseRow {\n num: string;\n title: string;\n status: string;\n value: string;\n}\n\nexport interface CoursesModel {\n view: 'courses';\n rows: CourseRow[];\n /** Cursor index *within the visible window*. */\n cursor: number;\n hasAbove: boolean;\n hasBelow: boolean;\n tableWidth: number;\n titleWidth: number;\n /** Y of the scroll-down indicator (relative to content top). */\n maxVisibleRows: number;\n}\n\nexport function buildCourses(state: BbsState, dim: Dimensions): CoursesModel {\n const titleWidth = Math.min(45, dim.width - 35);\n const allRows: CourseRow[] = state.courses.map((course: Course, index) => {\n const { status, value } = courseStatus(course);\n return {\n num: state.markedCourses.has(index) ? `[${index + 1}]` : ` ${index + 1} `,\n title: truncateTitle(course.title, 40),\n status,\n value,\n };\n });\n\n const maxVisibleRows = Math.min(dim.height - 15, 20);\n const win = windowRows(allRows, state.selectedIndex, maxVisibleRows);\n const tableWidth = 5 + titleWidth + 12 + 14 + 8;\n\n return {\n view: 'courses',\n rows: win.visible,\n cursor: state.selectedIndex - win.offset,\n hasAbove: win.hasAbove,\n hasBelow: win.hasBelow,\n tableWidth,\n titleWidth,\n maxVisibleRows,\n };\n}\n\n// ── Toys ─────────────────────────────────────────────────────────────────────\n\nexport interface ToyRow {\n num: string;\n name: string;\n size: string;\n downloads: number;\n type: string;\n format: string;\n}\n\nexport interface ToysModel {\n view: 'toys';\n rows: ToyRow[];\n cursor: number;\n tableWidth: number;\n}\n\nexport function buildToys(state: BbsState, dim: Dimensions): ToysModel {\n const rows: ToyRow[] = state.toys.map((toy, index) => ({\n num: state.markedToys.has(index) ? `[${index + 1}]` : ` ${index + 1} `,\n name: toy.name,\n size: toy.size,\n downloads: toy.downloads,\n type: toy.modeltype,\n format: toy.filetype,\n }));\n return {\n view: 'toys',\n rows,\n cursor: state.toysSelectedIndex,\n tableWidth: dim.width - 2,\n };\n}\n\n// ── Downloads ──────────────────────────────────────────────────────────────\n\nexport interface DownloadRow {\n num: string;\n fileName: string;\n product: string;\n size: string;\n type: string;\n downloads: number;\n lastDL: string;\n}\n\nexport interface DownloadsModel {\n view: 'downloads';\n empty: boolean;\n rows: DownloadRow[];\n cursor: number;\n hasAbove: boolean;\n hasBelow: boolean;\n tableWidth: number;\n scrollIndicatorX: number;\n maxVisibleRows: number;\n}\n\nexport function buildDownloads(state: BbsState, dim: Dimensions): DownloadsModel {\n if (state.downloads.length === 0) {\n return {\n view: 'downloads',\n empty: true,\n rows: [],\n cursor: 0,\n hasAbove: false,\n hasBelow: false,\n tableWidth: 0,\n scrollIndicatorX: 0,\n maxVisibleRows: 0,\n };\n }\n\n const allRows: DownloadRow[] = state.downloads.map((download: Download, index) => ({\n num: state.markedDownloads.has(index) ? `[${index + 1}]` : ` ${index + 1} `,\n fileName: download.fileName.length > 30 ? download.fileName.substring(0, 27) + '...' : download.fileName,\n product: download.productTitle.length > 25 ? download.productTitle.substring(0, 22) + '...' : download.productTitle,\n size: download.fileSize,\n type: download.fileType,\n downloads: download.totalDownloads,\n lastDL: download.lastDownloaded ? new Date(download.lastDownloaded).toLocaleDateString() : 'Never',\n }));\n\n const maxVisibleRows = Math.min(dim.height - 15, 20);\n const win = windowRows(allRows, state.downloadsSelectedIndex, maxVisibleRows);\n\n return {\n view: 'downloads',\n empty: false,\n rows: win.visible,\n cursor: state.downloadsSelectedIndex - win.offset,\n hasAbove: win.hasAbove,\n hasBelow: win.hasBelow,\n tableWidth: Math.min(dim.width - 2, 110),\n scrollIndicatorX: Math.min(dim.width - 2, 112),\n maxVisibleRows,\n };\n}\n\n// ── Projects ─────────────────────────────────────────────────────────────────\n\nexport interface ProjectListRow {\n name: string;\n selected: boolean;\n}\n\nexport interface ProjectsModel {\n view: 'projects';\n empty: boolean;\n /** When empty: whether a projects dir is configured (drives the message). */\n hasProjectsDir?: boolean;\n projectsDir?: string;\n // Non-empty:\n listRows?: ProjectListRow[];\n listHasAbove?: boolean;\n listHasBelow?: boolean;\n selected?: ProjectLike;\n /** Which library sub-panel (if any) is active. */\n panel?: 'components' | 'gameModes' | 'sceneCreator' | 'default';\n}\n\n/**\n * `projectsDir` is supplied by the orchestrator (it comes from AuthManager,\n * which is not pure). Selectors stay pure by taking it as input.\n */\nexport function buildProjects(\n state: BbsState,\n dim: Dimensions,\n ctx: { projectsDir?: string },\n): ProjectsModel {\n if (state.projects.length === 0) {\n return {\n view: 'projects',\n empty: true,\n hasProjectsDir: !!ctx.projectsDir,\n projectsDir: ctx.projectsDir,\n };\n }\n\n const listWidth = 32;\n const detailX = listWidth + 4;\n const detailWidth = Math.min(dim.width - detailX - 2, 50);\n const panelHeight = Math.min(dim.height - 6 - 6, 18);\n const maxVisibleProjects = panelHeight - 2;\n\n const win = windowRows(state.projects, state.projectsSelectedIndex, maxVisibleProjects);\n const listRows: ProjectListRow[] = win.visible.map((p, i) => ({\n name: p.name,\n selected: i + win.offset === state.projectsSelectedIndex,\n }));\n\n let panel: ProjectsModel['panel'] = 'default';\n if (state.componentBrowserActive) panel = 'components';\n else if (state.gameModeBrowserActive) panel = 'gameModes';\n else if (state.sceneCreatorActive) panel = 'sceneCreator';\n\n return {\n view: 'projects',\n empty: false,\n listRows,\n listHasAbove: win.hasAbove,\n listHasBelow: win.hasBelow,\n selected: state.projects[state.projectsSelectedIndex],\n panel,\n };\n}\n\n// ── Settings ─────────────────────────────────────────────────────────────────\n\nexport interface SettingsModel {\n view: 'settings';\n themes: string[];\n /** Selected settings list index (0..5 themes, 6 anim, 7 mouse, …). */\n cursor: number;\n currentTheme: string;\n animations: boolean;\n mouse: boolean;\n // Projects dir\n editingProjectsDir: boolean;\n projectsDirInput: string;\n projectsDirError: string;\n projectsDirSuccess: string;\n projectsDirDisplay: string; // current saved value (from ctx)\n // Library path\n editingLibraryPath: boolean;\n libraryPathInput: string;\n libraryPathError: string;\n libraryPathSuccess: string;\n libraryPathDisplay: string;\n libraryInitialized: boolean;\n // Sync\n syncingLibrary: boolean;\n librarySyncMessage: string;\n librarySyncError: string;\n librarySyncProgress: string;\n lastSyncLabel: string; // e.g. \"Last sync: 5m ago\" / \"Never synced\"\n}\n\n/**\n * Pulls auth/library facts from `ctx` so the selector stays pure. `lastSyncAt`\n * is a Date | null; when present the label uses the (pure) getTimeAgo helper.\n */\nexport function buildSettings(\n state: BbsState,\n ctx: {\n projectsDir?: string;\n libraryPath: string;\n libraryInitialized: boolean;\n lastSyncAt: Date | null;\n now?: number;\n },\n): SettingsModel {\n const projectsDirSaved = ctx.projectsDir || 'Not set';\n const lastSyncLabel = ctx.lastSyncAt\n ? `Last sync: ${getTimeAgo(ctx.lastSyncAt, ctx.now)}`\n : 'Never synced';\n\n return {\n view: 'settings',\n themes: ['classic', 'desert', 'matrix', 'commando', 'sandiego', 'ed209'],\n cursor: state.settingsSelectedIndex,\n currentTheme: state.theme,\n animations: state.animations,\n mouse: state.mouse,\n\n editingProjectsDir: state.editingProjectsDir,\n projectsDirInput: state.projectsDirInput,\n projectsDirError: state.projectsDirError,\n projectsDirSuccess: state.projectsDirSuccess,\n projectsDirDisplay: projectsDirSaved,\n\n editingLibraryPath: state.editingLibraryPath,\n libraryPathInput: state.libraryPathInput,\n libraryPathError: state.libraryPathError,\n libraryPathSuccess: state.libraryPathSuccess,\n libraryPathDisplay: ctx.libraryPath,\n libraryInitialized: ctx.libraryInitialized,\n\n syncingLibrary: state.syncingLibrary,\n librarySyncMessage: state.librarySyncMessage,\n librarySyncError: state.librarySyncError,\n librarySyncProgress: state.librarySyncProgress,\n lastSyncLabel,\n };\n}\n\n// ── Header / footer status ───────────────────────────────────────────────────\n\n/** Count of marked items for the current view (drives the header badge). */\nexport function markedCount(state: BbsState): number {\n switch (state.currentView) {\n case 'courses':\n return state.markedCourses.size;\n case 'toys':\n return state.markedToys.size;\n case 'downloads':\n return state.markedDownloads.size;\n case 'projects':\n return state.markedProjects.size;\n default:\n return 0;\n }\n}\n\n/** Navigation footer text per view (verbatim from the monolith). */\nexport function navFooter(state: BbsState): string {\n switch (state.currentView) {\n case 'home':\n return '[C]ourses [T]oys [P]rojects [F]iles [S]ettings [Q]uit';\n case 'courses':\n return '[↑↓] Navigate [Enter] View Details [D]ownload [M]ark [B]uy [Space] Select [ESC] Back [Q]uit';\n case 'toys':\n return '[↑↓] Navigate [Enter] View [D]ownload [M]ark [B]uy [Space] Select [ESC] Back [Q]uit';\n case 'projects':\n return '[↑↓] Navigate [N] New Project [I] Install Lib [Enter] Manage [ESC] Back [Q]uit';\n case 'downloads':\n return '[↑↓] Navigate [D]ownload [M]ark [A]ll Downloads [Space] Select [ESC] Back [Q]uit';\n case 'settings':\n return '[↑↓] Navigate [Enter] Toggle [Space] Select [ESC] Back [Q]uit';\n default:\n return '';\n }\n}\n","/**\n * Thin terminal-kit renderer for the BBS.\n *\n * Takes pre-computed view models (from viewmodel.ts) plus the BufferedBBS draw\n * surface and draws them. This is the ONLY terminal-coupled view code; all\n * layout math + data shaping lives in the pure selectors. The per-view draw\n * branches are ported verbatim from the bbs.ts monolith to preserve pixel\n * behavior.\n *\n * Some panels (the projects library browser, settings input fields) read\n * derived data that the model intentionally leaves to state, so this module\n * receives `state` alongside the models — but it never *mutates* state.\n */\n\nimport type { BufferedBBS } from '../../utils/buffered-bbs.js';\nimport type { BbsState } from './state.js';\nimport {\n type Dimensions,\n type HomeModel,\n type CoursesModel,\n type ToysModel,\n type DownloadsModel,\n type ProjectsModel,\n type SettingsModel,\n navFooter,\n} from './viewmodel.js';\n\n/** Context the projects/settings panels need from the (impure) AuthManager etc. */\nexport interface RenderContext {\n componentCatalogLength: number;\n gameModeCatalogLength: number;\n /** Scenes in the selected project (from getProjectScenes). */\n projectScenesCount: number;\n /** Sync comparison summary for the settings panel. */\n syncUpdates?: number;\n serverManifest?: { unlockedFiles: number; totalFiles: number } | null;\n}\n\nconst CONTENT_Y = 6;\n\nexport function renderHome(bbs: BufferedBBS, model: HomeModel): void {\n const { box, items } = model;\n bbs.drawBox(box.x, box.y, box.width, box.height, 'MAIN MENU');\n items.forEach((item, i) => {\n const y = box.y + 3 + i * 2;\n bbs.put(box.x + 4, y, `[${item.key}]`, bbs.getTheme().accent, true);\n bbs.put(box.x + 8, y, item.label, 'white', true);\n bbs.put(box.x + 20, y, item.desc, bbs.getTheme().dim);\n });\n}\n\nexport function renderCourses(bbs: BufferedBBS, model: CoursesModel): void {\n bbs.drawTable(2, CONTENT_Y, {\n data: model.rows,\n columns: [\n { key: 'num', label: ' # ', width: 5 },\n { key: 'title', label: 'Course Title', width: model.titleWidth },\n { key: 'status', label: 'Status', width: 12 },\n { key: 'value', label: 'Progress/Price', width: 14 },\n ],\n selectedIndex: model.cursor,\n width: model.tableWidth,\n });\n\n if (model.hasAbove) {\n bbs.put(model.tableWidth + 1, CONTENT_Y, '↑', bbs.getTheme().accent);\n }\n if (model.hasBelow) {\n bbs.put(model.tableWidth + 1, CONTENT_Y + model.maxVisibleRows + 1, '↓', bbs.getTheme().accent);\n }\n}\n\nexport function renderToys(bbs: BufferedBBS, model: ToysModel): void {\n bbs.drawTable(2, CONTENT_Y, {\n data: model.rows,\n columns: [\n { key: 'num', label: ' # ', width: 5 },\n { key: 'name', label: 'Name' },\n { key: 'size', label: 'Size', width: 10 },\n { key: 'downloads', label: 'DLs', width: 8 },\n { key: 'type', label: 'Type', width: 10 },\n { key: 'format', label: 'Format', width: 8 },\n ],\n selectedIndex: model.cursor,\n width: model.tableWidth,\n });\n}\n\nexport function renderDownloads(bbs: BufferedBBS, model: DownloadsModel, dim: Dimensions): void {\n if (model.empty) {\n bbs.drawBox(Math.floor((dim.width - 50) / 2), CONTENT_Y + 2, 50, 5, 'NO DOWNLOADS');\n const msgX = Math.floor((dim.width - 40) / 2);\n bbs.put(msgX, CONTENT_Y + 4, 'No course downloads available yet.', bbs.getTheme().dim);\n return;\n }\n\n bbs.drawTable(2, CONTENT_Y, {\n data: model.rows,\n columns: [\n { key: 'num', label: ' # ', width: 5 },\n { key: 'fileName', label: 'File Name', width: 30 },\n { key: 'product', label: 'Course', width: 25 },\n { key: 'size', label: 'Size', width: 10 },\n { key: 'type', label: 'Type', width: 6 },\n { key: 'downloads', label: 'DLs', width: 5 },\n { key: 'lastDL', label: 'Last Downloaded', width: 15 },\n ],\n selectedIndex: model.cursor,\n width: model.tableWidth,\n });\n\n if (model.hasAbove) {\n bbs.put(model.scrollIndicatorX, CONTENT_Y, '↑', bbs.getTheme().accent);\n }\n if (model.hasBelow) {\n bbs.put(model.scrollIndicatorX, CONTENT_Y + model.maxVisibleRows + 1, '↓', bbs.getTheme().accent);\n }\n}\n\nexport function renderProjects(\n bbs: BufferedBBS,\n model: ProjectsModel,\n state: BbsState,\n dim: Dimensions,\n ctx: RenderContext,\n): void {\n if (model.empty) {\n bbs.drawBox(Math.floor((dim.width - 60) / 2), CONTENT_Y + 2, 60, 11, 'NO PROJECTS FOUND');\n const msgX = Math.floor((dim.width - 55) / 2);\n if (!model.hasProjectsDir) {\n bbs.put(msgX, CONTENT_Y + 4, 'Projects directory not configured.', bbs.getTheme().dim);\n bbs.put(msgX, CONTENT_Y + 6, 'Press [S] to go to Settings and set your', bbs.getTheme().primary);\n bbs.put(msgX, CONTENT_Y + 7, 'projects directory.', bbs.getTheme().primary);\n } else {\n const projDir = model.projectsDir as string;\n bbs.put(msgX, CONTENT_Y + 4, 'No game projects found in:', bbs.getTheme().dim);\n bbs.put(msgX, CONTENT_Y + 5, projDir.length > 54 ? '...' + projDir.slice(-51) : projDir, 'yellow');\n bbs.put(msgX, CONTENT_Y + 7, 'Press [N] to create a new project', bbs.getTheme().primary);\n bbs.put(msgX, CONTENT_Y + 8, 'or [S] to change the projects directory', bbs.getTheme().dim);\n }\n return;\n }\n\n const listWidth = 32;\n const detailX = listWidth + 4;\n const detailWidth = Math.min(dim.width - detailX - 2, 50);\n const panelHeight = Math.min(dim.height - CONTENT_Y - 6, 18);\n const maxVisibleProjects = panelHeight - 2;\n const scrollOffset = Math.max(0, state.projectsSelectedIndex - maxVisibleProjects + 1);\n\n // Project list box\n bbs.drawBox(1, CONTENT_Y, listWidth, panelHeight, 'PROJECTS');\n for (let i = 0; i < maxVisibleProjects && i + scrollOffset < state.projects.length; i++) {\n const idx = i + scrollOffset;\n const project = state.projects[idx];\n const isSelected = idx === state.projectsSelectedIndex;\n const y = CONTENT_Y + 1 + i;\n if (isSelected) bbs.put(2, y, '▶', bbs.getTheme().accent);\n const displayName =\n project.name.length > listWidth - 6 ? project.name.substring(0, listWidth - 9) + '...' : project.name;\n bbs.put(4, y, displayName, isSelected ? bbs.getTheme().accent : 'white', isSelected);\n }\n if (scrollOffset > 0) bbs.put(listWidth - 1, CONTENT_Y, '↑', bbs.getTheme().accent);\n if (scrollOffset + maxVisibleProjects < state.projects.length) {\n bbs.put(listWidth - 1, CONTENT_Y + panelHeight - 1, '↓', bbs.getTheme().accent);\n }\n\n // Detail panel\n const selectedProject = state.projects[state.projectsSelectedIndex];\n if (selectedProject) {\n bbs.drawBox(detailX, CONTENT_Y, detailWidth, panelHeight, 'DETAILS');\n let detailY = CONTENT_Y + 1;\n const labelColor = bbs.getTheme().dim;\n const valueColor = bbs.getTheme().primary;\n\n bbs.put(detailX + 2, detailY, 'Name:', labelColor);\n bbs.put(detailX + 8, detailY, selectedProject.name.substring(0, detailWidth - 10), valueColor);\n detailY += 2;\n\n bbs.put(detailX + 2, detailY, 'Engine:', labelColor);\n const engineColor =\n selectedProject.engine === 'BabylonJS' ? 'cyan' : selectedProject.engine === 'ThreeJS' ? 'green' : 'gray';\n bbs.put(detailX + 10, detailY, selectedProject.engine, engineColor);\n detailY += 1;\n\n bbs.put(detailX + 2, detailY, 'Genre:', labelColor);\n bbs.put(detailX + 10, detailY, selectedProject.genre, 'yellow');\n detailY += 2;\n\n bbs.put(detailX + 2, detailY, 'Components:', labelColor);\n detailY += 1;\n\n const maxComponents = panelHeight - 9;\n if (selectedProject.components.length === 0) {\n bbs.put(detailX + 4, detailY, '(none found)', bbs.getTheme().dim);\n } else {\n for (let i = 0; i < Math.min(selectedProject.components.length, maxComponents); i++) {\n const comp = selectedProject.components[i];\n const displayComp = comp.length > detailWidth - 8 ? comp.substring(0, detailWidth - 11) + '...' : comp;\n bbs.put(detailX + 4, detailY + i, '• ' + displayComp, 'white');\n }\n if (selectedProject.components.length > maxComponents) {\n bbs.put(\n detailX + 4,\n detailY + maxComponents,\n `+${selectedProject.components.length - maxComponents} more...`,\n bbs.getTheme().dim,\n );\n }\n }\n }\n\n // Library panel\n const libraryY = CONTENT_Y + panelHeight + 1;\n const libraryPanelHeight = Math.min(dim.height - libraryY - 4, 10);\n const fullWidth = Math.min(dim.width - 2, listWidth + detailWidth + 4);\n\n if (libraryPanelHeight >= 5) {\n let panelTitle: string;\n if (state.componentBrowserActive) {\n panelTitle = '► COMPONENTS [C] Game Modes [G] New Scene [+]';\n } else if (state.gameModeBrowserActive) {\n panelTitle = 'Components [C] ► GAME MODES [G] New Scene [+]';\n } else if (state.sceneCreatorActive) {\n panelTitle = 'Components [C] Game Modes [G] ► NEW SCENE [+]';\n } else {\n panelTitle = '[C] Components [G] Game Modes [+] New Scene';\n }\n bbs.drawBox(1, libraryY, fullWidth, libraryPanelHeight, panelTitle);\n\n if (state.componentBrowserActive) {\n if (state.availableComponents.length > 0) {\n const compListWidth = 28;\n const compDescX = compListWidth + 2;\n const maxVisibleComps = libraryPanelHeight - 2;\n const compScrollOffset = Math.max(0, state.componentSelectedIndex - maxVisibleComps + 1);\n\n for (let i = 0; i < maxVisibleComps && i + compScrollOffset < state.availableComponents.length; i++) {\n const idx = i + compScrollOffset;\n const comp = state.availableComponents[idx];\n const isSelected = idx === state.componentSelectedIndex;\n const y = libraryY + 1 + i;\n if (isSelected) bbs.put(2, y, '▶', bbs.getTheme().accent);\n const displayName =\n comp.name.length > compListWidth - 4 ? comp.name.substring(0, compListWidth - 7) + '...' : comp.name;\n bbs.put(4, y, displayName, isSelected ? bbs.getTheme().accent : 'white', isSelected);\n }\n\n if (state.availableComponents[state.componentSelectedIndex]) {\n const comp = state.availableComponents[state.componentSelectedIndex];\n const descWidth = fullWidth - compDescX - 2;\n bbs.put(compDescX, libraryY + 1, comp.category, 'cyan');\n bbs.put(compDescX, libraryY + 2, comp.description.substring(0, descWidth), bbs.getTheme().primary);\n if (comp.hasDataFile) bbs.put(compDescX, libraryY + 3, '+ Includes data definition', 'green');\n if (state.componentInstallMessage) {\n bbs.put(\n compDescX,\n libraryY + libraryPanelHeight - 2,\n state.componentInstallMessage,\n state.componentInstallSuccess ? 'green' : 'red',\n );\n } else {\n bbs.put(compDescX, libraryY + libraryPanelHeight - 2, 'ENTER to install', bbs.getTheme().dim);\n }\n }\n\n if (compScrollOffset > 0) bbs.put(compListWidth - 1, libraryY, '↑', bbs.getTheme().accent);\n if (compScrollOffset + maxVisibleComps < state.availableComponents.length) {\n bbs.put(compListWidth - 1, libraryY + libraryPanelHeight - 1, '↓', bbs.getTheme().accent);\n }\n } else {\n bbs.put(3, libraryY + 1, 'All components already installed!', 'green');\n }\n } else if (state.gameModeBrowserActive) {\n if (state.availableGameModes.length > 0) {\n const modeListWidth = 20;\n const modeDescX = modeListWidth + 2;\n const maxVisibleModes = libraryPanelHeight - 2;\n const modeScrollOffset = Math.max(0, state.gameModeSelectedIndex - maxVisibleModes + 1);\n\n for (let i = 0; i < maxVisibleModes && i + modeScrollOffset < state.availableGameModes.length; i++) {\n const idx = i + modeScrollOffset;\n const mode = state.availableGameModes[idx];\n const isSelected = idx === state.gameModeSelectedIndex;\n const y = libraryY + 1 + i;\n if (isSelected) bbs.put(2, y, '▶', bbs.getTheme().accent);\n bbs.put(4, y, mode.name, isSelected ? bbs.getTheme().accent : 'white', isSelected);\n }\n\n if (state.availableGameModes[state.gameModeSelectedIndex]) {\n const mode = state.availableGameModes[state.gameModeSelectedIndex];\n const descWidth = fullWidth - modeDescX - 2;\n bbs.put(modeDescX, libraryY + 1, mode.description.substring(0, descWidth), bbs.getTheme().primary);\n const includes: string[] = [];\n if (mode.hasScenes) includes.push('Scenes');\n if (mode.hasScreens) includes.push('Screens');\n if (mode.hasShared) includes.push('Shared');\n if (includes.length > 0) {\n bbs.put(modeDescX, libraryY + 2, 'Includes: ' + includes.join(', '), 'cyan');\n }\n if (state.gameModeInstallMessage) {\n bbs.put(\n modeDescX,\n libraryY + libraryPanelHeight - 2,\n state.gameModeInstallMessage,\n state.gameModeInstallSuccess ? 'green' : 'red',\n );\n } else {\n bbs.put(modeDescX, libraryY + libraryPanelHeight - 2, 'ENTER to install data directory', bbs.getTheme().dim);\n }\n }\n } else {\n bbs.put(3, libraryY + 1, 'All game modes already installed!', 'green');\n if (state.installedGameModes.length > 0) {\n bbs.put(3, libraryY + 2, 'Installed: ' + state.installedGameModes.join(', '), 'cyan');\n }\n }\n } else if (state.sceneCreatorActive) {\n if (state.installedGameModes.length === 0) {\n bbs.put(3, libraryY + 1, 'No game modes installed!', 'red');\n bbs.put(3, libraryY + 2, 'Press [G] to install a game mode first', bbs.getTheme().dim);\n } else {\n bbs.put(3, libraryY + 1, 'Game Mode:', bbs.getTheme().dim);\n const selectedMode = state.installedGameModes[state.sceneGameModeIndex] || state.installedGameModes[0];\n bbs.put(14, libraryY + 1, `◄ ${selectedMode} ►`, 'cyan');\n bbs.put(14 + selectedMode.length + 5, libraryY + 1, '(←/→ to change)', bbs.getTheme().dim);\n\n bbs.put(3, libraryY + 3, 'Scene Name:', bbs.getTheme().dim);\n const cursorVisible = Math.floor(Date.now() / 500) % 2 === 0;\n const inputDisplay = state.sceneNameInput + (cursorVisible ? '▌' : ' ');\n bbs.put(15, libraryY + 3, inputDisplay, 'cyan');\n\n if (state.sceneCreatorMessage) {\n bbs.put(\n 3,\n libraryY + libraryPanelHeight - 2,\n state.sceneCreatorMessage,\n state.sceneCreatorSuccess ? 'green' : 'red',\n );\n } else {\n bbs.put(3, libraryY + libraryPanelHeight - 2, 'Type scene name, ENTER to create', bbs.getTheme().dim);\n }\n }\n } else {\n bbs.put(\n 3,\n libraryY + 1,\n `${ctx.componentCatalogLength} components • ${ctx.gameModeCatalogLength} game modes`,\n bbs.getTheme().dim,\n );\n bbs.put(3, libraryY + 2, `${ctx.projectScenesCount} scenes in this project`, bbs.getTheme().dim);\n bbs.put(3, libraryY + 4, '[C] Components [G] Game Modes [+] New Scene', bbs.getTheme().primary);\n }\n }\n\n // Helpful footer\n const helpY = libraryY + libraryPanelHeight + 1;\n let helpText = '[N] New [I] Install [ENTER] Editor [D] Dev [R] Rescan';\n if (state.componentBrowserActive || state.gameModeBrowserActive) {\n helpText = '[↑↓] Select [ENTER] Install [ESC] Close [C/G/+] Switch';\n } else if (state.sceneCreatorActive) {\n helpText = '[←→] Mode [ENTER] Create [ESC] Close [C/G] Switch';\n }\n bbs.put(2, helpY, helpText, bbs.getTheme().dim);\n}\n\nexport function renderSettings(\n bbs: BufferedBBS,\n model: SettingsModel,\n dim: Dimensions,\n ctx: RenderContext,\n): void {\n const settingsWidth = 70;\n const settingsX = Math.floor((dim.width - settingsWidth) / 2);\n\n bbs.drawBox(settingsX, CONTENT_Y, settingsWidth, 22, 'SETTINGS');\n\n bbs.put(settingsX + 2, CONTENT_Y + 2, 'Theme:', bbs.getTheme().primary, true);\n model.themes.forEach((t, i) => {\n const y = CONTENT_Y + 3 + i;\n const isSelected = model.cursor === i;\n const isCurrent = model.currentTheme === t;\n if (isSelected) bbs.put(settingsX + 4, y, '▶', bbs.getTheme().accent);\n bbs.put(\n settingsX + 6,\n y,\n t.charAt(0).toUpperCase() + t.slice(1),\n isCurrent ? bbs.getTheme().accent : 'white',\n isCurrent,\n );\n });\n\n // Animations (6)\n const animY = CONTENT_Y + 10;\n if (model.cursor === 6) bbs.put(settingsX + 4, animY, '▶', bbs.getTheme().accent);\n bbs.put(settingsX + 6, animY, `Animations: ${model.animations ? 'ON' : 'OFF'}`, model.animations ? 'green' : 'red');\n\n // Mouse (7)\n const mouseY = CONTENT_Y + 12;\n if (model.cursor === 7) bbs.put(settingsX + 4, mouseY, '▶', bbs.getTheme().accent);\n bbs.put(settingsX + 6, mouseY, `Mouse: ${model.mouse ? 'ON' : 'OFF'}`, model.mouse ? 'green' : 'red');\n\n // Projects dir (8)\n const projectsDirY = CONTENT_Y + 14;\n if (model.cursor === 8) bbs.put(settingsX + 4, projectsDirY, '▶', bbs.getTheme().accent);\n bbs.put(settingsX + 6, projectsDirY, 'Projects Directory:', bbs.getTheme().primary);\n\n if (model.editingProjectsDir) {\n const inputWidth = settingsWidth - 10;\n const inputLine =\n model.projectsDirInput.length > inputWidth - 2\n ? '...' + model.projectsDirInput.slice(-(inputWidth - 5))\n : model.projectsDirInput;\n const cursorVisible = Math.floor(Date.now() / 500) % 2 === 0;\n const displayWithCursor = inputLine + (cursorVisible ? '▌' : ' ');\n bbs.put(settingsX + 6, projectsDirY + 1, displayWithCursor, 'cyan');\n const clearLen = inputWidth - displayWithCursor.length;\n if (clearLen > 0) {\n bbs.put(settingsX + 6 + displayWithCursor.length, projectsDirY + 1, ' '.repeat(clearLen), 'white');\n }\n if (model.projectsDirError) {\n bbs.put(settingsX + 6, projectsDirY + 2, model.projectsDirError.slice(0, inputWidth), 'red');\n } else if (model.projectsDirSuccess) {\n bbs.put(settingsX + 6, projectsDirY + 2, model.projectsDirSuccess.slice(0, inputWidth), 'green');\n } else {\n bbs.put(settingsX + 6, projectsDirY + 2, 'TAB: autocomplete ENTER: save ESC: cancel', bbs.getTheme().dim);\n }\n } else {\n const currentProjDir = model.projectsDirDisplay;\n const displayDir = currentProjDir.length > 50 ? '...' + currentProjDir.slice(-47) : currentProjDir;\n bbs.put(settingsX + 6, projectsDirY + 1, displayDir, currentProjDir === 'Not set' ? 'yellow' : 'green');\n }\n\n // Library path (9)\n const libraryPathY = CONTENT_Y + 17;\n if (model.cursor === 9) bbs.put(settingsX + 4, libraryPathY, '>', bbs.getTheme().accent);\n bbs.put(settingsX + 6, libraryPathY, 'Library Path:', bbs.getTheme().primary);\n\n if (model.editingLibraryPath) {\n const inputWidth = settingsWidth - 10;\n const inputLine =\n model.libraryPathInput.length > inputWidth - 2\n ? '...' + model.libraryPathInput.slice(-(inputWidth - 5))\n : model.libraryPathInput;\n const cursorVisible = Math.floor(Date.now() / 500) % 2 === 0;\n const displayWithCursor = inputLine + (cursorVisible ? '▌' : ' ');\n bbs.put(settingsX + 6, libraryPathY + 1, displayWithCursor, 'cyan');\n if (model.libraryPathError) {\n bbs.put(settingsX + 6, libraryPathY + 2, model.libraryPathError.slice(0, inputWidth), 'red');\n } else if (model.libraryPathSuccess) {\n bbs.put(settingsX + 6, libraryPathY + 2, model.libraryPathSuccess.slice(0, inputWidth), 'green');\n } else {\n bbs.put(settingsX + 6, libraryPathY + 2, 'TAB: autocomplete ENTER: save ESC: cancel', bbs.getTheme().dim);\n }\n } else {\n const currentLibPath = model.libraryPathDisplay;\n const displayPath = currentLibPath.length > 50 ? '...' + currentLibPath.slice(-47) : currentLibPath;\n bbs.put(settingsX + 6, libraryPathY + 1, displayPath, model.libraryInitialized ? 'green' : 'yellow');\n if (!model.libraryInitialized) {\n bbs.put(settingsX + 6, libraryPathY + 2, 'Press ENTER to initialize Library', bbs.getTheme().dim);\n }\n }\n\n // Sync Library (10)\n const syncLibY = CONTENT_Y + 20;\n const isSyncLibSelected = model.cursor === 10;\n if (isSyncLibSelected) bbs.put(settingsX + 4, syncLibY, '>', bbs.getTheme().accent);\n\n if (model.syncingLibrary) {\n bbs.put(settingsX + 6, syncLibY, '[Syncing Library...]', isSyncLibSelected ? bbs.getTheme().accent : bbs.getTheme().primary);\n if (model.librarySyncProgress) {\n bbs.put(settingsX + 6, syncLibY + 1, model.librarySyncProgress.slice(0, 40), bbs.getTheme().dim);\n }\n } else {\n bbs.put(settingsX + 6, syncLibY, '[Sync Library]', isSyncLibSelected ? bbs.getTheme().accent : bbs.getTheme().primary);\n if (ctx.serverManifest) {\n const updates = ctx.syncUpdates ?? 0;\n if (updates > 0) {\n bbs.put(settingsX + 6, syncLibY + 1, `${updates} file${updates !== 1 ? 's' : ''} to sync`, 'yellow');\n } else {\n bbs.put(settingsX + 6, syncLibY + 1, 'Up to date', 'green');\n }\n bbs.put(\n settingsX + 6,\n syncLibY + 2,\n `${ctx.serverManifest.unlockedFiles}/${ctx.serverManifest.totalFiles} files unlocked`,\n bbs.getTheme().dim,\n );\n } else {\n bbs.put(settingsX + 6, syncLibY + 1, model.lastSyncLabel, bbs.getTheme().dim);\n }\n }\n\n if (model.librarySyncMessage) {\n bbs.put(settingsX + 6, syncLibY + 3, model.librarySyncMessage.slice(0, 40), 'green');\n } else if (model.librarySyncError) {\n bbs.put(settingsX + 6, syncLibY + 3, model.librarySyncError.slice(0, 40), 'red');\n }\n\n // Migrate (11)\n const migrateY = CONTENT_Y + 24;\n if (model.cursor === 11) bbs.put(settingsX + 4, migrateY, '>', bbs.getTheme().accent);\n bbs.put(settingsX + 6, migrateY, '[Migrate from arcade-ref]', model.cursor === 11 ? bbs.getTheme().accent : bbs.getTheme().primary);\n\n const helpText =\n model.editingProjectsDir || model.editingLibraryPath ? 'Type path, TAB for autocomplete' : 'Press ENTER to select/toggle';\n bbs.put(settingsX + 2, CONTENT_Y + 27, helpText, bbs.getTheme().dim);\n}\n\n/** Draw the centered navigation footer (verbatim positioning from the monolith). */\nexport function renderFooter(bbs: BufferedBBS, state: BbsState, dim: Dimensions): void {\n const navY = dim.height - 1;\n const navText = navFooter(state);\n if (!navText) return;\n\n for (let x = 1; x <= dim.width; x++) {\n bbs.put(x, navY, ' ', 'black');\n }\n const textLen = navText.replace(/\\[|\\]/g, '').length + Math.floor(navText.match(/\\[/g)?.length || 0);\n const startX = textLen < dim.width ? Math.floor((dim.width - textLen) / 2) : 2;\n bbs.put(startX, navY, navText, bbs.getTheme().dim);\n}\n","import { Command } from 'commander';\nimport { mkdtempSync, existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\nimport { tmpdir } from 'os';\nimport { AuthManager } from '../utils/auth.js';\nimport { applyTheme } from '../utils/theme-colors.js';\nimport { API_URL } from '../config/constants.js';\nimport { getVersion } from '../utils/version.js';\nimport { inject as injectEngine, type InjectCollectResult } from '../lib/inject/index.js';\n\nexport const injectCommand = new Command('inject')\n .description('Submit a component or system to BabylonJS Market for curator review')\n .argument('[names...]', 'Component / system name(s) to submit')\n .option('--target <target>', 'arcade | viz (skip auto-detection; legacy arcade-pro/viz-pro accepted)')\n .option('--source <path>', 'override <cwd>/src/components/<Name>/')\n .option('--layer <layer>', 'viz only; skip per-file layer detection (core|solid|ecs)')\n .option('--force', 'allow overwriting an existing target')\n .option('--dry-run', 'print the plan, write nothing, do not submit')\n .allowUnknownOption(false)\n .action(async (names: string[], options) => {\n const auth = new AuthManager();\n const theme = applyTheme();\n\n // ── Auth gate (matches whoami / download conventions) ─────────────────\n if (!auth.isAuthenticated()) {\n console.log(theme.error('You must be logged in to submit an injection.'));\n console.log(theme.dim('Run \"bjs login\" first.'));\n process.exit(1);\n }\n\n if (!names || names.length === 0) {\n console.log(theme.error('No component names given. Pass at least one, e.g. `bjs inject Foo`.'));\n process.exit(1);\n }\n\n // ── Build a tmpdir workRoot for engine-internal scratch (the engine itself\n // does not write anything in collect mode; the workRoot is reserved for any\n // future side-buffer the engine might want and to give us a clean parent if\n // we ever extend collect to spill).\n const workRoot = mkdtempSync(join(tmpdir(), 'bjs-inject-'));\n\n // ── Forward flags to the engine as positional argv ────────────────────\n const engineArgs: string[] = [...names];\n if (options.target) engineArgs.push('--target', options.target);\n if (options.source) engineArgs.push('--source', options.source);\n if (options.layer) engineArgs.push('--layer', options.layer);\n if (options.force) engineArgs.push('--force');\n if (options.dryRun) engineArgs.push('--dry-run');\n\n let result: InjectCollectResult | void;\n try {\n result = await injectEngine(engineArgs, {\n mode: 'collect',\n projectDir: process.cwd(),\n cwd: process.cwd(),\n });\n } catch (err) {\n // The engine calls process.exit(1) on validation errors; if it threw for\n // some other reason, surface it.\n console.error(theme.error('Inject failed:'), (err as Error).message);\n process.exit(1);\n }\n\n if (!result) {\n // Engine emitted only help text or hit a validation path that already exited.\n return;\n }\n\n if (options.dryRun) {\n console.log(theme.dim(`Dry run — ${result.files.length} file(s), ${result.patches.length} patch(es). No submission made.`));\n return;\n }\n\n // ── Build submission payload (plan §B.3) ──────────────────────────────\n const meta = readSeedMeta(process.cwd(), names[0]);\n const payload = {\n target: result.target,\n componentNames: names,\n files: result.files,\n patches: result.patches,\n cli: { version: getVersion() },\n ...(meta ? { meta } : {}),\n };\n\n // ── Submit ────────────────────────────────────────────────────────────\n // POSTs the diff payload to the marketplace's `/api/auth/submissions`\n // endpoint; success returns 201 with `{ id, status, createdAt }`.\n let response: Response;\n try {\n response = await auth.makeAuthenticatedRequest(\n `${API_URL}/api/auth/submissions`,\n {\n method: 'POST',\n body: JSON.stringify(payload),\n },\n );\n } catch (err) {\n console.log(theme.error('Submission failed; try again later.'));\n console.log(theme.dim((err as Error).message));\n process.exit(1);\n }\n\n if (response.status === 401) {\n console.log(theme.error('Your session is invalid or expired.'));\n console.log(theme.dim('Run \"bjs login\" to refresh.'));\n process.exit(1);\n }\n\n if (response.status >= 500) {\n console.log(theme.error('Submission failed; try again later.'));\n try {\n const text = await response.text();\n if (text) console.log(theme.dim(text.slice(0, 500)));\n } catch {\n /* ignore */\n }\n process.exit(1);\n }\n\n if (response.status === 413) {\n console.log(theme.error('Payload too large.'));\n console.log(theme.dim('Keep total payload under 2 MB and each file under 256 KB. Strip binaries before submitting.'));\n process.exit(1);\n }\n\n let body: any = null;\n try {\n body = await response.json();\n } catch {\n /* tolerate empty body */\n }\n\n if (!response.ok) {\n const msg = (body && body.error) || `HTTP ${response.status}`;\n console.log(theme.error(`Submission rejected: ${msg}`));\n process.exit(1);\n }\n\n const id = body?.id;\n const status = body?.status ?? 'pending';\n console.log(theme.success(`Submitted! id=${id} status=${status}`));\n if (id !== undefined) {\n console.log(theme.dim(`${API_URL}/account/submissions/${id}`));\n }\n // Keep workRoot around for caller inspection during the local session; it\n // lives in the system tmpdir and gets reaped on reboot.\n void workRoot;\n });\n\n/**\n * Read the seed component's meta.json (if present) so we can attach the\n * marketplace-facing description / dependencies to the submission payload.\n */\nfunction readSeedMeta(projectDir: string, seedName: string): Record<string, unknown> | undefined {\n const metaPath = join(projectDir, 'src', 'components', seedName, 'meta.json');\n if (!existsSync(metaPath)) return undefined;\n try {\n return JSON.parse(readFileSync(metaPath, 'utf-8'));\n } catch {\n return undefined;\n }\n}\n","import { readFileSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport function getVersion(): string {\n try {\n const packagePath = join(__dirname, '../../package.json');\n const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));\n return packageJson.version;\n } catch {\n return '1.0.0';\n }\n}","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport mri from \"mri\";\nimport colors from \"picocolors\";\nimport { INJECT_HELP } from \"./inject-options.js\";\nimport {\n detectTarget,\n detectLayer,\n type Target,\n type VizLayer,\n type SeedFile,\n} from \"./detect-target.js\";\nimport { findMonorepoRoot } from \"./monorepo-root.js\";\n\nconst { cyan, green, yellow, dim, bold } = colors;\n\n// ─── Public collect-mode result shape ────────────────────────────────────────\n\nexport interface InjectPatch {\n /** Path of the file being patched, relative to the target package root. */\n file: string;\n kind: \"registry-append\" | \"barrel-append\";\n /** The line that would be appended/inserted. */\n line: string;\n}\n\nexport interface InjectFile {\n /** Path relative to the target package root (e.g. `src/Components/Foo/Foo.ts`). */\n path: string;\n contents: string;\n}\n\nexport interface InjectCollectResult {\n target: Target;\n files: InjectFile[];\n patches: InjectPatch[];\n warnings: string[];\n}\n\n// ─── Filesystem helpers (mirrors eject.ts) ────────────────────────────────────\n\n/** Every .ts/.tsx file inside a project component folder. */\nfunction componentFiles(dir: string): string[] {\n const out: string[] = [];\n const walk = (d: string) => {\n for (const e of fs.readdirSync(d, { withFileTypes: true })) {\n const p = path.join(d, e.name);\n if (e.isDirectory()) walk(p);\n else if (/\\.(ts|tsx)$/.test(e.name)) out.push(p);\n }\n };\n if (fs.existsSync(dir)) walk(dir);\n return out;\n}\n\n/** Every file (including non-ts assets like meta.json) inside a component folder. */\nfunction allComponentFiles(dir: string): string[] {\n const out: string[] = [];\n const walk = (d: string) => {\n for (const e of fs.readdirSync(d, { withFileTypes: true })) {\n const p = path.join(d, e.name);\n if (e.isDirectory()) walk(p);\n else out.push(p);\n }\n };\n if (fs.existsSync(dir)) walk(dir);\n return out;\n}\n\n/** All top-level project component names = `<project>/src/components/*` (minus `_shared`). */\nfunction projectComponentNames(projectDir: string): string[] {\n const dir = path.join(projectDir, \"src\", \"components\");\n if (!fs.existsSync(dir)) return [];\n return fs\n .readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && e.name !== \"_shared\")\n .map((e) => e.name);\n}\n\n/** Component names a given seed imports via `../Sibling/`, `~/components/Sibling/`, or its meta.json deps. */\nfunction directDeps(\n name: string,\n componentsDir: string,\n allNames: Set<string>,\n): Set<string> {\n const deps = new Set<string>();\n const metaPath = path.join(componentsDir, name, \"meta.json\");\n if (fs.existsSync(metaPath)) {\n try {\n const meta = JSON.parse(fs.readFileSync(metaPath, \"utf8\")) as { dependencies?: string[] };\n for (const d of meta.dependencies ?? []) if (allNames.has(d)) deps.add(d);\n } catch {\n /* tolerate malformed meta.json — import scan is the safety net */\n }\n }\n const relRe = /['\"]\\.\\.\\/([A-Z][A-Za-z0-9_]*)\\//g;\n const aliasRe = /['\"]~\\/components\\/([A-Z][A-Za-z0-9_]*)\\//g;\n for (const file of componentFiles(path.join(componentsDir, name))) {\n const src = fs.readFileSync(file, \"utf8\");\n let m: RegExpExecArray | null;\n while ((m = relRe.exec(src))) if (allNames.has(m[1])) deps.add(m[1]);\n while ((m = aliasRe.exec(src))) if (allNames.has(m[1])) deps.add(m[1]);\n }\n return deps;\n}\n\n/** Expand a seed set to its transitive sibling closure. */\nfunction resolveClosure(\n seed: Set<string>,\n componentsDir: string,\n allNames: string[],\n): Set<string> {\n const all = new Set(allNames);\n const out = new Set(seed);\n const queue = [...seed];\n while (queue.length) {\n const next = queue.pop()!;\n for (const dep of directDeps(next, componentsDir, all)) {\n if (!out.has(dep)) {\n out.add(dep);\n queue.push(dep);\n }\n }\n }\n return out;\n}\n\n/**\n * Reverse of eject's rewriteImports:\n *\n * `'@babylonjsmarket/arcade/<Sibling>'` → `'../<Sibling>/<Sibling>'`\n * `'@babylonjsmarket/arcade-pro/<Sibling>'` → `'../<Sibling>/<Sibling>'`\n *\n * …but only when <Sibling> is co-injected for the same target package. Other\n * package subpaths (including ecs / babylon / solid-js / etc.) are left alone.\n *\n * For arcade-pro, components share a parent (`src/Components/`), so the\n * relative path is always `../<Sibling>/<Sibling>`. For viz-pro the caller\n * supplies a `layerMap` and the originating file's layer; the relative path\n * resolves through the per-file layer routing.\n */\nfunction rewriteArcadeImports(src: string, injected: Set<string>): string {\n return src.replace(\n /(['\"])@babylonjsmarket\\/(?:arcade|arcade-pro)\\/([A-Z][A-Za-z0-9_]*)\\1/g,\n (whole, quote, sibling) => {\n if (injected.has(sibling)) {\n return `${quote}../${sibling}/${sibling}${quote}`;\n }\n return whole;\n },\n );\n}\n\n/**\n * viz variant. Rewrites `@babylonjsmarket/viz/<Sibling>` (the canonical name),\n * the legacy `@babylonjsmarket/viz-pro/<Sibling>`, or\n * `@babylonjsmarket/arcade/<Sibling>` referencing a viz sibling) to the\n * correct flat-layer relative path: `../<targetLayer>/<Sibling>`. Same-layer\n * siblings collapse to `./<Sibling>`. Both `viz` and `viz-pro` prefixes are\n * matched so seeds ejected against either package name still rewrite.\n */\nfunction rewriteVizImports(\n src: string,\n injected: Set<string>,\n layerOf: (name: string) => VizLayer | undefined,\n fromLayer: VizLayer,\n): string {\n return src.replace(\n /(['\"])@babylonjsmarket\\/(?:viz-pro|viz|arcade|arcade-pro)\\/([A-Z][A-Za-z0-9_]*)\\1/g,\n (whole, quote, sibling) => {\n if (!injected.has(sibling)) return whole;\n const dest = layerOf(sibling);\n if (!dest) return whole;\n const rel = dest === fromLayer ? `./${sibling}` : `../${dest}/${sibling}`;\n return `${quote}${rel}${quote}`;\n },\n );\n}\n\n// ─── Registry / barrel patchers ───────────────────────────────────────────────\n\n/**\n * Append lazy resolver lines into ARCADE_PRO_COMPONENT_REGISTRY. Pure decision\n * step: returns what to add without touching disk.\n *\n * `existingRegistry` is the current registry.ts contents, or `undefined` when\n * the file isn't present (apply mode missing the marker emits a warning; in\n * collect mode we always assume the marker is present).\n */\nfunction planArcadeProRegistry(\n existingRegistry: string | undefined,\n names: string[],\n registryRelPath = \"src/registry.ts\",\n): { lines: string[]; added: string[]; warnings: string[]; markerFound: boolean } {\n const warnings: string[] = [];\n if (existingRegistry === undefined) {\n warnings.push(\n `! packages/arcade/${registryRelPath} not found — add resolvers manually for: ${names.join(\", \")}`,\n );\n return { lines: [], added: [], warnings, markerFound: false };\n }\n const marker = /ARCADE_PRO_COMPONENT_REGISTRY:\\s*Record<string,\\s*LazyComponentResolver>\\s*=\\s*\\{/;\n if (!marker.test(existingRegistry)) {\n warnings.push(\n `! Could not find 'ARCADE_PRO_COMPONENT_REGISTRY' marker — add resolvers manually for: ${names.join(\", \")}`,\n );\n return { lines: [], added: [], warnings, markerFound: false };\n }\n const added: string[] = [];\n const lines: string[] = [];\n for (const name of names) {\n if (existingRegistry.includes(`./Components/${name}/${name}`)) continue; // already wired\n lines.push(` ${name}: () => import('./Components/${name}/${name}'),`);\n added.push(name);\n }\n return { lines, added, warnings, markerFound: true };\n}\n\n/** Append a lazy resolver line into ARCADE_PRO_COMPONENT_REGISTRY (idempotent, on-disk). */\nfunction patchArcadeProRegistry(\n arcadeProRoot: string,\n names: string[],\n dryRun: boolean,\n): string[] {\n const registryPath = path.join(arcadeProRoot, \"src\", \"registry.ts\");\n const existing = fs.existsSync(registryPath) ? fs.readFileSync(registryPath, \"utf8\") : undefined;\n const plan = planArcadeProRegistry(existing, names);\n if (plan.warnings.length) return plan.warnings;\n if (plan.added.length && !dryRun) {\n const marker = /ARCADE_PRO_COMPONENT_REGISTRY:\\s*Record<string,\\s*LazyComponentResolver>\\s*=\\s*\\{/;\n const next = (existing as string).replace(marker, (m) => `${m}\\n${plan.lines.join(\"\\n\")}`);\n fs.writeFileSync(registryPath, next);\n }\n return plan.added.map((n) => ` patched registry: ${n}`);\n}\n\n/**\n * Pure planner for the viz-pro layer barrel: returns the line to append if any.\n */\nfunction planVizProBarrel(\n existingBarrel: string | undefined,\n layer: VizLayer,\n fileName: string,\n): { line: string | null; warnings: string[] } {\n if (existingBarrel === undefined) {\n return {\n line: null,\n warnings: [\n `! packages/viz-pro/src/${layer}/index.ts not found — add the barrel re-export manually for ${fileName}`,\n ],\n };\n }\n const needle = `from './${fileName}'`;\n if (existingBarrel.includes(needle)) return { line: null, warnings: [] };\n return { line: `export * from './${fileName}';`, warnings: [] };\n}\n\n/** Append `export * from './<FileName>';` to a viz-pro layer barrel (idempotent, on-disk). */\nfunction patchVizProBarrel(\n vizProRoot: string,\n layer: VizLayer,\n fileName: string,\n dryRun: boolean,\n): string[] {\n const barrelPath = path.join(vizProRoot, \"src\", layer, \"index.ts\");\n const existing = fs.existsSync(barrelPath) ? fs.readFileSync(barrelPath, \"utf8\") : undefined;\n const plan = planVizProBarrel(existing, layer, fileName);\n if (plan.warnings.length) return plan.warnings;\n if (plan.line === null) return [];\n if (!dryRun) {\n const next = existing!.endsWith(\"\\n\")\n ? existing + plan.line + \"\\n\"\n : existing + \"\\n\" + plan.line + \"\\n\";\n fs.writeFileSync(barrelPath, next);\n }\n return [` patched ${layer}/index.ts: ${fileName}`];\n}\n\n/**\n * Strip a lazy-resolver line of the form\n * ` Foo: () => import('./components/Foo/Foo'),`\n * from `<project>/src/registry.ts`. Returns the list of names actually removed.\n */\nfunction stripProjectRegistry(\n projectDir: string,\n names: string[],\n dryRun: boolean,\n): string[] {\n const registryPath = path.join(projectDir, \"src\", \"registry.ts\");\n if (!fs.existsSync(registryPath)) return [];\n let text = fs.readFileSync(registryPath, \"utf8\");\n const removed: string[] = [];\n for (const name of names) {\n const re = new RegExp(\n `^\\\\s*${name}\\\\s*:\\\\s*\\\\(\\\\)\\\\s*=>\\\\s*import\\\\(\\\\s*['\"]\\\\.\\\\/components\\\\/${name}\\\\/${name}['\"]\\\\s*\\\\)\\\\s*,?\\\\s*\\\\r?\\\\n`,\n \"m\",\n );\n if (re.test(text)) {\n text = text.replace(re, \"\");\n removed.push(name);\n }\n }\n if (removed.length && !dryRun) fs.writeFileSync(registryPath, text);\n return removed;\n}\n\n// ─── Plan + main entry ────────────────────────────────────────────────────────\n\ninterface ResolvedSeed {\n /** Name as the operator typed it (and as it lives under `src/components/`). */\n name: string;\n /** Absolute path to the seed's source directory (post `--source` override). */\n sourceDir: string;\n}\n\nexport interface InjectOptions {\n /**\n * What the engine does with the resolved file list:\n * - 'apply' → writes into the resolved packageRoot/vizProRoot (operator mode).\n * - 'collect' → returns the file map + patch plan without touching disk\n * (member mode; payload goes to the marketplace endpoint).\n */\n mode?: \"apply\" | \"collect\";\n /** Tmpdir-friendly: the arcade-pro package root (the dir containing `src/registry.ts`). Apply mode only. */\n packageRoot?: string;\n /** Tmpdir-friendly: the viz-pro package root (the dir containing `src/{core,solid,ecs}/index.ts`). Apply mode only. */\n vizProRoot?: string;\n /** The project we're injecting FROM. Defaults to `cwd`. */\n projectDir?: string;\n /** Override for `process.cwd()`. Tests use this; the CLI entry passes `process.cwd()`. */\n cwd?: string;\n}\n\nexport async function inject(\n args: string[],\n opts: InjectOptions = {},\n): Promise<InjectCollectResult | void> {\n if (args.includes(\"-h\") || args.includes(\"--help\")) {\n console.log(INJECT_HELP);\n return;\n }\n\n const argv = mri(args, {\n boolean: [\"dry-run\", \"move\", \"confirm\", \"force\"],\n string: [\"target\", \"source\", \"layer\"],\n });\n\n const mode: \"apply\" | \"collect\" = opts.mode ?? \"apply\";\n const dryRun = Boolean(argv[\"dry-run\"]);\n const move = Boolean(argv.move);\n const confirm = Boolean(argv.confirm);\n const force = Boolean(argv.force);\n // Normalize the legacy package-name target aliases to the canonical target\n // names early, so existing user scripts passing `--target arcade-pro` or\n // `--target viz-pro` keep working:\n // arcade-pro → arcade (mirrors the original arcade alias)\n // viz-pro → viz\n const rawTarget = argv.target as string | undefined;\n const explicitTarget = (\n rawTarget === \"arcade-pro\" ? \"arcade\" : rawTarget === \"viz-pro\" ? \"viz\" : rawTarget\n ) as Target | undefined;\n const sourceOverride = argv.source as string | undefined;\n const layerOverride = argv.layer as VizLayer | undefined;\n const names = argv._.map(String);\n\n const cwd = opts.cwd ?? process.cwd();\n const projectDir = opts.projectDir ?? cwd;\n\n // ─── Arg validation ───\n if (names.length === 0) {\n console.error(yellow(\"No component names given. Pass at least one, e.g. `bjs inject Foo`.\"));\n process.exit(1);\n return;\n }\n // --move / --confirm are operator-only knobs. In collect mode they're\n // meaningless (no project to mutate); flag and bail.\n if (mode === \"collect\" && (move || confirm)) {\n console.error(yellow(\"--move and --confirm are not available in member submission mode.\"));\n process.exit(1);\n return;\n }\n if (move && !confirm) {\n console.error(yellow(\"--move requires --confirm (it deletes project files). Pass --move --confirm.\"));\n process.exit(1);\n return;\n }\n if (move && dryRun) {\n console.error(yellow(\"--move and --dry-run are mutually exclusive. Drop one.\"));\n process.exit(1);\n return;\n }\n if (explicitTarget && explicitTarget !== \"arcade\" && explicitTarget !== \"viz\") {\n console.error(yellow(`Unknown --target ${rawTarget}. Use arcade or viz.`));\n process.exit(1);\n return;\n }\n if (layerOverride && layerOverride !== \"core\" && layerOverride !== \"solid\" && layerOverride !== \"ecs\") {\n console.error(yellow(`Unknown --layer ${layerOverride}. Use core, solid, or ecs.`));\n process.exit(1);\n return;\n }\n if (sourceOverride && names.length > 1) {\n console.error(yellow(\"--source applies to a single seed; pass one NAME with --source.\"));\n process.exit(1);\n return;\n }\n\n // ─── Phase 0: resolve roots (apply mode only) ───\n let packageRoot = opts.packageRoot;\n let vizProRoot = opts.vizProRoot;\n if (mode === \"apply\" && (!packageRoot || !vizProRoot)) {\n try {\n const monorepo = findMonorepoRoot();\n packageRoot ??= monorepo.arcadeProRoot;\n vizProRoot ??= monorepo.vizProRoot;\n } catch (e) {\n console.error(yellow((e as Error).message));\n process.exit(1);\n return;\n }\n }\n\n // ─── Phase 1: locate seeds + walk closure ───\n const componentsDir = path.join(projectDir, \"src\", \"components\");\n const allProjectNames = projectComponentNames(projectDir);\n\n const seeds: ResolvedSeed[] = [];\n for (const name of names) {\n const sourceDir = sourceOverride\n ? path.resolve(cwd, sourceOverride)\n : path.join(componentsDir, name);\n if (!fs.existsSync(sourceDir)) {\n console.error(\n yellow(\n `Could not find source for \"${name}\". Looked at ${sourceDir}. ` +\n `Use --source <path> to point at the seed explicitly.`,\n ),\n );\n process.exit(1);\n return;\n }\n seeds.push({ name, sourceDir });\n }\n\n // Run the closure walk in the project's components dir (only when seeds live\n // under <project>/src/components/, which is the default and the case we can\n // reason about transitively). With --source we still inject the seed itself\n // but skip the transitive walk — caller is in unusual territory.\n const seedNames = new Set(seeds.map((s) => s.name));\n const closure: Set<string> = sourceOverride\n ? seedNames\n : resolveClosure(seedNames, componentsDir, allProjectNames);\n\n // ─── Phase 2: target detection ───\n const closureFiles: SeedFile[] = [];\n for (const name of closure) {\n const dir = sourceOverride && seedNames.has(name)\n ? seeds.find((s) => s.name === name)!.sourceDir\n : path.join(componentsDir, name);\n for (const f of componentFiles(dir)) {\n closureFiles.push({ path: f, source: fs.readFileSync(f, \"utf8\") });\n }\n }\n\n const target: Target = explicitTarget ?? detectTarget(closureFiles);\n\n // For multi-seed inputs, every seed individually must agree with `target`.\n if (!explicitTarget && seeds.length > 1) {\n for (const seed of seeds) {\n const dir = seed.sourceDir;\n const files: SeedFile[] = componentFiles(dir).map((f) => ({\n path: f,\n source: fs.readFileSync(f, \"utf8\"),\n }));\n const perSeed = detectTarget(files);\n if (perSeed !== target) {\n console.error(\n yellow(\n `Auto-detect disagrees across seeds: \"${seed.name}\" → ${perSeed}, ` +\n `others → ${target}. Pass --target explicitly or split into separate runs.`,\n ),\n );\n process.exit(1);\n return;\n }\n }\n }\n\n // ─── Apply-mode root checks ───\n let chosenRoot: string | undefined;\n if (mode === \"apply\") {\n try {\n if (target === \"arcade\") {\n if (!fs.existsSync(packageRoot!)) {\n throw new Error(\n `packages/arcade is not checked out at ${packageRoot}. Run \\`git submodule update --init packages/arcade\\` and retry.`,\n );\n }\n chosenRoot = packageRoot!;\n } else {\n if (!fs.existsSync(vizProRoot!)) {\n throw new Error(\n `packages/viz-pro is not checked out at ${vizProRoot}. Run \\`git submodule update --init packages/viz-pro\\` and retry.`,\n );\n }\n chosenRoot = vizProRoot!;\n }\n } catch (e) {\n console.error(yellow((e as Error).message));\n process.exit(1);\n return;\n }\n }\n\n // ─── Plan logging header ───\n console.log(\n bold(dryRun ? \"\\nInject plan (dry run — nothing written):\" : \"\\nInjecting:\"),\n );\n console.log(` target: ${cyan(target)}`);\n console.log(` components: ${cyan([...closure].sort().join(\", \"))}`);\n\n // ─── Phase 3: copy files ───\n if (mode === \"collect\") {\n const result =\n target === \"arcade\"\n ? collectArcadePro({ seeds, closure, componentsDir, sourceOverride })\n : collectVizPro({ seeds, closure, componentsDir, sourceOverride, layerOverride });\n for (const f of result.files) console.log(green(` + packages/${target}/${f.path}`));\n for (const w of result.warnings) console.log(yellow(w));\n console.log(\n dryRun\n ? dim(\"\\nRe-run without --dry-run to submit.\\n\")\n : dim(\"\\nCollect-mode plan ready (no submission performed by the library).\\n\"),\n );\n return { ...result, target };\n }\n\n // mode === 'apply'\n if (target === \"arcade\") {\n await injectArcadePro({\n seeds,\n closure,\n componentsDir,\n sourceOverride,\n arcadeProRoot: chosenRoot!,\n dryRun,\n force,\n });\n } else {\n await injectVizPro({\n seeds,\n closure,\n componentsDir,\n sourceOverride,\n vizProRoot: chosenRoot!,\n dryRun,\n force,\n layerOverride,\n });\n }\n\n // ─── Phase 6 (optional): source cleanup ───\n if (move) {\n if (sourceOverride) {\n console.log(\n yellow(\n \" ! --move with --source: only the source dir is removed; cannot reliably patch a foreign project's registry.\",\n ),\n );\n }\n for (const seed of seeds) {\n if (fs.existsSync(seed.sourceDir)) {\n if (!dryRun) fs.rmSync(seed.sourceDir, { recursive: true, force: true });\n console.log(dim(` - ${path.relative(projectDir, seed.sourceDir)}/ (project copy removed)`));\n }\n }\n const removed = stripProjectRegistry(\n projectDir,\n seeds.map((s) => s.name),\n dryRun,\n );\n for (const name of removed) {\n console.log(dim(` - project registry entry: ${name}`));\n }\n }\n\n console.log(\n dryRun\n ? dim(\"\\nRe-run without --dry-run to apply.\\n\")\n : green(`\\nDone. Components landed in packages/${target}/.\\n`),\n );\n}\n\n// ─── arcade-pro injection (apply mode) ───────────────────────────────────────\n\nasync function injectArcadePro(args: {\n seeds: ResolvedSeed[];\n closure: Set<string>;\n componentsDir: string;\n sourceOverride: string | undefined;\n arcadeProRoot: string;\n dryRun: boolean;\n force: boolean;\n}): Promise<void> {\n const { seeds, closure, componentsDir, sourceOverride, arcadeProRoot, dryRun, force } = args;\n const destComponents = path.join(arcadeProRoot, \"src\", \"Components\");\n if (!dryRun) fs.mkdirSync(destComponents, { recursive: true });\n\n const sourceOf = (name: string): string => {\n const seed = seeds.find((s) => s.name === name);\n return seed && sourceOverride ? seed.sourceDir : path.join(componentsDir, name);\n };\n\n for (const name of [...closure].sort()) {\n const src = sourceOf(name);\n const dest = path.join(destComponents, name);\n if (fs.existsSync(dest) && !force) {\n console.log(\n yellow(` ! packages/arcade/src/Components/${name}/ already exists — pass --force to overwrite.`),\n );\n continue;\n }\n if (!dryRun) {\n if (fs.existsSync(dest)) fs.rmSync(dest, { recursive: true, force: true });\n fs.cpSync(src, dest, { recursive: true });\n }\n console.log(green(` + packages/arcade/src/Components/${name}/`));\n }\n\n // Phase 4: import rewriting across each copied folder.\n if (!dryRun) {\n for (const name of closure) {\n const dest = path.join(destComponents, name);\n if (!fs.existsSync(dest)) continue;\n rewriteTree(dest, (text) => rewriteArcadeImports(text, closure));\n }\n }\n\n // Phase 5: arcade-pro registry patch.\n for (const line of patchArcadeProRegistry(\n arcadeProRoot,\n [...closure].sort(),\n dryRun,\n )) {\n console.log(line.startsWith(\"!\") ? yellow(line) : dim(line));\n }\n}\n\n// ─── arcade-pro collection (collect mode) ────────────────────────────────────\n\nfunction collectArcadePro(args: {\n seeds: ResolvedSeed[];\n closure: Set<string>;\n componentsDir: string;\n sourceOverride: string | undefined;\n}): { files: InjectFile[]; patches: InjectPatch[]; warnings: string[] } {\n const { seeds, closure, componentsDir, sourceOverride } = args;\n const sourceOf = (name: string): string => {\n const seed = seeds.find((s) => s.name === name);\n return seed && sourceOverride ? seed.sourceDir : path.join(componentsDir, name);\n };\n\n const files: InjectFile[] = [];\n const warnings: string[] = [];\n\n for (const name of [...closure].sort()) {\n const src = sourceOf(name);\n if (!fs.existsSync(src)) {\n warnings.push(` ! source for ${name} missing at ${src}`);\n continue;\n }\n for (const abs of allComponentFiles(src)) {\n const rel = path.relative(src, abs);\n const baseRel = path.posix.join(\"src\", \"Components\", name, rel.split(path.sep).join(\"/\"));\n const isText = /\\.(ts|tsx)$/i.test(abs);\n const raw = fs.readFileSync(abs, \"utf8\");\n const contents = isText ? rewriteArcadeImports(raw, closure) : raw;\n files.push({ path: baseRel, contents });\n }\n }\n\n // Plan the registry patch — but submit the *desired* added lines, not the\n // raw existing+new file. The server applies the patch against whatever the\n // pro package looks like at merge time.\n const patches: InjectPatch[] = [];\n for (const name of [...closure].sort()) {\n patches.push({\n file: \"src/registry.ts\",\n kind: \"registry-append\",\n line: ` ${name}: () => import('./Components/${name}/${name}'),`,\n });\n }\n\n return { files, patches, warnings };\n}\n\n// ─── viz-pro injection (apply mode) ──────────────────────────────────────────\n\ninterface ViewFile {\n src: string;\n base: string;\n owner: string;\n source: string;\n layer: VizLayer;\n destBase: string;\n}\n\nfunction classifyVizFiles(args: {\n seeds: ResolvedSeed[];\n closure: Set<string>;\n componentsDir: string;\n sourceOverride: string | undefined;\n layerOverride: VizLayer | undefined;\n}): { files: ViewFile[]; primaryLayer: Map<string, VizLayer> } {\n const { seeds, closure, componentsDir, sourceOverride, layerOverride } = args;\n\n const sourceOf = (name: string): string => {\n const seed = seeds.find((s) => s.name === name);\n return seed && sourceOverride ? seed.sourceDir : path.join(componentsDir, name);\n };\n\n const files: ViewFile[] = [];\n\n // Pass A — non-tests\n for (const name of closure) {\n const dir = sourceOf(name);\n for (const abs of componentFiles(dir)) {\n const base = path.basename(abs);\n if (/\\.test\\.tsx?$/.test(base)) continue;\n const source = fs.readFileSync(abs, \"utf8\");\n const layer = layerOverride ?? detectLayer(abs, source);\n files.push({ src: abs, base, owner: name, source, layer, destBase: base });\n }\n }\n // Pass B — tests (look up their subject's layer)\n for (const name of closure) {\n const dir = sourceOf(name);\n for (const abs of componentFiles(dir)) {\n const base = path.basename(abs);\n if (!/\\.test\\.tsx?$/.test(base)) continue;\n const source = fs.readFileSync(abs, \"utf8\");\n const subjectBase = base.replace(/\\.test(\\.tsx?)$/, \"$1\");\n const subjectAlt = base.replace(/\\.test\\.tsx?$/, \".tsx\");\n const subject = files.find((f) => f.owner === name && (f.base === subjectBase || f.base === subjectAlt));\n const layer = layerOverride ?? detectLayer(abs, source, subject?.layer);\n files.push({ src: abs, base, owner: name, source, layer, destBase: base });\n }\n }\n\n const primaryLayer = new Map<string, VizLayer>();\n for (const f of files) {\n if (/\\.test\\.tsx?$/.test(f.base)) continue;\n if (!primaryLayer.has(f.owner)) primaryLayer.set(f.owner, f.layer);\n }\n\n return { files, primaryLayer };\n}\n\nasync function injectVizPro(args: {\n seeds: ResolvedSeed[];\n closure: Set<string>;\n componentsDir: string;\n sourceOverride: string | undefined;\n vizProRoot: string;\n dryRun: boolean;\n force: boolean;\n layerOverride: VizLayer | undefined;\n}): Promise<void> {\n const { closure, vizProRoot, dryRun, force } = args;\n const { files, primaryLayer } = classifyVizFiles(args);\n const layerOf = (name: string): VizLayer | undefined => primaryLayer.get(name);\n\n for (const f of files) {\n const dest = path.join(vizProRoot, \"src\", f.layer, f.destBase);\n if (fs.existsSync(dest) && !force) {\n console.log(\n yellow(\n ` ! packages/viz-pro/src/${f.layer}/${f.destBase} already exists — pass --force to overwrite.`,\n ),\n );\n }\n }\n\n for (const f of files) {\n const destDir = path.join(vizProRoot, \"src\", f.layer);\n const dest = path.join(destDir, f.destBase);\n if (fs.existsSync(dest) && !force) continue;\n if (!dryRun) {\n fs.mkdirSync(destDir, { recursive: true });\n const rewritten = rewriteVizImports(f.source, closure, layerOf, f.layer);\n fs.writeFileSync(dest, rewritten);\n }\n console.log(green(` + packages/viz-pro/src/${f.layer}/${f.destBase}`));\n }\n\n // Phase 5 — patch the layer barrels.\n const barrelNames = new Set<string>();\n for (const f of files) {\n if (/\\.test\\.tsx?$/.test(f.base)) continue;\n const stem = f.destBase.replace(/\\.tsx?$/, \"\");\n const key = `${f.layer}:${stem}`;\n if (barrelNames.has(key)) continue;\n barrelNames.add(key);\n for (const line of patchVizProBarrel(vizProRoot, f.layer, stem, dryRun)) {\n console.log(line.startsWith(\"!\") ? yellow(line) : dim(line));\n }\n }\n\n console.log(\n dim(\n \" hint: if you want named re-exports from the package root, edit packages/viz-pro/src/index.ts by hand.\",\n ),\n );\n}\n\n// ─── viz-pro collection (collect mode) ───────────────────────────────────────\n\nfunction collectVizPro(args: {\n seeds: ResolvedSeed[];\n closure: Set<string>;\n componentsDir: string;\n sourceOverride: string | undefined;\n layerOverride: VizLayer | undefined;\n}): { files: InjectFile[]; patches: InjectPatch[]; warnings: string[] } {\n const { closure } = args;\n const { files: classified, primaryLayer } = classifyVizFiles(args);\n const layerOf = (name: string): VizLayer | undefined => primaryLayer.get(name);\n\n const files: InjectFile[] = [];\n const warnings: string[] = [];\n\n for (const f of classified) {\n const rel = path.posix.join(\"src\", f.layer, f.destBase);\n const contents = rewriteVizImports(f.source, closure, layerOf, f.layer);\n files.push({ path: rel, contents });\n }\n\n const patches: InjectPatch[] = [];\n const barrelKeys = new Set<string>();\n for (const f of classified) {\n if (/\\.test\\.tsx?$/.test(f.base)) continue;\n const stem = f.destBase.replace(/\\.tsx?$/, \"\");\n const key = `${f.layer}:${stem}`;\n if (barrelKeys.has(key)) continue;\n barrelKeys.add(key);\n patches.push({\n file: `src/${f.layer}/index.ts`,\n kind: \"barrel-append\",\n line: `export * from './${stem}';`,\n });\n }\n\n return { files, patches, warnings };\n}\n\n/** Run a rewriter over every .ts/.tsx file under a directory tree. */\nfunction rewriteTree(dir: string, rewrite: (text: string) => string): void {\n for (const e of fs.readdirSync(dir, { withFileTypes: true })) {\n const p = path.join(dir, e.name);\n if (e.isDirectory()) rewriteTree(p, rewrite);\n else if (/\\.(ts|tsx)$/.test(e.name)) {\n const before = fs.readFileSync(p, \"utf8\");\n const after = rewrite(before);\n if (after !== before) fs.writeFileSync(p, after);\n }\n }\n}\n\n// Re-export pure classifiers + helpers so callers can pick them up from one place.\nexport { detectTarget, detectLayer };\nexport type { Target, VizLayer, SeedFile };\n","import colors from \"picocolors\";\n\nconst { cyan, bold } = colors;\n\nexport const INJECT_HELP = `\\\nUsage: bjs inject [OPTION]... NAME...\n\nSubmit a component or system from your project's ${cyan(\"src/components/<Name>/\")} to\nBabylonJS Market for curator review (reverse of ${cyan(\"arcade eject\")}).\n\nWith no ${bold(\"--target\")}, the tool auto-detects per seed:\n * any file extending ${cyan(\"PanelDebuggerSystem\")} / ${cyan(\"StateStepperSystem\")} or\n importing from ${cyan(\"@babylonjsmarket/viz\")} → ${cyan(\"viz\")},\n * otherwise → ${cyan(\"arcade\")}.\n\nMulti-seed inputs must all detect to the same target.\n\nOptions:\n --target <arcade|viz> skip auto-detection (legacy: arcade-pro, viz-pro)\n --source <path> override <cwd>/src/components/<Name>/\n --layer <core|solid|ecs> viz only; skip per-file layer detection\n --force allow overwriting an existing target\n --dry-run print the plan, write nothing, do not submit\n -h, --help print this help message\n\nExamples:\n bjs inject Foo # auto-detect target\n bjs inject Foo Bar --dry-run # multi-name, preview\n bjs inject MyPanelDebugger --target viz\n bjs inject Foo --source ./packages/demo/src/components/Foo\n`;\n","/**\n * Pure classifiers for the inject engine.\n *\n * `detectTarget` decides whether a seed of project files belongs in\n * `@babylonjsmarket/arcade` (per-component, registered) or the viz package\n * (flat per-layer barrels).\n *\n * `detectLayer` decides which viz layer (`core`, `solid`, `ecs`) owns a\n * single source file. Order matters: rules are evaluated top-down and the\n * first match wins. The order mirrors the plan.\n *\n * Target naming: the canonical user-facing target names are `arcade` and\n * `viz`. The legacy `arcade-pro` / `viz-pro` package names live on only as\n * back-compat aliases (normalized to the canonical names by callers) and as\n * import-prefix patterns we still recognize in existing seeds.\n */\n\nexport type Target = \"arcade\" | \"viz\";\nexport type VizLayer = \"core\" | \"solid\" | \"ecs\";\n\nexport interface SeedFile {\n path: string;\n source: string;\n}\n\n/**\n * Classify a closure of seed files to one of the two packages. Any single\n * file extending a viz System class or importing from `@babylonjsmarket/viz`\n * (or the legacy `@babylonjsmarket/viz-pro`) tips the whole seed to `viz`.\n */\nexport function detectTarget(seedFiles: SeedFile[]): Target {\n for (const { source } of seedFiles) {\n // Recognize BOTH the canonical `@babylonjsmarket/viz` and the legacy\n // `@babylonjsmarket/viz-pro` import prefix — existing seeds were ejected\n // against `viz-pro` and must still classify correctly.\n if (/from\\s+['\"]@babylonjsmarket\\/viz(?:-pro)?['\"]/.test(source)) return \"viz\";\n if (/extends\\s+(PanelDebuggerSystem|StateStepperSystem)\\b/.test(source)) return \"viz\";\n }\n return \"arcade\";\n}\n\n/**\n * Classify a single source file to a viz layer.\n *\n * Order is load-bearing:\n * 1. *.test.ts(x) → route alongside the subject file (re-detect on the\n * subject's source if known, else default 'core').\n * 2. *.tsx that imports from 'solid-js' → 'solid'.\n * 3. extends (PanelDebuggerSystem|StateStepperSystem|System) or filename\n * ends in 'System.ts' → 'ecs'.\n * 4. extends Component and no Solid import → 'ecs'.\n * 5. contains `definePanel(` and no Solid import → 'core'.\n * 6. fallback → 'core'.\n *\n * `subjectLayer` lets the caller pin a test file to its subject's layer; pass\n * `undefined` when the subject isn't co-injected, which falls through to\n * rule (1)'s default.\n */\nexport function detectLayer(\n filePath: string,\n source: string,\n subjectLayer?: VizLayer,\n): VizLayer {\n const base = filePath.split(/[\\\\/]/).pop() ?? filePath;\n\n // (1) test files travel with their subject\n if (/\\.test\\.tsx?$/.test(base)) {\n return subjectLayer ?? \"core\";\n }\n\n const hasSolidImport = /from\\s+['\"]solid-js['\"]/.test(source);\n\n // (2) Solid .tsx\n if (/\\.tsx$/.test(base) && hasSolidImport) return \"solid\";\n\n // (3) System subclasses or *System.ts filenames\n if (/extends\\s+(PanelDebuggerSystem|StateStepperSystem|System)\\b/.test(source)) return \"ecs\";\n if (/System\\.ts$/.test(base)) return \"ecs\";\n\n // (4) Component subclasses (no Solid)\n if (/extends\\s+Component\\b/.test(source) && !hasSolidImport) return \"ecs\";\n\n // (5) definePanel files (no Solid)\n if (/\\bdefinePanel\\s*\\(/.test(source) && !hasSolidImport) return \"core\";\n\n // (6) fallback\n return \"core\";\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport interface MonorepoPaths {\n root: string;\n arcadeProRoot: string;\n vizProRoot: string;\n}\n\n/**\n * ⚠️ DEFUNCT DESTINATIONS — apply mode is being retired.\n *\n * The `arcadeProRoot` / `vizProRoot` destinations below point at\n * `packages/arcade-pro` and `packages/viz-pro`, which have been REMOVED from\n * the monorepo. Premium components are now authored directly in the game\n * project's `src/` and delivered per-component via the CLI's `collect` mode\n * (which never touches these paths); apply mode that copies into a local\n * pro-package checkout no longer has a valid target.\n *\n * This operator-only function is kept in place (not ripped out) so the\n * walk-up-to-umbrella logic stays available, but callers should not rely on\n * `arcadeProRoot` / `vizProRoot` resolving to real directories — they won't.\n *\n * Walk up from this file (dist/lib/inject/monorepo-root.js or\n * src/lib/inject/monorepo-root.ts) looking for the umbrella `package.json`\n * whose `name === \"babylonjs-market-monorepo\"`. Returns the umbrella root plus\n * the two (now-defunct) pro-package roots.\n *\n * Only called from `apply` mode — `collect` mode never touches the local\n * monorepo because it operates against a tmpdir workRoot supplied by the\n * caller.\n *\n * Does NOT validate that the pro-package directories exist — `requireTargetRoot`\n * does that lazily so callers can run --help / classifier-only paths without\n * the submodule being present.\n */\nexport function findMonorepoRoot(): MonorepoPaths {\n const here = path.dirname(fileURLToPath(import.meta.url));\n let dir = here;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const pkgPath = path.join(dir, \"package.json\");\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf8\")) as { name?: string };\n if (pkg.name === \"babylonjs-market-monorepo\") {\n return {\n root: dir,\n arcadeProRoot: path.join(dir, \"packages\", \"arcade-pro\"),\n vizProRoot: path.join(dir, \"packages\", \"viz-pro\"),\n };\n }\n } catch {\n /* unreadable / non-JSON — keep walking */\n }\n }\n const parent = path.dirname(dir);\n if (parent === dir) {\n throw new Error(\n `Could not locate umbrella repo (no ancestor package.json with name \"babylonjs-market-monorepo\" above ${here}).`,\n );\n }\n dir = parent;\n }\n}\n\n/**\n * ⚠️ DEFUNCT — see findMonorepoRoot above. Both `packages/arcade-pro` and\n * `packages/viz-pro` have been removed, so this check can no longer succeed in\n * practice. Retained as operator-only scaffolding while apply mode is retired\n * in favor of authoring premium components in the game project's `src/`.\n *\n * Verify the requested target package's submodule directory exists on disk.\n * Throws with a precise message naming the missing path so the operator knows\n * to `git submodule update --init` the relevant repo.\n *\n * `target` uses the canonical names (`arcade` | `viz`); they map to the legacy\n * `packages/arcade-pro` / `packages/viz-pro` dirs that this defunct path used.\n */\nexport function requireTargetRoot(\n paths: MonorepoPaths,\n target: \"arcade\" | \"viz\",\n): string {\n const root = target === \"arcade\" ? paths.arcadeProRoot : paths.vizProRoot;\n const legacyPkg = target === \"arcade\" ? \"arcade-pro\" : \"viz-pro\";\n if (!fs.existsSync(root)) {\n throw new Error(\n `packages/${legacyPkg} is not checked out at ${root} (and is now defunct). ` +\n `Premium components are authored in the game project's src/ — apply mode is retired.`,\n );\n }\n return root;\n}\n","/**\n * `bjs submissions` — list, show, and withdraw marketplace submissions.\n *\n * Talks to the `/api/auth/submissions` endpoint family on babylonjsmarket.com.\n * Auth is gated through the standard `AuthManager` Bearer flow.\n *\n * Subcommands:\n * - `bjs submissions list` (also the default action)\n * - `bjs submissions show <id>`\n * - `bjs submissions withdraw <id>`\n */\n\nimport { Command } from 'commander';\nimport { createInterface } from 'readline';\nimport { AuthManager } from '../utils/auth.js';\nimport { applyTheme } from '../utils/theme-colors.js';\nimport { API_URL } from '../config/constants.js';\n\ninterface SubmissionRow {\n id: number;\n status: string;\n target: string;\n componentNames: string[];\n reviewerNotes?: string | null;\n cliVersion?: string | null;\n createdAt: string;\n updatedAt?: string;\n}\n\ninterface ListResponse {\n submissions: SubmissionRow[];\n total: number;\n hasMore: boolean;\n}\n\ninterface ListOpts {\n status?: string;\n limit?: number;\n json?: boolean;\n}\n\ninterface ShowOpts {\n json?: boolean;\n}\n\ninterface WithdrawOpts {\n yes?: boolean;\n json?: boolean;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Helpers\n// ──────────────────────────────────────────────────────────────────────────\n\n/** Small wrapper around AuthManager.makeAuthenticatedRequest. */\nasync function apiCall(\n auth: AuthManager,\n method: string,\n path: string,\n): Promise<Response> {\n return auth.makeAuthenticatedRequest(`${API_URL}${path}`, { method });\n}\n\n/** Format an ISO datetime as a compact human-readable string. */\nfunction formatDate(s: string | undefined): string {\n if (!s) return '';\n try {\n const d = new Date(s);\n if (isNaN(d.getTime())) return s;\n // YYYY-MM-DD HH:MM\n const pad = (n: number) => String(n).padStart(2, '0');\n return (\n `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ` +\n `${pad(d.getHours())}:${pad(d.getMinutes())}`\n );\n } catch {\n return s;\n }\n}\n\n/** Validate id argument; on bad input prints an error and exits. */\nfunction requireValidId(idArg: string, theme: ReturnType<typeof applyTheme>): number {\n const n = Number(idArg);\n if (!Number.isInteger(n) || n <= 0 || String(n) !== String(idArg).trim()) {\n console.log(theme.error('Invalid id'));\n process.exit(1);\n }\n return n;\n}\n\n/**\n * Render an array of submissions as a column-aligned table.\n * Columns: id | status | target | components | created\n */\nfunction printTable(\n rows: SubmissionRow[],\n theme: ReturnType<typeof applyTheme>,\n): void {\n if (rows.length === 0) {\n console.log(theme.dim('No submissions.'));\n return;\n }\n const header = ['id', 'status', 'target', 'components', 'created'];\n const data = rows.map((r) => [\n String(r.id),\n r.status,\n r.target,\n (r.componentNames || []).join(','),\n formatDate(r.createdAt),\n ]);\n const widths = header.map((h, i) =>\n Math.max(h.length, ...data.map((row) => row[i].length)),\n );\n const fmt = (cells: string[]) =>\n cells.map((c, i) => c.padEnd(widths[i])).join(' ');\n\n console.log(theme.header(fmt(header)));\n console.log(theme.dim(widths.map((w) => '-'.repeat(w)).join(' ')));\n for (const row of data) {\n console.log(fmt(row));\n }\n}\n\n/** Prompt y/N on stdin. Returns true only if the user typed `y` or `Y`. */\nasync function confirm(question: string): Promise<boolean> {\n return new Promise((resolve) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question(question, (answer) => {\n rl.close();\n resolve(/^y(es)?$/i.test(answer.trim()));\n });\n });\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Actions\n// ──────────────────────────────────────────────────────────────────────────\n\nasync function listSubmissionsAction(opts: ListOpts): Promise<void> {\n const auth = new AuthManager();\n const theme = applyTheme();\n\n if (!auth.isAuthenticated()) {\n console.log(theme.error('You must be logged in to view submissions.'));\n console.log(theme.dim('Run \"bjs login\" first.'));\n process.exit(1);\n }\n\n const qsParts: string[] = [];\n if (opts.status) qsParts.push(`status=${encodeURIComponent(opts.status)}`);\n if (opts.limit !== undefined && !Number.isNaN(opts.limit)) {\n qsParts.push(`limit=${opts.limit}`);\n }\n const qs = qsParts.length ? `?${qsParts.join('&')}` : '';\n\n let response: Response;\n try {\n response = await apiCall(auth, 'GET', `/api/auth/submissions${qs}`);\n } catch (err) {\n console.log(theme.error('Failed to fetch submissions; try again later.'));\n console.log(theme.dim((err as Error).message));\n process.exit(1);\n }\n\n if (response.status === 401) {\n console.log(theme.error('Your session is invalid or expired.'));\n console.log(theme.dim('Run \"bjs login\" to refresh.'));\n process.exit(1);\n }\n\n if (response.status >= 500) {\n console.log(theme.error('Failed to fetch submissions; try again later.'));\n process.exit(1);\n }\n\n let body: any = null;\n try {\n body = await response.json();\n } catch {\n /* tolerate empty body */\n }\n\n if (response.status === 400) {\n const msg = (body && body.error) || `HTTP ${response.status}`;\n console.log(theme.error(`Submission query rejected: ${msg}`));\n process.exit(1);\n }\n\n if (!response.ok) {\n const msg = (body && body.error) || `HTTP ${response.status}`;\n console.log(theme.error(`Failed to fetch submissions: ${msg}`));\n process.exit(1);\n }\n\n const list: ListResponse = body || { submissions: [], total: 0, hasMore: false };\n\n if (opts.json) {\n console.log(JSON.stringify(list, null, 2));\n return;\n }\n\n printTable(list.submissions || [], theme);\n if (list.hasMore) {\n const shown = list.submissions?.length ?? 0;\n console.log(\n theme.dim(`(showing ${shown} of ${list.total}; pass --limit higher)`),\n );\n }\n}\n\nasync function showSubmissionAction(idArg: string, opts: ShowOpts): Promise<void> {\n const auth = new AuthManager();\n const theme = applyTheme();\n\n if (!auth.isAuthenticated()) {\n console.log(theme.error('You must be logged in to view submissions.'));\n console.log(theme.dim('Run \"bjs login\" first.'));\n process.exit(1);\n }\n\n const id = requireValidId(idArg, theme);\n\n let response: Response;\n try {\n response = await apiCall(auth, 'GET', `/api/auth/submissions/${id}`);\n } catch (err) {\n console.log(theme.error('Failed to fetch submission; try again later.'));\n console.log(theme.dim((err as Error).message));\n process.exit(1);\n }\n\n if (response.status === 401) {\n console.log(theme.error('Your session is invalid or expired.'));\n console.log(theme.dim('Run \"bjs login\" to refresh.'));\n process.exit(1);\n }\n\n if (response.status === 404) {\n console.log(theme.error('Submission not found.'));\n process.exit(1);\n }\n\n if (response.status >= 500) {\n console.log(theme.error('Failed to fetch submission; try again later.'));\n process.exit(1);\n }\n\n let body: any = null;\n try {\n body = await response.json();\n } catch {\n /* tolerate empty body */\n }\n\n if (!response.ok) {\n const msg = (body && body.error) || `HTTP ${response.status}`;\n console.log(theme.error(`Failed to fetch submission: ${msg}`));\n process.exit(1);\n }\n\n if (opts.json) {\n console.log(JSON.stringify(body, null, 2));\n return;\n }\n\n // Pretty-print each public field.\n const row: SubmissionRow = body;\n const lines: Array<[string, string]> = [\n ['id', String(row.id)],\n ['status', row.status],\n ['target', row.target],\n ['components', (row.componentNames || []).join(', ')],\n ['created', formatDate(row.createdAt)],\n ];\n if (row.updatedAt) lines.push(['updated', formatDate(row.updatedAt)]);\n if (row.cliVersion) lines.push(['cli', row.cliVersion]);\n if (row.reviewerNotes) lines.push(['reviewer notes', row.reviewerNotes]);\n\n for (const [label, value] of lines) {\n console.log(`${theme.dim(label + ':')} ${value}`);\n }\n}\n\nasync function withdrawSubmissionAction(\n idArg: string,\n opts: WithdrawOpts,\n): Promise<void> {\n const auth = new AuthManager();\n const theme = applyTheme();\n\n if (!auth.isAuthenticated()) {\n console.log(theme.error('You must be logged in to view submissions.'));\n console.log(theme.dim('Run \"bjs login\" first.'));\n process.exit(1);\n }\n\n const id = requireValidId(idArg, theme);\n\n if (!opts.yes) {\n const ok = await confirm(`Withdraw submission ${id}? (y/N) `);\n if (!ok) {\n console.log(theme.dim('Aborted.'));\n process.exit(0);\n }\n }\n\n let response: Response;\n try {\n response = await apiCall(auth, 'DELETE', `/api/auth/submissions/${id}`);\n } catch (err) {\n console.log(theme.error('Failed to withdraw submission; try again later.'));\n console.log(theme.dim((err as Error).message));\n process.exit(1);\n }\n\n if (response.status === 401) {\n console.log(theme.error('Your session is invalid or expired.'));\n console.log(theme.dim('Run \"bjs login\" to refresh.'));\n process.exit(1);\n }\n\n if (response.status === 404) {\n console.log(theme.error('Submission not found.'));\n process.exit(1);\n }\n\n if (response.status === 409) {\n console.log(theme.error(\"Already in review or finalized — can't withdraw.\"));\n process.exit(1);\n }\n\n if (response.status >= 500) {\n console.log(theme.error('Failed to withdraw submission; try again later.'));\n process.exit(1);\n }\n\n let body: any = null;\n try {\n body = await response.json();\n } catch {\n /* tolerate empty body */\n }\n\n if (!response.ok) {\n const msg = (body && body.error) || `HTTP ${response.status}`;\n console.log(theme.error(`Failed to withdraw submission: ${msg}`));\n process.exit(1);\n }\n\n if (opts.json) {\n console.log(JSON.stringify(body, null, 2));\n return;\n }\n console.log(theme.success('Withdrawn.'));\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Command wiring\n// ──────────────────────────────────────────────────────────────────────────\n\nexport const submissionsCommand = new Command('submissions')\n .description('List or inspect your marketplace submissions')\n .action(async () => {\n // Default action: behave like `bjs submissions list`.\n await listSubmissionsAction({});\n });\n\nsubmissionsCommand\n .command('list')\n .description('List your submissions')\n .option('--status <status>', 'filter: pending|reviewing|merged|rejected|withdrawn')\n .option('--limit <n>', 'max results (default 20, capped at 100 server-side)', (v) => parseInt(v, 10))\n .option('--json', 'machine-readable output')\n .action(async (opts: ListOpts) => {\n await listSubmissionsAction(opts);\n });\n\nsubmissionsCommand\n .command('show <id>')\n .description('Show detail for one submission')\n .option('--json', 'machine-readable output')\n .action(async (id: string, opts: ShowOpts) => {\n await showSubmissionAction(id, opts);\n });\n\nsubmissionsCommand\n .command('withdraw <id>')\n .description('Withdraw a pending submission')\n .option('-y, --yes', 'skip confirmation prompt')\n .option('--json', 'machine-readable output')\n .action(async (id: string, opts: WithdrawOpts) => {\n await withdrawSubmissionAction(id, opts);\n });\n"],"mappings":"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","names":["Command","chalk","fetch","join","join","fetch","Command","chalk","chalk","Command","Command","Command","Command","ora","existsSync","mkdirSync","fetch","path","Command","ora","Command","terminalKit","bold","markedCount","terminalKit","chalk","chalk","chalk","fetch","chalk","_","text","padding","EventEmitter","execSync","open","maxScroll","ScreenBuffer","terminalKit","EventEmitter","line","chalk","bold","isCopiedLine","open","execSync","fs","path","homedir","process","fetch","fs","pipeline","fetch","fs","pipeline","fs","path","fs","path","fs","path","path","fs","targetComponentDir","targetComponentPath","path","fs","componentFiles","open","fetch","reduce","dim","dim","terminalKit","ScreenBuffer","process","Command","path","fetch","open","fs","reduce","dim","homedir","intent","Command","existsSync","readFileSync","join","readFileSync","join","__dirname","fs","path","colors","fs","path","fileURLToPath","cyan","bold","colors","fs","path","confirm","Command","join","existsSync","readFileSync","Command","path","Command","Command","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/login-simple.ts","../src/utils/auth.ts","../src/config/constants.ts","../src/commands/logout.ts","../src/utils/theme-colors.ts","../src/commands/whoami.ts","../src/commands/download.ts","../src/commands/bbs.ts","../src/utils/buffered-bbs.ts","../src/utils/course-detail-viewer.ts","../src/utils/markdown-terminal.ts","../src/utils/code-highlighter.ts","../src/utils/course-detail/layout.ts","../src/utils/course-detail/windowing.ts","../src/utils/course-detail/reducer.ts","../src/utils/asset-downloader.ts","../src/utils/project-scanner.ts","../src/utils/component-catalog.ts","../src/commands/bbs/state.ts","../src/commands/bbs/keymap.ts","../src/commands/bbs/format.ts","../src/commands/bbs/layout.ts","../src/commands/bbs/viewmodel.ts","../src/commands/bbs/render.ts","../src/commands/inject.ts","../src/utils/version.ts","../src/lib/inject/engine.ts","../src/lib/inject/inject-options.ts","../src/lib/inject/detect-target.ts","../src/lib/inject/monorepo-root.ts","../src/commands/submissions.ts"],"sourcesContent":["import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { loginCommand } from './commands/login-simple.js';\nimport { logoutCommand } from './commands/logout.js';\nimport { whoamiCommand } from './commands/whoami.js';\nimport { downloadCommand } from './commands/download.js';\nimport { bbsCommand } from './commands/bbs.js';\nimport { injectCommand } from './commands/inject.js';\nimport { submissionsCommand } from './commands/submissions.js';\nimport { getVersion } from './utils/version.js';\n\nconst program = new Command();\n\nprogram\n .name('bjs')\n .description('BabylonJS Market CLI - BBS-style interface for courses and assets')\n .version(getVersion());\n\n// Add commands\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(whoamiCommand);\nprogram.addCommand(downloadCommand);\nprogram.addCommand(injectCommand);\nprogram.addCommand(submissionsCommand);\nprogram.addCommand(bbsCommand);\n\n// Error handling\nprogram.exitOverride();\n\ntry {\n await program.parseAsync(process.argv);\n} catch (error: any) {\n if (error.code === 'commander.executeSubCommandAsync') {\n // Normal exit from subcommand\n process.exit(error.exitCode);\n }\n console.error(chalk.red('Error:'), error.message);\n process.exit(1);\n}","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport open from 'open';\nimport ora from 'ora';\nimport fetch from 'node-fetch';\nimport { AuthManager } from '../utils/auth.js';\nimport { API_URL } from '../config/constants.js';\nimport { createServer as createHttpServer } from 'http';\nimport { URL } from 'url';\n\nexport const loginCommand = new Command('login')\n .description('Authenticate with BabylonJS Market')\n .option('--no-browser', 'Don\\'t open browser automatically')\n .action(async (options) => {\n const authManager = new AuthManager();\n \n // Check if already authenticated\n if (authManager.isAuthenticated()) {\n const user = authManager.getUser();\n console.log(chalk.yellow('You are already logged in as:'), chalk.cyan(user?.email || 'Unknown'));\n console.log(chalk.gray('Run \"bjs-cli logout\" to log out first.'));\n return;\n }\n\n console.log(chalk.blue('Starting authentication flow...'));\n \n try {\n // Start a local server to receive the callback\n const port = 8765;\n let token: string | null = null;\n \n // Local HTTP server to receive the auth callback. localhost over HTTP is\n // a browser \"secure context\" and needs no certificate. A self-signed\n // HTTPS server is worse than useless here: when the auth page redirects\n // the browser to it, the browser blocks the untrusted cert and the token\n // never arrives.\n const protocol = 'http';\n const server = createHttpServer((req, res) => {\n handleRequest(req, res);\n });\n \n const handleRequest = (req: any, res: any) => {\n const url = new URL(req.url!, `${protocol}://localhost:${port}`);\n token = url.searchParams.get('token');\n \n if (token) {\n res.writeHead(200, { 'Content-Type': 'text/html' });\n res.end(`\n <!DOCTYPE html>\n <html>\n <head>\n <title>Authentication Successful</title>\n <style>\n body { font-family: system-ui; padding: 40px; text-align: center; }\n .success { color: green; }\n .token { background: #f0f0f0; padding: 10px; margin: 20px; font-family: monospace; word-break: break-all; }\n </style>\n </head>\n <body>\n <h1 class=\"success\">✓ Authentication Successful!</h1>\n <p>You can close this window and return to your terminal.</p>\n <div class=\"token\">Token received: ${token.substring(0, 8)}...</div>\n <script>setTimeout(() => window.close(), 3000);</script>\n </body>\n </html>\n `);\n server.close();\n } else {\n res.writeHead(400, { 'Content-Type': 'text/plain' });\n res.end('Missing token parameter');\n }\n };\n \n await new Promise<void>((resolve) => {\n server.listen(port, () => {\n console.log(chalk.gray(`Local callback server started on port ${port} (${protocol.toUpperCase()})`));\n resolve();\n });\n });\n \n // Open browser to auth page\n const callbackUrl = `${protocol}://localhost:${port}`;\n const authUrl = `${API_URL}/auth/cli?callback=${encodeURIComponent(callbackUrl)}`;\n console.log('\\n' + chalk.green('To authenticate, visit:'));\n console.log(chalk.cyan.bold(authUrl));\n \n if (options.browser !== false) {\n console.log('\\n' + chalk.gray('Opening browser...'));\n await open(authUrl);\n }\n \n // Wait for token\n console.log('\\n' + chalk.blue('Waiting for authentication...'));\n const spinner = ora('Waiting for browser authentication...').start();\n \n // Wait for server to receive token (with timeout)\n const timeout = setTimeout(() => {\n server.close();\n spinner.fail(chalk.red('Authentication timed out'));\n process.exit(1);\n }, 300000); // 5 minutes timeout\n \n await new Promise<void>((resolve) => {\n server.on('close', () => {\n clearTimeout(timeout);\n resolve();\n });\n });\n \n if (!token) {\n spinner.fail(chalk.red('No token received'));\n process.exit(1);\n }\n \n spinner.text = 'Exchanging token...';\n \n // Exchange the token for JWT\n const exchangeResponse = await fetch(`${API_URL}/api/auth/cli/exchange`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token })\n });\n \n if (!exchangeResponse.ok) {\n const error = await exchangeResponse.text();\n spinner.fail(chalk.red('Failed to exchange token'));\n console.error(chalk.red('Error:'), error);\n process.exit(1);\n }\n \n const tokenData = await exchangeResponse.json() as any;\n \n // Save tokens and user info\n authManager.saveTokens(\n tokenData.access_token,\n tokenData.refresh_token,\n tokenData.expires_in\n );\n \n authManager.saveUser(tokenData.user);\n \n spinner.succeed(chalk.green('Authentication successful!'));\n \n console.log(chalk.blue('\\nLogged in as:'), chalk.cyan(tokenData.user.email));\n console.log(chalk.gray(`\\nAuthentication data saved to ~/.bjs/config.json`));\n \n } catch (error: any) {\n console.error(chalk.red('Login failed:'), error.message);\n process.exit(1);\n }\n });","import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';\nimport { join } from 'path';\nimport { CONFIG_DIR, CONFIG_FILE } from '../config/constants.js';\nimport fetch from 'node-fetch';\n\nconst LIBRARY_MANIFEST_FILE = join(CONFIG_DIR, 'library-manifest.json');\n\n// Tracks installed library files and their versions\nexport interface LibraryFileInfo {\n version: string; // File version hash/id from server\n installedAt: string; // ISO date when first installed\n updatedAt: string; // ISO date when last updated\n}\n\nexport interface LibraryManifest {\n files: Record<string, LibraryFileInfo>; // path -> info\n lastSyncAt?: string; // ISO date of last sync\n}\n\ninterface AuthConfig {\n accessToken?: string;\n refreshToken?: string;\n expiresAt?: number;\n user?: {\n id: string;\n email: string;\n name?: string;\n };\n preferences?: {\n theme?: string;\n animations?: boolean;\n mouse?: boolean;\n projectsDirectory?: string;\n libraryPath?: string;\n };\n}\n\nexport class AuthManager {\n private config: AuthConfig = {};\n\n constructor() {\n this.loadConfig();\n }\n\n private loadConfig(): void {\n try {\n if (existsSync(CONFIG_FILE)) {\n const data = readFileSync(CONFIG_FILE, 'utf-8');\n this.config = JSON.parse(data);\n }\n } catch (error) {\n console.error('Failed to load config:', error);\n this.config = {};\n }\n }\n\n private saveConfig(): void {\n try {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true });\n }\n writeFileSync(CONFIG_FILE, JSON.stringify(this.config, null, 2));\n } catch (error) {\n console.error('Failed to save config:', error);\n throw new Error('Failed to save authentication data');\n }\n }\n\n public saveTokens(accessToken: string, refreshToken?: string, expiresIn?: number): void {\n this.config.accessToken = accessToken;\n if (refreshToken) {\n this.config.refreshToken = refreshToken;\n }\n if (expiresIn) {\n this.config.expiresAt = Date.now() + (expiresIn * 1000);\n }\n this.saveConfig();\n }\n\n public saveUser(user: AuthConfig['user']): void {\n this.config.user = user;\n this.saveConfig();\n }\n\n public getAccessToken(): string | undefined {\n // Check if token is expired\n if (this.config.expiresAt && Date.now() > this.config.expiresAt) {\n // TODO: Implement token refresh\n return undefined;\n }\n return this.config.accessToken;\n }\n\n public getUser(): AuthConfig['user'] | undefined {\n return this.config.user;\n }\n\n public isAuthenticated(): boolean {\n return !!this.getAccessToken();\n }\n\n public clearAuth(): void {\n // Keep preferences when clearing auth\n const preferences = this.config.preferences;\n this.config = { preferences };\n this.saveConfig();\n }\n\n public savePreferences(preferences: Partial<AuthConfig['preferences']>): void {\n this.config.preferences = {\n ...this.config.preferences,\n ...preferences\n };\n this.saveConfig();\n }\n\n public getPreferences(): AuthConfig['preferences'] {\n return this.config.preferences || {};\n }\n\n public getProjectsDirectory(): string | undefined {\n return this.config.preferences?.projectsDirectory;\n }\n\n public setProjectsDirectory(directory: string): void {\n this.savePreferences({ projectsDirectory: directory });\n }\n\n public getLibraryPath(): string {\n // Return configured path or default to ~/.bjs/Library/\n return this.config.preferences?.libraryPath || join(CONFIG_DIR, 'Library');\n }\n\n public setLibraryPath(directory: string): void {\n this.savePreferences({ libraryPath: directory });\n }\n\n public async makeAuthenticatedRequest(url: string, options: any = {}): Promise<Response> {\n const token = this.getAccessToken();\n if (!token) {\n throw new Error('Not authenticated. Please run \"bjs login\" first.');\n }\n\n return fetch(url, {\n ...options,\n headers: {\n ...options.headers,\n 'Authorization': `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n }) as any;\n }\n\n // Library manifest management\n public getLibraryManifest(): LibraryManifest {\n try {\n if (existsSync(LIBRARY_MANIFEST_FILE)) {\n const data = readFileSync(LIBRARY_MANIFEST_FILE, 'utf-8');\n return JSON.parse(data);\n }\n } catch {\n // Return empty manifest on error\n }\n return { files: {} };\n }\n\n public saveLibraryManifest(manifest: LibraryManifest): void {\n try {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true });\n }\n writeFileSync(LIBRARY_MANIFEST_FILE, JSON.stringify(manifest, null, 2));\n } catch (error) {\n console.error('Failed to save library manifest:', error);\n }\n }\n\n public updateLibraryFile(filePath: string, version: string): void {\n const manifest = this.getLibraryManifest();\n const now = new Date().toISOString();\n\n if (manifest.files[filePath]) {\n manifest.files[filePath].version = version;\n manifest.files[filePath].updatedAt = now;\n } else {\n manifest.files[filePath] = {\n version,\n installedAt: now,\n updatedAt: now\n };\n }\n\n this.saveLibraryManifest(manifest);\n }\n\n public getInstalledFileVersion(filePath: string): string | undefined {\n const manifest = this.getLibraryManifest();\n return manifest.files[filePath]?.version;\n }\n\n public markLibrarySynced(): void {\n const manifest = this.getLibraryManifest();\n manifest.lastSyncAt = new Date().toISOString();\n this.saveLibraryManifest(manifest);\n }\n}","import { homedir } from 'os';\nimport { join } from 'path';\n\n// API endpoints\nexport const API_BASE_URL = process.env.BJS_API_URL || 'https://babylonjsmarket.com';\nexport const DEV_API_URL = process.env.BJS_DEV_API_URL || 'https://dev.babylonjsmarket.com';\n\n// Default to production. Opt into the dev backend with BJS_ENV=development\n// (or override the host entirely with BJS_API_URL / BJS_DEV_API_URL).\nexport const USE_DEV = process.env.BJS_ENV === 'development';\nexport const API_URL = USE_DEV ? DEV_API_URL : API_BASE_URL;\n\n// Auth endpoints\nexport const AUTH_DEVICE_CODE_URL = `${API_URL}/api/auth/device/code`;\nexport const AUTH_DEVICE_TOKEN_URL = `${API_URL}/api/auth/device/token`;\nexport const AUTH_USER_INFO_URL = `${API_URL}/api/auth/user`;\nexport const AUTH_COURSES_URL = `${API_URL}/api/auth/courses`;\n\n// Storage\nexport const CONFIG_DIR = join(homedir(), '.bjs');\nexport const CONFIG_FILE = join(CONFIG_DIR, 'config.json');\nexport const TOKEN_SERVICE = 'bjs-cli';\nexport const TOKEN_ACCOUNT = 'bjsmarket';\n\n// OAuth Device Flow\nexport const CLIENT_ID = 'bjs-cli';\nexport const DEVICE_POLL_INTERVAL = 5000; // 5 seconds\nexport const DEVICE_TIMEOUT = 900000; // 15 minutes","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { AuthManager } from '../utils/auth.js';\nimport { applyTheme } from '../utils/theme-colors.js';\n\nexport const logoutCommand = new Command('logout')\n .description('Log out from BabylonJS Market')\n .action(async () => {\n const authManager = new AuthManager();\n const theme = applyTheme();\n \n if (!authManager.isAuthenticated()) {\n console.log(theme.warning('You are not logged in.'));\n return;\n }\n \n const user = authManager.getUser();\n authManager.clearAuth();\n \n console.log(theme.success('Successfully logged out'));\n if (user?.email) {\n console.log(theme.dim(`Was logged in as: ${user.email}`));\n }\n });","import chalk from 'chalk';\nimport { AuthManager } from './auth.js';\n\nexport type ThemeName = 'classic' | 'desert' | 'matrix' | 'commando' | 'sandiego' | 'ed209';\n\ninterface ThemeColors {\n primary: (text: string) => string;\n secondary: (text: string) => string;\n accent: (text: string) => string;\n success: (text: string) => string;\n error: (text: string) => string;\n warning: (text: string) => string;\n info: (text: string) => string;\n dim: (text: string) => string;\n}\n\nconst themes: Record<ThemeName, ThemeColors> = {\n classic: {\n primary: (text) => chalk.cyan(text),\n secondary: (text) => chalk.yellow(text),\n accent: (text) => chalk.magenta(text),\n success: (text) => chalk.green(text),\n error: (text) => chalk.red(text),\n warning: (text) => chalk.yellow(text),\n info: (text) => chalk.blue(text),\n dim: (text) => chalk.gray(text)\n },\n desert: {\n primary: (text) => chalk.yellow(text),\n secondary: (text) => chalk.red(text),\n accent: (text) => chalk.green(text),\n success: (text) => chalk.green(text),\n error: (text) => chalk.red(text),\n warning: (text) => chalk.yellow(text),\n info: (text) => chalk.cyan(text),\n dim: (text) => chalk.gray(text)\n },\n matrix: {\n primary: (text) => chalk.green(text),\n secondary: (text) => chalk.greenBright(text),\n accent: (text) => chalk.cyan(text),\n success: (text) => chalk.greenBright(text),\n error: (text) => chalk.red(text),\n warning: (text) => chalk.yellow(text),\n info: (text) => chalk.green(text),\n dim: (text) => chalk.gray(text)\n },\n commando: {\n primary: (text) => chalk.rgb(107, 142, 35)(text), // Olive green\n secondary: (text) => chalk.rgb(139, 90, 43)(text), // Brown\n accent: (text) => chalk.rgb(47, 79, 47)(text), // Dark green\n success: (text) => chalk.green(text),\n error: (text) => chalk.rgb(139, 0, 0)(text), // Dark red\n warning: (text) => chalk.rgb(189, 183, 107)(text), // Khaki\n info: (text) => chalk.rgb(85, 107, 47)(text), // Dark olive green\n dim: (text) => chalk.gray(text)\n },\n sandiego: {\n primary: (text) => chalk.red(text),\n secondary: (text) => chalk.yellow(text),\n accent: (text) => chalk.white(text),\n success: (text) => chalk.green(text),\n error: (text) => chalk.redBright(text),\n warning: (text) => chalk.yellowBright(text),\n info: (text) => chalk.blue(text),\n dim: (text) => chalk.gray(text)\n },\n ed209: {\n primary: (text) => chalk.rgb(192, 192, 192)(text), // Silver\n secondary: (text) => chalk.rgb(135, 206, 235)(text), // Sky blue\n accent: (text) => chalk.rgb(105, 105, 105)(text), // Dim gray\n success: (text) => chalk.greenBright(text),\n error: (text) => chalk.redBright(text),\n warning: (text) => chalk.rgb(255, 140, 0)(text), // Dark orange\n info: (text) => chalk.cyanBright(text),\n dim: (text) => chalk.gray(text)\n }\n};\n\nexport function getThemeColors(themeName?: ThemeName): ThemeColors {\n // Try to get theme from preferences if not specified\n if (!themeName) {\n const authManager = new AuthManager();\n const prefs = authManager.getPreferences();\n themeName = (prefs?.theme as ThemeName) || 'classic';\n }\n \n return themes[themeName] || themes.classic;\n}\n\nexport function applyTheme(themeName?: ThemeName) {\n const theme = getThemeColors(themeName);\n \n return {\n ...theme,\n // Add some convenience methods\n header: (text: string) => theme.primary(chalk.bold(text)),\n subheader: (text: string) => theme.secondary(chalk.bold(text)),\n highlight: (text: string) => theme.accent(chalk.bold(text)),\n code: (text: string) => theme.dim(`\\`${text}\\``),\n link: (text: string) => theme.info(chalk.underline(text))\n };\n}","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { AuthManager } from '../utils/auth.js';\nimport { applyTheme } from '../utils/theme-colors.js';\n\nexport const whoamiCommand = new Command('whoami')\n .description('Display current authenticated user')\n .action(async () => {\n const authManager = new AuthManager();\n const theme = applyTheme();\n \n if (!authManager.isAuthenticated()) {\n console.log(theme.warning('Not logged in.'));\n console.log(theme.dim('Run \"bjs login\" to authenticate.'));\n return;\n }\n \n const user = authManager.getUser();\n if (user) {\n console.log(theme.info('Logged in as:'));\n console.log(theme.primary(` Email: ${user.email}`));\n if (user.name) {\n console.log(theme.primary(` Name: ${user.name}`));\n }\n if (user.id) {\n console.log(theme.dim(` ID: ${user.id}`));\n }\n } else {\n console.log(theme.warning('Logged in but user information not available.'));\n }\n });","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport { AuthManager } from '../utils/auth.js';\nimport { applyTheme } from '../utils/theme-colors.js';\nimport { API_URL } from '../config/constants.js';\nimport { createWriteStream, existsSync, mkdirSync } from 'fs';\nimport { pipeline } from 'stream/promises';\nimport fetch from 'node-fetch';\nimport path from 'path';\n\nexport const downloadCommand = new Command('download')\n .description('Download assets from BabylonJS Market')\n .argument('<asset-key>', 'Asset key to download')\n .option('-o, --output <path>', 'Output directory (default: current directory)')\n .action(async (assetKey: string, options) => {\n const authManager = new AuthManager();\n const theme = applyTheme();\n \n if (!authManager.isAuthenticated()) {\n console.log(theme.error('You must be logged in to download assets.'));\n console.log(theme.dim('Run \"bjs login\" to authenticate.'));\n process.exit(1);\n }\n \n const spinner = ora('Requesting download token...').start();\n \n try {\n // Step 1: Request download token from the correct endpoint\n const tokenResponse = await authManager.makeAuthenticatedRequest(\n `${API_URL}/api/assets/download?key=${encodeURIComponent(assetKey)}`\n );\n \n if (!tokenResponse.ok) {\n if (tokenResponse.status === 429) {\n const errorData = await tokenResponse.json() as any;\n spinner.fail(theme.warning(`Rate limited: ${errorData.error}`));\n console.log(theme.dim('Please wait before trying again.'));\n process.exit(1);\n }\n \n const error = await tokenResponse.text();\n throw new Error(`Failed to get download token: ${error}`);\n }\n \n const tokenData = await tokenResponse.json() as any;\n \n if (!tokenData.success) {\n throw new Error(tokenData.error || 'Failed to get download URL');\n }\n \n const { fileName, downloadUrl, expiresInSeconds } = tokenData.data;\n spinner.text = `Downloading ${fileName} (token expires in ${expiresInSeconds} seconds)...`;\n\n // Step 2: Download the file immediately using the token URL\n // Handle different URL formats from the server\n let fullDownloadUrl = downloadUrl;\n\n if (downloadUrl.includes('localhost:3333')) {\n // Replace localhost URL with actual API URL\n // The server returns /assets/retrieve but it should be /api/assets/retrieve\n fullDownloadUrl = downloadUrl\n .replace('http://localhost:3333/assets/retrieve', `${API_URL}/api/assets/retrieve`)\n .replace('https://localhost:3333/assets/retrieve', `${API_URL}/api/assets/retrieve`)\n .replace('http://localhost:3333', API_URL)\n .replace('https://localhost:3333', API_URL);\n } else if (downloadUrl.startsWith('http://') || downloadUrl.startsWith('https://')) {\n // It's already a full URL, use as-is\n fullDownloadUrl = downloadUrl;\n } else if (downloadUrl.startsWith('/')) {\n // Relative path - prepend base URL\n fullDownloadUrl = `${API_URL}${downloadUrl}`;\n } else {\n // Assume it's a relative path without leading slash\n fullDownloadUrl = `${API_URL}/${downloadUrl}`;\n }\n\n const fileResponse = await fetch(fullDownloadUrl);\n \n if (!fileResponse.ok) {\n throw new Error(`Failed to download file: ${fileResponse.status}`);\n }\n \n // Determine output path\n const outputDir = options.output || process.cwd();\n\n // Create output directory if it doesn't exist\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n }\n\n const outputPath = path.join(outputDir, fileName);\n\n // Save to file with progress tracking\n const contentLength = fileResponse.headers.get('content-length');\n const total = contentLength ? parseInt(contentLength, 10) : 0;\n let loaded = 0;\n \n const fileStream = createWriteStream(outputPath);\n \n if (total > 0) {\n // Track progress if we have content length\n const reader = fileResponse.body;\n reader?.on('data', (chunk: Buffer) => {\n loaded += chunk.length;\n const percentage = Math.round((loaded / total) * 100);\n spinner.text = `Downloading ${fileName}: ${percentage}%`;\n });\n }\n \n await pipeline(fileResponse.body as any, fileStream);\n \n spinner.succeed(theme.success(`Downloaded ${fileName} to ${outputPath}`));\n \n } catch (error: any) {\n spinner.fail(theme.error('Download failed'));\n console.error(theme.error('Error:'), error.message);\n process.exit(1);\n }\n });","import { Command } from 'commander';\nimport terminalKit from 'terminal-kit';\nimport { AuthManager } from '../utils/auth.js';\nimport {\n API_URL,\n AUTH_DEVICE_CODE_URL,\n AUTH_DEVICE_TOKEN_URL,\n AUTH_USER_INFO_URL,\n CLIENT_ID,\n DEVICE_TIMEOUT\n} from '../config/constants.js';\nimport { BufferedBBS, Theme } from '../utils/buffered-bbs.js';\nimport { CourseDetailViewer } from '../utils/course-detail-viewer.js';\nimport type { CourseDetail } from '../utils/course-detail/types.js';\nimport fs from 'fs';\nimport path from 'path';\nimport { homedir } from 'os';\nimport process from 'process';\nimport { AssetDownloader } from '../utils/asset-downloader.js';\nimport { scanForProjects, Project } from '../utils/project-scanner.js';\nimport {\n getAvailableComponents, installComponent, ComponentInfo, COMPONENT_CATALOG,\n getAvailableGameModes, installGameMode, GameModeInfo, getGameModeCatalog,\n getInstalledGameModes, getProjectScenes, createScene,\n initializeLibrary, isLibraryInitialized, migrateFromArcadeRef,\n fetchLibraryManifest, syncLibrary, compareManifests, getLibrarySyncStatus,\n ServerManifest\n} from '../utils/component-catalog.js';\nimport open from 'open';\nimport fetch from 'node-fetch';\nimport {\n BbsState,\n Action,\n Course,\n Toy,\n Download,\n ProjectLike,\n THEMES,\n createInitialState,\n reduce,\n} from './bbs/state.js';\nimport { keyToAction, Effect } from './bbs/keymap.js';\nimport {\n buildHome,\n buildCourses,\n buildToys,\n buildDownloads,\n buildProjects,\n buildSettings,\n markedCount,\n type Dimensions,\n} from './bbs/viewmodel.js';\nimport {\n renderHome,\n renderCourses,\n renderToys,\n renderDownloads,\n renderProjects,\n renderSettings,\n renderFooter,\n type RenderContext,\n} from './bbs/render.js';\n\nconst term = terminalKit.terminal;\nconst { ScreenBuffer } = terminalKit;\n\ninterface DeviceCodeResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n}\n\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n token_type: string;\n}\n\n// Cleanup function to restore terminal state\nfunction cleanupTerminal() {\n try {\n term.clear();\n term.hideCursor(false);\n term.grabInput(false);\n } catch (e) {\n // Ignore cleanup errors\n }\n}\n\n// Fatal error handler - cleans up terminal and prints error\nfunction fatalError(error: Error | string, context?: string) {\n cleanupTerminal();\n console.error('\\n\\x1b[31m═══ BBS FATAL ERROR ═══\\x1b[0m');\n if (context) {\n console.error(`\\x1b[33mContext:\\x1b[0m ${context}`);\n }\n console.error(`\\x1b[33mError:\\x1b[0m ${typeof error === 'string' ? error : error.message}`);\n if (typeof error === 'object' && error.stack) {\n console.error(`\\x1b[90m${error.stack}\\x1b[0m`);\n }\n process.exit(1);\n}\n\nexport const bbsCommand = new Command('bbs')\n .description('BabylonJS Market BBS - Browse courses and assets in retro style')\n .option('-t, --theme <theme>', 'Color theme (classic, desert, matrix, commando, sandiego, ed209)', 'classic')\n .option('--no-animations', 'Disable animations')\n .option('--no-mouse', 'Disable mouse support')\n .option('--no-browser', 'Don\\'t open browser automatically during authentication')\n .option('--saveTo <path>', 'Directory to save downloaded files (default: current directory)')\n .action(async (options) => {\n // Global error handlers to catch unhandled errors and clean up terminal\n process.on('uncaughtException', (error) => {\n fatalError(error, 'Uncaught Exception');\n });\n process.on('unhandledRejection', (reason) => {\n fatalError(reason instanceof Error ? reason : new Error(String(reason)), 'Unhandled Promise Rejection');\n });\n\n const authManager = new AuthManager();\n\n // Capture the initial working directory for downloads\n const downloadDirectory = options.saveTo ? path.resolve(options.saveTo) : process.cwd();\n\n // Load saved preferences even if not authenticated\n const savedPrefs = authManager.getPreferences();\n if (savedPrefs && savedPrefs.theme && THEMES.includes(savedPrefs.theme as Theme)) {\n options.theme = savedPrefs.theme;\n }\n if (savedPrefs && savedPrefs.animations !== undefined) {\n options.animations = savedPrefs.animations;\n }\n if (savedPrefs && savedPrefs.mouse !== undefined) {\n options.mouse = savedPrefs.mouse;\n }\n\n // Setup terminal\n term.clear();\n term.hideCursor();\n term.grabInput({ mouse: options.mouse ? 'button' : undefined });\n\n // Create main screen buffer with delta optimization\n const termWidth = Math.min(term.width || 80, 500); // Cap at reasonable max\n const termHeight = Math.min(term.height || 24, 100);\n\n let screenBuffer = new ScreenBuffer({\n dst: term,\n width: termWidth,\n height: termHeight,\n x: 1,\n y: 1,\n noFill: true\n });\n\n // Create back buffer for double buffering\n let backBuffer = new ScreenBuffer({\n width: termWidth,\n height: termHeight,\n dst: term,\n noFill: true\n });\n\n // Clear both buffers initially\n backBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n screenBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n screenBuffer.draw();\n\n // Create BBS component with back buffer\n let bbs = new BufferedBBS(backBuffer, options.theme as Theme, options.animations);\n\n // Store original console.error\n const originalConsoleError = console.error;\n\n // Redirect console.error to prevent terminal corruption\n const errorLogs: string[] = [];\n console.error = (...args: any[]) => {\n // Store errors but don't print to stderr\n errorLogs.push(args.map(a => String(a)).join(' '));\n };\n\n // Check authentication - if not authenticated, show auth flow with BBS UI\n if (!authManager.isAuthenticated()) {\n try {\n // Show initial loading animation\n if (options.animations) {\n await bbs.showLoadingAnimation('Connecting to BabylonJS Market BBS...', 1000);\n }\n\n // Clear screen for auth popup\n backBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n\n // Draw BBS header even during auth\n bbs.drawBBSHeader('GUEST', 'AUTHENTICATION', 0);\n\n // Step 1: Request device code\n bbs.showPollingStatus('checking', 'Requesting authentication code...');\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n\n const deviceCodeResponse = await fetch(AUTH_DEVICE_CODE_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ client_id: CLIENT_ID })\n });\n\n if (!deviceCodeResponse.ok) {\n const error = await deviceCodeResponse.text();\n throw new Error(`Failed to get device code: ${error}`);\n }\n\n const deviceData = await deviceCodeResponse.json() as DeviceCodeResponse;\n\n // Step 2: Display device code in BBS-style popup\n backBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n bbs.drawBBSHeader('GUEST', 'AUTHENTICATION', 0);\n bbs.showAuthPopup(deviceData.user_code, deviceData.verification_uri);\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n\n // Step 3: Open browser if enabled\n if (options.browser !== false) {\n const urlToOpen = deviceData.verification_uri_complete || deviceData.verification_uri;\n await open(urlToOpen);\n }\n\n // Step 4: Poll for token with BBS-style status updates\n const startTime = Date.now();\n const pollInterval = (deviceData.interval || 5) * 1000;\n let authenticated = false;\n\n while (Date.now() - startTime < DEVICE_TIMEOUT && !authenticated) {\n await new Promise(resolve => setTimeout(resolve, pollInterval));\n\n // Update polling status\n bbs.showPollingStatus('checking', 'Checking authentication status...');\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n\n const tokenResponse = await fetch(AUTH_DEVICE_TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n client_id: CLIENT_ID,\n device_code: deviceData.device_code,\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code'\n })\n });\n\n if (tokenResponse.ok) {\n const tokenData = await tokenResponse.json() as TokenResponse;\n\n // Save tokens\n authManager.saveTokens(\n tokenData.access_token,\n tokenData.refresh_token,\n tokenData.expires_in\n );\n\n // Get user info\n const userResponse = await authManager.makeAuthenticatedRequest(AUTH_USER_INFO_URL);\n if (userResponse.ok) {\n const userData = await userResponse.json() as any;\n authManager.saveUser({\n id: userData.id,\n email: userData.email,\n name: userData.name\n });\n }\n\n // Show success\n bbs.showPollingStatus('success', 'Authentication successful!');\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n\n authenticated = true;\n\n // Brief pause to show success message\n await new Promise(resolve => setTimeout(resolve, 1500));\n\n // Transition animation\n if (options.animations) {\n const theme = bbs.getTheme();\n await bbs.transition(theme.animation);\n }\n\n break;\n }\n\n const errorData = await tokenResponse.json() as any;\n\n if (errorData.error === 'authorization_pending') {\n // Still waiting for user to authorize\n bbs.showPollingStatus('waiting', 'Waiting for authorization...');\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n } else if (errorData.error === 'slow_down') {\n // Too many requests, slow down\n await new Promise(resolve => setTimeout(resolve, 5000));\n } else if (errorData.error === 'expired_token') {\n throw new Error('Authentication timed out. Please try again.');\n } else if (errorData.error === 'access_denied') {\n throw new Error('Authentication was denied.');\n } else {\n throw new Error(`Authentication failed: ${errorData.error}`);\n }\n }\n\n if (!authenticated) {\n throw new Error('Authentication timed out. Please try again.');\n }\n\n } catch (error: any) {\n // Show error in BBS style\n bbs.showErrorPopup(error, 'Authentication Failed');\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n\n // Wait for user to press a key\n await new Promise<void>((resolve) => {\n term.once('key', () => resolve());\n });\n\n // Cleanup and exit\n console.error = originalConsoleError;\n term.clear();\n term.hideCursor(false);\n term.grabInput(false);\n term.processExit(1);\n return;\n }\n }\n\n const user = authManager.getUser();\n\n try {\n // Terminal, buffers, and BBS component are already set up above\n\n fs.appendFileSync('/tmp/bbs-debug.log', `${new Date().toISOString()} BBS starting - animations: ${options.animations}\\n`);\n // Show loading animation with theme-specific transition\n if (options.animations) {\n await bbs.showLoadingAnimation('Dialing BabylonJS Market BBS...', 1500);\n const theme = bbs.getTheme();\n await bbs.transition(theme.animation);\n } else {\n // Show static loading message\n bbs.put(2, 2, 'Connecting to BabylonJS Market BBS...', bbs.getTheme().primary, true);\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n }\n\n // Fetch ALL courses (both owned and unowned) from authenticated endpoint\n fs.appendFileSync('/tmp/bbs-debug.log', `${new Date().toISOString()} Fetching courses from ${API_URL}\\n`);\n let allCoursesResponse;\n try {\n allCoursesResponse = await authManager.makeAuthenticatedRequest(`${API_URL}/api/auth/courses/all`);\n fs.appendFileSync('/tmp/bbs-debug.log', `${new Date().toISOString()} Courses fetched OK\\n`);\n } catch (fetchError: any) {\n throw new Error(`Network error: ${fetchError.message}`);\n }\n\n if (!allCoursesResponse.ok) {\n const errorText = await allCoursesResponse.text();\n throw new Error(`Failed to fetch courses (${allCoursesResponse.status}): ${errorText}`);\n }\n\n const allCoursesData = await allCoursesResponse.json() as any;\n // The /api/auth/courses/all endpoint already includes ownership status\n const courses: Course[] = allCoursesData.courses || [];\n\n // Fetch downloads (course assets)\n let downloads: Download[] = [];\n try {\n const downloadsResponse = await authManager.makeAuthenticatedRequest(`${API_URL}/api/auth/downloads`);\n if (downloadsResponse.ok) {\n const downloadsData = await downloadsResponse.json() as any;\n downloads = downloadsData.downloads || [];\n }\n } catch (fetchError: any) {\n console.error(\"Failed to fetch downloads:\", fetchError.message);\n }\n\n // Scan for projects in the configured projects directory (with timeout)\n let scannedProjects: Project[] = [];\n const configuredProjectsDir = authManager.getProjectsDirectory();\n\n if (configuredProjectsDir && fs.existsSync(configuredProjectsDir)) {\n try {\n // Add 3 second timeout to prevent hangs\n const scanPromise = scanForProjects(configuredProjectsDir, 2);\n const timeoutPromise = new Promise<Project[]>((_, reject) =>\n setTimeout(() => reject(new Error('Project scan timed out')), 3000)\n );\n scannedProjects = await Promise.race([scanPromise, timeoutPromise]);\n } catch (scanError: any) {\n // Silently fail - projects will just be empty\n }\n }\n // If no projects directory is configured, projects will be empty\n\n // Dummy toys data with asset keys for testing\n const toys: Toy[] = [\n { id: 1, name: 'Spaceship Fighter', size: '2.4 MB', downloads: 1234, filetype: '.glb', modeltype: 'Arcade', assetKey: 'spaceship-fighter' },\n { id: 2, name: 'Robot Walker', size: '3.1 MB', downloads: 892, filetype: '.glb', modeltype: 'Rigged', assetKey: 'robot-walker' },\n { id: 3, name: 'City Buildings Pack', size: '15.2 MB', downloads: 3421, filetype: '.zip', modeltype: 'Static', assetKey: 'city-buildings' },\n { id: 4, name: 'Vehicle Collection', size: '8.7 MB', downloads: 2103, filetype: '.zip', modeltype: 'Static', assetKey: 'vehicle-collection' },\n { id: 5, name: 'Character Animations', size: '5.5 MB', downloads: 1567, filetype: '.glb', modeltype: 'Animated', assetKey: 'character-anims' }\n ];\n\n // ── Single source of truth: the pure BBS state. ──\n let state: BbsState = createInitialState({\n courses,\n toys,\n downloads,\n projects: scannedProjects as ProjectLike[],\n theme: options.theme as Theme,\n animations: !!options.animations,\n mouse: !!options.mouse,\n });\n\n // Impure handles that live alongside (but outside) the pure state.\n let courseDetailViewer: CourseDetailViewer | null = null;\n let currentCourseDetail: CourseDetail | null = null;\n let actionInProgress = false; // Prevent multiple actions\n let lastActionTime = 0; // Track last action time\n let currentError: Error | null = null; // Store current error\n let serverManifest: ServerManifest | null = null;\n\n // Dispatch a pure action into the state (does not render).\n const dispatch = (action: Action) => {\n state = reduce(state, action);\n };\n\n // Status display helper function (moved to outer scope)\n const statusY = term.height - 2;\n const showStatus = (msg: string, color: string = 'gray') => {\n term.moveTo(1, statusY);\n term.eraseLine();\n (term as any)[color](msg);\n };\n\n // Debug log file for tracking hangs\n const debugLog = (msg: string) => {\n fs.appendFileSync('/tmp/bbs-debug.log', `${new Date().toISOString()} ${msg}\\n`);\n };\n\n // Build the render context from the (impure) AuthManager + catalogs.\n const buildRenderContext = (): RenderContext => {\n const selectedProject = state.projects[state.projectsSelectedIndex];\n let syncUpdates: number | undefined;\n if (serverManifest) {\n const localManifest = authManager.getLibraryManifest();\n const comparison = compareManifests(serverManifest, localManifest);\n syncUpdates = comparison.toInstall.length + comparison.toUpdate.length;\n }\n return {\n componentCatalogLength: COMPONENT_CATALOG.length,\n gameModeCatalogLength: getGameModeCatalog().length,\n projectScenesCount: selectedProject ? getProjectScenes(selectedProject.path).length : 0,\n syncUpdates,\n serverManifest: serverManifest\n ? { unlockedFiles: serverManifest.unlockedFiles, totalFiles: serverManifest.totalFiles }\n : null,\n };\n };\n\n // Main render function using double buffering\n const render = async () => {\n try {\n debugLog(`render() start - currentView: ${state.currentView}`);\n // If in course detail view, let the viewer handle rendering\n if (state.currentView === 'courseDetail' && courseDetailViewer) {\n return;\n }\n\n // Clear back buffer\n backBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n\n const dim: Dimensions = { width: term.width, height: term.height };\n\n // Draw header with marked count\n bbs.drawBBSHeader(user?.email || user?.name || 'Guest', state.currentView.toUpperCase(), markedCount(state));\n\n // Keep the projects library data fresh for the selected project (the\n // original render() recomputed these inline each frame).\n if (state.currentView === 'projects' && state.projects.length > 0) {\n const selectedProject = state.projects[state.projectsSelectedIndex];\n if (selectedProject) {\n state = reduce(state, {\n type: 'SetLibraryData',\n components: getAvailableComponents(selectedProject.path),\n gameModes: getAvailableGameModes(selectedProject.path),\n installed: getInstalledGameModes(selectedProject.path),\n });\n }\n }\n\n const ctx = buildRenderContext();\n\n if (state.currentView === 'home') {\n renderHome(bbs, buildHome(state, dim));\n } else if (state.currentView === 'courses') {\n renderCourses(bbs, buildCourses(state, dim));\n } else if (state.currentView === 'toys') {\n renderToys(bbs, buildToys(state, dim));\n } else if (state.currentView === 'projects') {\n const projDir = authManager.getProjectsDirectory();\n renderProjects(bbs, buildProjects(state, dim, { projectsDir: projDir }), state, dim, ctx);\n } else if (state.currentView === 'downloads') {\n renderDownloads(bbs, buildDownloads(state, dim), dim);\n } else if (state.currentView === 'settings') {\n const settingsModel = buildSettings(state, {\n projectsDir: authManager.getProjectsDirectory(),\n libraryPath: authManager.getLibraryPath(),\n libraryInitialized: isLibraryInitialized(),\n lastSyncAt: (() => {\n const localStatus = getLibrarySyncStatus();\n return localStatus.lastSyncAt ? new Date(localStatus.lastSyncAt) : null;\n })(),\n });\n renderSettings(bbs, settingsModel, dim, ctx);\n } else if (state.currentView === 'courseDetail') {\n // Course detail view handles its own navigation display\n return;\n }\n\n // Navigation footer\n renderFooter(bbs, state, dim);\n\n // CRITICAL: Draw back buffer to screen buffer, then to terminal\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true }); // Only update changed cells\n\n // If there's an error popup, draw it on top\n if (state.errorPopupVisible && currentError) {\n bbs.showErrorPopup(currentError, 'BBS Error');\n backBuffer.draw({ dst: screenBuffer });\n screenBuffer.draw({ delta: true });\n }\n } catch (renderError: any) {\n // Handle render errors without printing to stderr\n errorLogs.push(`Render error: ${renderError.message}`);\n currentError = renderError;\n state = reduce(state, { type: 'ShowError' });\n }\n };\n\n // Initial render\n debugLog('About to call initial render()');\n await render();\n debugLog('Initial render() complete');\n\n // Update the display every second to keep the timer fresh\n const timerInterval = setInterval(async () => {\n await render();\n }, 1000);\n\n // Handle terminal resize\n term.on('resize', async (width: number, height: number) => {\n // Recreate buffers with new size - cap at reasonable max\n const newWidth = Math.min(width || term.width || 80, 500);\n const newHeight = Math.min(height || term.height || 24, 100);\n\n screenBuffer = new ScreenBuffer({\n dst: term,\n width: newWidth,\n height: newHeight,\n x: 1,\n y: 1,\n noFill: true\n });\n\n backBuffer = new ScreenBuffer({\n width: newWidth,\n height: newHeight,\n dst: term,\n noFill: true\n });\n\n // Update course detail viewer if it exists\n if (courseDetailViewer) {\n courseDetailViewer.resize(newWidth, newHeight);\n }\n\n // Update BBS with new buffer\n bbs = new BufferedBBS(backBuffer, state.theme, state.animations);\n\n await render();\n });\n\n // Asset downloader instance\n const assetDownloader = new AssetDownloader(authManager);\n\n // Download function - shows status without blocking\n const downloadAsset = async (item: Course | Toy | Download, type: 'course' | 'toy' | 'download') => {\n let name: string;\n let assetKey: string;\n let fileName: string;\n\n if (type === 'download') {\n const dl = item as Download;\n name = dl.fileName;\n assetKey = dl.assetKey;\n fileName = dl.fileName;\n } else if (type === 'course') {\n const course = item as Course;\n name = course.title;\n assetKey = course.assetKey || `course-${course.slug}`;\n fileName = assetKey + '.zip';\n } else {\n const toy = item as Toy;\n name = toy.name;\n assetKey = toy.assetKey || toy.name.toLowerCase().replace(/\\s+/g, '-');\n fileName = assetKey + '.glb';\n }\n\n const outputPath = path.join(downloadDirectory, fileName);\n\n try {\n // Ensure download directory exists\n if (!fs.existsSync(downloadDirectory)) {\n fs.mkdirSync(downloadDirectory, { recursive: true });\n }\n\n showStatus(`Downloading ${name}...`, 'yellow');\n\n const success = await assetDownloader.downloadAsset(\n assetKey,\n outputPath,\n (progress) => {\n showStatus(`Downloading ${name}: ${progress.percentage}%`, 'yellow');\n }\n );\n\n if (success) {\n showStatus(`✓ Downloaded ${name} to ${outputPath}`, 'green');\n } else {\n showStatus(`✗ Failed to download ${name}`, 'red');\n }\n } catch (error: any) {\n showStatus(`✗ Error: ${error.message}`, 'red');\n }\n\n // Clear status after 3 seconds\n setTimeout(() => {\n term.moveTo(1, statusY);\n term.eraseLine();\n }, 3000);\n };\n\n // ── Path autocomplete (shared by projectsDir + libraryPath editing). ──\n const autocompletePath = (input: string): string => {\n try {\n if (!input || input.trim() === '') {\n return homedir() + '/';\n }\n const dir = path.dirname(input);\n const base = path.basename(input);\n if (dir && fs.existsSync(dir)) {\n const entries = fs.readdirSync(dir);\n const matches = entries\n .filter(e => e.toLowerCase().startsWith(base.toLowerCase()))\n .filter(e => {\n try {\n return fs.statSync(path.join(dir, e)).isDirectory();\n } catch {\n return false;\n }\n });\n if (matches.length === 1) {\n return path.join(dir, matches[0]) + '/';\n } else if (matches.length > 1) {\n const commonPrefix = matches.reduce((prefix, match) => {\n let i = 0;\n while (i < prefix.length && i < match.length && prefix[i].toLowerCase() === match[i].toLowerCase()) {\n i++;\n }\n return match.slice(0, i);\n });\n if (commonPrefix.length > base.length) {\n return path.join(dir, commonPrefix);\n }\n }\n } else if (input.startsWith('~')) {\n return homedir() + input.slice(1);\n }\n } catch (err) {\n // Ignore autocomplete errors\n }\n return input;\n };\n\n // ── Effect runner: executes the side-effecting intents from keymap. ──\n const runEffect = async (effect: Effect): Promise<void> => {\n switch (effect.type) {\n case 'CommitProjectsDir': {\n if (state.projectsDirInput.trim()) {\n const resolvedPath = path.resolve(state.projectsDirInput.trim());\n if (fs.existsSync(resolvedPath)) {\n authManager.setProjectsDirectory(resolvedPath);\n dispatch({ type: 'SetProjectsDirResult', success: '✓ Saved! Scanning...' });\n await render();\n\n const newProjects = await scanForProjects(resolvedPath, 2);\n state = { ...state, projects: newProjects as ProjectLike[], projectsSelectedIndex: 0, editingProjectsDir: false, projectsDirInput: '' };\n dispatch({\n type: 'SetProjectsDirResult',\n success: `✓ Found ${state.projects.length} project${state.projects.length === 1 ? '' : 's'}`,\n });\n\n setTimeout(async () => {\n dispatch({ type: 'SetProjectsDirResult', success: '' });\n await render();\n }, 2000);\n } else {\n dispatch({ type: 'SetProjectsDirResult', error: '✗ Directory not found' });\n }\n }\n await render();\n break;\n }\n\n case 'AutocompleteProjectsDir':\n dispatch({ type: 'InputSet', value: autocompletePath(state.projectsDirInput) });\n await render();\n break;\n\n case 'CommitLibraryPath': {\n if (state.libraryPathInput.trim()) {\n const resolvedPath = path.resolve(state.libraryPathInput.trim());\n authManager.setLibraryPath(resolvedPath);\n\n if (!fs.existsSync(path.join(resolvedPath, 'Components'))) {\n const result = await initializeLibrary(resolvedPath);\n state = { ...state, libraryPathSuccess: result.success ? '✓ Library initialized!' : result.message };\n } else {\n state = { ...state, libraryPathSuccess: '✓ Saved!' };\n }\n state = { ...state, libraryPathError: '', editingLibraryPath: false, libraryPathInput: '' };\n\n setTimeout(async () => {\n dispatch({ type: 'SetLibraryPathResult', success: '' });\n await render();\n }, 2000);\n }\n await render();\n break;\n }\n\n case 'AutocompleteLibraryPath':\n dispatch({ type: 'InputSet', value: autocompletePath(state.libraryPathInput) });\n await render();\n break;\n\n case 'InstallComponent': {\n const comp = state.availableComponents[state.componentSelectedIndex];\n const project = state.projects[state.projectsSelectedIndex];\n if (comp && project) {\n const result = await installComponent(comp.name, project.path);\n dispatch({ type: 'SetComponentInstallResult', message: result.message, success: result.success });\n if (result.success) {\n const projDir = authManager.getProjectsDirectory();\n if (projDir) {\n state = { ...state, projects: (await scanForProjects(projDir, 2)) as ProjectLike[] };\n }\n dispatch({ type: 'SetAvailableComponents', components: getAvailableComponents(project.path) });\n }\n await render();\n }\n break;\n }\n\n case 'InstallGameMode': {\n const mode = state.availableGameModes[state.gameModeSelectedIndex];\n const project = state.projects[state.projectsSelectedIndex];\n if (mode && project) {\n const result = await installGameMode(mode.name, project.path);\n dispatch({ type: 'SetGameModeInstallResult', message: result.message, success: result.success });\n if (result.success) {\n dispatch({ type: 'SetAvailableGameModes', gameModes: getAvailableGameModes(project.path) });\n dispatch({ type: 'SetInstalledGameModes', gameModes: getInstalledGameModes(project.path) });\n }\n await render();\n }\n break;\n }\n\n case 'CreateScene': {\n const project = state.projects[state.projectsSelectedIndex];\n if (state.sceneNameInput.trim() && state.installedGameModes.length > 0 && project) {\n const gameMode = state.installedGameModes[state.sceneGameModeIndex] || state.installedGameModes[0];\n const result = await createScene(project.path, gameMode, state.sceneNameInput.trim());\n dispatch({ type: 'SetSceneCreatorResult', message: result.message, success: result.success });\n if (result.success) {\n dispatch({ type: 'ClearSceneNameInput' });\n setTimeout(async () => {\n if (result.path) {\n const editor = process.env.EDITOR || 'code';\n const { spawn } = await import('child_process');\n const editorProcess = spawn(editor, [result.path], { detached: true, stdio: 'ignore' });\n editorProcess.unref();\n }\n }, 500);\n }\n await render();\n } else if (!state.sceneNameInput.trim()) {\n dispatch({ type: 'SetSceneCreatorResult', message: 'Please enter a scene name', success: false });\n await render();\n }\n break;\n }\n\n case 'ActivateSettings': {\n // Debounce only applies to the ENTER path historically; SPACE path\n // had no debounce. Preserve that distinction.\n const idx = effect.index;\n if (!effect.viaSpace) {\n const now = Date.now();\n if (actionInProgress || (now - lastActionTime) < 500) break;\n lastActionTime = now;\n }\n\n if (effect.viaSpace) {\n // Space only handles theme/anim/mouse rows (0..7).\n if (idx < 6) {\n const theme = THEMES[idx];\n dispatch({ type: 'SetTheme', theme });\n bbs.setTheme(theme);\n options.theme = theme;\n authManager.savePreferences({ theme });\n } else if (idx === 6) {\n dispatch({ type: 'ToggleAnimations' });\n options.animations = state.animations;\n authManager.savePreferences({ animations: state.animations });\n } else if (idx === 7) {\n dispatch({ type: 'ToggleMouse' });\n options.mouse = state.mouse;\n authManager.savePreferences({ mouse: state.mouse });\n term.grabInput({ mouse: state.mouse ? 'button' : undefined });\n }\n await render();\n break;\n }\n\n // ENTER path: full settings activation.\n if (idx < 6) {\n const theme = THEMES[idx];\n dispatch({ type: 'SetTheme', theme });\n bbs.setTheme(theme);\n options.theme = theme;\n authManager.savePreferences({ theme });\n } else if (idx === 6) {\n dispatch({ type: 'ToggleAnimations' });\n options.animations = state.animations;\n authManager.savePreferences({ animations: state.animations });\n } else if (idx === 7) {\n dispatch({ type: 'ToggleMouse' });\n options.mouse = state.mouse;\n authManager.savePreferences({ mouse: state.mouse });\n term.grabInput({ mouse: state.mouse ? 'button' : undefined });\n } else if (idx === 8) {\n const currentDir = authManager.getProjectsDirectory();\n dispatch({ type: 'StartEditProjectsDir', value: currentDir || '' });\n } else if (idx === 9) {\n if (!isLibraryInitialized()) {\n const result = await initializeLibrary();\n if (result.success) {\n dispatch({ type: 'SetLibraryPathResult', success: '✓ Library initialized!' });\n setTimeout(async () => {\n dispatch({ type: 'SetLibraryPathResult', success: '' });\n await render();\n }, 2000);\n } else {\n dispatch({ type: 'SetLibraryPathResult', error: result.message });\n }\n } else {\n dispatch({ type: 'StartEditLibraryPath', value: authManager.getLibraryPath() });\n }\n } else if (idx === 10) {\n if (!state.syncingLibrary) {\n dispatch({ type: 'SetSyncState', syncing: true, message: '', error: '', progress: '' });\n await render();\n\n const result = await syncLibrary((current, total, fileName) => {\n // Best-effort progress (can't await render in callback).\n state = reduce(state, { type: 'SetSyncState', progress: `${current}/${total}: ${fileName}` });\n });\n\n dispatch({ type: 'SetSyncState', syncing: false, progress: '' });\n\n if (result.success) {\n dispatch({ type: 'SetSyncState', message: result.message });\n const manifestResult = await fetchLibraryManifest();\n if (manifestResult.success && manifestResult.manifest) {\n serverManifest = manifestResult.manifest;\n }\n } else {\n dispatch({ type: 'SetSyncState', error: result.message });\n }\n\n setTimeout(async () => {\n dispatch({ type: 'SetSyncState', message: '', error: '' });\n await render();\n }, 3000);\n }\n } else if (idx === 11) {\n dispatch({ type: 'SetLibraryPathResult', success: 'Migrating from arcade-ref...' });\n await render();\n\n const result = await migrateFromArcadeRef();\n if (result.success) {\n dispatch({ type: 'SetLibraryPathResult', success: `✓ ${result.message}` });\n } else {\n dispatch({ type: 'SetLibraryPathResult', error: result.message });\n }\n\n setTimeout(async () => {\n dispatch({ type: 'SetLibraryPathResult', success: '', error: '' });\n await render();\n }, 3000);\n }\n await render();\n break;\n }\n\n case 'OpenCourse': {\n const now = Date.now();\n if (actionInProgress || (now - lastActionTime) < 500) break;\n lastActionTime = now;\n\n const course = state.courses[state.selectedIndex];\n if (!course) break;\n\n if (!actionInProgress) {\n actionInProgress = true;\n try {\n if (course.isOwned) {\n showStatus(`Loading course details for ${course.title}...`, 'yellow');\n\n const detailsResponse = await authManager.makeAuthenticatedRequest(\n `${API_URL}/api/auth/courses/${course.slug}`\n );\n\n if (detailsResponse.ok) {\n const detailData = await detailsResponse.json() as any;\n\n currentCourseDetail = {\n ...detailData.course,\n articles: detailData.articles || []\n };\n\n courseDetailViewer = new CourseDetailViewer(\n backBuffer,\n screenBuffer,\n state.theme,\n state.animations\n );\n courseDetailViewer.setUserInfo(user?.email || user?.name || 'Guest');\n\n try {\n if (!currentCourseDetail) {\n throw new Error('Course detail unavailable');\n }\n courseDetailViewer.loadCourse(currentCourseDetail);\n } catch (loadError: any) {\n errorLogs.push(`Error loading course details: ${loadError.message}`);\n currentError = loadError;\n dispatch({ type: 'ShowError' });\n courseDetailViewer = null;\n currentCourseDetail = null;\n await render();\n break;\n }\n\n courseDetailViewer.once('exit', () => {\n courseDetailViewer = null;\n currentCourseDetail = null;\n state = { ...state, currentView: 'courses' };\n render();\n });\n\n courseDetailViewer.on('error', (error: Error) => {\n currentError = error;\n dispatch({ type: 'ShowError' });\n render();\n });\n\n // Switch to detail view (push history like the monolith).\n state = { ...state, navigationHistory: [...state.navigationHistory, 'courses'], currentView: 'courseDetail' };\n\n term.moveTo(1, statusY);\n term.eraseLine();\n } else {\n showStatus(`Failed to load course details`, 'red');\n }\n } else {\n showStatus(`Opening browser to purchase: ${course.title}...`, 'yellow');\n const category = course.category || 'foundations';\n await open(`https://dev.babylonjsmarket.com/products/${category}/${course.slug}/`);\n showStatus(`Opened browser for course purchase`, 'green');\n setTimeout(() => {\n term.moveTo(1, statusY);\n term.eraseLine();\n render();\n }, 2000);\n }\n } catch (error: any) {\n showStatus(`Error loading course: ${error.message}`, 'red');\n } finally {\n actionInProgress = false;\n }\n }\n break;\n }\n\n case 'ShowToyInfo': {\n const toy = state.toys[state.toysSelectedIndex];\n if (toy) {\n term.moveTo(1, statusY);\n term.eraseLine();\n term.gray(`${toy.name} - ${toy.size} - ${toy.modeltype} model`);\n setTimeout(() => {\n term.moveTo(1, statusY);\n term.eraseLine();\n }, 3000);\n }\n break;\n }\n\n case 'OpenProjectInEditor': {\n const project = state.projects[state.projectsSelectedIndex];\n if (project) {\n const editor = process.env.EDITOR || 'code';\n const editorName = path.basename(editor);\n showStatus(`Opening ${project.name} in ${editorName}...`, 'yellow');\n const { spawn } = await import('child_process');\n const editorProcess = spawn(editor, [project.path], { detached: true, stdio: 'ignore' });\n editorProcess.unref();\n showStatus(`✓ Opened ${project.name} in ${editorName}`, 'green');\n setTimeout(() => {\n showStatus('', 'gray');\n }, 3000);\n }\n break;\n }\n\n case 'Download': {\n if (state.currentView === 'courses' && state.courses[state.selectedIndex]) {\n downloadAsset(state.courses[state.selectedIndex], 'course');\n } else if (state.currentView === 'toys' && state.toys[state.toysSelectedIndex]) {\n downloadAsset(state.toys[state.toysSelectedIndex], 'toy');\n } else if (state.currentView === 'downloads' && state.downloads[state.downloadsSelectedIndex]) {\n downloadAsset(state.downloads[state.downloadsSelectedIndex], 'download');\n }\n break;\n }\n\n case 'DevServer': {\n const project = state.projects[state.projectsSelectedIndex];\n if (project) {\n if (project.hasPackageJson) {\n showStatus(`Starting dev server for ${project.name}...`, 'yellow');\n const { exec } = await import('child_process');\n const script = `cd \"${project.path}\" && npm run dev`;\n exec(`osascript -e 'tell app \"Terminal\" to do script \"${script.replace(/\"/g, '\\\\\"')}\"'`);\n showStatus(`✓ Opened terminal for dev server`, 'green');\n setTimeout(() => {\n showStatus('', 'gray');\n }, 3000);\n } else {\n showStatus(`✗ No package.json found in ${project.name}`, 'red');\n }\n }\n break;\n }\n\n case 'DownloadAllMarked': {\n if (state.currentView === 'downloads' && state.markedDownloads.size > 0) {\n showStatus(`Starting batch download of ${state.markedDownloads.size} files...`, 'yellow');\n let downloadedCount = 0;\n const total = state.markedDownloads.size;\n for (const index of state.markedDownloads) {\n if (state.downloads[index]) {\n await downloadAsset(state.downloads[index], 'download');\n downloadedCount++;\n if (downloadedCount < total) {\n await new Promise(resolve => setTimeout(resolve, 31000)); // avoid rate limit\n }\n }\n }\n state = { ...state, markedDownloads: new Set<number>() };\n showStatus(`✓ Batch download complete: ${downloadedCount} files`, 'green');\n await render();\n }\n break;\n }\n\n case 'BuyInBrowser': {\n const now = Date.now();\n if (actionInProgress || (now - lastActionTime) < 500) break;\n lastActionTime = now;\n actionInProgress = true;\n try {\n if (state.currentView === 'courses' && state.courses[state.selectedIndex]) {\n const openFn = (await import('open')).default;\n const course = state.courses[state.selectedIndex];\n const category = course.category || 'foundations';\n await openFn(`${API_URL}/products/${category}/${course.slug}/`);\n await new Promise(resolve => setTimeout(resolve, 1000));\n } else if (state.currentView === 'toys' && state.toys[state.toysSelectedIndex]) {\n const openFn = (await import('open')).default;\n await openFn(`${API_URL}/toys`);\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n } finally {\n actionInProgress = false;\n }\n break;\n }\n\n case 'NewProject': {\n const projDir = authManager.getProjectsDirectory();\n if (!projDir) {\n showStatus('✗ Set projects directory in Settings first', 'red');\n } else {\n showStatus('Creating new project with create-arcade...', 'yellow');\n const { exec } = await import('child_process');\n const createArcadePath = '/Users/law/Programming/Web/BJSM/tools/create-arcade/dist/index.mjs';\n const script = `cd \"${projDir}\" && node \"${createArcadePath}\"`;\n exec(`osascript -e 'tell app \"Terminal\" to do script \"${script.replace(/\"/g, '\\\\\"')}\"'`);\n showStatus('✓ Opened terminal for create-arcade wizard', 'green');\n setTimeout(async () => {\n showStatus('Press R to rescan projects when done', 'gray');\n }, 3000);\n }\n break;\n }\n\n case 'RescanProjects': {\n const projDir = authManager.getProjectsDirectory();\n if (projDir) {\n showStatus('Rescanning projects...', 'yellow');\n state = { ...state, projects: (await scanForProjects(projDir, 2)) as ProjectLike[], projectsSelectedIndex: 0 };\n showStatus(`✓ Found ${state.projects.length} project${state.projects.length === 1 ? '' : 's'}`, 'green');\n await render();\n setTimeout(() => {\n showStatus('', 'gray');\n }, 3000);\n }\n break;\n }\n\n case 'InstallLibraryDeps': {\n const project = state.projects[state.projectsSelectedIndex];\n if (project) {\n if (!project.hasPackageJson) {\n showStatus(`✗ No package.json in ${project.name}`, 'red');\n } else {\n showStatus(`Running npm install in ${project.name}...`, 'yellow');\n const { exec } = await import('child_process');\n const script = `cd \"${project.path}\" && npm install; echo \"\"; echo \"Press any key to close...\"; read -n 1`;\n exec(`osascript -e 'tell app \"Terminal\" to do script \"${script.replace(/\"/g, '\\\\\"')}\"'`);\n showStatus(`✓ Opened terminal for npm install`, 'green');\n setTimeout(() => {\n showStatus('', 'gray');\n }, 3000);\n }\n }\n break;\n }\n\n case 'TestError':\n if (process.env.DEBUG) {\n throw new Error('This is a test error to demonstrate the error popup functionality. The error message can be quite long and will wrap appropriately in the popup dialog.');\n }\n break;\n\n case 'Quit': {\n clearInterval(timerInterval);\n\n if (state.animations) {\n const theme = bbs.getTheme();\n await bbs.transition(theme.animation);\n }\n\n term.clear();\n term.hideCursor(false);\n term.grabInput(false);\n\n term.moveTo(1, 2);\n term.cyan(`\n ╔══════════════════════════════════════════╗\n ║ ║\n ║ Thank you for using BJ's BBS! ║\n ║ ║\n ║ NO CARRIER ║\n ║ ║\n ╚══════════════════════════════════════════╝\n `);\n\n console.error = originalConsoleError;\n term.processExit(0);\n break;\n }\n }\n };\n\n // ── Main key handler: key → keyToAction → reduce/effect → render. ──\n const mainKeyHandler = async (name: string) => {\n try {\n // Gate order mirrors the original monolith exactly:\n // 1. error-popup ESC (full-screen redraw) 2. error-popup swallow\n // 3. inline editing gates 4. scene-creator text input\n // 5. actionInProgress block 6. courseDetail input 7. main switch.\n // keyToAction() resolves gates 1–4 purely, so we only need to special-\n // case the error-popup redraw, then enforce gates 5 & 6 here.\n\n // Gate 1: error popup full-screen redraw on dismiss.\n if (state.errorPopupVisible && name === 'ESCAPE') {\n dispatch({ type: 'DismissError' });\n currentError = null;\n backBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n screenBuffer.fill({ char: ' ', attr: { color: 'white', bgColor: 'black' }});\n screenBuffer.draw();\n await render();\n return;\n }\n // Gate 2: error popup swallows everything else.\n if (state.errorPopupVisible) {\n return;\n }\n\n // Gates 3 & 4 are pure: route them through keyToAction immediately so\n // they run *before* the actionInProgress block (matching original).\n const inEditingMode =\n state.editingProjectsDir ||\n state.editingLibraryPath ||\n (state.sceneCreatorActive && state.currentView === 'projects');\n if (inEditingMode) {\n const intent = keyToAction(name, state);\n // Scene-creator falls through for ENTER/ESC/LEFT/RIGHT — those are\n // handled below by the normal path, so only short-circuit when the\n // editing gate actually produced an intent for a consumed key.\n if (intent && (state.editingProjectsDir || state.editingLibraryPath)) {\n if (intent.kind === 'action') {\n dispatch(intent.action);\n await render();\n } else {\n await runEffect(intent.effect);\n }\n return;\n }\n if (intent && state.sceneCreatorActive) {\n // Only consume if it's the scene-name text input (InputChar / Backspace).\n if (\n intent.kind === 'action' &&\n (intent.action.type === 'InputChar' || intent.action.type === 'InputBackspace')\n ) {\n dispatch(intent.action);\n await render();\n return;\n }\n // otherwise fall through to the normal path below\n }\n }\n\n // Gate 5: block ordinary keys while an action is in progress.\n if (actionInProgress) {\n return;\n }\n\n // Gate 6: course detail view handles its own input.\n if (state.currentView === 'courseDetail' && courseDetailViewer) {\n const handled = courseDetailViewer.handleInput(name);\n if (handled) return;\n }\n\n // Gate 7: main switch.\n const intent = keyToAction(name, state);\n if (!intent) {\n return;\n }\n\n if (intent.kind === 'action') {\n dispatch(intent.action);\n await render();\n } else {\n await runEffect(intent.effect);\n }\n } catch (keyError: any) {\n errorLogs.push(`Key handler error: ${keyError.message}`);\n currentError = keyError;\n dispatch({ type: 'ShowError' });\n await render();\n }\n };\n\n // Register the main key handler\n debugLog('Registering key handler');\n term.on('key', mainKeyHandler);\n debugLog('Key handler registered - BBS ready for input');\n\n } catch (error: any) {\n // Restore console.error before exiting\n if (typeof originalConsoleError !== 'undefined') {\n console.error = originalConsoleError;\n }\n\n term.clear();\n term.red.bold('ERROR: ');\n term.white(error.message || 'Failed to connect to BBS\\n');\n term.hideCursor(false);\n term.grabInput(false);\n term.processExit(1);\n }\n });\n","import terminalKit from 'terminal-kit';\nimport { EventEmitter } from 'events';\n\nconst { ScreenBuffer, TextBuffer } = terminalKit;\n\nexport type Theme = 'classic' | 'desert' | 'matrix' | 'commando' | 'sandiego' | 'ed209';\n\ninterface ThemeColors {\n primary: string;\n secondary: string;\n accent: string;\n text: string;\n dim: string;\n animation: 'fade' | 'wipe' | 'matrix' | 'sweep';\n}\n\nexport class BufferedBBS extends EventEmitter {\n private buffer: any;\n private term: any;\n private theme: Theme;\n private themes: Record<Theme, ThemeColors> = {\n classic: {\n primary: 'cyan',\n secondary: 'yellow', \n accent: 'magenta',\n text: 'white',\n dim: 'gray',\n animation: 'fade'\n },\n desert: {\n primary: 'yellow',\n secondary: 'red',\n accent: 'green',\n text: 'white', \n dim: 'gray',\n animation: 'wipe'\n },\n matrix: {\n primary: 'green',\n secondary: 'brightGreen',\n accent: 'cyan',\n text: 'green',\n dim: 'darkGray',\n animation: 'matrix'\n },\n commando: {\n primary: 'green',\n secondary: 'yellow',\n accent: 'darkGray',\n text: 'white',\n dim: 'darkGray',\n animation: 'sweep'\n },\n sandiego: {\n primary: 'red',\n secondary: 'yellow',\n accent: 'brightWhite',\n text: 'white',\n dim: 'gray',\n animation: 'fade'\n },\n ed209: {\n primary: 'cyan',\n secondary: 'brightBlue',\n accent: 'gray',\n text: 'brightWhite',\n dim: 'darkGray',\n animation: 'wipe'\n }\n };\n \n private nodeNumber: number;\n public connectStartTime: number;\n private transferProtocol: 'Xmodem' | 'Ymodem' | 'Zmodem' = 'Zmodem';\n public animations: boolean;\n\n constructor(buffer: any, theme: Theme = 'classic', animations = true) {\n super();\n this.buffer = buffer;\n this.term = terminalKit.terminal;\n this.theme = theme;\n this.animations = animations;\n this.nodeNumber = Math.floor(Math.random() * 8) + 1;\n this.connectStartTime = Date.now();\n }\n\n getTheme(): ThemeColors {\n return this.themes[this.theme];\n }\n\n setTheme(theme: Theme) {\n this.theme = theme;\n this.emit('themeChanged', theme);\n }\n\n // Convert color name to terminal-kit attribute\n private getColorAttr(colorName: string): any {\n const colorMap: Record<string, any> = {\n 'black': { color: 0 },\n 'red': { color: 1 },\n 'green': { color: 2 },\n 'yellow': { color: 3 },\n 'blue': { color: 4 },\n 'magenta': { color: 5 },\n 'cyan': { color: 6 },\n 'white': { color: 7 },\n 'gray': { color: 8 },\n 'darkGray': { color: 8 },\n 'brightRed': { color: 9 },\n 'brightGreen': { color: 10 },\n 'brightYellow': { color: 11 },\n 'brightBlue': { color: 12 },\n 'brightMagenta': { color: 13 },\n 'brightCyan': { color: 14 },\n 'brightWhite': { color: 15 }\n };\n return colorMap[colorName] || { color: 7 };\n }\n\n // Draw text to buffer at position\n put(x: number, y: number, text: string | number | boolean | undefined | null, colorName?: string, bold: boolean = false) {\n // Ensure text is a string\n const textStr = text === undefined || text === null ? '' : String(text);\n \n const attr = colorName ? this.getColorAttr(colorName) : { color: 7 };\n if (bold) attr.bold = true;\n \n this.buffer.put({ \n x: x - 1, // Convert to 0-based\n y: y - 1, \n attr,\n wrap: false\n }, textStr);\n }\n\n // Draw a box to buffer\n drawBox(x: number, y: number, width: number, height: number, title?: string, focused: boolean = false) {\n const theme = this.getTheme();\n const color = theme.secondary;\n \n const chars = {\n topLeft: '╔', topRight: '╗', bottomLeft: '╚', bottomRight: '╝',\n horizontal: '═', vertical: '║'\n };\n\n // Top border\n this.put(x, y, chars.topLeft, color);\n for (let i = 1; i < width - 1; i++) {\n this.put(x + i, y, chars.horizontal, color);\n }\n this.put(x + width - 1, y, chars.topRight, color);\n\n // Title if provided\n if (title) {\n if (focused) {\n // Draw shadow/highlight effect for focused window\n const titlePadding = 3;\n const titleWidth = title.length + (titlePadding * 2);\n const titleX = x + Math.floor((width - titleWidth) / 2);\n \n // Draw shadow background\n this.put(titleX, y, '╔', theme.accent);\n for (let i = 1; i < titleWidth - 1; i++) {\n this.put(titleX + i, y, '═', theme.accent);\n }\n this.put(titleX + titleWidth - 1, y, '╗', theme.accent);\n \n // Draw title with padding\n const paddedTitle = ' '.repeat(titlePadding) + title + ' '.repeat(titlePadding);\n this.put(titleX + 1, y, paddedTitle.substring(1, paddedTitle.length - 1), theme.primary, true);\n } else {\n const titleX = x + Math.floor((width - title.length - 2) / 2);\n this.put(titleX, y, ' ', color);\n this.put(titleX + 1, y, title, theme.primary, true);\n this.put(titleX + title.length + 1, y, ' ', color);\n }\n }\n\n // Sides\n for (let i = 1; i < height - 1; i++) {\n this.put(x, y + i, chars.vertical, color);\n // Clear inside of box\n for (let j = 1; j < width - 1; j++) {\n this.put(x + j, y + i, ' ');\n }\n this.put(x + width - 1, y + i, chars.vertical, color);\n }\n\n // Bottom border\n this.put(x, y + height - 1, chars.bottomLeft, color);\n for (let i = 1; i < width - 1; i++) {\n this.put(x + i, y + height - 1, chars.horizontal, color);\n }\n this.put(x + width - 1, y + height - 1, chars.bottomRight, color);\n }\n\n // Draw BBS header to buffer\n drawBBSHeader(username: string, currentPage: string = 'MAIN', markedCount: number = 0) {\n const width = this.buffer.width;\n const theme = this.getTheme();\n \n // Top border\n for (let i = 0; i < width; i++) {\n this.put(i + 1, 1, '═', theme.secondary);\n }\n \n // Title and info line\n this.put(2, 2, \"BJ's BBS\", theme.primary, true);\n \n // Node info\n const nodeText = `Node ${this.nodeNumber}`;\n this.put(15, 2, nodeText, theme.accent);\n \n // Current page\n const pageX = Math.floor((width - currentPage.length) / 2);\n this.put(pageX, 2, currentPage, theme.primary, true);\n \n // Protocol on the right\n this.put(width - 10, 2, this.transferProtocol, theme.accent);\n \n // Connection info line\n const connectTime = Math.floor((Date.now() - this.connectStartTime) / 1000 / 60);\n const baud = '2400 BAUD';\n const protocol = 'ANSI';\n const timeStr = `${connectTime}:${String(new Date().getSeconds()).padStart(2, '0')}`;\n \n this.put(2, 3, baud, theme.dim);\n this.put(15, 3, protocol, theme.dim);\n this.put(30, 3, timeStr, theme.dim);\n \n // Show marked count if any\n if (markedCount > 0) {\n const markedText = `Marked: ${markedCount}`;\n this.put(width - 20, 3, markedText, theme.accent, true);\n }\n \n // Bottom border\n for (let i = 0; i < width; i++) {\n this.put(i + 1, 4, '═', theme.secondary);\n }\n }\n\n // Draw a table to buffer\n drawTable(x: number, y: number, options: {\n data: any[];\n columns: Array<{ key: string; label: string; width?: number }>;\n selectedIndex?: number;\n width?: number;\n }) {\n const theme = this.getTheme();\n const width = options.width || this.buffer.width - x;\n \n // Calculate column widths\n const numCols = options.columns.length;\n const borderWidth = numCols + 1;\n const paddingWidth = numCols * 2;\n const availableWidth = width - borderWidth - paddingWidth;\n \n const colWidths: number[] = [];\n let assignedWidth = 0;\n \n options.columns.forEach((col, i) => {\n if (col.width) {\n colWidths[i] = col.width;\n assignedWidth += col.width;\n } else {\n colWidths[i] = 0;\n }\n });\n \n // Distribute remaining width\n const flexCols = options.columns.filter((_, i) => colWidths[i] === 0).length;\n if (flexCols > 0) {\n const flexWidth = Math.floor((availableWidth - assignedWidth) / flexCols);\n options.columns.forEach((_, i) => {\n if (colWidths[i] === 0) {\n colWidths[i] = flexWidth;\n }\n });\n }\n \n // Draw top border\n this.put(x, y, '╔', theme.secondary);\n let xPos = x + 1;\n colWidths.forEach((w, i) => {\n for (let j = 0; j < w + 2; j++) {\n this.put(xPos++, y, '═', theme.secondary);\n }\n if (i < colWidths.length - 1) {\n this.put(xPos++, y, '╦', theme.secondary);\n }\n });\n this.put(xPos, y, '╗', theme.secondary);\n \n // Draw header\n y++;\n this.put(x, y, '║', theme.secondary);\n xPos = x + 1;\n options.columns.forEach((col, i) => {\n this.put(xPos++, y, ' ');\n const text = this.truncate(col.label, colWidths[i]);\n this.put(xPos, y, text, theme.primary, true);\n xPos += colWidths[i];\n this.put(xPos++, y, ' ');\n this.put(xPos++, y, '║', theme.secondary);\n });\n \n // Draw separator\n y++;\n this.put(x, y, '╠', theme.secondary);\n xPos = x + 1;\n colWidths.forEach((w, i) => {\n for (let j = 0; j < w + 2; j++) {\n this.put(xPos++, y, '═', theme.secondary);\n }\n if (i < colWidths.length - 1) {\n this.put(xPos++, y, '╬', theme.secondary);\n }\n });\n this.put(xPos, y, '╣', theme.secondary);\n \n // Draw data rows\n options.data.forEach((row, rowIndex) => {\n y++;\n const isSelected = rowIndex === options.selectedIndex;\n \n this.put(x, y, '║', theme.secondary);\n xPos = x + 1;\n \n options.columns.forEach((col, i) => {\n this.put(xPos++, y, ' ');\n const value = String(row[col.key] || '');\n const text = this.truncate(value, colWidths[i]);\n const color = isSelected ? \n (this.theme === 'desert' ? 'brightYellow' : \n this.theme === 'matrix' ? 'brightGreen' : 'brightCyan') : \n 'white';\n this.put(xPos, y, text, color, isSelected);\n xPos += colWidths[i];\n this.put(xPos++, y, ' ');\n this.put(xPos++, y, '║', theme.secondary);\n });\n });\n \n // Draw bottom border\n y++;\n this.put(x, y, '╚', theme.secondary);\n xPos = x + 1;\n colWidths.forEach((w, i) => {\n for (let j = 0; j < w + 2; j++) {\n this.put(xPos++, y, '═', theme.secondary);\n }\n if (i < colWidths.length - 1) {\n this.put(xPos++, y, '╩', theme.secondary);\n }\n });\n this.put(xPos, y, '╝', theme.secondary);\n \n return y - options.data.length - 3; // Return starting Y position\n }\n \n private truncate(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text.padEnd(maxLength);\n return text.substring(0, maxLength - 3) + '...';\n }\n\n // Show notification (draw to a temporary position)\n showNotification(message: string, type: 'info' | 'success' | 'error') {\n const theme = this.getTheme();\n const color = type === 'error' ? 'red' : type === 'success' ? 'green' : theme.primary;\n const y = this.buffer.height - 2;\n const x = 2;\n \n // Clear line\n for (let i = 0; i < this.buffer.width; i++) {\n this.put(i + 1, y, ' ');\n }\n \n // Draw message\n this.put(x, y, message, color, true);\n }\n \n // Loading animation\n async showLoadingAnimation(message: string, duration: number = 1500) {\n const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n const startTime = Date.now();\n let frameIndex = 0;\n \n while (Date.now() - startTime < duration) {\n this.term.moveTo(2, 2);\n this.term[this.getTheme().primary](frames[frameIndex] + ' ' + message);\n frameIndex = (frameIndex + 1) % frames.length;\n await new Promise(resolve => setTimeout(resolve, 80));\n }\n }\n\n // Show error in a popup dialog\n showErrorPopup(error: Error | string, title: string = 'Error') {\n const theme = this.getTheme();\n const errorMessage = typeof error === 'string' ? error : error.message;\n const errorStack = typeof error === 'object' && error.stack ? error.stack : '';\n\n // Calculate popup dimensions\n const maxWidth = Math.min(70, this.term.width - 10);\n const lines = this.wrapText(errorMessage, maxWidth - 4);\n\n // Add stack trace lines if available (limit to 5 lines)\n const stackLines: string[] = [];\n if (errorStack && process.env.DEBUG) {\n const stack = errorStack.split('\\n').slice(1, 6); // Skip first line (it's the message)\n stackLines.push('', '--- Stack Trace ---');\n stack.forEach(line => {\n const wrapped = this.wrapText(line.trim(), maxWidth - 4);\n stackLines.push(...wrapped);\n });\n }\n\n const allLines = [...lines, ...stackLines];\n const popupHeight = Math.min(allLines.length + 6, this.term.height - 4);\n const popupWidth = maxWidth;\n\n const x = Math.floor((this.term.width - popupWidth) / 2);\n const y = Math.floor((this.term.height - popupHeight) / 2);\n\n // Draw error popup box with red border\n this.drawBox(x, y, popupWidth, popupHeight, `⚠ ${title}`);\n\n // Override border color to red for error\n const chars = {\n topLeft: '╔', topRight: '╗', bottomLeft: '╚', bottomRight: '╝',\n horizontal: '═', vertical: '║'\n };\n\n // Redraw borders in red\n for (let i = 0; i < popupWidth; i++) {\n this.put(x + i, y, i === 0 ? chars.topLeft : i === popupWidth - 1 ? chars.topRight : chars.horizontal, 'red');\n this.put(x + i, y + popupHeight - 1, i === 0 ? chars.bottomLeft : i === popupWidth - 1 ? chars.bottomRight : chars.horizontal, 'red');\n }\n for (let i = 1; i < popupHeight - 1; i++) {\n this.put(x, y + i, chars.vertical, 'red');\n this.put(x + popupWidth - 1, y + i, chars.vertical, 'red');\n }\n\n // Draw title with warning icon\n const titleText = `⚠ ${title}`;\n const titleX = x + Math.floor((popupWidth - titleText.length - 2) / 2);\n this.put(titleX, y, ' ', 'red');\n this.put(titleX + 1, y, titleText, 'brightRed', true);\n this.put(titleX + titleText.length + 1, y, ' ', 'red');\n\n // Draw error message\n let lineY = y + 2;\n allLines.forEach((line, idx) => {\n if (lineY < y + popupHeight - 2) {\n const isStackTrace = idx >= lines.length;\n const color = isStackTrace ? 'gray' : 'white';\n this.put(x + 2, lineY, line, color);\n lineY++;\n }\n });\n\n // Draw instructions at bottom\n const instruction = '[ESC] to close';\n const instrX = x + Math.floor((popupWidth - instruction.length) / 2);\n this.put(instrX, y + popupHeight - 2, instruction, theme.accent);\n\n return { x, y, width: popupWidth, height: popupHeight };\n }\n\n // Show authentication device code popup\n showAuthPopup(deviceCode: string, verificationUri: string) {\n const theme = this.getTheme();\n const popupWidth = 60;\n const popupHeight = 14;\n\n const x = Math.floor((this.buffer.width - popupWidth) / 2);\n const y = Math.floor((this.buffer.height - popupHeight) / 2);\n\n // Draw authentication popup box\n this.drawBox(x, y, popupWidth, popupHeight, '🔐 AUTHENTICATION REQUIRED');\n\n // Override border color to theme accent\n const chars = {\n topLeft: '╔', topRight: '╗', bottomLeft: '╚', bottomRight: '╝',\n horizontal: '═', vertical: '║'\n };\n\n // Redraw borders in accent color\n for (let i = 0; i < popupWidth; i++) {\n this.put(x + i, y, i === 0 ? chars.topLeft : i === popupWidth - 1 ? chars.topRight : chars.horizontal, theme.secondary);\n this.put(x + i, y + popupHeight - 1, i === 0 ? chars.bottomLeft : i === popupWidth - 1 ? chars.bottomRight : chars.horizontal, theme.secondary);\n }\n for (let i = 1; i < popupHeight - 1; i++) {\n this.put(x, y + i, chars.vertical, theme.secondary);\n this.put(x + popupWidth - 1, y + i, chars.vertical, theme.secondary);\n }\n\n // Draw title\n const titleText = '🔐 AUTHENTICATION REQUIRED';\n const titleX = x + Math.floor((popupWidth - titleText.length - 2) / 2);\n this.put(titleX, y, ' ', theme.secondary);\n this.put(titleX + 1, y, titleText, theme.primary, true);\n this.put(titleX + titleText.length + 1, y, ' ', theme.secondary);\n\n // Instructions\n let lineY = y + 2;\n const instructions = [\n 'To connect to BabylonJS Market BBS, enter this code:',\n '',\n ];\n\n instructions.forEach(line => {\n const lineX = x + Math.floor((popupWidth - line.length) / 2);\n this.put(lineX, lineY, line, theme.text);\n lineY++;\n });\n\n // Device code in a box\n const codeBoxWidth = deviceCode.length + 6;\n const codeBoxX = x + Math.floor((popupWidth - codeBoxWidth) / 2);\n\n // Draw code box\n this.put(codeBoxX, lineY, '┌', theme.accent);\n for (let i = 1; i < codeBoxWidth - 1; i++) {\n this.put(codeBoxX + i, lineY, '─', theme.accent);\n }\n this.put(codeBoxX + codeBoxWidth - 1, lineY, '┐', theme.accent);\n\n lineY++;\n this.put(codeBoxX, lineY, '│', theme.accent);\n this.put(codeBoxX + 2, lineY, ' ', theme.text);\n this.put(codeBoxX + 3, lineY, deviceCode, 'yellow', true);\n this.put(codeBoxX + 3 + deviceCode.length, lineY, ' ', theme.text);\n this.put(codeBoxX + codeBoxWidth - 1, lineY, '│', theme.accent);\n\n lineY++;\n this.put(codeBoxX, lineY, '└', theme.accent);\n for (let i = 1; i < codeBoxWidth - 1; i++) {\n this.put(codeBoxX + i, lineY, '─', theme.accent);\n }\n this.put(codeBoxX + codeBoxWidth - 1, lineY, '┘', theme.accent);\n\n // URL\n lineY += 2;\n const urlText = 'On this page:';\n const urlX = x + Math.floor((popupWidth - urlText.length) / 2);\n this.put(urlX, lineY, urlText, theme.text);\n\n lineY++;\n const urlLinkX = x + Math.floor((popupWidth - verificationUri.length) / 2);\n this.put(urlLinkX, lineY, verificationUri, 'cyan', true);\n\n // Status line\n lineY = y + popupHeight - 2;\n const statusText = 'Opening browser automatically...';\n const statusX = x + Math.floor((popupWidth - statusText.length) / 2);\n this.put(statusX, lineY, statusText, theme.dim);\n\n return { x, y, width: popupWidth, height: popupHeight };\n }\n\n // Show polling status\n showPollingStatus(status: 'waiting' | 'checking' | 'success' | 'error', message?: string) {\n const theme = this.getTheme();\n const y = this.buffer.height - 3;\n const x = 2;\n\n // Clear the status line\n for (let i = 0; i < this.buffer.width - 4; i++) {\n this.put(x + i, y, ' ');\n }\n\n // Status icons and colors\n const statusConfig = {\n waiting: { icon: '⏳', color: theme.accent, text: message || 'Waiting for authentication...' },\n checking: { icon: '🔄', color: 'yellow', text: message || 'Checking authentication status...' },\n success: { icon: '✓', color: 'green', text: message || 'Authentication successful!' },\n error: { icon: '✗', color: 'red', text: message || 'Authentication failed' }\n };\n\n const config = statusConfig[status];\n const fullText = `${config.icon} ${config.text}`;\n\n // Center the status text\n const textX = Math.floor((this.buffer.width - fullText.length) / 2);\n this.put(textX, y, config.icon, config.color);\n this.put(textX + 2, y, config.text, config.color, status === 'success');\n }\n \n // Helper function to wrap text\n private wrapText(text: string, maxWidth: number): string[] {\n const words = text.split(' ');\n const lines: string[] = [];\n let currentLine = '';\n \n for (const word of words) {\n if (currentLine.length + word.length + 1 <= maxWidth) {\n currentLine += (currentLine ? ' ' : '') + word;\n } else {\n if (currentLine) lines.push(currentLine);\n currentLine = word;\n \n // Handle very long words\n while (currentLine.length > maxWidth) {\n lines.push(currentLine.substring(0, maxWidth));\n currentLine = currentLine.substring(maxWidth);\n }\n }\n }\n \n if (currentLine) lines.push(currentLine);\n return lines.length > 0 ? lines : [''];\n }\n \n // Page transition animations (preserve header - only animate content area)\n async transition(type: 'fade' | 'wipe' | 'matrix' | 'sweep' = 'fade') {\n if (!this.animations) return;\n \n const width = this.term.width;\n const height = this.term.height;\n const contentStartY = 5; // Start transitions below the header\n \n switch(type) {\n case 'fade':\n // Fade out effect (only content area)\n for (let i = 0; i < 3; i++) {\n for (let y = contentStartY; y < height; y++) {\n this.term.moveTo(1, y);\n for (let x = 0; x < width; x++) {\n this.term.gray(String.fromCharCode(9617)); // Light shade\n }\n }\n await new Promise(resolve => setTimeout(resolve, 50));\n }\n // Clear only content area\n for (let y = contentStartY; y <= height; y++) {\n this.term.moveTo(1, y);\n this.term.eraseLine();\n }\n break;\n \n case 'wipe':\n // Wipe from left to right (only content area)\n for (let x = 0; x < width; x += 2) {\n for (let y = contentStartY; y <= height; y++) {\n this.term.moveTo(x, y);\n this.term(' ');\n if (x + 1 < width) {\n this.term.moveTo(x + 1, y);\n this.term(' ');\n }\n }\n await new Promise(resolve => setTimeout(resolve, 10));\n }\n break;\n \n case 'matrix':\n // Matrix rain effect (only in content area)\n const columns = Math.floor(width / 2);\n const drops: number[] = [];\n const contentHeight = height - contentStartY;\n \n for (let i = 0; i < columns; i++) {\n drops[i] = Math.floor(Math.random() * -contentHeight);\n }\n \n for (let frame = 0; frame < 20; frame++) {\n for (let i = 0; i < columns; i++) {\n const x = i * 2;\n const y = drops[i] + contentStartY;\n \n if (y >= contentStartY && y <= height) {\n this.term.moveTo(x + 1, y);\n this.term.brightGreen(String.fromCharCode(33 + Math.floor(Math.random() * 94)));\n }\n \n if (y > contentStartY + 3 && y - 3 >= contentStartY) {\n this.term.moveTo(x + 1, y - 3);\n this.term.green(String.fromCharCode(33 + Math.floor(Math.random() * 94)));\n }\n \n if (y > contentStartY + 6 && y - 6 >= contentStartY) {\n this.term.moveTo(x + 1, y - 6);\n this.term.dim.green(String.fromCharCode(33 + Math.floor(Math.random() * 94)));\n }\n \n if (y > contentStartY + 9 && y - 9 >= contentStartY) {\n this.term.moveTo(x + 1, y - 9);\n this.term(' ');\n }\n \n drops[i]++;\n if (drops[i] > contentHeight + 10) {\n drops[i] = Math.floor(Math.random() * -10);\n }\n }\n await new Promise(resolve => setTimeout(resolve, 50));\n }\n // Clear only content area\n for (let y = contentStartY; y <= height; y++) {\n this.term.moveTo(1, y);\n this.term.eraseLine();\n }\n break;\n \n case 'sweep':\n // Diagonal sweep animation (only content area)\n for (let i = 0; i < width + (height - contentStartY); i++) {\n for (let y = contentStartY; y <= height; y++) {\n const x = i - (y - contentStartY);\n if (x >= 0 && x < width) {\n this.term.moveTo(x + 1, y);\n this.term(' ');\n }\n }\n await new Promise(resolve => setTimeout(resolve, 15));\n }\n break;\n }\n }\n}","import terminalKit from 'terminal-kit';\nimport chalk from 'chalk';\nimport { BufferedBBS, Theme } from './buffered-bbs.js';\nimport { MarkdownTerminalRenderer } from './markdown-terminal.js';\nimport { CodeHighlighter } from './code-highlighter.js';\nimport { EventEmitter } from 'events';\nimport { execSync } from 'child_process';\nimport asciify from 'asciify-image';\nimport fetch from 'node-fetch';\nimport open from 'open';\nimport { API_URL } from '../config/constants.js';\n\n// Pure modules – no terminal-kit\nimport {\n computeTocWidth,\n computeContentStartX,\n computeContentHeight,\n computeWrapWidth,\n computeCodeBlockWidth,\n maxContentScrollOffset,\n maxTocScrollOffset,\n isCodeBlockVisible,\n isImageVisible,\n isCopiedLine as _isCopiedLine,\n reduce,\n makeInitialState,\n} from './course-detail/index.js';\nimport type {\n Article,\n CourseDetail,\n TOCEntry,\n TrackedImage,\n CodeBlock,\n ViewerState,\n} from './course-detail/index.js';\n\nconst { ScreenBuffer } = terminalKit;\n\nexport class CourseDetailViewer extends EventEmitter {\n private backBuffer: any;\n private screenBuffer: any;\n private term: any;\n private bbs: BufferedBBS;\n private renderer: MarkdownTerminalRenderer;\n\n // ── Pure viewer state (all navigation / dimension data) ──────────────────\n private vs: ViewerState;\n\n // ── Content arrays (produced by content-generation, consumed by renderer) ─\n private contentLines: string[] = [];\n private tocEntries: TOCEntry[] = [];\n private codeBlocks: CodeBlock[] = [];\n private trackedImages: TrackedImage[] = [];\n\n // Fixed header/footer heights (unchanged from original)\n private readonly headerHeight: number = 5;\n private readonly footerHeight: number = 3;\n\n constructor(\n backBuffer: any,\n screenBuffer: any,\n theme: Theme = 'classic',\n animations: boolean = true\n ) {\n super();\n this.backBuffer = backBuffer;\n this.screenBuffer = screenBuffer;\n this.term = terminalKit.terminal;\n this.bbs = new BufferedBBS(backBuffer, theme, animations);\n\n const w = this.term.width as number;\n const h = this.term.height as number;\n const tocW = computeTocWidth(w);\n const startX = computeContentStartX(tocW);\n\n this.vs = makeInitialState(w, h, this.headerHeight, this.footerHeight, tocW, startX);\n\n this.renderer = new MarkdownTerminalRenderer(theme, w - startX - 2);\n\n // Update layout based on initial terminal width\n this._updateLayout();\n }\n\n // ── Accessors used by rendering helpers (keep backward-compat references) ─\n\n private get width() { return this.vs.width; }\n private get height() { return this.vs.height; }\n private get contentHeight() { return this.vs.contentHeight; }\n private get tocWidth() { return this.vs.tocWidth; }\n private get contentStartX() { return this.vs.contentStartX; }\n private get scrollOffset() { return this.vs.scrollOffset; }\n private get tocScrollOffset() { return this.vs.tocScrollOffset; }\n private get selectedTocIndex() { return this.vs.selectedTocIndex; }\n private get viewMode() { return this.vs.viewMode; }\n private get focusPanel() { return this.vs.focusPanel; }\n private get copiedBlockIndex() { return this.vs.copiedBlockIndex; }\n private get copiedTimestamp() { return this.vs.copiedTimestamp; }\n private get courseTitle() { return this.vs.courseTitle; }\n private get username() { return this.vs.username; }\n\n /**\n * Update layout calculations based on terminal width (delegates to pure helpers).\n */\n private _updateLayout() {\n const tocW = computeTocWidth(this.vs.width);\n const startX = computeContentStartX(tocW);\n this.vs = { ...this.vs, tocWidth: tocW, contentStartX: startX };\n }\n\n /** @deprecated internal alias kept so that resize() still works */\n private updateLayout() { this._updateLayout(); }\n\n /**\n * Handle terminal resize\n */\n resize(width: number, height: number) {\n this.vs = {\n ...this.vs,\n width,\n height,\n contentHeight: computeContentHeight(height, this.headerHeight, this.footerHeight),\n };\n\n // Update layout calculations (tocWidth + contentStartX)\n this._updateLayout();\n\n // Update renderer width\n const contentWidth = this.viewMode === 'content' ? this.width - 6 : this.width - this.contentStartX - 2;\n this.renderer = new MarkdownTerminalRenderer(\n (this.bbs as any).theme || 'classic',\n contentWidth\n );\n\n // Re-wrap content for new width if needed\n if (this.contentLines.length > 0) {\n // Store current course data to re-process with new width\n const currentCourse = (this as any).currentCourse;\n if (currentCourse) {\n // Regenerate content with new width\n const { lines, tocEntries } = this.generateCourseContent(currentCourse);\n this.contentLines = lines.filter(line => line !== undefined && line !== null);\n this.tocEntries = tocEntries;\n }\n }\n\n // Re-render with new dimensions\n this.render();\n }\n\n /**\n * Set user information for header\n */\n setUserInfo(username: string) {\n this.vs = { ...this.vs, username };\n }\n\n /**\n * Load course data and prepare content\n */\n loadCourse(course: CourseDetail) {\n // Store course for resize reprocessing\n (this as any).currentCourse = course;\n\n // Reset navigation state while preserving dimension fields\n this.vs = {\n ...this.vs,\n courseTitle: course.title || 'COURSE',\n scrollOffset: 0,\n tocScrollOffset: 0,\n selectedTocIndex: 0,\n };\n\n // Clear existing content\n this.contentLines = [];\n this.tocEntries = [];\n\n // Validate course data\n if (!course || !course.articles) {\n this.contentLines = ['Error: Invalid course data'];\n this.render();\n return;\n }\n\n // Generate content and TOC\n const { lines, tocEntries } = this.generateCourseContent(course);\n // Filter out any undefined or null lines\n this.contentLines = lines.filter(line => line !== undefined && line !== null);\n this.tocEntries = tocEntries;\n\n // Initial render\n this.render();\n }\n\n /**\n * Generate course content with articles\n */\n private generateCourseContent(course: CourseDetail): {\n lines: string[];\n tocEntries: TOCEntry[];\n } {\n const allLines: string[] = [];\n const tocEntries: TOCEntry[] = [];\n const theme = this.bbs.getTheme();\n\n // Clear code blocks and images tracking\n this.codeBlocks = [];\n this.trackedImages = [];\n\n // Add course header\n allLines.push('');\n this.addColoredLine(allLines, `═══ ${course.title.toUpperCase()} ═══`, theme.primary);\n if (course.category) {\n this.addColoredLine(allLines, `Category: ${course.category}`, theme.secondary);\n }\n if (course.description) {\n allLines.push('');\n const wrappedDesc = this.wrapText(course.description, this.width - this.contentStartX - 4);\n // Push description lines directly without color metadata\n wrappedDesc.forEach(line => allLines.push(line));\n }\n allLines.push('');\n this.addColoredLine(allLines, '─'.repeat(60), theme.dim);\n allLines.push('');\n\n // Sort articles by order (with safety check)\n const sortedArticles = course.articles ?\n [...course.articles].sort((a, b) => (a.order || 0) - (b.order || 0)) :\n [];\n\n // Process each article\n sortedArticles.forEach((article, index) => {\n // Skip invalid articles\n if (!article || !article.title) return;\n const articleStartLine = allLines.length;\n\n // Add article to TOC as a section header\n tocEntries.push({\n title: `Article ${article.order}: ${article.title}`,\n line: articleStartLine,\n type: 'article'\n });\n\n // Article separator\n if (index > 0) {\n allLines.push('');\n this.addColoredLine(allLines, '═'.repeat(70), theme.primary);\n allLines.push('');\n }\n\n // Article header\n this.addColoredLine(\n allLines,\n `ARTICLE ${article.order}: ${article.title.toUpperCase()}`,\n theme.primary,\n true\n );\n this.addColoredLine(allLines, '─'.repeat(70), theme.dim);\n allLines.push('');\n\n if (course.isOwned && article.markdown) {\n // Extract headings for TOC\n const headings = this.extractHeadings(article.markdown);\n\n // Process markdown with proper code block handling\n // Pass the current position in allLines as the base line number\n const currentLinePosition = allLines.length;\n const renderedContent = this.renderMarkdownWithCodeBlocks(\n article.markdown,\n theme,\n currentLinePosition\n );\n\n // Add headings to TOC under this article\n headings.forEach(heading => {\n // Find the line number where this heading appears\n let lineNum = articleStartLine;\n for (let i = 0; i < renderedContent.length; i++) {\n // For H2 headings, search for uppercase version since they're rendered that way\n const searchText = heading.level === 2 ? heading.text.toUpperCase() : heading.text;\n if (renderedContent[i].includes(searchText)) {\n lineNum = allLines.length + i; // Use current position in allLines, not articleStartLine\n break;\n }\n }\n\n tocEntries.push({\n title: heading.text,\n line: lineNum,\n type: 'heading',\n level: heading.level\n });\n });\n\n allLines.push(...renderedContent);\n } else {\n // Show preview for unowned content\n this.addColoredLine(allLines, '⚠ Premium Content', theme.accent);\n allLines.push('');\n if (article.description) {\n const wrapped = this.wrapText(article.description, this.width - this.contentStartX - 4);\n wrapped.forEach(line => this.addColoredLine(allLines, line, theme.dim));\n } else {\n this.addColoredLine(\n allLines,\n 'This article is part of the premium course.',\n theme.dim\n );\n this.addColoredLine(\n allLines,\n 'Purchase the course to access full content.',\n theme.dim\n );\n }\n }\n\n allLines.push('');\n allLines.push('');\n });\n\n return { lines: allLines, tocEntries };\n }\n\n /**\n * Extract headings from markdown\n */\n private extractHeadings(markdown: string): Array<{ level: number; text: string }> {\n const headings: Array<{ level: number; text: string }> = [];\n const lines = markdown.split('\\n');\n\n lines.forEach(line => {\n // Match headings that might be in numbered lists or at start of line\n // This handles cases like \"1. ### Heading\" or \"### Heading\"\n const match = line.match(/(?:^\\d+\\.\\s+)?(#{2,3})\\s+(.+)$/);\n if (match) {\n headings.push({\n level: match[1].length,\n text: match[2].trim()\n });\n }\n });\n\n return headings;\n }\n\n /**\n * Render markdown with proper code block handling\n */\n private renderMarkdownWithCodeBlocks(\n markdown: string,\n theme: any,\n startLine: number\n ): string[] {\n const result: string[] = [];\n const lines = markdown.split('\\n');\n let inCodeBlock = false;\n let codeBlockLines: string[] = [];\n let codeBlockLanguage = '';\n let inFrontmatter = false;\n let skipNextTitle = false;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // Handle frontmatter\n if (line === '---') {\n if (i === 0 || (i > 0 && lines[i-1] === '')) {\n // Start of frontmatter\n inFrontmatter = true;\n skipNextTitle = true; // Skip the title that follows frontmatter\n continue;\n } else if (inFrontmatter) {\n // End of frontmatter\n inFrontmatter = false;\n continue;\n }\n }\n\n // Skip lines inside frontmatter\n if (inFrontmatter) {\n continue;\n }\n\n // Skip the first # header after frontmatter (it's redundant with article title)\n if (skipNextTitle && line.startsWith('# ')) {\n skipNextTitle = false;\n continue;\n }\n\n // Handle code blocks\n if (line.startsWith('```')) {\n if (!inCodeBlock) {\n // Starting a code block - parse language and metadata\n inCodeBlock = true;\n const fenceInfo = line.substring(3).trim();\n\n // Parse metadata like: ts FILENAME=\"SRC/COMPONENTS/LOGGING.TS\" LINENUMSTART=\"75\"\n let language = 'javascript';\n let filename = '';\n let lineNumStart = 1;\n\n if (fenceInfo) {\n // Extract language (first word)\n const parts = fenceInfo.split(/\\s+/);\n if (parts[0] && !parts[0].includes('=')) {\n language = parts[0];\n }\n\n // Extract metadata\n const filenameMatch = fenceInfo.match(/FILENAME=[\"']([^\"']+)[\"']/i);\n if (filenameMatch) {\n filename = filenameMatch[1];\n }\n\n const lineNumMatch = fenceInfo.match(/LINENUMSTART=[\"']?(\\d+)[\"']?/i);\n if (lineNumMatch) {\n lineNumStart = parseInt(lineNumMatch[1], 10);\n }\n }\n\n codeBlockLanguage = language;\n codeBlockLines = [];\n\n // Store metadata for use when rendering\n (codeBlockLines as any).filename = filename;\n (codeBlockLines as any).lineNumStart = lineNumStart;\n } else {\n // Ending a code block - render with highlighting\n inCodeBlock = false;\n const codeContent = codeBlockLines.join('\\n');\n const filename = (codeBlockLines as any).filename || '';\n const lineNumStart = (codeBlockLines as any).lineNumStart || 1;\n\n // Track code block position relative to the overall content\n // startLine is the base line number for this article in the full content\n // result.length is current position in the article's rendered content\n const codeBlockStartLine = startLine + result.length; // Absolute position in contentLines\n\n\n // Format code block with syntax highlighting\n // Get the actual theme name from the bbs instance\n const themeName = (this.bbs as any).theme || 'classic';\n\n // Use full width for code blocks in full mode, appropriate width in split mode\n // In split mode, content starts at contentStartX and needs padding\n // In full mode, content starts at 4 and uses most of the width\n const isFullMode = this.viewMode === 'content';\n const codeBlockWidth = isFullMode ? this.width - 10 : this.width - this.contentStartX - 6;\n\n const formattedBlock = CodeHighlighter.formatCodeBlock(\n codeContent,\n codeBlockLanguage,\n codeBlockWidth,\n themeName,\n filename,\n lineNumStart\n );\n\n // Add formatted lines without additional color metadata\n formattedBlock.forEach(line => {\n // The formatCodeBlock already returns colored strings, just add them\n result.push(line);\n });\n\n // Track this code block for copy functionality\n this.codeBlocks.push({\n startLine: codeBlockStartLine,\n endLine: codeBlockStartLine + formattedBlock.length - 1, // -1 for zero-based end\n code: codeContent,\n language: codeBlockLanguage\n });\n\n result.push(''); // Add spacing after code block\n }\n continue;\n }\n\n if (inCodeBlock) {\n codeBlockLines.push(line);\n continue;\n }\n\n // Render non-code-block lines\n const rendered = this.renderMarkdownLine(line, theme);\n result.push(...rendered);\n }\n\n return result;\n }\n\n /**\n * Render a single markdown line (non-code-block)\n */\n private renderMarkdownLine(line: string, theme: any): string[] {\n const result: string[] = [];\n \n // Calculate proper wrap width based on view mode\n const isFullMode = this.viewMode === 'content';\n const wrapWidth = isFullMode ? this.width - 8 : this.width - this.contentStartX - 6;\n\n // Skip any remaining frontmatter markers that weren't caught\n if (line === '---') {\n return result;\n }\n\n // Headers - skip # headers as they're shown as article titles\n if (line.startsWith('# ')) {\n // Skip top-level headers as they duplicate the article title\n return result;\n }\n\n // Check for H2 headings (including in numbered lists)\n const h2Match = line.match(/^(?:\\d+\\.\\s+)?(##)\\s+(.+)$/);\n if (h2Match) {\n result.push('');\n this.addColoredLine(result, h2Match[2].toUpperCase(), theme.secondary, true);\n return result;\n }\n\n // Check for H3 headings (including in numbered lists)\n const h3Match = line.match(/^(?:\\d+\\.\\s+)?(###)\\s+(.+)$/);\n if (h3Match) {\n result.push('');\n this.addColoredLine(result, h3Match[2], theme.accent);\n return result;\n }\n\n // Lists\n if (line.match(/^[-*+]\\s+/)) {\n const content = line.replace(/^[-*+]\\s+/, '');\n // Wrap list content properly\n const wrapped = this.wrapText('- ' + content, wrapWidth);\n wrapped.forEach((wl, idx) => {\n // Indent continuation lines\n if (idx > 0) {\n result.push(' ' + wl);\n } else {\n result.push(wl);\n }\n });\n return result;\n }\n\n // Blockquotes\n if (line.startsWith('>')) {\n this.addColoredLine(result, '│ ' + line.substring(1).trim(), theme.dim);\n return result;\n }\n\n // Image handling\n if (line.includes('![')) {\n const imageMatch = line.match(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/);\n if (imageMatch) {\n const alt = imageMatch[1] || 'Image';\n let url = imageMatch[2];\n \n // Prepend API_URL if the URL is relative\n if (!url.startsWith('http')) {\n url = `${API_URL}${url.startsWith('/') ? '' : '/'}${url}`;\n }\n \n // Simple, clean image indicator\n const imageStartLine = result.length;\n result.push('');\n result.push(chalk.cyan('[IMAGE] ') + chalk.white(alt || 'Image'));\n result.push(chalk.yellow('Press [I] to view in browser'));\n \n // Track the image with its line range for [I] key handling\n const imageEndLine = result.length;\n this.trackedImages.push({ url, alt, lineNumber: imageStartLine, endLine: imageEndLine });\n result.push('');\n \n // Process any text before or after the image on the same line\n const beforeImage = line.substring(0, line.indexOf('!['));\n const afterImage = line.substring(line.indexOf(')') + 1);\n \n if (beforeImage.trim()) {\n const wrapped = this.wrapText(beforeImage, wrapWidth);\n wrapped.forEach(wl => result.unshift(wl));\n }\n \n if (afterImage.trim()) {\n const wrapped = this.wrapText(afterImage, wrapWidth);\n wrapped.forEach(wl => result.push(wl));\n }\n \n return result;\n }\n }\n \n // Inline code handling\n if (line.includes('`')) {\n const formatted = this.formatInlineCode(line, theme);\n // Push formatted line directly without adding color metadata\n result.push(formatted);\n return result;\n }\n\n // Regular text - check for inline color markers\n if (line.trim()) {\n // Check if line starts with a color marker like \"green:text\" or \"green: text\"\n const colorMatch = line.match(/^(red|green|blue|yellow|cyan|magenta|white|gray|brightRed|brightGreen|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n if (colorMatch) {\n const color = colorMatch[1].toLowerCase();\n const text = colorMatch[2] || '';\n // If there's text after the color, use it WITHOUT the color prefix\n if (text.trim()) {\n const cleanText = text.trim();\n const wrapped = this.wrapText(cleanText, wrapWidth);\n // Push directly with color metadata, don't let theme add more\n wrapped.forEach(wl => {\n result.push(`${color}:${wl}`);\n });\n } else {\n // No text after color marker, treat as regular text\n const wrapped = this.wrapText(line, wrapWidth);\n wrapped.forEach(wl => result.push(wl));\n }\n } else {\n // For non-colored lines, just add the plain text without color metadata\n const wrapped = this.wrapText(line, wrapWidth);\n wrapped.forEach(wl => result.push(wl));\n }\n } else {\n result.push('');\n }\n\n return result;\n }\n\n /**\n * Format inline code in text\n */\n private formatInlineCode(text: string, theme: any): string {\n // Replace inline code with formatted version\n const themeName = (this.bbs as any).theme || 'classic';\n return text.replace(/`([^`]+)`/g, (_, code) => {\n return CodeHighlighter.formatInlineCode(code, themeName);\n });\n }\n\n /**\n * Add a colored line to the content array\n */\n private addColoredLine(\n lines: string[],\n text: string,\n color: string,\n bold: boolean = false\n ) {\n // Check if text already has a color tag - if so, don't add another\n const hasColorTag = /^(red|green|blue|yellow|cyan|magenta|white|gray|brightRed|brightGreen|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):/i.test(text);\n\n if (hasColorTag) {\n // Text already has color specified, push as-is\n lines.push(text);\n } else if (color === 'white' || color === 'text') {\n // For default text color, don't add metadata - just push the plain text\n lines.push(text);\n } else {\n // Store the line with color metadata for non-default colors\n lines.push(`${color}${bold ? ':BOLD' : ''}:${text}`);\n }\n }\n\n /**\n * Parse ANSI escape codes and render text with terminal-kit colors\n */\n private parseAndRenderANSI(line: string, x: number, y: number) {\n // Common ANSI color codes mapping\n const ansiToColor: Record<string, string> = {\n '30': 'black',\n '31': 'red',\n '32': 'green',\n '33': 'yellow',\n '34': 'blue',\n '35': 'magenta',\n '36': 'cyan',\n '37': 'white',\n '90': 'gray',\n '91': 'brightRed',\n '92': 'brightGreen',\n '93': 'brightYellow',\n '94': 'brightBlue',\n '95': 'brightMagenta',\n '96': 'brightCyan',\n '97': 'brightWhite',\n '38;5;250': 'gray', // Common gray shade\n '39': 'white' // Default color\n };\n\n // Split the line by ANSI escape sequences\n const parts = line.split(/\\x1b\\[([0-9;]+)m/);\n let currentX = x;\n let currentColor = 'white';\n let isBold = false;\n let isDim = false;\n\n for (let i = 0; i < parts.length; i++) {\n if (i % 2 === 0) {\n // This is text content\n const text = parts[i];\n if (text) {\n // Apply current formatting\n let color = currentColor;\n if (isDim && color === 'white') {\n color = 'gray';\n }\n this.bbs.put(currentX, y, text, color, isBold);\n currentX += text.length;\n }\n } else {\n // This is an ANSI code\n const codes = parts[i].split(';');\n for (const code of codes) {\n if (code === '0') {\n // Reset\n currentColor = 'white';\n isBold = false;\n isDim = false;\n } else if (code === '1') {\n isBold = true;\n } else if (code === '2') {\n isDim = true;\n } else if (code === '22') {\n isBold = false;\n isDim = false;\n } else if (code === '23') {\n // Not italic (we don't support italic in terminal)\n } else if (ansiToColor[code]) {\n currentColor = ansiToColor[code];\n } else if (parts[i] in ansiToColor) {\n // Handle compound codes like '38;5;250'\n currentColor = ansiToColor[parts[i]];\n }\n }\n }\n }\n }\n\n /**\n * Render the current view to buffers\n */\n render() {\n try {\n // Clear back buffer\n this.backBuffer.fill({\n char: ' ',\n attr: { color: 'white', bgColor: 'black' }\n });\n\n const theme = this.bbs.getTheme();\n\n // Draw header\n this.drawHeader();\n\n // Draw content area based on view mode\n switch (this.viewMode) {\n case 'split':\n this.drawTOC();\n this.drawContent();\n break;\n case 'toc':\n this.drawTOCFullScreen();\n break;\n case 'content':\n this.drawContentFullScreen();\n break;\n }\n\n // Draw footer with navigation hints\n this.drawFooter();\n\n // Copy back buffer to screen buffer\n this.backBuffer.draw({ dst: this.screenBuffer });\n this.screenBuffer.draw({ delta: true });\n } catch (error: any) {\n // Emit error to parent for handling without logging to stderr\n this.emit('error', error);\n }\n }\n\n /**\n * Draw the header\n */\n private drawHeader() {\n // Use the BBS header with course title - truncate if needed\n const maxTitleLength = 30;\n const displayTitle = this.courseTitle.length > maxTitleLength ?\n this.courseTitle.substring(0, maxTitleLength - 3) + '...' :\n this.courseTitle.toUpperCase();\n this.bbs.drawBBSHeader(this.username, displayTitle, 0);\n }\n\n /**\n * Draw table of contents panel\n */\n private drawTOC() {\n const theme = this.bbs.getTheme();\n\n // TOC box - highlight if focused in split view\n const isFocused = this.viewMode === 'split' && this.focusPanel === 'toc';\n this.bbs.drawBox(0, this.headerHeight, this.tocWidth, this.contentHeight, 'JUMP TO', isFocused);\n\n // Render TOC entries\n const visibleTocItems = Math.min(\n this.tocEntries.length - this.tocScrollOffset,\n this.contentHeight - 2\n );\n\n let currentArticle = '';\n for (let i = 0; i < visibleTocItems; i++) {\n const entry = this.tocEntries[this.tocScrollOffset + i];\n const y = this.headerHeight + 1 + i;\n const isSelected = this.tocScrollOffset + i === this.selectedTocIndex;\n\n // Clear line first\n for (let x = 1; x < this.tocWidth - 1; x++) {\n this.bbs.put(x, y, ' ');\n }\n\n // Check if we're starting a new article section\n if (entry.type === 'article') {\n currentArticle = entry.title;\n // Draw article separator if not the first item\n if (i > 0) {\n // Draw a subtle separator line above the article\n for (let x = 2; x < this.tocWidth - 2; x++) {\n this.bbs.put(x, y - 1, '─', theme.dim);\n }\n }\n // Draw article title in a distinct style\n const maxLength = this.tocWidth - 4;\n const displayText = entry.title.length > maxLength ?\n entry.title.substring(0, maxLength - 3) + '...' :\n entry.title;\n \n if (isSelected) {\n this.bbs.put(1, y, '>', theme.accent);\n }\n this.bbs.put(2, y, displayText, theme.primary, true);\n } else if (entry.type === 'heading') {\n // Indentation and color based on heading level\n let indent = 4;\n let color = theme.secondary;\n \n if (entry.level === 2) {\n // H2 headings - less indented\n indent = 4;\n color = theme.secondary;\n } else if (entry.level === 3) {\n // H3 headings - more indented, same color as H2\n indent = 6;\n color = theme.secondary;\n }\n\n // Selection indicator\n if (isSelected) {\n this.bbs.put(indent - 2, y, '>', theme.accent);\n }\n\n // Truncate text if needed\n const maxLength = this.tocWidth - indent - 2;\n let displayText = entry.title;\n \n // Don't uppercase in TOC - keep original case\n if (displayText.length > maxLength) {\n displayText = displayText.substring(0, maxLength - 3) + '...';\n }\n\n this.bbs.put(indent, y, displayText, color, false);\n }\n }\n\n // Scroll indicators on the right side of the TOC window\n if (this.tocScrollOffset > 0) {\n this.bbs.put(this.tocWidth - 2, this.headerHeight, '▲', theme.accent);\n }\n if (this.tocScrollOffset + visibleTocItems < this.tocEntries.length) {\n this.bbs.put(this.tocWidth - 2, this.headerHeight + this.contentHeight - 1, '▼', theme.accent);\n }\n }\n\n /**\n * Draw content panel\n */\n private drawContent() {\n const theme = this.bbs.getTheme();\n const contentWidth = this.width - this.contentStartX;\n\n // Content box - highlight if focused in split view\n const isFocused = this.viewMode === 'split' && this.focusPanel === 'content';\n this.bbs.drawBox(this.contentStartX, this.headerHeight, contentWidth, this.contentHeight, 'ARTICLE', isFocused);\n\n // Render visible content lines\n const visibleLines = Math.min(\n this.contentLines.length - this.scrollOffset,\n this.contentHeight - 2\n );\n\n for (let i = 0; i < visibleLines; i++) {\n const line = this.contentLines[this.scrollOffset + i];\n const y = this.headerHeight + 1 + i;\n\n // Clear line first\n for (let x = this.contentStartX + 1; x < this.width - 1; x++) {\n this.bbs.put(x, y, ' ');\n }\n\n // Check if the line contains ANSI codes (from syntax highlighting)\n if (line && line.includes('\\x1b[')) {\n // Check if this line is part of a copied code block\n const lineNum = this.scrollOffset + i;\n const isCopiedLine = this.copiedBlockIndex >= 0 &&\n Date.now() - this.copiedTimestamp < 3000 &&\n this.codeBlocks[this.copiedBlockIndex] &&\n lineNum >= this.codeBlocks[this.copiedBlockIndex].startLine &&\n lineNum <= this.codeBlocks[this.copiedBlockIndex].endLine;\n\n // Parse and render with proper colors\n this.parseAndRenderANSI(line, this.contentStartX + 2, y);\n \n // Show success message at the bottom line of the code block\n if (isCopiedLine && lineNum === this.codeBlocks[this.copiedBlockIndex].endLine) {\n // Show success message at the bottom of the code block\n const msg = ' ✓ COPIED TO CLIPBOARD!';\n this.bbs.put(this.contentStartX + 2, y, msg, 'brightGreen', true);\n }\n }\n // Parse color metadata from line (original format) - check for specific pattern first\n else if (line && line.match(/^([a-zA-Z]+)((?::BOLD)?):(.*)$/)) {\n const match = line.match(/^([a-zA-Z]+)((?::BOLD)?):(.*)$/);\n if (match) {\n const color = match[1].toLowerCase();\n const isBold = match[2] === ':BOLD';\n let text = match[3] || '';\n\n\n // Check if the text itself starts with another color tag (double-tagged)\n // This can happen when theme adds a color and content has color:\n const doubleTagMatch = text.match(/^(red|green|blue|yellow|cyan|magenta|white|gray|brightRed|brightGreen|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n if (doubleTagMatch) {\n // Use the inner color and text\n const innerColor = doubleTagMatch[1].toLowerCase();\n let innerText = doubleTagMatch[2] || '';\n // Strip any additional color tags that might have slipped through\n innerText = innerText.replace(/^(green|red|blue|yellow|cyan|magenta|white|gray|brightGreen|brightRed|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*/i, '');\n // Only display if there's text after the inner color tag\n if (innerText.trim()) {\n this.bbs.put(this.contentStartX + 2, y, innerText.trim(), innerColor, isBold);\n }\n } else if (text) {\n // Check one more time if text starts with a color tag\n const cleanText = text.replace(/^(green|red|blue|yellow|cyan|magenta|white|gray|brightGreen|brightRed|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*/i, '');\n // Normal case - display with the metadata color\n this.bbs.put(this.contentStartX + 2, y, cleanText || text, color, isBold);\n }\n }\n } else if (line) {\n // Check if this might be a line that starts with a color tag in the content\n const inlineColorMatch = line.match(/^(red|green|blue|yellow|cyan|magenta|white|gray|brightRed|brightGreen|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n if (inlineColorMatch) {\n // This is a color-tagged line that wasn't caught by metadata parsing\n const color = inlineColorMatch[1].toLowerCase();\n const text = inlineColorMatch[2] || line;\n this.bbs.put(this.contentStartX + 2, y, text, color);\n } else {\n // Check if this line is part of a copied code block\n const lineNum = this.scrollOffset + i;\n const isCopiedLine = this.copiedBlockIndex >= 0 &&\n Date.now() - this.copiedTimestamp < 3000 &&\n this.codeBlocks[this.copiedBlockIndex] &&\n lineNum >= this.codeBlocks[this.copiedBlockIndex].startLine &&\n lineNum <= this.codeBlocks[this.copiedBlockIndex].endLine;\n\n // Plain text - no truncation for regular text\n const displayText = line;\n\n // Check if this line looks like it's from a code block (has frame characters)\n const isCodeBlockFrame = displayText.includes('╭─') || displayText.includes('│') ||\n displayText.includes('╰─') || displayText.includes('─╮') ||\n displayText.includes('─╯');\n\n // Ensure we have a valid string\n if (displayText) {\n // Check if this line itself starts with a color tag that wasn't caught\n const lineColorMatch = displayText.match(/^(green|red|blue|yellow|cyan|magenta|white|gray|brightGreen|brightRed|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n\n // Show success message at the bottom line of the code block\n if (isCopiedLine && lineNum === this.codeBlocks[this.copiedBlockIndex].endLine) {\n // Show copied message at bottom of code block\n this.bbs.put(this.contentStartX + 2, y, ' ✓ COPIED TO CLIPBOARD!', 'brightGreen', true);\n } else if (isCopiedLine && isCodeBlockFrame) {\n // Highlight the code block frame\n this.bbs.put(this.contentStartX + 2, y, displayText, 'brightGreen');\n } else if (lineColorMatch) {\n // This line has an inline color tag - display with that color\n const inlineColor = lineColorMatch[1].toLowerCase();\n const inlineText = lineColorMatch[2] || '';\n // Only display if there's actual text after the color tag\n if (inlineText.trim()) {\n this.bbs.put(this.contentStartX + 2, y, inlineText, inlineColor);\n } else {\n // Just a color tag with no text - skip or show the original\n this.bbs.put(this.contentStartX + 2, y, displayText, theme.text);\n }\n } else {\n // Normal rendering\n const color = isCodeBlockFrame ? 'gray' : theme.text;\n this.bbs.put(this.contentStartX + 2, y, displayText, color);\n }\n }\n }\n }\n }\n\n // Scroll indicators on the right side of the content window\n if (this.scrollOffset > 0) {\n this.bbs.put(this.width - 2, this.headerHeight, '▲', theme.accent);\n }\n if (this.scrollOffset + visibleLines < this.contentLines.length) {\n this.bbs.put(this.width - 2, this.headerHeight + this.contentHeight - 1, '▼', theme.accent);\n }\n\n // Line counter\n const lineInfo = `${this.scrollOffset + 1}-${Math.min(\n this.scrollOffset + visibleLines,\n this.contentLines.length\n )}/${this.contentLines.length}`;\n this.bbs.put(this.width - lineInfo.length - 2, this.headerHeight, lineInfo, theme.dim);\n }\n\n /**\n * Draw TOC in full screen mode\n */\n private drawTOCFullScreen() {\n // Similar to drawTOC but uses full width\n const theme = this.bbs.getTheme();\n\n this.bbs.drawBox(0, this.headerHeight, this.width, this.contentHeight, 'JUMP TO');\n\n const visibleTocItems = Math.min(\n this.tocEntries.length - this.tocScrollOffset,\n this.contentHeight - 2\n );\n\n let currentArticle = '';\n for (let i = 0; i < visibleTocItems; i++) {\n const entry = this.tocEntries[this.tocScrollOffset + i];\n const y = this.headerHeight + 1 + i;\n const isSelected = this.tocScrollOffset + i === this.selectedTocIndex;\n\n // Clear line\n for (let x = 1; x < this.width - 1; x++) {\n this.bbs.put(x, y, ' ');\n }\n\n // Check if we're starting a new article section\n if (entry.type === 'article') {\n currentArticle = entry.title;\n // Draw article separator if not the first item\n if (i > 0) {\n // Draw a subtle separator line above the article\n for (let x = 4; x < this.width - 4; x++) {\n this.bbs.put(x, y - 1, '─', theme.dim);\n }\n }\n // Draw article title in a distinct style\n if (isSelected) {\n this.bbs.put(2, y, '>', theme.accent);\n }\n this.bbs.put(4, y, entry.title, theme.primary, true);\n } else if (entry.type === 'heading') {\n // Indentation and color based on heading level\n let indent = 6;\n let color = theme.secondary;\n \n if (entry.level === 2) {\n // H2 headings - less indented\n indent = 6;\n color = theme.secondary;\n } else if (entry.level === 3) {\n // H3 headings - more indented, same color as H2\n indent = 10;\n color = theme.secondary;\n }\n\n // Selection indicator\n if (isSelected) {\n this.bbs.put(indent - 2, y, '>', theme.accent);\n }\n\n // Display text - keep original case in TOC\n let displayText = entry.title;\n\n this.bbs.put(indent, y, displayText, color, false);\n }\n }\n \n // Scroll indicators on the right side\n if (this.tocScrollOffset > 0) {\n this.bbs.put(this.width - 2, this.headerHeight, '▲', theme.accent);\n }\n if (this.tocScrollOffset + visibleTocItems < this.tocEntries.length) {\n this.bbs.put(this.width - 2, this.headerHeight + this.contentHeight - 1, '▼', theme.accent);\n }\n }\n\n /**\n * Draw content in full screen mode\n */\n private drawContentFullScreen() {\n // Similar to drawContent but uses full width\n const theme = this.bbs.getTheme();\n\n this.bbs.drawBox(0, this.headerHeight, this.width, this.contentHeight, 'ARTICLE');\n\n const visibleLines = Math.min(\n this.contentLines.length - this.scrollOffset,\n this.contentHeight - 2\n );\n\n for (let i = 0; i < visibleLines; i++) {\n const line = this.contentLines[this.scrollOffset + i];\n const y = this.headerHeight + 1 + i;\n\n // Clear line\n for (let x = 1; x < this.width - 1; x++) {\n this.bbs.put(x, y, ' ');\n }\n\n // Check if the line contains ANSI codes (from syntax highlighting)\n if (line && line.includes('\\x1b[')) {\n // Check if this line is part of a copied code block\n const lineNum = this.scrollOffset + i;\n const isCopiedLine = this.copiedBlockIndex >= 0 &&\n Date.now() - this.copiedTimestamp < 3000 &&\n this.codeBlocks[this.copiedBlockIndex] &&\n lineNum >= this.codeBlocks[this.copiedBlockIndex].startLine &&\n lineNum <= this.codeBlocks[this.copiedBlockIndex].endLine;\n\n // Parse and render with proper colors\n this.parseAndRenderANSI(line, 4, y);\n \n // Show success message at the bottom line of the code block\n if (isCopiedLine && lineNum === this.codeBlocks[this.copiedBlockIndex].endLine) {\n // Show success message at the bottom of the code block\n const msg = ' ✓ COPIED TO CLIPBOARD!';\n this.bbs.put(4, y, msg, 'brightGreen', true);\n }\n }\n // Parse color metadata from line (original format) - check for specific pattern first\n else if (line && line.match(/^([a-zA-Z]+)((?::BOLD)?):(.*)$/)) {\n // More flexible pattern to match color metadata\n const match = line.match(/^([a-zA-Z]+)((?::BOLD)?):(.*)$/);\n if (match) {\n const color = match[1].toLowerCase();\n const isBold = match[2] === ':BOLD';\n let text = match[3] || '';\n\n // Check if the text itself starts with another color tag (double-tagged)\n // This can happen when theme adds a color and content has color:\n const doubleTagMatch = text.match(/^(red|green|blue|yellow|cyan|magenta|white|gray|brightRed|brightGreen|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n if (doubleTagMatch) {\n // Use the inner color and text\n const innerColor = doubleTagMatch[1].toLowerCase();\n let innerText = doubleTagMatch[2] || '';\n // Strip any additional color tags that might have slipped through\n innerText = innerText.replace(/^(green|red|blue|yellow|cyan|magenta|white|gray|brightGreen|brightRed|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*/i, '');\n // Only display if there's text after the inner color tag\n if (innerText.trim()) {\n this.bbs.put(4, y, innerText.trim(), innerColor, isBold);\n }\n } else if (text) {\n // Check one more time if text starts with a color tag\n const cleanText = text.replace(/^(green|red|blue|yellow|cyan|magenta|white|gray|brightGreen|brightRed|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*/i, '');\n // Normal case - display with the metadata color\n this.bbs.put(4, y, cleanText || text, color, isBold);\n }\n } else {\n // Not a color-coded line, treat as plain text\n const displayText = line;\n\n if (displayText) {\n this.bbs.put(4, y, displayText, theme.text);\n }\n }\n } else if (line) {\n // Check if this might be a line that starts with a color tag in the content\n const inlineColorMatch = line.match(/^(red|green|blue|yellow|cyan|magenta|white|gray|brightRed|brightGreen|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n if (inlineColorMatch) {\n // This is a color-tagged line that wasn't caught by metadata parsing\n const color = inlineColorMatch[1].toLowerCase();\n const text = inlineColorMatch[2] || line;\n this.bbs.put(4, y, text, color);\n } else {\n // Check if this line is part of a copied code block\n const lineNum = this.scrollOffset + i;\n const isCopiedLine = this.copiedBlockIndex >= 0 &&\n Date.now() - this.copiedTimestamp < 3000 &&\n this.codeBlocks[this.copiedBlockIndex] &&\n lineNum >= this.codeBlocks[this.copiedBlockIndex].startLine &&\n lineNum <= this.codeBlocks[this.copiedBlockIndex].endLine;\n\n // In full mode, use the full width\n const displayText = line;\n\n // Check if this line looks like it's from a code block (has frame characters)\n const isCodeBlockFrame = displayText.includes('╭─') || displayText.includes('│') ||\n displayText.includes('╰─') || displayText.includes('─╮') ||\n displayText.includes('─╯');\n\n if (displayText) {\n // Check if this line itself starts with a color tag that wasn't caught\n const lineColorMatch = displayText.match(/^(green|red|blue|yellow|cyan|magenta|white|gray|brightGreen|brightRed|brightBlue|brightYellow|brightCyan|brightMagenta|brightWhite):\\s*(.*)/i);\n\n // Show success message at the bottom line of the code block\n if (isCopiedLine && lineNum === this.codeBlocks[this.copiedBlockIndex].endLine) {\n // Show copied message at bottom of code block\n this.bbs.put(4, y, ' ✓ COPIED TO CLIPBOARD!', 'brightGreen', true);\n } else if (isCopiedLine && isCodeBlockFrame) {\n // Highlight the code block frame\n this.bbs.put(4, y, displayText, 'brightGreen');\n } else if (lineColorMatch) {\n // This line has an inline color tag - display with that color\n const inlineColor = lineColorMatch[1].toLowerCase();\n const inlineText = lineColorMatch[2] || displayText;\n this.bbs.put(4, y, inlineText, inlineColor);\n } else {\n this.bbs.put(4, y, displayText, theme.text);\n }\n }\n }\n }\n }\n \n // Scroll indicators on the right side\n if (this.scrollOffset > 0) {\n this.bbs.put(this.width - 2, this.headerHeight, '▲', theme.accent);\n }\n if (this.scrollOffset + visibleLines < this.contentLines.length) {\n this.bbs.put(this.width - 2, this.headerHeight + this.contentHeight - 1, '▼', theme.accent);\n }\n }\n\n /**\n * Draw footer with navigation hints\n */\n private drawFooter() {\n const theme = this.bbs.getTheme();\n const y = this.height - 2;\n\n // Footer border\n this.bbs.drawBox(0, y - 1, this.width, this.footerHeight, '');\n\n // Navigation hints based on current mode\n let hints: string[] = [];\n if (this.viewMode === 'split') {\n hints = [\n '[↑↓] Scroll',\n '[←→] Focus',\n '[Tab] Switch',\n '[Enter] Jump',\n '[C] Copy Code',\n '[F] Full',\n '[Q] Back'\n ];\n // Add focus indicator\n const focusText = `[Focus: ${this.focusPanel.toUpperCase()}]`;\n this.bbs.put(this.width - focusText.length - 2, y - 2, focusText, theme.accent);\n } else {\n hints = [\n '[↑↓] Scroll',\n '[Tab] Mode',\n '[Enter] Jump',\n '[C] Copy Code',\n '[T] TOC',\n '[F] Full',\n '[Q] Back'\n ];\n }\n\n let x = 2;\n hints.forEach(hint => {\n if (x + hint.length < this.width - 2) {\n this.bbs.put(x, y, hint, theme.dim);\n x += hint.length + 2;\n }\n });\n }\n\n /**\n * Copy code block to clipboard\n */\n private openImageAtCurrentPosition(): boolean {\n // Find if current viewport contains any part of an image\n const viewportStart = this.scrollOffset;\n const viewportEnd = this.scrollOffset + this.contentHeight - 2;\n\n // Find any image that overlaps with the current viewport\n for (const image of this.trackedImages) {\n // Check if any part of the image is visible in the current viewport\n const imageVisible = (\n // Image starts within viewport\n (image.lineNumber >= viewportStart && image.lineNumber <= viewportEnd) ||\n // Image ends within viewport (if endLine is set)\n (image.endLine && image.endLine >= viewportStart && image.endLine <= viewportEnd) ||\n // Image spans entire viewport\n (image.lineNumber <= viewportStart && image.endLine && image.endLine >= viewportEnd)\n );\n\n if (imageVisible) {\n // Open the image URL in browser\n open(image.url);\n \n // Show status message (if we have a status message system)\n // For now, just return true to indicate success\n return true;\n }\n }\n\n return false;\n }\n\n private copyCodeBlockAtCurrentPosition(): boolean {\n // Find if current viewport contains any part of a code block\n const viewportStart = this.scrollOffset;\n const viewportEnd = this.scrollOffset + this.contentHeight - 2;\n\n // Debug: Check what code blocks we have\n // console.error(`Viewport: ${viewportStart}-${viewportEnd}, Code blocks:`, this.codeBlocks.map(b => `${b.startLine}-${b.endLine}`));\n\n // Find any code block that overlaps with the current viewport\n for (const block of this.codeBlocks) {\n // Check if any part of the code block is visible in the current viewport\n const blockVisible = (\n // Block starts within viewport\n (block.startLine >= viewportStart && block.startLine <= viewportEnd) ||\n // Block ends within viewport\n (block.endLine >= viewportStart && block.endLine <= viewportEnd) ||\n // Block spans entire viewport\n (block.startLine <= viewportStart && block.endLine >= viewportEnd)\n );\n\n if (blockVisible) {\n try {\n // Try to copy to clipboard using platform-specific commands\n const platform = process.platform;\n let command: string;\n\n if (platform === 'darwin') {\n // macOS\n command = 'pbcopy';\n } else if (platform === 'win32') {\n // Windows\n command = 'clip';\n } else {\n // Linux/Unix - try xclip first, then xsel\n try {\n execSync('which xclip', { stdio: 'ignore' });\n command = 'xclip -selection clipboard';\n } catch {\n command = 'xsel --clipboard --input';\n }\n }\n\n execSync(command, { input: block.code });\n\n // Track which block was copied (update pure state)\n const nowMs = Date.now();\n this.vs = {\n ...this.vs,\n copiedBlockIndex: this.codeBlocks.indexOf(block),\n copiedTimestamp: nowMs,\n };\n\n // Show feedback with language info\n const theme = this.bbs.getTheme();\n const langInfo = block.language ? ` (${block.language})` : '';\n const lineCount = block.code.split('\\n').length;\n this.showNotification(`✓ Copied ${lineCount} lines${langInfo}!`, 'green');\n\n // Re-render to show the highlight\n this.render();\n\n // Clear the highlight after 3 seconds\n setTimeout(() => {\n if (Date.now() - this.vs.copiedTimestamp >= 2900) {\n this.vs = { ...this.vs, copiedBlockIndex: -1 };\n this.render();\n }\n }, 3000);\n\n return true;\n } catch (error) {\n this.showNotification('✗ Failed to copy. Install xclip (Linux) or try manual selection.', 'red');\n return false;\n }\n }\n }\n\n // Debug message\n const debugMsg = this.codeBlocks.length === 0 ?\n '⚠ No code blocks found in this article' :\n '⚠ No code block visible. Scroll to a code block and try again.';\n this.showNotification(debugMsg, 'yellow');\n return false;\n }\n\n /**\n * Show a temporary notification\n */\n private showNotification(message: string, color: string) {\n const y = Math.floor(this.height / 2); // Center vertically\n const boxWidth = message.length + 6;\n const x = Math.floor((this.width - boxWidth) / 2);\n\n // Draw a box around the message for prominence\n const theme = this.bbs.getTheme();\n\n // Clear area for the notification box\n for (let row = y - 1; row <= y + 1; row++) {\n for (let col = x; col < x + boxWidth; col++) {\n this.bbs.put(col, row, ' ', 'black');\n }\n }\n\n // Draw box border\n this.bbs.put(x, y - 1, '╭' + '─'.repeat(boxWidth - 2) + '╮', color);\n this.bbs.put(x, y, '│', color);\n this.bbs.put(x + boxWidth - 1, y, '│', color);\n this.bbs.put(x, y + 1, '╰' + '─'.repeat(boxWidth - 2) + '╯', color);\n\n // Show the message in the center\n this.bbs.put(x + 3, y, message, color, true);\n\n // Update screen immediately\n this.backBuffer.draw({ dst: this.screenBuffer });\n this.screenBuffer.draw({ delta: true });\n\n // Clear after 2 seconds\n setTimeout(() => {\n // Just re-render to clear the notification\n this.render();\n }, 2000);\n }\n\n /**\n * Handle keyboard input.\n *\n * Navigation logic is delegated to the pure `reduce()` function; only\n * side effects (copy to clipboard, open image, emit exit) live here.\n */\n handleInput(key: string): boolean {\n try {\n const tocLines = this.tocEntries.map(e => e.line);\n const result = reduce(\n this.vs,\n key,\n this.contentLines.length,\n this.tocEntries.length,\n tocLines\n );\n\n // Update state (always safe — reducer returns the same object on no-op)\n this.vs = result.state;\n\n // Dispatch side effects\n if (result.effect === 'copy_code') {\n this.copyCodeBlockAtCurrentPosition();\n } else if (result.effect === 'open_image') {\n this.openImageAtCurrentPosition();\n } else if (result.effect === 'exit') {\n this.emit('exit');\n }\n\n // Re-render whenever the key was handled (except pure side-effect keys\n // that already call render() themselves via copy/notification helpers)\n if (result.handled && result.effect === 'none') {\n this.render();\n }\n\n return result.handled;\n } catch (error: any) {\n // Emit error to parent for handling without logging to stderr\n this.emit('error', error);\n return false;\n }\n }\n\n /**\n * Wrap text to fit width\n */\n private wrapText(text: string, maxWidth: number): string[] {\n if (text.length <= maxWidth) {\n return [text];\n }\n\n const words = text.split(' ');\n const lines: string[] = [];\n let currentLine = '';\n\n for (const word of words) {\n if (currentLine.length + word.length + 1 > maxWidth) {\n if (currentLine) {\n lines.push(currentLine);\n currentLine = word;\n } else {\n lines.push(word);\n }\n } else {\n currentLine = currentLine ? currentLine + ' ' + word : word;\n }\n }\n\n if (currentLine) {\n lines.push(currentLine);\n }\n\n return lines;\n }\n}\n","import chalk from 'chalk';\nimport { marked } from 'marked';\nimport stripAnsi from 'strip-ansi';\nimport { applyTheme, ThemeName } from './theme-colors.js';\nimport { CodeHighlighter } from './code-highlighter.js';\nimport { API_URL } from '../config/constants.js';\nimport asciify from 'asciify-image';\nimport fetch from 'node-fetch';\n\ninterface Heading {\n level: number;\n text: string;\n id: string;\n line: number;\n}\n\ninterface Article {\n id: number;\n title: string;\n markdown?: string;\n description?: string;\n order: number;\n}\n\nexport interface ImageInfo {\n url: string;\n alt: string;\n lineNumber: number;\n}\n\nexport class MarkdownTerminalRenderer {\n private theme: ReturnType<typeof applyTheme>;\n private width: number;\n private themeName: ThemeName;\n public trackedImages: ImageInfo[] = [];\n private pendingImages: Array<{alt: string, url: string}> = [];\n \n constructor(themeName?: ThemeName, width: number = 80) {\n this.themeName = themeName || 'classic';\n this.theme = applyTheme(this.themeName);\n this.width = width;\n }\n \n /**\n * Extract H2 and H3 headings from markdown to create a table of contents\n */\n extractHeadings(markdown: string): Heading[] {\n const headings: Heading[] = [];\n const lines = markdown.split('\\n');\n \n lines.forEach((line, index) => {\n // Match H2 (##) and H3 (###) headings\n const match = line.match(/^(#{2,3})\\s+(.+)$/);\n if (match) {\n const level = match[1].length;\n const text = match[2].trim();\n const id = text.toLowerCase().replace(/[^a-z0-9]+/g, '-');\n \n if (level === 2 || level === 3) {\n headings.push({\n level,\n text,\n id,\n line: index\n });\n }\n }\n });\n \n return headings;\n }\n \n /**\n * Render markdown content for terminal display\n */\n renderMarkdown(markdown: string): string[] {\n const lines = markdown.split('\\n');\n const rendered: string[] = [];\n let inCodeBlock = false;\n let inList = false;\n let codeBlockLines: string[] = [];\n let codeBlockLanguage = '';\n \n for (const line of lines) {\n // Code blocks with syntax highlighting\n if (line.startsWith('```')) {\n if (!inCodeBlock) {\n // Starting a code block\n inCodeBlock = true;\n codeBlockLanguage = line.substring(3).trim() || 'javascript';\n codeBlockLines = [];\n } else {\n // Ending a code block - render with highlighting\n inCodeBlock = false;\n const codeContent = codeBlockLines.join('\\n');\n const highlightedBlock = CodeHighlighter.formatCodeBlock(\n codeContent,\n codeBlockLanguage,\n this.width,\n this.themeName\n );\n rendered.push(...highlightedBlock);\n rendered.push(''); // Add spacing after code block\n }\n continue;\n }\n \n if (inCodeBlock) {\n codeBlockLines.push(line);\n continue;\n }\n \n // Headers\n if (line.startsWith('# ')) {\n rendered.push('');\n rendered.push('═'.repeat(Math.min(this.width, 60)));\n rendered.push(line.substring(2).toUpperCase());\n rendered.push('═'.repeat(Math.min(this.width, 60)));\n rendered.push('');\n continue;\n }\n \n if (line.startsWith('## ')) {\n rendered.push('');\n rendered.push(line.substring(3).toUpperCase());\n rendered.push('');\n continue;\n }\n \n if (line.startsWith('### ')) {\n rendered.push('');\n rendered.push(line.substring(4));\n continue;\n }\n \n if (line.startsWith('#### ')) {\n rendered.push(line.substring(5));\n continue;\n }\n \n // Lists\n if (line.match(/^[\\s]*[-*+]\\s+/)) {\n const indent = line.search(/\\S/);\n const bullet = indent > 0 ? '-' : '-';\n const content = line.replace(/^[\\s]*[-*+]\\s+/, '');\n rendered.push(' '.repeat(indent) + bullet + ' ' + this.processInlineFormatting(content));\n inList = true;\n continue;\n }\n \n // Numbered lists\n if (line.match(/^[\\s]*\\d+\\.\\s+/)) {\n const match = line.match(/^([\\s]*)(\\d+)\\.\\s+(.*)$/);\n if (match) {\n const [, indent, num, content] = match;\n rendered.push(indent + num + '. ' + this.processInlineFormatting(content));\n inList = true;\n }\n continue;\n }\n \n // Blockquotes\n if (line.startsWith('>')) {\n const content = line.substring(1).trim();\n rendered.push('> ' + content);\n continue;\n }\n \n // Horizontal rules\n if (line.match(/^[-*_]{3,}$/)) {\n rendered.push('');\n rendered.push('─'.repeat(Math.min(this.width, 60)));\n rendered.push('');\n continue;\n }\n \n // Empty lines\n if (line.trim() === '') {\n if (inList) {\n inList = false;\n }\n rendered.push('');\n continue;\n }\n \n // Regular paragraphs - process and check for images\n const processed = this.processInlineFormatting(line);\n \n // Check if line contains image placeholders\n if (processed.includes('\\x00IMAGE')) {\n // Process images asynchronously\n const parts = processed.split(/(\\x00IMAGE\\d+\\x00)/);\n for (const part of parts) {\n const imageMatch = part.match(/\\x00IMAGE(\\d+)\\x00/);\n if (imageMatch) {\n const index = parseInt(imageMatch[1]);\n if (this.pendingImages && this.pendingImages[index]) {\n const image = this.pendingImages[index];\n // Track image for [I] key handling; async rendering done separately\n this.trackedImages.push({ url: image.url, alt: image.alt, lineNumber: rendered.length });\n rendered.push(`[Image: ${image.alt}]`);\n }\n } else if (part) {\n const wrappedLines = this.wrapText(part, this.width - 4);\n rendered.push(...wrappedLines);\n }\n }\n } else {\n const wrappedLines = this.wrapText(processed, this.width - 4);\n rendered.push(...wrappedLines);\n }\n }\n \n return rendered.flat();\n }\n \n /**\n * Process inline markdown formatting (bold, italic, code, links, images)\n * Using a simpler, more reliable approach\n */\n private processInlineFormatting(text: string): string {\n let result = text;\n \n // Store code blocks, links, and images to protect them from formatting\n const codeBlocks: string[] = [];\n const links: Array<{text: string, url: string}> = [];\n \n // Clear pending images for this processing run\n this.pendingImages = [];\n \n // Extract and replace images FIRST (before regular links)\n result = result.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, (_, alt, url) => {\n const index = this.pendingImages.length;\n // Prepend API_URL if the URL is relative\n const fullUrl = url.startsWith('http') ? url : `${API_URL}${url.startsWith('/') ? '' : '/'}${url}`;\n this.pendingImages.push({ alt: alt || 'Image', url: fullUrl });\n return `\\x00IMAGE${index}\\x00`;\n });\n \n // Extract and replace inline code\n result = result.replace(/`([^`]+)`/g, (_, content) => {\n const index = codeBlocks.length;\n codeBlocks.push(CodeHighlighter.formatInlineCode(content, this.themeName));\n return `\\x00CODE${index}\\x00`;\n });\n \n // Extract and replace links\n result = result.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_, linkText, url) => {\n const index = links.length;\n links.push({ text: linkText, url });\n return `\\x00LINK${index}\\x00`;\n });\n \n // Apply formatting in the correct order to handle nesting\n // Handle triple asterisk/underscore (bold + italic) first\n result = result.replace(/\\*\\*\\*(.+?)\\*\\*\\*/g, (_, content) => {\n return chalk.bold(chalk.italic(content));\n });\n result = result.replace(/___(.+?)___/g, (_, content) => {\n return chalk.bold(chalk.italic(content));\n });\n \n // Handle double asterisk/underscore (bold)\n result = result.replace(/\\*\\*(.+?)\\*\\*/g, (_, content) => {\n // Check for nested italic\n const withItalic = content.replace(/\\*(.+?)\\*/g, (_: string, text: string) => chalk.italic(text));\n return chalk.bold(withItalic);\n });\n result = result.replace(/__(.+?)__/g, (_, content) => {\n // Check for nested italic\n const withItalic = content.replace(/_(.+?)_/g, (_: string, text: string) => chalk.italic(text));\n return chalk.bold(withItalic);\n });\n \n // Handle single asterisk/underscore (italic)\n result = result.replace(/(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)/g, (_, content) => {\n return chalk.italic(content);\n });\n result = result.replace(/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g, (_, content) => {\n return chalk.italic(content);\n });\n \n // Handle strikethrough\n result = result.replace(/~~(.+?)~~/g, (_, content) => {\n return chalk.strikethrough(content);\n });\n \n // Restore code blocks\n result = result.replace(/\\x00CODE(\\d+)\\x00/g, (_, index) => {\n return codeBlocks[parseInt(index)];\n });\n \n // Restore links with formatted text\n result = result.replace(/\\x00LINK(\\d+)\\x00/g, (_, index) => {\n const link = links[parseInt(index)];\n // Apply formatting to link text\n let formattedText = link.text;\n formattedText = formattedText.replace(/\\*\\*(.+?)\\*\\*/g, (_: string, text: string) => chalk.bold(text));\n formattedText = formattedText.replace(/\\*(.+?)\\*/g, (_: string, text: string) => chalk.italic(text));\n return chalk.underline(chalk.blue(formattedText)) + chalk.gray(` (${link.url})`);\n });\n \n // Note: Image placeholders will be processed later in renderMarkdownContent\n // Keep the placeholders for now\n \n return result;\n }\n \n /**\n * Create ASCII art representation of an image\n */\n private async createAsciiImage(alt: string, url: string, lineNumber: number): Promise<string> {\n const width = Math.min(70, this.width - 4);\n const border = '─'.repeat(width);\n \n // Track this image for [I] key handling\n this.trackedImages.push({ url, alt, lineNumber });\n const imageIndex = this.trackedImages.length;\n \n // Create ASCII art frame\n const lines: string[] = [];\n lines.push('');\n lines.push(chalk.gray('┌' + border + '┐'));\n \n try {\n // Try to fetch and convert the image to ASCII\n const response = await fetch(url);\n if (response.ok) {\n const buffer = await response.buffer();\n const asciiArt = await asciify(buffer, {\n fit: 'box',\n width: width - 4,\n height: 25,\n color: false,\n format: 'string'\n });\n \n // Add the ASCII art (asciify returns string | string[] depending on `format`)\n const asciiLines = Array.isArray(asciiArt) ? asciiArt : asciiArt.split('\\n');\n for (const line of asciiLines) {\n if (line) {\n const padding = Math.max(0, width - line.length);\n lines.push(chalk.gray('│ ') + chalk.cyan(line) + ' '.repeat(padding) + chalk.gray('│'));\n }\n }\n } else {\n // Fallback if image can't be loaded\n lines.push(chalk.gray('│') + chalk.yellow(' 🖼 Image could not be loaded ') + ' '.repeat(Math.max(0, width - 32)) + chalk.gray('│'));\n }\n } catch (error) {\n // Fallback on error - but still trackable\n lines.push(chalk.gray('│') + chalk.yellow(' 🖼 Image (local/offline) ') + ' '.repeat(Math.max(0, width - 28)) + chalk.gray('│'));\n }\n \n if (lines.length === 2) {\n // No image content was added, add a placeholder\n lines.push(chalk.gray('│') + chalk.dim(' [Image] ') + ' '.repeat(Math.max(0, width - 10)) + chalk.gray('│'));\n }\n \n lines.push(chalk.gray('├' + border + '┤'));\n \n // Add alt text if present\n if (alt && alt.trim()) {\n const altLines = this.wrapText(alt, width - 2);\n for (const line of altLines) {\n const padding = Math.max(0, width - stripAnsi(line).length);\n lines.push(chalk.gray('│ ') + chalk.white(line) + ' '.repeat(padding) + chalk.gray('│'));\n }\n lines.push(chalk.gray('├' + border + '┤'));\n }\n \n // Add instruction\n const instruction = `Press [I] to open image ${imageIndex} in browser`;\n const padding = Math.max(0, width - instruction.length);\n lines.push(chalk.gray('│ ') + chalk.yellow(instruction) + ' '.repeat(padding) + chalk.gray('│'));\n \n lines.push(chalk.gray('└' + border + '┘'));\n lines.push('');\n \n return lines.join('\\n');\n }\n \n /**\n * Wrap text to fit within specified width\n * Improved to handle ANSI codes better\n */\n private wrapText(text: string, maxWidth: number): string[] {\n // Use stripAnsi for accurate length calculation\n const plainText = stripAnsi(text);\n \n if (plainText.length <= maxWidth) {\n return [text];\n }\n \n const words = text.split(' ');\n const lines: string[] = [];\n let currentLine = '';\n \n for (const word of words) {\n const plainWord = stripAnsi(word);\n const plainLine = stripAnsi(currentLine);\n \n if (plainLine.length + plainWord.length + 1 > maxWidth) {\n if (currentLine) {\n lines.push(currentLine);\n currentLine = word;\n } else {\n // Word is longer than max width, force break\n lines.push(word);\n }\n } else {\n currentLine = currentLine ? currentLine + ' ' + word : word;\n }\n }\n \n if (currentLine) {\n lines.push(currentLine);\n }\n \n return lines;\n }\n \n /**\n * Render a table of contents from headings\n */\n renderTableOfContents(headings: Heading[]): string[] {\n const lines: string[] = [];\n \n lines.push('TABLE OF CONTENTS');\n lines.push('─'.repeat(40));\n lines.push('');\n \n let h2Count = 0;\n headings.forEach((heading) => {\n const indent = heading.level === 2 ? '' : ' ';\n let number = '';\n \n if (heading.level === 2) {\n h2Count++;\n number = `${h2Count}.`;\n } else {\n number = '•';\n }\n \n lines.push(\n indent + number + ' ' + heading.text\n );\n });\n \n lines.push('');\n lines.push('─'.repeat(40));\n \n return lines;\n }\n \n /**\n * Render article preview (for unowned courses)\n */\n renderArticlePreview(article: Article): string[] {\n const lines: string[] = [];\n \n lines.push(`Article ${article.order}: ${article.title}`);\n lines.push('─'.repeat(50));\n lines.push('');\n lines.push('⚠ Premium Content');\n \n if (article.description) {\n lines.push('');\n lines.push(...this.wrapText(article.description, this.width - 4));\n lines.push('');\n } else {\n lines.push('');\n lines.push('This article is part of the premium course.');\n lines.push('Purchase the course to access full content.');\n lines.push('');\n }\n \n return lines;\n }\n \n /**\n * Create a scrollable view data structure\n */\n createScrollableContent(articles: Article[], isOwned: boolean): {\n lines: string[];\n tocEntries: Array<{ title: string; line: number; type: 'article' | 'heading' }>;\n } {\n const allLines: string[] = [];\n const tocEntries: Array<{ title: string; line: number; type: 'article' | 'heading' }> = [];\n \n articles.sort((a, b) => a.order - b.order);\n \n articles.forEach((article, articleIndex) => {\n const startLine = allLines.length;\n \n // Add article to TOC\n tocEntries.push({\n title: `Article ${article.order}: ${article.title}`,\n line: startLine,\n type: 'article'\n });\n \n // Add article separator\n if (articleIndex > 0) {\n allLines.push('');\n allLines.push('═'.repeat(Math.min(this.width, 70)));\n allLines.push('');\n }\n \n // Add article header\n allLines.push(`ARTICLE ${article.order}: ${article.title.toUpperCase()}`);\n allLines.push('─'.repeat(Math.min(this.width, 70)));\n allLines.push('');\n \n if (isOwned && article.markdown) {\n // Render full markdown content\n const rendered = this.renderMarkdown(article.markdown);\n \n // Extract and add headings to TOC\n const headings = this.extractHeadings(article.markdown);\n headings.forEach(heading => {\n // Find the actual line number in rendered content\n const headingLine = startLine + allLines.length + \n rendered.findIndex(line => \n line.includes(heading.text)\n );\n \n tocEntries.push({\n title: (heading.level === 2 ? ' ' : ' ') + heading.text,\n line: headingLine,\n type: 'heading'\n });\n });\n \n allLines.push(...rendered);\n } else {\n // Show preview for unowned courses\n allLines.push(...this.renderArticlePreview(article));\n }\n \n allLines.push('');\n });\n \n return { lines: allLines, tocEntries };\n }\n}","import chalk from 'chalk';\nimport { highlight, supportsLanguage } from 'cli-highlight';\n\ninterface CodeBlockInfo {\n language: string;\n code: string;\n startLine: number;\n}\n\nexport class CodeHighlighter {\n private static readonly SUPPORTED_LANGUAGES = [\n 'javascript', 'js', 'typescript', 'ts', 'jsx', 'tsx',\n 'python', 'py', 'java', 'c', 'cpp', 'c++', 'csharp', 'cs',\n 'html', 'css', 'scss', 'sass', 'less',\n 'json', 'xml', 'yaml', 'yml',\n 'bash', 'sh', 'shell', 'powershell',\n 'sql', 'graphql', 'markdown', 'md',\n 'rust', 'go', 'php', 'ruby', 'swift', 'kotlin'\n ];\n\n /**\n * Extract code blocks from markdown with their language\n */\n static extractCodeBlocks(markdown: string): CodeBlockInfo[] {\n const codeBlocks: CodeBlockInfo[] = [];\n const lines = markdown.split('\\n');\n let inCodeBlock = false;\n let currentBlock: string[] = [];\n let currentLanguage = '';\n let blockStartLine = 0;\n\n lines.forEach((line, index) => {\n if (line.startsWith('```')) {\n if (!inCodeBlock) {\n // Starting a code block\n inCodeBlock = true;\n currentLanguage = line.substring(3).trim().toLowerCase() || 'text';\n blockStartLine = index;\n currentBlock = [];\n } else {\n // Ending a code block\n inCodeBlock = false;\n codeBlocks.push({\n language: currentLanguage,\n code: currentBlock.join('\\n'),\n startLine: blockStartLine\n });\n currentBlock = [];\n }\n } else if (inCodeBlock) {\n currentBlock.push(line);\n }\n });\n\n return codeBlocks;\n }\n\n /**\n * Highlight code with syntax highlighting\n */\n static highlightCode(code: string, language: string): string[] {\n try {\n // Map common aliases to cli-highlight language names\n const languageMap: Record<string, string> = {\n 'js': 'javascript',\n 'ts': 'typescript',\n 'py': 'python',\n 'yml': 'yaml',\n 'sh': 'bash',\n 'shell': 'bash',\n 'c++': 'cpp',\n 'cs': 'csharp',\n 'md': 'markdown'\n };\n\n const mappedLang = languageMap[language] || language;\n\n // Check if the language is supported\n if (supportsLanguage(mappedLang)) {\n const highlighted = highlight(code, { language: mappedLang });\n return highlighted.split('\\n');\n }\n } catch (error) {\n // Fall through to basic highlighting\n }\n\n // Fallback: Basic syntax highlighting using chalk\n return code.split('\\n').map(line => {\n // Basic JavaScript/TypeScript highlighting\n const lang = language.toLowerCase();\n if (lang === 'javascript' || lang === 'typescript' || lang === 'js' || lang === 'ts') {\n return line\n // Keywords\n .replace(/\\b(const|let|var|function|class|interface|type|return|if|else|for|while|import|export|from|extends|implements|new|this|super|async|await|try|catch|throw|switch|case|break|continue|default)\\b/g, chalk.blue('$1'))\n // Strings\n .replace(/([\"'])(?:(?=(\\\\?))\\2.)*?\\1/g, chalk.green('$&'))\n // Numbers\n .replace(/\\b(\\d+)\\b/g, chalk.cyan('$1'))\n // Comments\n .replace(/(\\/\\/.*$)/g, chalk.gray('$1'))\n // Functions\n .replace(/(\\w+)(?=\\()/g, chalk.yellow('$1'))\n // Properties\n .replace(/\\.(\\w+)/g, '.' + chalk.cyan('$1'));\n }\n \n // Default: return with minimal styling\n return chalk.white(line);\n });\n }\n\n /**\n * Format code block for terminal display with frame\n */\n static formatCodeBlock(\n code: string, \n language: string, \n width: number = 80,\n theme: 'classic' | 'desert' | 'matrix' | 'commando' | 'sandiego' | 'ed209' = 'classic',\n filename: string = '',\n lineNumStart: number = 1\n ): string[] {\n const lines: string[] = [];\n const maxWidth = width - 4; // Use the full provided width\n \n // Theme-based colors\n const frameColors = {\n classic: chalk.cyan,\n desert: chalk.yellow,\n matrix: chalk.green,\n commando: chalk.rgb(107, 142, 35), // Olive green\n sandiego: chalk.red,\n ed209: chalk.rgb(192, 192, 192) // Silver\n };\n \n const frameColor = frameColors[theme] || chalk.cyan;\n \n // Map language aliases\n const languageAliases: Record<string, string> = {\n 'ts': 'typescript',\n 'js': 'javascript',\n 'sh': 'bash',\n 'shell': 'bash',\n 'py': 'python',\n 'yml': 'yaml',\n 'c++': 'cpp',\n 'cs': 'csharp',\n 'md': 'markdown'\n };\n \n const displayLang = languageAliases[language.toLowerCase()] || language;\n const langDisplay = displayLang.toUpperCase();\n \n // Create header text with filename if provided\n let headerText = langDisplay;\n if (filename) {\n // Show filename with language\n headerText = `${filename} ─ ${langDisplay}`;\n // Truncate if too long\n if (headerText.length > maxWidth - 6) {\n headerText = '...' + headerText.substring(headerText.length - (maxWidth - 9));\n }\n }\n \n // Top frame with language/filename indicator\n const padding = Math.max(2, maxWidth - 2 - headerText.length - 2);\n const topBorder = '╭' + '─'.repeat(padding) + ` ${headerText} ` + '─╮';\n lines.push(frameColor(topBorder));\n \n // Highlight the code - use displayLang for better language detection\n const highlightedLines = this.highlightCode(code, displayLang);\n \n // Add line numbers and code\n highlightedLines.forEach((line, index) => {\n const lineNum = String(lineNumStart + index).padStart(3, ' ');\n const lineNumFormatted = chalk.dim.gray(`${lineNum} │`);\n \n // Don't truncate code lines - let them use full width\n let codeLine = line;\n const maxLineLength = maxWidth - 8;\n // Only truncate if extremely long (over 200 chars) to prevent terminal issues\n if (codeLine.length > 200) {\n codeLine = codeLine.substring(0, 197) + chalk.dim('...');\n }\n \n lines.push(`${frameColor('│')} ${lineNumFormatted} ${codeLine}`);\n });\n \n // Bottom frame with copy hint\n const bottomBorder = '╰' + '─'.repeat(maxWidth - 2) + '╯';\n lines.push(frameColor(bottomBorder));\n \n return lines;\n }\n\n /**\n * Create a selectable code block (stores position for interaction)\n */\n static createSelectableCodeBlock(\n code: string,\n language: string,\n startY: number,\n width: number = 80\n ): {\n lines: string[];\n bounds: { startY: number; endY: number; code: string; language: string };\n } {\n const formattedLines = this.formatCodeBlock(code, language, width);\n \n return {\n lines: formattedLines,\n bounds: {\n startY,\n endY: startY + formattedLines.length,\n code,\n language\n }\n };\n }\n\n /**\n * Format inline code\n */\n static formatInlineCode(code: string, theme: string = 'classic'): string {\n const themeColors = {\n classic: chalk.bgGray.white,\n desert: chalk.bgYellow.black,\n matrix: chalk.bgGreen.black,\n commando: chalk.bgRgb(107, 142, 35).white,\n sandiego: chalk.bgRed.white,\n ed209: chalk.bgRgb(105, 105, 105).white\n };\n \n const colorFn = themeColors[theme as keyof typeof themeColors] || chalk.bgGray.white;\n return ` ${colorFn(code)} `;\n }\n\n /**\n * Detect language from code content (heuristic)\n */\n static detectLanguage(code: string): string {\n // Simple heuristics for language detection\n const patterns = [\n { pattern: /\\bfunction\\s+\\w+\\s*\\(|const\\s+\\w+\\s*=|let\\s+\\w+\\s*=|var\\s+\\w+\\s*=/, lang: 'javascript' },\n { pattern: /\\bclass\\s+\\w+\\s*{|\\binterface\\s+\\w+\\s*{|\\btype\\s+\\w+\\s*=/, lang: 'typescript' },\n { pattern: /\\bdef\\s+\\w+\\s*\\(|\\bimport\\s+\\w+|\\bfrom\\s+\\w+\\s+import/, lang: 'python' },\n { pattern: /\\bpublic\\s+class\\s+\\w+|\\bprivate\\s+\\w+\\s+\\w+\\s*\\(/, lang: 'java' },\n { pattern: /<\\w+>.*<\\/\\w+>|<\\w+\\s+.*\\/>/, lang: 'html' },\n { pattern: /\\{\\s*\"[\\w-]+\"\\s*:/, lang: 'json' },\n { pattern: /^\\s*#include\\s+<\\w+>|int\\s+main\\s*\\(/, lang: 'c' },\n { pattern: /\\bfn\\s+\\w+\\s*\\(|\\blet\\s+mut\\s+\\w+/, lang: 'rust' },\n { pattern: /\\bfunc\\s+\\w+\\s*\\(|\\bpackage\\s+\\w+/, lang: 'go' },\n { pattern: /^\\s*\\$\\w+\\s*=|\\becho\\s+/, lang: 'bash' }\n ];\n\n for (const { pattern, lang } of patterns) {\n if (pattern.test(code)) {\n return lang;\n }\n }\n\n return 'text';\n }\n}","/**\n * Pure layout calculations — no terminal-kit, no side effects.\n */\n\n/**\n * Compute the TOC panel width based on terminal width.\n * Mirrors the logic in CourseDetailViewer.updateLayout().\n */\nexport function computeTocWidth(terminalWidth: number): number {\n if (terminalWidth < 80) {\n return Math.min(25, Math.floor(terminalWidth * 0.35));\n } else if (terminalWidth < 120) {\n return 30;\n } else if (terminalWidth < 160) {\n return 35;\n } else {\n return Math.min(45, Math.floor(terminalWidth * 0.25));\n }\n}\n\n/**\n * Compute the x-column where content starts (one past the TOC divider).\n */\nexport function computeContentStartX(tocWidth: number): number {\n return tocWidth + 1;\n}\n\n/**\n * Compute the usable content area height (rows between header and footer).\n */\nexport function computeContentHeight(\n terminalHeight: number,\n headerHeight: number,\n footerHeight: number\n): number {\n return terminalHeight - headerHeight - footerHeight;\n}\n\n/**\n * Compute the wrap width for content text based on view mode.\n *\n * @param viewMode - 'content' | 'split' | 'toc'\n * @param termWidth - full terminal width\n * @param contentStartX - column where the content panel starts (split mode)\n */\nexport function computeWrapWidth(\n viewMode: 'split' | 'content' | 'toc',\n termWidth: number,\n contentStartX: number\n): number {\n if (viewMode === 'content') {\n return termWidth - 8;\n }\n return termWidth - contentStartX - 6;\n}\n\n/**\n * Compute the code block display width.\n */\nexport function computeCodeBlockWidth(\n viewMode: 'split' | 'content' | 'toc',\n termWidth: number,\n contentStartX: number\n): number {\n if (viewMode === 'content') {\n return termWidth - 10;\n }\n return termWidth - contentStartX - 6;\n}\n","/**\n * Pure windowing calculations — which lines/entries are visible for a given\n * scroll offset and viewport height. No terminal-kit, no side effects.\n */\n\nimport type { TOCEntry, CodeBlock, TrackedImage } from './types.js';\n\n/**\n * Maximum scroll offset for the main content.\n * Clamps to 0 so we never return a negative number.\n */\nexport function maxContentScrollOffset(\n totalLines: number,\n contentHeight: number\n): number {\n return Math.max(0, totalLines - contentHeight + 2);\n}\n\n/**\n * Maximum scroll offset for the TOC panel.\n */\nexport function maxTocScrollOffset(\n totalEntries: number,\n contentHeight: number\n): number {\n return Math.max(0, totalEntries - contentHeight + 2);\n}\n\n/**\n * Number of TOC entries visible in a given viewport.\n */\nexport function visibleTocCount(\n totalEntries: number,\n tocScrollOffset: number,\n contentHeight: number\n): number {\n return Math.min(totalEntries - tocScrollOffset, contentHeight - 2);\n}\n\n/**\n * Number of content lines visible in a given viewport.\n */\nexport function visibleContentCount(\n totalLines: number,\n scrollOffset: number,\n contentHeight: number\n): number {\n return Math.min(totalLines - scrollOffset, contentHeight - 2);\n}\n\n/**\n * Returns `true` if any part of a code block overlaps the current viewport.\n */\nexport function isCodeBlockVisible(\n block: CodeBlock,\n viewportStart: number,\n viewportEnd: number\n): boolean {\n return (\n (block.startLine >= viewportStart && block.startLine <= viewportEnd) ||\n (block.endLine >= viewportStart && block.endLine <= viewportEnd) ||\n (block.startLine <= viewportStart && block.endLine >= viewportEnd)\n );\n}\n\n/**\n * Returns `true` if any part of a tracked image overlaps the current viewport.\n */\nexport function isImageVisible(\n image: TrackedImage,\n viewportStart: number,\n viewportEnd: number\n): boolean {\n return (\n (image.lineNumber >= viewportStart && image.lineNumber <= viewportEnd) ||\n (image.endLine !== undefined &&\n image.endLine >= viewportStart &&\n image.endLine <= viewportEnd) ||\n (image.lineNumber <= viewportStart &&\n image.endLine !== undefined &&\n image.endLine >= viewportEnd)\n );\n}\n\n/**\n * Given a viewport and a set of code blocks, find the first visible block.\n * Returns `undefined` when none is visible.\n */\nexport function findVisibleCodeBlock(\n blocks: readonly CodeBlock[],\n viewportStart: number,\n viewportEnd: number\n): CodeBlock | undefined {\n return blocks.find(b => isCodeBlockVisible(b, viewportStart, viewportEnd));\n}\n\n/**\n * Given a viewport and a set of tracked images, find the first visible image.\n */\nexport function findVisibleImage(\n images: readonly TrackedImage[],\n viewportStart: number,\n viewportEnd: number\n): TrackedImage | undefined {\n return images.find(img => isImageVisible(img, viewportStart, viewportEnd));\n}\n\n/**\n * Returns `true` if the `copiedBlock` highlight is still active (within 3 s)\n * and the given `lineNum` falls inside that block's range.\n */\nexport function isCopiedLine(\n lineNum: number,\n copiedBlockIndex: number,\n copiedTimestamp: number,\n blocks: readonly CodeBlock[],\n nowMs: number\n): boolean {\n if (copiedBlockIndex < 0) return false;\n if (nowMs - copiedTimestamp >= 3000) return false;\n const block = blocks[copiedBlockIndex];\n if (!block) return false;\n return lineNum >= block.startLine && lineNum <= block.endLine;\n}\n","/**\n * Pure navigation reducer for CourseDetailViewer.\n *\n * Takes the current ViewerState + a key name, returns a new (or the same)\n * ViewerState. Has zero terminal-kit / side-effect dependencies.\n *\n * Keys that trigger side effects (C – copy, I – open image, q/Q/ESCAPE – exit)\n * are represented by action tags that the caller interprets; the reducer still\n * returns the resulting state so the caller only needs to apply the side effects.\n */\n\nimport type { ViewerState } from './types.js';\nimport {\n maxContentScrollOffset,\n maxTocScrollOffset,\n} from './windowing.js';\n\nexport type ReducerEffect =\n | 'none'\n | 'exit'\n | 'copy_code'\n | 'open_image';\n\nexport interface ReducerResult {\n state: ViewerState;\n /**\n * Side-effect the renderer/controller must carry out (clipboard, browser,\n * EventEmitter.emit('exit'), …).\n */\n effect: ReducerEffect;\n /**\n * `true` when the key was consumed (same semantics as the original\n * handleInput return value).\n */\n handled: boolean;\n}\n\n// ─── helpers ────────────────────────────────────────────────────────────────\n\nfunction scrollTocUp(s: ViewerState): ViewerState {\n if (s.selectedTocIndex <= 0) return s;\n const next = s.selectedTocIndex - 1;\n return {\n ...s,\n selectedTocIndex: next,\n tocScrollOffset: Math.min(s.tocScrollOffset, next),\n };\n}\n\nfunction scrollTocDown(s: ViewerState, totalEntries: number): ViewerState {\n if (s.selectedTocIndex >= totalEntries - 1) return s;\n const next = s.selectedTocIndex + 1;\n const visibleItems = s.contentHeight - 2;\n const newOffset =\n next >= s.tocScrollOffset + visibleItems\n ? next - visibleItems + 1\n : s.tocScrollOffset;\n return { ...s, selectedTocIndex: next, tocScrollOffset: newOffset };\n}\n\nfunction scrollContentUp(s: ViewerState): ViewerState {\n if (s.scrollOffset <= 0) return s;\n return { ...s, scrollOffset: Math.max(0, s.scrollOffset - 1) };\n}\n\nfunction scrollContentDown(s: ViewerState, totalLines: number): ViewerState {\n const maxScroll = maxContentScrollOffset(totalLines, s.contentHeight);\n if (s.scrollOffset >= maxScroll) return s;\n return { ...s, scrollOffset: Math.min(maxScroll, s.scrollOffset + 1) };\n}\n\n// ─── reducer ────────────────────────────────────────────────────────────────\n\nexport function reduce(\n state: ViewerState,\n key: string,\n totalContentLines: number,\n totalTocEntries: number,\n tocEntryLines: readonly number[] // line numbers of each TOC entry\n): ReducerResult {\n const s = state;\n\n // Helper to return a \"handled, no side-effect\" result\n const ok = (next: ViewerState): ReducerResult => ({\n state: next,\n effect: 'none',\n handled: true,\n });\n\n switch (key) {\n // ── UP ───────────────────────────────────────────────────────────────\n case 'UP': {\n if (s.viewMode === 'split') {\n if (s.focusPanel === 'toc') {\n return ok(scrollTocUp(s));\n }\n return ok(scrollContentUp(s));\n }\n if (s.viewMode === 'toc') {\n return ok(scrollTocUp(s));\n }\n // content\n return ok(scrollContentUp(s));\n }\n\n // ── DOWN ─────────────────────────────────────────────────────────────\n case 'DOWN': {\n if (s.viewMode === 'split') {\n if (s.focusPanel === 'toc') {\n return ok(scrollTocDown(s, totalTocEntries));\n }\n return ok(scrollContentDown(s, totalContentLines));\n }\n if (s.viewMode === 'toc') {\n return ok(scrollTocDown(s, totalTocEntries));\n }\n return ok(scrollContentDown(s, totalContentLines));\n }\n\n // ── PAGE_UP ───────────────────────────────────────────────────────────\n case 'PAGE_UP': {\n const pageSize = s.contentHeight - 2;\n if (s.viewMode === 'split') {\n if (s.focusPanel === 'toc') {\n return ok({\n ...s,\n tocScrollOffset: Math.max(0, s.tocScrollOffset - pageSize),\n selectedTocIndex: Math.max(0, s.selectedTocIndex - pageSize),\n });\n }\n return ok({ ...s, scrollOffset: Math.max(0, s.scrollOffset - pageSize) });\n }\n if (s.viewMode === 'toc') {\n return ok({\n ...s,\n tocScrollOffset: Math.max(0, s.tocScrollOffset - pageSize),\n selectedTocIndex: Math.max(0, s.selectedTocIndex - pageSize),\n });\n }\n return ok({ ...s, scrollOffset: Math.max(0, s.scrollOffset - pageSize) });\n }\n\n // ── PAGE_DOWN ─────────────────────────────────────────────────────────\n case 'PAGE_DOWN': {\n const pageSize = s.contentHeight - 2;\n if (s.viewMode === 'split') {\n if (s.focusPanel === 'toc') {\n const maxToc = maxTocScrollOffset(totalTocEntries, s.contentHeight);\n return ok({\n ...s,\n tocScrollOffset: Math.min(maxToc, s.tocScrollOffset + pageSize),\n selectedTocIndex: Math.min(\n totalTocEntries - 1,\n s.selectedTocIndex + pageSize\n ),\n });\n }\n const maxScroll = maxContentScrollOffset(totalContentLines, s.contentHeight);\n return ok({\n ...s,\n scrollOffset: Math.min(maxScroll, s.scrollOffset + pageSize),\n });\n }\n if (s.viewMode === 'toc') {\n const maxToc = maxTocScrollOffset(totalTocEntries, s.contentHeight);\n return ok({\n ...s,\n tocScrollOffset: Math.min(maxToc, s.tocScrollOffset + pageSize),\n selectedTocIndex: Math.min(\n totalTocEntries - 1,\n s.selectedTocIndex + pageSize\n ),\n });\n }\n const maxScroll = maxContentScrollOffset(totalContentLines, s.contentHeight);\n return ok({\n ...s,\n scrollOffset: Math.min(maxScroll, s.scrollOffset + pageSize),\n });\n }\n\n // ── ENTER ─────────────────────────────────────────────────────────────\n case 'ENTER': {\n if (\n (s.viewMode === 'split' || s.viewMode === 'toc') &&\n s.selectedTocIndex < tocEntryLines.length\n ) {\n // Scroll so the heading appears with 1 blank line above it (matches original)\n const targetLine = Math.max(0, tocEntryLines[s.selectedTocIndex] + 2);\n let next: ViewerState = { ...s, scrollOffset: targetLine };\n if (s.viewMode === 'toc') {\n next = { ...next, viewMode: 'content' };\n } else {\n next = { ...next, focusPanel: 'content' };\n }\n return ok(next);\n }\n return ok(s);\n }\n\n // ── TAB ───────────────────────────────────────────────────────────────\n case 'TAB': {\n if (s.viewMode === 'split') {\n return ok({\n ...s,\n focusPanel: s.focusPanel === 'toc' ? 'content' : 'toc',\n });\n }\n // cycle toc → content → split\n if (s.viewMode === 'toc') {\n return ok({ ...s, viewMode: 'content' });\n }\n return ok({ ...s, viewMode: 'split' });\n }\n\n // ── LEFT ──────────────────────────────────────────────────────────────\n case 'LEFT': {\n if (s.viewMode === 'split') {\n return ok({ ...s, focusPanel: 'toc' });\n }\n return ok(s);\n }\n\n // ── RIGHT ─────────────────────────────────────────────────────────────\n case 'RIGHT': {\n if (s.viewMode === 'split') {\n return ok({ ...s, focusPanel: 'content' });\n }\n return ok(s);\n }\n\n // ── T / t ─────────────────────────────────────────────────────────────\n case 't':\n case 'T': {\n return ok({\n ...s,\n viewMode: s.viewMode === 'toc' ? 'split' : 'toc',\n });\n }\n\n // ── F / f ─────────────────────────────────────────────────────────────\n case 'f':\n case 'F': {\n return ok({\n ...s,\n viewMode: s.viewMode === 'content' ? 'split' : 'content',\n });\n }\n\n // ── C / c ─── copy code (side effect handled by caller) ───────────────\n case 'c':\n case 'C': {\n return { state: s, effect: 'copy_code', handled: true };\n }\n\n // ── I / i ─── open image (side effect handled by caller) ──────────────\n case 'i':\n case 'I': {\n return { state: s, effect: 'open_image', handled: true };\n }\n\n // ── q / Q / ESCAPE ────────────────────────────────────────────────────\n case 'q':\n case 'Q':\n case 'ESCAPE': {\n return { state: s, effect: 'exit', handled: true };\n }\n\n default:\n return { state: s, effect: 'none', handled: false };\n }\n}\n\n// ─── state factory ────────────────────────────────────────────────────────────\n\nexport function makeInitialState(\n width: number,\n height: number,\n headerHeight: number,\n footerHeight: number,\n tocWidth: number,\n contentStartX: number\n): ViewerState {\n return {\n scrollOffset: 0,\n tocScrollOffset: 0,\n selectedTocIndex: 0,\n viewMode: 'split',\n focusPanel: 'content',\n copiedBlockIndex: -1,\n copiedTimestamp: 0,\n width,\n height,\n contentHeight: height - headerHeight - footerHeight,\n headerHeight,\n footerHeight,\n tocWidth,\n contentStartX,\n courseTitle: 'COURSE',\n username: 'Guest',\n };\n}\n","import fetch from 'node-fetch';\nimport fs from 'fs';\nimport { pipeline } from 'stream/promises';\nimport { AuthManager } from './auth.js';\nimport { API_URL } from '../config/constants.js';\n\nexport interface DownloadProgress {\n loaded: number;\n total: number;\n percentage: number;\n}\n\nexport interface AssetDownloadResponse {\n success: boolean;\n data?: {\n fileName: string;\n downloadUrl: string;\n mimeType: string;\n expiresAt: string;\n expiresInSeconds: number;\n };\n error?: string;\n}\n\nexport class AssetDownloader {\n private authManager: AuthManager;\n private baseUrl: string;\n\n constructor(authManager: AuthManager) {\n this.authManager = authManager;\n this.baseUrl = API_URL;\n }\n\n async downloadAsset(\n assetKey: string, \n outputPath: string,\n onProgress?: (progress: DownloadProgress) => void\n ): Promise<boolean> {\n try {\n // Step 1: Request download token\n const tokenResponse = await this.authManager.makeAuthenticatedRequest(\n `${this.baseUrl}/api/assets/download?key=${assetKey}`\n );\n\n if (!tokenResponse.ok) {\n const error = await tokenResponse.json() as any;\n \n // Handle rate limiting\n if (tokenResponse.status === 429) {\n const waitTime = this.extractWaitTime(error.error || '');\n throw new Error(`Rate limited. Please wait ${waitTime} seconds before downloading again.`);\n }\n \n if (tokenResponse.status === 403) {\n throw new Error('Access denied. This asset requires a purchase.');\n }\n \n if (tokenResponse.status === 404) {\n throw new Error('Asset not found.');\n }\n \n throw new Error(error.error || `Failed to get download token: ${tokenResponse.status}`);\n }\n\n const tokenData = await tokenResponse.json() as AssetDownloadResponse;\n \n if (!tokenData.success || !tokenData.data) {\n throw new Error(tokenData.error || 'Failed to get download URL');\n }\n\n // Step 2: Download the file immediately (token expires in 30 seconds)\n // Note: The retrieve endpoint doesn't require auth, just the token\n let downloadUrl = tokenData.data.downloadUrl;\n\n // Handle different URL formats from the server\n if (downloadUrl.includes('localhost:3333')) {\n // Replace localhost URL with actual API URL\n // The server returns /assets/retrieve but it should be /api/assets/retrieve\n downloadUrl = downloadUrl\n .replace('http://localhost:3333/assets/retrieve', `${this.baseUrl}/api/assets/retrieve`)\n .replace('https://localhost:3333/assets/retrieve', `${this.baseUrl}/api/assets/retrieve`)\n .replace('http://localhost:3333', this.baseUrl)\n .replace('https://localhost:3333', this.baseUrl);\n } else if (downloadUrl.startsWith('http://') || downloadUrl.startsWith('https://')) {\n // It's already a full URL, use as-is\n downloadUrl = downloadUrl;\n } else if (downloadUrl.startsWith('/')) {\n // Relative path - prepend base URL\n downloadUrl = `${this.baseUrl}${downloadUrl}`;\n } else {\n // Assume it's a relative path without leading slash\n downloadUrl = `${this.baseUrl}/${downloadUrl}`;\n }\n\n const fileResponse = await fetch(downloadUrl);\n\n if (!fileResponse.ok) {\n if (fileResponse.status === 401) {\n throw new Error('Download token expired. Please try again.');\n }\n throw new Error(`Failed to download file: ${fileResponse.status}`);\n }\n\n // Step 3: Save to disk with progress tracking if available\n if (onProgress && fileResponse.body) {\n const contentLength = fileResponse.headers.get('content-length');\n const total = parseInt(contentLength || '0', 10);\n let loaded = 0;\n\n // Use Node.js stream handling\n const writer = fs.createWriteStream(outputPath);\n \n // Handle progress with stream events\n fileResponse.body.on('data', (chunk: Buffer) => {\n loaded += chunk.length;\n writer.write(chunk);\n \n if (onProgress && total > 0) {\n onProgress({\n loaded,\n total,\n percentage: Math.round((loaded / total) * 100)\n });\n }\n });\n \n // Wait for download to complete\n await pipeline(fileResponse.body as any, writer);\n } else {\n // Simple download without progress\n const fileStream = fs.createWriteStream(outputPath);\n await pipeline(fileResponse.body as any, fileStream);\n }\n \n return true;\n\n } catch (error: any) {\n throw error;\n }\n }\n\n private extractWaitTime(errorMessage: string): number {\n // Try to extract wait time from error message\n const match = errorMessage.match(/(\\d+)\\s*seconds?/i);\n return match ? parseInt(match[1], 10) : 30;\n }\n\n async getAssetInfo(assetKey: string): Promise<AssetDownloadResponse> {\n const response = await this.authManager.makeAuthenticatedRequest(\n `${this.baseUrl}/api/assets/download?key=${assetKey}`\n );\n\n if (!response.ok) {\n const error = await response.json() as any;\n return {\n success: false,\n error: error.error || `Failed to get asset info: ${response.status}`\n };\n }\n\n return await response.json() as AssetDownloadResponse;\n }\n}","import fs from 'fs';\nimport path from 'path';\n\nexport interface Project {\n id: number;\n name: string;\n path: string;\n engine: 'BabylonJS' | 'ThreeJS' | 'Unknown';\n genre: string; // FPS, ThirdPerson, BulletHell, Fighter, Platformer, Custom, etc.\n components: string[]; // List of component names found in src/Components/\n hasPackageJson: boolean;\n}\n\n/**\n * Scans a directory for game projects\n */\nexport async function scanForProjects(baseDir: string, maxDepth: number = 2): Promise<Project[]> {\n const projects: Project[] = [];\n let projectId = 1;\n\n async function scanDirectory(dir: string, depth: number): Promise<void> {\n if (depth > maxDepth) return;\n\n try {\n const entries = await fs.promises.readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n // Skip node_modules, .git, and other common ignore patterns\n if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'dist' || entry.name === '.next') {\n continue;\n }\n\n // Skip symlinks to avoid circular references\n if (entry.isSymbolicLink()) {\n continue;\n }\n\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n // Check if this directory is a project\n const isProject = await isProjectDirectory(fullPath);\n\n if (isProject) {\n const project = await analyzeProject(fullPath, projectId++);\n projects.push(project);\n // Don't scan inside projects\n continue;\n }\n\n // Recursively scan subdirectories\n await scanDirectory(fullPath, depth + 1);\n }\n }\n } catch (error) {\n // Ignore directories we can't read\n }\n }\n\n await scanDirectory(baseDir, 0);\n return projects;\n}\n\n/**\n * Check if a directory is a project directory\n */\nasync function isProjectDirectory(dir: string): Promise<boolean> {\n try {\n const entries = await fs.promises.readdir(dir);\n\n // Check for package.json\n if (entries.includes('package.json')) {\n const packageJsonPath = path.join(dir, 'package.json');\n const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, 'utf-8'));\n\n // Check for babylonjs or threejs dependencies\n const allDeps = {\n ...packageJson.dependencies || {},\n ...packageJson.devDependencies || {}\n };\n\n const hasBabylonJS = Object.keys(allDeps).some(dep =>\n dep.includes('babylon') || dep.includes('@babylonjs')\n );\n const hasThreeJS = Object.keys(allDeps).some(dep =>\n dep === 'three' || dep.includes('@three')\n );\n\n if (hasBabylonJS || hasThreeJS) {\n return true;\n }\n }\n\n return false;\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Detect the game genre from project files\n */\nasync function detectGenre(dir: string): Promise<string> {\n // Check for .arcade or arcade.json config file\n const configFiles = ['arcade.json', '.arcade', '.arcade.json'];\n for (const configFile of configFiles) {\n const configPath = path.join(dir, configFile);\n if (fs.existsSync(configPath)) {\n try {\n const config = JSON.parse(await fs.promises.readFile(configPath, 'utf-8'));\n if (config.genre || config.template) {\n return config.genre || config.template;\n }\n } catch {\n // Ignore parse errors\n }\n }\n }\n\n // Check package.json for template info\n const packageJsonPath = path.join(dir, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n try {\n const pkg = JSON.parse(await fs.promises.readFile(packageJsonPath, 'utf-8'));\n if (pkg.arcade?.genre) return pkg.arcade.genre;\n if (pkg.arcade?.template) return pkg.arcade.template;\n if (pkg.gameType) return pkg.gameType;\n } catch {\n // Ignore parse errors\n }\n }\n\n // Try to detect from directory structure or component names\n const componentsDir = path.join(dir, 'src', 'Components');\n if (fs.existsSync(componentsDir)) {\n try {\n const components = await fs.promises.readdir(componentsDir);\n const componentNames = components.map(c => c.toLowerCase());\n\n if (componentNames.some(c => c.includes('fps') || c.includes('firstperson'))) {\n return 'FPS';\n }\n if (componentNames.some(c => c.includes('thirdperson') || c.includes('followcamera'))) {\n return 'ThirdPerson';\n }\n if (componentNames.some(c => c.includes('bullet') || c.includes('projectile') || c.includes('shooter'))) {\n return 'BulletHell';\n }\n if (componentNames.some(c => c.includes('fighter') || c.includes('combo') || c.includes('hitbox'))) {\n return 'Fighter';\n }\n if (componentNames.some(c => c.includes('platformer') || c.includes('jump'))) {\n return 'Platformer';\n }\n } catch {\n // Ignore errors\n }\n }\n\n // Check data directory for game modes\n const dataDir = path.join(dir, 'data');\n if (fs.existsSync(dataDir)) {\n try {\n const dataDirs = await fs.promises.readdir(dataDir);\n for (const d of dataDirs) {\n const lowerName = d.toLowerCase();\n if (lowerName === 'thirdperson') return 'ThirdPerson';\n if (lowerName === 'firstperson' || lowerName === 'fps') return 'FPS';\n if (lowerName === 'arcade') return 'Arcade';\n if (lowerName === 'platformer') return 'Platformer';\n }\n } catch {\n // Ignore errors\n }\n }\n\n return 'Custom';\n}\n\n/**\n * Scan for components in the project\n */\nasync function scanComponents(dir: string): Promise<string[]> {\n const components: string[] = [];\n const componentsDir = path.join(dir, 'src', 'Components');\n\n if (!fs.existsSync(componentsDir)) {\n return components;\n }\n\n try {\n const files = await fs.promises.readdir(componentsDir);\n for (const file of files) {\n if (file.endsWith('.ts') || file.endsWith('.js')) {\n // Remove extension and add to list\n const componentName = file.replace(/\\.(ts|js)$/, '');\n // Skip index files\n if (componentName.toLowerCase() !== 'index') {\n components.push(componentName);\n }\n }\n }\n } catch {\n // Ignore errors\n }\n\n return components.sort();\n}\n\n/**\n * Analyze a project directory to get details\n */\nasync function analyzeProject(dir: string, id: number): Promise<Project> {\n const name = path.basename(dir);\n\n let hasPackageJson = false;\n let engine: 'BabylonJS' | 'ThreeJS' | 'Unknown' = 'Unknown';\n\n try {\n const packageJsonPath = path.join(dir, 'package.json');\n if (fs.existsSync(packageJsonPath)) {\n hasPackageJson = true;\n const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, 'utf-8'));\n\n const allDeps = {\n ...packageJson.dependencies || {},\n ...packageJson.devDependencies || {}\n };\n\n const depNames = Object.keys(allDeps);\n\n // Detect engine\n if (depNames.some(d => d.includes('@babylonjs') || d.includes('babylonjs'))) {\n engine = 'BabylonJS';\n } else if (depNames.some(d => d === 'three' || d.includes('@three'))) {\n engine = 'ThreeJS';\n }\n }\n } catch {\n // Ignore errors reading package.json\n }\n\n const genre = await detectGenre(dir);\n const components = await scanComponents(dir);\n\n return {\n id,\n name,\n path: dir,\n engine,\n genre,\n components,\n hasPackageJson\n };\n}\n\n/**\n * Get a single project by path\n */\nexport async function getProjectByPath(projectPath: string): Promise<Project | null> {\n const isProject = await isProjectDirectory(projectPath);\n if (!isProject) return null;\n\n return analyzeProject(projectPath, 1);\n}\n","import fs from 'fs';\nimport path from 'path';\nimport { AuthManager, LibraryManifest } from './auth.js';\nimport { API_URL } from '../config/constants.js';\n\n// ============================================\n// Library Path Management\n// ============================================\n\nexport function getLibraryPath(): string {\n const auth = new AuthManager();\n return auth.getLibraryPath();\n}\n\nexport function isLibraryInitialized(): boolean {\n const libraryPath = getLibraryPath();\n return fs.existsSync(path.join(libraryPath, 'Components'));\n}\n\nexport async function initializeLibrary(libraryPath?: string): Promise<{ success: boolean; message: string }> {\n const targetPath = libraryPath || getLibraryPath();\n\n const dirs = [\n '',\n 'Components',\n 'Systems',\n 'Data',\n 'Tests',\n 'GameModes'\n ];\n\n try {\n for (const dir of dirs) {\n const fullPath = path.join(targetPath, dir);\n if (!fs.existsSync(fullPath)) {\n fs.mkdirSync(fullPath, { recursive: true });\n }\n }\n\n // Create README\n const readmePath = path.join(targetPath, 'README.md');\n if (!fs.existsSync(readmePath)) {\n const readme = `# BJS Library\n\nYour personal library of BabylonJS components, systems, and game mode presets.\n\n## Structure\n\n- \\`Components/\\` - Reusable component .ts files\n- \\`Systems/\\` - System .ts files\n- \\`Data/\\` - Shared data definition .ts files\n- \\`Tests/\\` - Component test files\n- \\`GameModes/\\` - Game mode presets with gamemode.json schemas\n\n## GameMode Schema (gamemode.json)\n\n\\`\\`\\`json\n{\n \"name\": \"ThirdPerson\",\n \"description\": \"Third-person camera game mode\",\n \"components\": [\"Movement\", \"FollowCamera\", \"PlayerInput\"],\n \"data\": [\"Light\", \"FollowCamera\"],\n \"scenes\": [\"Main.ts\"]\n}\n\\`\\`\\`\n\nContent from babylonjsmarket.com will be downloaded here automatically.\n`;\n fs.writeFileSync(readmePath, readme);\n }\n\n return { success: true, message: `Library initialized at ${targetPath}` };\n } catch (error: any) {\n return { success: false, message: `Failed to initialize library: ${error.message}` };\n }\n}\n\n// ============================================\n// GameMode Schema\n// ============================================\n\nexport interface GameModeSchema {\n name: string;\n description: string;\n version?: string;\n components: string[];\n systems?: string[];\n data?: string[];\n includeShared?: boolean;\n scenes?: string[];\n screens?: string[];\n metadata?: {\n author?: string;\n category?: string;\n tags?: string[];\n };\n}\n\nexport function getGameModeSchema(modeName: string): GameModeSchema | null {\n const libraryPath = getLibraryPath();\n const schemaPath = path.join(libraryPath, 'GameModes', modeName, 'gamemode.json');\n\n if (!fs.existsSync(schemaPath)) {\n return null;\n }\n\n try {\n const content = fs.readFileSync(schemaPath, 'utf-8');\n return JSON.parse(content) as GameModeSchema;\n } catch {\n return null;\n }\n}\n\n// ============================================\n// Component Catalog\n// ============================================\n\nexport interface ComponentInfo {\n name: string;\n description: string;\n category: 'Core' | 'Input' | 'Camera' | 'Physics' | 'Visual' | 'AI' | 'UI' | 'Debug';\n hasDataFile: boolean;\n dependencies?: string[]; // Other components this depends on\n}\n\n// Component catalog with descriptions\nexport const COMPONENT_CATALOG: ComponentInfo[] = [\n // Core\n { name: 'Mesh', description: 'Load and display 3D models (GLB/GLTF)', category: 'Core', hasDataFile: false },\n { name: 'MeshPrimitive', description: 'Create basic shapes (box, sphere, cylinder)', category: 'Core', hasDataFile: false },\n { name: 'Position', description: 'Set entity position in 3D space', category: 'Core', hasDataFile: false },\n { name: 'Rotation', description: 'Control entity rotation', category: 'Core', hasDataFile: false },\n { name: 'Animation', description: 'Play skeletal animations from models', category: 'Core', hasDataFile: false },\n { name: 'GameMode', description: 'Manage game states and mode switching', category: 'Core', hasDataFile: false },\n\n // Input\n { name: 'KeyboardControl', description: 'Basic WASD keyboard input', category: 'Input', hasDataFile: false },\n { name: 'SimpleKeyboard', description: 'Simplified keyboard controls', category: 'Input', hasDataFile: false },\n { name: 'GamepadInput', description: 'Gamepad/controller support', category: 'Input', hasDataFile: false },\n { name: 'GamepadControl', description: 'Map gamepad to game actions', category: 'Input', hasDataFile: false },\n { name: 'DeviceInput', description: 'Unified input from any device', category: 'Input', hasDataFile: false },\n { name: 'InputAction', description: 'Action-based input mapping', category: 'Input', hasDataFile: false },\n { name: 'PlayerInput', description: 'Full player input handling', category: 'Input', hasDataFile: false },\n { name: 'PlayerInputMore', description: 'Extended player input options', category: 'Input', hasDataFile: false },\n { name: 'ComboKeys', description: 'Detect key combinations/combos', category: 'Input', hasDataFile: false },\n { name: 'KeyboardTiming', description: 'Timed input detection', category: 'Input', hasDataFile: false },\n { name: 'Actions', description: 'Define and trigger game actions', category: 'Input', hasDataFile: true },\n\n // Camera\n { name: 'Camera', description: 'Basic camera setup and control', category: 'Camera', hasDataFile: false },\n { name: 'FollowCamera', description: 'Camera that follows a target', category: 'Camera', hasDataFile: false },\n { name: 'SimpleCamera', description: 'Quick camera setup', category: 'Camera', hasDataFile: false },\n { name: 'MultiCamera', description: 'Multiple camera support', category: 'Camera', hasDataFile: false },\n { name: 'VRCamera', description: 'Virtual reality camera', category: 'Camera', hasDataFile: false },\n\n // Physics\n { name: 'Physics', description: 'Havok physics integration', category: 'Physics', hasDataFile: false },\n { name: 'SimplePhysics', description: 'Basic physics without Havok', category: 'Physics', hasDataFile: false },\n { name: 'Movement', description: 'Character movement with physics', category: 'Physics', hasDataFile: false },\n { name: 'SimpleMovement', description: 'Basic movement without physics', category: 'Physics', hasDataFile: false },\n { name: 'MovementImproved', description: 'Enhanced movement system', category: 'Physics', hasDataFile: false },\n { name: 'MovementRefactored', description: 'Clean movement implementation', category: 'Physics', hasDataFile: false },\n { name: 'MovementPhysicsController', description: 'Physics-based character controller', category: 'Physics', hasDataFile: false },\n { name: 'RampMovement', description: 'Handle slopes and ramps', category: 'Physics', hasDataFile: false },\n { name: 'Intersection', description: 'Collision detection and triggers', category: 'Physics', hasDataFile: false },\n { name: 'Collectible', description: 'Pickups and collectible items', category: 'Physics', hasDataFile: false },\n { name: 'Obstacle', description: 'Obstacles and hazards', category: 'Physics', hasDataFile: false },\n { name: 'PushableBlocks', description: 'Pushable physics objects', category: 'Physics', hasDataFile: false },\n { name: 'Ragdoll', description: 'Ragdoll physics on death', category: 'Physics', hasDataFile: false },\n\n // Visual\n { name: 'Lighting', description: 'Scene lighting setup', category: 'Visual', hasDataFile: false },\n { name: 'Light', description: 'Individual light sources', category: 'Visual', hasDataFile: false },\n { name: 'SimpleLight', description: 'Quick lighting setup', category: 'Visual', hasDataFile: false },\n { name: 'Shadow', description: 'Dynamic shadows', category: 'Visual', hasDataFile: false },\n { name: 'SkyBox', description: 'Skybox/environment background', category: 'Visual', hasDataFile: false },\n { name: 'Background', description: '2D background images', category: 'Visual', hasDataFile: false },\n { name: 'Ground', description: 'Ground plane/terrain', category: 'Visual', hasDataFile: true },\n { name: 'FootDust', description: 'Dust particles when walking', category: 'Visual', hasDataFile: false },\n { name: 'VideoTexture', description: 'Video as texture', category: 'Visual', hasDataFile: false },\n\n // AI\n { name: 'AI', description: 'Enemy AI behavior', category: 'AI', hasDataFile: false },\n\n // UI\n { name: 'GamesMenuGUI', description: 'In-game menu system', category: 'UI', hasDataFile: false },\n { name: 'Pause', description: 'Pause menu functionality', category: 'UI', hasDataFile: false },\n\n // Debug\n { name: 'Debug', description: 'Debug overlays and tools', category: 'Debug', hasDataFile: false },\n { name: 'Inspector', description: 'BabylonJS Inspector integration', category: 'Debug', hasDataFile: false },\n];\n\n// Get components grouped by category\nexport function getComponentsByCategory(): Map<string, ComponentInfo[]> {\n const grouped = new Map<string, ComponentInfo[]>();\n for (const comp of COMPONENT_CATALOG) {\n if (!grouped.has(comp.category)) {\n grouped.set(comp.category, []);\n }\n grouped.get(comp.category)!.push(comp);\n }\n return grouped;\n}\n\n// Get a flat list of all components\nexport function getAllComponents(): ComponentInfo[] {\n return COMPONENT_CATALOG;\n}\n\n// Find component by name\nexport function getComponentInfo(name: string): ComponentInfo | undefined {\n return COMPONENT_CATALOG.find(c => c.name === name);\n}\n\n// Install a component to a project from Library\n// New folder-based structure: Library/Components/Movement/{Movement.ts, Movement.test.ts}\nexport async function installComponent(\n componentName: string,\n targetProjectPath: string\n): Promise<{ success: boolean; message: string; files: string[] }> {\n const libraryPath = getLibraryPath();\n const componentDir = path.join(libraryPath, 'Components', componentName);\n const componentFile = path.join(componentDir, `${componentName}.ts`);\n const files: string[] = [];\n\n // Check if component folder exists with main .ts file\n if (!fs.existsSync(componentFile)) {\n // Fallback to legacy flat file structure\n const legacyPath = path.join(libraryPath, 'Components', `${componentName}.ts`);\n if (fs.existsSync(legacyPath)) {\n // Legacy mode - single file\n const targetComponentDir = path.join(targetProjectPath, 'src', 'Components');\n if (!fs.existsSync(targetComponentDir)) {\n fs.mkdirSync(targetComponentDir, { recursive: true });\n }\n const targetComponentPath = path.join(targetComponentDir, `${componentName}.ts`);\n if (fs.existsSync(targetComponentPath)) {\n return { success: false, message: `${componentName}.ts already exists`, files };\n }\n fs.copyFileSync(legacyPath, targetComponentPath);\n files.push(`src/Components/${componentName}.ts`);\n return { success: true, message: `Installed ${componentName} (${files.length} files)`, files };\n }\n return { success: false, message: `Component ${componentName} not found in Library`, files };\n }\n\n // Create target directories if needed\n const targetComponentDir = path.join(targetProjectPath, 'src', 'Components');\n if (!fs.existsSync(targetComponentDir)) {\n fs.mkdirSync(targetComponentDir, { recursive: true });\n }\n\n // Copy main component file\n const targetComponentPath = path.join(targetComponentDir, `${componentName}.ts`);\n if (fs.existsSync(targetComponentPath)) {\n return { success: false, message: `${componentName}.ts already exists`, files };\n }\n\n fs.copyFileSync(componentFile, targetComponentPath);\n files.push(`src/Components/${componentName}.ts`);\n\n // Check for test file in component folder\n const testPath = path.join(componentDir, `${componentName}.test.ts`);\n if (fs.existsSync(testPath)) {\n const targetTestDir = path.join(targetProjectPath, 'tests', 'Components');\n if (!fs.existsSync(targetTestDir)) {\n fs.mkdirSync(targetTestDir, { recursive: true });\n }\n const targetTestPath = path.join(targetTestDir, `${componentName}.test.ts`);\n if (!fs.existsSync(targetTestPath)) {\n fs.copyFileSync(testPath, targetTestPath);\n files.push(`tests/Components/${componentName}.test.ts`);\n }\n }\n\n return {\n success: true,\n message: `Installed ${componentName} (${files.length} files)`,\n files\n };\n}\n\n// Get list of components not yet in target project (scans Library)\n// Supports both folder-based (Components/Movement/) and legacy flat file structure\nexport function getAvailableComponents(targetProjectPath: string): ComponentInfo[] {\n const libraryPath = getLibraryPath();\n const libraryComponentsDir = path.join(libraryPath, 'Components');\n const targetComponentDir = path.join(targetProjectPath, 'src', 'Components');\n\n const installedComponents = new Set<string>();\n const availableComponents: ComponentInfo[] = [];\n\n // Get installed components in target project\n if (fs.existsSync(targetComponentDir)) {\n const files = fs.readdirSync(targetComponentDir);\n for (const file of files) {\n if (file.endsWith('.ts')) {\n installedComponents.add(file.replace('.ts', ''));\n }\n }\n }\n\n // Scan Library for available components\n if (fs.existsSync(libraryComponentsDir)) {\n const entries = fs.readdirSync(libraryComponentsDir, { withFileTypes: true });\n for (const entry of entries) {\n let name: string;\n\n if (entry.isDirectory()) {\n // New folder structure: Components/Movement/Movement.ts\n name = entry.name;\n const mainFile = path.join(libraryComponentsDir, name, `${name}.ts`);\n if (!fs.existsSync(mainFile)) {\n continue; // Skip folders without main .ts file\n }\n } else if (entry.isFile() && entry.name.endsWith('.ts')) {\n // Legacy flat structure: Components/Movement.ts\n name = entry.name.replace('.ts', '');\n } else {\n continue;\n }\n\n if (!installedComponents.has(name)) {\n // Check catalog for metadata, otherwise create basic entry\n const catalogInfo = COMPONENT_CATALOG.find(c => c.name === name);\n availableComponents.push(catalogInfo || {\n name,\n description: `${name} component`,\n category: 'Core' as const,\n hasDataFile: false\n });\n }\n }\n }\n\n return availableComponents;\n}\n\n// ============================================\n// Game Mode / Data Directory Management\n// ============================================\n\nexport interface GameModeInfo {\n name: string;\n description: string;\n hasScenes: boolean;\n hasScreens: boolean;\n hasShared: boolean;\n}\n\n// Static fallback catalog (used when Library is empty)\nexport const GAME_MODE_CATALOG: GameModeInfo[] = [];\n\n// Get game mode catalog dynamically from Library\nexport function getGameModeCatalog(): GameModeInfo[] {\n const libraryPath = getLibraryPath();\n const gameModesDir = path.join(libraryPath, 'GameModes');\n const modes: GameModeInfo[] = [];\n\n if (!fs.existsSync(gameModesDir)) {\n return modes;\n }\n\n try {\n const dirs = fs.readdirSync(gameModesDir, { withFileTypes: true });\n for (const dir of dirs) {\n if (!dir.isDirectory()) continue;\n\n const schema = getGameModeSchema(dir.name);\n if (schema) {\n modes.push({\n name: schema.name,\n description: schema.description,\n hasScenes: (schema.scenes?.length || 0) > 0,\n hasScreens: (schema.screens?.length || 0) > 0,\n hasShared: schema.includeShared || false\n });\n } else {\n // Legacy mode without schema - check folder structure\n const modePath = path.join(gameModesDir, dir.name);\n modes.push({\n name: dir.name,\n description: `${dir.name} game mode`,\n hasScenes: fs.existsSync(path.join(modePath, 'Scenes')),\n hasScreens: fs.existsSync(path.join(modePath, 'Screens')),\n hasShared: fs.existsSync(path.join(modePath, 'Data'))\n });\n }\n }\n } catch {\n // Return empty if can't read directory\n }\n\n return modes;\n}\n\n// Get game modes not yet in target project\nexport function getAvailableGameModes(targetProjectPath: string): GameModeInfo[] {\n const targetDataDir = path.join(targetProjectPath, 'data');\n const installedModes = new Set<string>();\n\n if (fs.existsSync(targetDataDir)) {\n const dirs = fs.readdirSync(targetDataDir);\n for (const dir of dirs) {\n const stat = fs.statSync(path.join(targetDataDir, dir));\n if (stat.isDirectory()) {\n installedModes.add(dir);\n }\n }\n }\n\n return getGameModeCatalog().filter(m => !installedModes.has(m.name));\n}\n\n// Get installed game modes in target project\nexport function getInstalledGameModes(targetProjectPath: string): string[] {\n const targetDataDir = path.join(targetProjectPath, 'data');\n const modes: string[] = [];\n\n if (fs.existsSync(targetDataDir)) {\n const dirs = fs.readdirSync(targetDataDir);\n for (const dir of dirs) {\n const stat = fs.statSync(path.join(targetDataDir, dir));\n if (stat.isDirectory() && dir !== 'Shared') {\n modes.push(dir);\n }\n }\n }\n\n return modes;\n}\n\n// Helper for recursive directory copy\nfunction copyDir(src: string, dest: string, files: string[], baseRelPath: string) {\n fs.mkdirSync(dest, { recursive: true });\n const entries = fs.readdirSync(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n const relPath = path.join(baseRelPath, entry.name);\n\n if (entry.isDirectory()) {\n copyDir(srcPath, destPath, files, relPath);\n } else if (entry.name !== 'gamemode.json') { // Skip schema file\n fs.copyFileSync(srcPath, destPath);\n files.push(relPath);\n }\n }\n}\n\n// Install a game mode to a project (schema-based)\nexport async function installGameMode(\n modeName: string,\n targetProjectPath: string\n): Promise<{ success: boolean; message: string; files: string[] }> {\n const libraryPath = getLibraryPath();\n const gameModeDir = path.join(libraryPath, 'GameModes', modeName);\n const files: string[] = [];\n\n if (!fs.existsSync(gameModeDir)) {\n return { success: false, message: `Game mode ${modeName} not found in Library`, files };\n }\n\n const targetDataDir = path.join(targetProjectPath, 'data', modeName);\n if (fs.existsSync(targetDataDir)) {\n return { success: false, message: `${modeName} already exists`, files };\n }\n\n // Check for schema (new approach)\n const schema = getGameModeSchema(modeName);\n\n try {\n if (schema) {\n // Schema-based installation: install components first\n for (const compName of schema.components) {\n const result = await installComponent(compName, targetProjectPath);\n if (result.success) {\n files.push(...result.files);\n }\n // Continue even if component already exists\n }\n\n // Install systems if specified\n if (schema.systems) {\n for (const sysName of schema.systems) {\n const sysPath = path.join(libraryPath, 'Systems', `${sysName}.ts`);\n if (fs.existsSync(sysPath)) {\n const targetSysDir = path.join(targetProjectPath, 'src', 'Systems');\n if (!fs.existsSync(targetSysDir)) {\n fs.mkdirSync(targetSysDir, { recursive: true });\n }\n const targetSysPath = path.join(targetSysDir, `${sysName}.ts`);\n if (!fs.existsSync(targetSysPath)) {\n fs.copyFileSync(sysPath, targetSysPath);\n files.push(`src/Systems/${sysName}.ts`);\n }\n }\n }\n }\n\n // Create target data directory\n fs.mkdirSync(targetDataDir, { recursive: true });\n\n // Copy Data/ subdirectory if exists\n const modeDataDir = path.join(gameModeDir, 'Data');\n if (fs.existsSync(modeDataDir)) {\n const targetSharedDir = path.join(targetDataDir, 'Shared');\n copyDir(modeDataDir, targetSharedDir, files, `data/${modeName}/Shared`);\n }\n\n // Copy Scenes/ subdirectory if exists\n const modeScenesDir = path.join(gameModeDir, 'Scenes');\n if (fs.existsSync(modeScenesDir)) {\n const targetScenesDir = path.join(targetDataDir, 'Scenes');\n copyDir(modeScenesDir, targetScenesDir, files, `data/${modeName}/Scenes`);\n }\n\n // Copy Screens/ subdirectory if exists\n const modeScreensDir = path.join(gameModeDir, 'Screens');\n if (fs.existsSync(modeScreensDir)) {\n const targetScreensDir = path.join(targetDataDir, 'Screens');\n copyDir(modeScreensDir, targetScreensDir, files, `data/${modeName}/Screens`);\n }\n\n } else {\n // Legacy: copy entire directory\n copyDir(gameModeDir, targetDataDir, files, `data/${modeName}`);\n }\n\n return {\n success: true,\n message: `Installed ${modeName} preset (${files.length} files)`,\n files\n };\n } catch (error: any) {\n return { success: false, message: error.message, files };\n }\n}\n\n// ============================================\n// Scene Management\n// ============================================\n\nexport interface SceneInfo {\n name: string;\n path: string;\n gameMode: string;\n}\n\n// Get existing scenes in a project\nexport function getProjectScenes(targetProjectPath: string): SceneInfo[] {\n const scenes: SceneInfo[] = [];\n const dataDir = path.join(targetProjectPath, 'data');\n\n if (!fs.existsSync(dataDir)) return scenes;\n\n const modes = fs.readdirSync(dataDir);\n for (const mode of modes) {\n const scenesDir = path.join(dataDir, mode, 'Scenes');\n if (fs.existsSync(scenesDir)) {\n const sceneFiles = fs.readdirSync(scenesDir);\n for (const file of sceneFiles) {\n if (file.endsWith('.ts')) {\n scenes.push({\n name: file.replace('.ts', ''),\n path: path.join(scenesDir, file),\n gameMode: mode\n });\n }\n }\n }\n }\n\n return scenes;\n}\n\n// Create a new scene file\nexport async function createScene(\n targetProjectPath: string,\n gameMode: string,\n sceneName: string\n): Promise<{ success: boolean; message: string; path: string }> {\n const scenesDir = path.join(targetProjectPath, 'data', gameMode, 'Scenes');\n\n if (!fs.existsSync(scenesDir)) {\n fs.mkdirSync(scenesDir, { recursive: true });\n }\n\n const scenePath = path.join(scenesDir, `${sceneName}.ts`);\n if (fs.existsSync(scenePath)) {\n return { success: false, message: `Scene ${sceneName} already exists`, path: '' };\n }\n\n const template = `import Basics from \"../../Shared/Basics\";\nimport Light from \"../../Shared/Light\";\n\nexport default {\n gameTitle: \"${gameMode}\",\n sceneTitle: \"${sceneName}\",\n worldEntity: \"World\",\n entities: {\n World: {\n components: {\n Position: {\n startingPosition: [0, 0, 0],\n },\n Background: {\n color: [0.53, 0.81, 0.92],\n },\n Mesh: {\n name: \"Ground\",\n src: \"/Assets/Ground/sandbox.glb\",\n },\n },\n },\n ...Light,\n },\n};\n`;\n\n try {\n fs.writeFileSync(scenePath, template);\n return {\n success: true,\n message: `Created scene ${sceneName}`,\n path: scenePath\n };\n } catch (error: any) {\n return { success: false, message: error.message, path: '' };\n }\n}\n\n// ============================================\n// Migration from arcade-ref\n// ============================================\n\nconst ARCADE_REF_PATH = '/Users/law/Programming/Web/BJSM/arcades/arcade-ref';\n\nexport async function migrateFromArcadeRef(): Promise<{ success: boolean; message: string; files: string[] }> {\n const libraryPath = getLibraryPath();\n const files: string[] = [];\n\n // Ensure Library is initialized\n if (!isLibraryInitialized()) {\n const initResult = await initializeLibrary(libraryPath);\n if (!initResult.success) {\n return { success: false, message: initResult.message, files };\n }\n }\n\n try {\n // Copy Components\n const srcComponents = path.join(ARCADE_REF_PATH, 'src', 'Components');\n if (fs.existsSync(srcComponents)) {\n const targetComponents = path.join(libraryPath, 'Components');\n const componentFiles = fs.readdirSync(srcComponents);\n for (const file of componentFiles) {\n if (file.endsWith('.ts')) {\n const srcPath = path.join(srcComponents, file);\n const destPath = path.join(targetComponents, file);\n if (!fs.existsSync(destPath)) {\n fs.copyFileSync(srcPath, destPath);\n files.push(`Components/${file}`);\n }\n }\n }\n }\n\n // Copy Tests\n const srcTests = path.join(ARCADE_REF_PATH, 'tests', 'Components');\n if (fs.existsSync(srcTests)) {\n const targetTests = path.join(libraryPath, 'Tests');\n const testFiles = fs.readdirSync(srcTests);\n for (const file of testFiles) {\n if (file.endsWith('.test.ts')) {\n const srcPath = path.join(srcTests, file);\n const destPath = path.join(targetTests, file);\n if (!fs.existsSync(destPath)) {\n fs.copyFileSync(srcPath, destPath);\n files.push(`Tests/${file}`);\n }\n }\n }\n }\n\n // Copy Shared data\n const srcData = path.join(ARCADE_REF_PATH, 'data', 'Shared');\n if (fs.existsSync(srcData)) {\n const targetData = path.join(libraryPath, 'Data');\n const dataFiles = fs.readdirSync(srcData);\n for (const file of dataFiles) {\n if (file.endsWith('.ts')) {\n const srcPath = path.join(srcData, file);\n const destPath = path.join(targetData, file);\n if (!fs.existsSync(destPath)) {\n fs.copyFileSync(srcPath, destPath);\n files.push(`Data/${file}`);\n }\n }\n }\n }\n\n // Copy Game Modes with schemas\n const gameModes = ['ThirdPerson', 'Arcade'];\n for (const mode of gameModes) {\n const srcMode = path.join(ARCADE_REF_PATH, 'data', mode);\n if (fs.existsSync(srcMode)) {\n const targetMode = path.join(libraryPath, 'GameModes', mode);\n if (!fs.existsSync(targetMode)) {\n fs.mkdirSync(targetMode, { recursive: true });\n\n // Copy subdirectories (Scenes, Screens, Shared)\n const subdirs = ['Scenes', 'Screens', 'Shared'];\n for (const subdir of subdirs) {\n const srcSubdir = path.join(srcMode, subdir);\n if (fs.existsSync(srcSubdir)) {\n const targetSubdir = subdir === 'Shared'\n ? path.join(targetMode, 'Data')\n : path.join(targetMode, subdir);\n fs.mkdirSync(targetSubdir, { recursive: true });\n\n const subFiles = fs.readdirSync(srcSubdir);\n for (const file of subFiles) {\n const srcPath = path.join(srcSubdir, file);\n const destPath = path.join(targetSubdir, file);\n const stat = fs.statSync(srcPath);\n if (stat.isFile()) {\n fs.copyFileSync(srcPath, destPath);\n files.push(`GameModes/${mode}/${subdir === 'Shared' ? 'Data' : subdir}/${file}`);\n }\n }\n }\n }\n\n // Generate gamemode.json\n const schema: GameModeSchema = {\n name: mode,\n description: mode === 'ThirdPerson'\n ? 'Third-person camera game mode with player, terrain, and follow camera'\n : 'Classic arcade-style game mode with start screens and sandbox scenes',\n components: mode === 'ThirdPerson'\n ? ['Movement', 'FollowCamera', 'PlayerInput', 'Animation', 'Physics', 'KeyboardTiming']\n : ['Movement', 'SimpleCamera', 'PlayerInput', 'SimplePhysics'],\n data: ['Light', 'Basics'],\n includeShared: true,\n scenes: fs.existsSync(path.join(srcMode, 'Scenes'))\n ? fs.readdirSync(path.join(srcMode, 'Scenes')).filter(f => f.endsWith('.ts'))\n : [],\n screens: fs.existsSync(path.join(srcMode, 'Screens'))\n ? fs.readdirSync(path.join(srcMode, 'Screens')).filter(f => f.endsWith('.ts'))\n : []\n };\n\n fs.writeFileSync(\n path.join(targetMode, 'gamemode.json'),\n JSON.stringify(schema, null, 2)\n );\n files.push(`GameModes/${mode}/gamemode.json`);\n }\n }\n }\n\n return {\n success: true,\n message: `Migrated ${files.length} files from arcade-ref`,\n files\n };\n } catch (error: any) {\n return { success: false, message: error.message, files };\n }\n}\n\n// ============================================\n// API-Based Library Management\n// ============================================\n\n// Server manifest file info\nexport interface ServerFileInfo {\n path: string; // e.g., \"Components/Movement\" (folder path)\n version: string; // Version hash\n category: 'Components' | 'Systems' | 'Data' | 'Tests' | 'GameModes';\n hasAccess: boolean; // Whether user has access to this file\n price?: number; // Price if not owned (undefined if free or owned)\n description?: string; // File description\n updatedAt: string; // ISO date when file was last updated on server\n files: string[]; // Files within this component folder (e.g., [\"Movement.ts\", \"Movement.test.ts\"])\n dependencies?: string[]; // Other components this depends on\n}\n\nexport interface ServerManifest {\n files: ServerFileInfo[];\n totalFiles: number;\n unlockedFiles: number;\n}\n\nexport interface LibrarySyncStatus {\n totalFiles: number; // Total files in server library\n unlockedFiles: number; // Files user has access to\n installedFiles: number; // Files installed locally\n updatesAvailable: number; // Files with newer versions\n lastSyncAt?: string; // ISO date of last sync\n}\n\n// Fetch the library manifest from the server\nexport async function fetchLibraryManifest(): Promise<{\n success: boolean;\n manifest?: ServerManifest;\n error?: string;\n}> {\n const auth = new AuthManager();\n\n try {\n const response = await auth.makeAuthenticatedRequest(`${API_URL}/api/library/manifest`);\n\n if (!response.ok) {\n if (response.status === 401) {\n return { success: false, error: 'Not authenticated' };\n }\n return { success: false, error: `Server error: ${response.status}` };\n }\n\n const data = await response.json() as any;\n return { success: true, manifest: data };\n } catch (error: any) {\n return { success: false, error: error.message };\n }\n}\n\n// Download a single file from the library\nexport async function downloadLibraryFile(filePath: string): Promise<{\n success: boolean;\n content?: string;\n version?: string;\n error?: string;\n}> {\n const auth = new AuthManager();\n\n try {\n const response = await auth.makeAuthenticatedRequest(\n `${API_URL}/api/library/file/${encodeURIComponent(filePath)}`\n );\n\n if (!response.ok) {\n if (response.status === 401) {\n return { success: false, error: 'Not authenticated' };\n }\n if (response.status === 403) {\n return { success: false, error: 'No access to this file' };\n }\n if (response.status === 404) {\n return { success: false, error: 'File not found' };\n }\n return { success: false, error: `Server error: ${response.status}` };\n }\n\n const data = await response.json() as any;\n return {\n success: true,\n content: data.content,\n version: data.version\n };\n } catch (error: any) {\n return { success: false, error: error.message };\n }\n}\n\n// Get sync status (compare local vs server)\nexport function getLibrarySyncStatus(): LibrarySyncStatus {\n const auth = new AuthManager();\n const manifest = auth.getLibraryManifest();\n const installedFiles = Object.keys(manifest.files).length;\n\n return {\n totalFiles: 0, // Will be updated after fetching server manifest\n unlockedFiles: 0,\n installedFiles,\n updatesAvailable: 0,\n lastSyncAt: manifest.lastSyncAt\n };\n}\n\n// Compare local and server manifests to find updates\nexport function compareManifests(\n serverManifest: ServerManifest,\n localManifest: LibraryManifest\n): {\n toInstall: ServerFileInfo[]; // New files to download\n toUpdate: ServerFileInfo[]; // Files with newer versions\n upToDate: ServerFileInfo[]; // Files already current\n locked: ServerFileInfo[]; // Files user doesn't have access to\n} {\n const toInstall: ServerFileInfo[] = [];\n const toUpdate: ServerFileInfo[] = [];\n const upToDate: ServerFileInfo[] = [];\n const locked: ServerFileInfo[] = [];\n\n for (const file of serverManifest.files) {\n if (!file.hasAccess) {\n locked.push(file);\n continue;\n }\n\n const localFile = localManifest.files[file.path];\n\n if (!localFile) {\n toInstall.push(file);\n } else if (localFile.version !== file.version) {\n toUpdate.push(file);\n } else {\n upToDate.push(file);\n }\n }\n\n return { toInstall, toUpdate, upToDate, locked };\n}\n\n// Sync library - download/update all accessible components\nexport async function syncLibrary(\n onProgress?: (current: number, total: number, fileName: string) => void\n): Promise<{\n success: boolean;\n message: string;\n installed: number;\n updated: number;\n errors: string[];\n}> {\n const auth = new AuthManager();\n const libraryPath = getLibraryPath();\n const errors: string[] = [];\n let installed = 0;\n let updated = 0;\n\n // Ensure library directory exists\n if (!isLibraryInitialized()) {\n await initializeLibrary();\n }\n\n // Fetch server manifest\n const manifestResult = await fetchLibraryManifest();\n if (!manifestResult.success || !manifestResult.manifest) {\n return {\n success: false,\n message: manifestResult.error || 'Failed to fetch manifest',\n installed: 0,\n updated: 0,\n errors: [manifestResult.error || 'Unknown error']\n };\n }\n\n const serverManifest = manifestResult.manifest;\n const localManifest = auth.getLibraryManifest();\n const { toInstall, toUpdate } = compareManifests(serverManifest, localManifest);\n\n const componentsToSync = [...toInstall, ...toUpdate];\n const totalComponents = componentsToSync.length;\n\n if (totalComponents === 0) {\n auth.markLibrarySynced();\n return {\n success: true,\n message: 'Already up to date',\n installed: 0,\n updated: 0,\n errors: []\n };\n }\n\n // Count total files for progress\n let totalFiles = 0;\n for (const comp of componentsToSync) {\n totalFiles += comp.files.length || 1;\n }\n\n let currentFile = 0;\n\n // Download each component's files\n for (const component of componentsToSync) {\n const isInstall = toInstall.includes(component);\n const componentName = component.path.split('/').pop() || component.path;\n\n // Each component has multiple files (e.g., Movement.ts, Movement.test.ts)\n const filesToDownload = component.files.length > 0\n ? component.files\n : [`${componentName}.ts`]; // Fallback if files array is empty\n\n let componentSuccess = true;\n\n for (const fileName of filesToDownload) {\n currentFile++;\n\n // Full path like \"Components/Movement/Movement.ts\"\n const filePath = `${component.path}/${fileName}`;\n\n if (onProgress) {\n onProgress(currentFile, totalFiles, filePath);\n }\n\n const result = await downloadLibraryFile(filePath);\n\n if (!result.success) {\n errors.push(`${filePath}: ${result.error}`);\n componentSuccess = false;\n continue;\n }\n\n // Write file to library - maintain folder structure\n const fullPath = path.join(libraryPath, filePath);\n const dir = path.dirname(fullPath);\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n fs.writeFileSync(fullPath, result.content!);\n }\n\n // Update local manifest with component version (not individual files)\n if (componentSuccess) {\n auth.updateLibraryFile(component.path, component.version);\n\n if (isInstall) {\n installed++;\n } else {\n updated++;\n }\n }\n }\n\n auth.markLibrarySynced();\n\n const totalSynced = installed + updated;\n const message = errors.length > 0\n ? `Synced ${totalSynced} components with ${errors.length} errors`\n : `Synced ${totalSynced} components (${installed} new, ${updated} updated)`;\n\n return {\n success: errors.length === 0,\n message,\n installed,\n updated,\n errors\n };\n}\n","/**\n * Pure, renderer-agnostic BBS state + reducer (Elm/Redux pattern).\n *\n * This module holds every piece of state the old `term.on('key')` closure\n * mutated inline, plus a pure `reduce(state, action)` that performs all the\n * selection / marking / view-transition logic. No terminal I/O, no fs, no\n * network — those side effects stay in the orchestrator (bbs.ts), which\n * dispatches *intents* (Actions) here and runs effects separately.\n *\n * Behavior is preserved exactly from the original monolith.\n */\n\nexport type View =\n | 'home'\n | 'courses'\n | 'toys'\n | 'downloads'\n | 'settings'\n | 'projects'\n | 'courseDetail';\n\nexport type Theme =\n | 'classic'\n | 'desert'\n | 'matrix'\n | 'commando'\n | 'sandiego'\n | 'ed209';\n\nexport const THEMES: Theme[] = [\n 'classic',\n 'desert',\n 'matrix',\n 'commando',\n 'sandiego',\n 'ed209',\n];\n\n// ── Domain data shapes (mirrors of the interfaces in bbs.ts) ─────────────────\n\nexport interface Course {\n id: number;\n title: string;\n slug: string;\n description?: string;\n category?: string;\n progress?: number;\n completedArticles?: number;\n totalArticles?: number;\n assetKey?: string;\n isOwned?: boolean;\n price?: string;\n image?: string;\n banner?: string;\n}\n\nexport interface Toy {\n id: number;\n name: string;\n size: string;\n downloads: number;\n filetype: string;\n modeltype: 'Static' | 'Animated' | 'Rigged' | 'Arcade';\n downloadUrl?: string;\n assetKey?: string;\n}\n\nexport interface Download {\n id: string;\n assetKey: string;\n fileName: string;\n fileSize: string;\n fileSizeBytes: number;\n fileType: string;\n mimeType?: string;\n description: string;\n productTitle: string;\n productSlug: string;\n productCategory?: string;\n totalDownloads: number;\n lastDownloaded?: string;\n createdAt: string;\n}\n\n/** A scanned project (mirror of project-scanner's Project, fields the UI reads). */\nexport interface ProjectLike {\n name: string;\n path: string;\n engine: string;\n genre: string;\n components: string[];\n hasPackageJson?: boolean;\n}\n\n/** Component catalog entry the library browser lists. */\nexport interface ComponentLike {\n name: string;\n category: string;\n description: string;\n hasDataFile?: boolean;\n}\n\n/** Game mode catalog entry the library browser lists. */\nexport interface GameModeLike {\n name: string;\n description: string;\n hasScenes?: boolean;\n hasScreens?: boolean;\n hasShared?: boolean;\n}\n\n// ── State ────────────────────────────────────────────────────────────────────\n\nexport interface BbsState {\n // Navigation\n currentView: View;\n navigationHistory: View[];\n\n // Per-view selection indices\n selectedIndex: number; // courses\n toysSelectedIndex: number;\n downloadsSelectedIndex: number;\n settingsSelectedIndex: number;\n projectsSelectedIndex: number;\n componentSelectedIndex: number;\n gameModeSelectedIndex: number;\n sceneGameModeIndex: number;\n\n // Marked sets (indices into the respective data arrays)\n markedCourses: Set<number>;\n markedToys: Set<number>;\n markedDownloads: Set<number>;\n markedProjects: Set<number>;\n\n // Data\n courses: Course[];\n toys: Toy[];\n downloads: Download[];\n projects: ProjectLike[];\n availableComponents: ComponentLike[];\n availableGameModes: GameModeLike[];\n installedGameModes: string[];\n\n // Settings / preferences\n theme: Theme;\n animations: boolean;\n mouse: boolean;\n\n // Library browser sub-panels (projects view)\n componentBrowserActive: boolean;\n gameModeBrowserActive: boolean;\n sceneCreatorActive: boolean;\n\n // Inline text input: projects directory editing (settings)\n editingProjectsDir: boolean;\n projectsDirInput: string;\n projectsDirError: string;\n projectsDirSuccess: string;\n\n // Inline text input: library path editing (settings)\n editingLibraryPath: boolean;\n libraryPathInput: string;\n libraryPathError: string;\n libraryPathSuccess: string;\n\n // Library sync (settings)\n syncingLibrary: boolean;\n librarySyncMessage: string;\n librarySyncError: string;\n librarySyncProgress: string;\n\n // Scene creator text input (projects)\n sceneNameInput: string;\n sceneCreatorMessage: string;\n sceneCreatorSuccess: boolean;\n\n // Library browser install messages (projects)\n componentInstallMessage: string;\n componentInstallSuccess: boolean;\n gameModeInstallMessage: string;\n gameModeInstallSuccess: boolean;\n\n // Error popup\n errorPopupVisible: boolean;\n}\n\n/** A factory producing the initial state (parametrized by the data loaded at startup). */\nexport function createInitialState(init: {\n courses: Course[];\n toys: Toy[];\n downloads: Download[];\n projects: ProjectLike[];\n theme: Theme;\n animations: boolean;\n mouse: boolean;\n}): BbsState {\n return {\n currentView: 'home',\n navigationHistory: [],\n\n selectedIndex: 0,\n toysSelectedIndex: 0,\n downloadsSelectedIndex: 0,\n settingsSelectedIndex: 0,\n projectsSelectedIndex: 0,\n componentSelectedIndex: 0,\n gameModeSelectedIndex: 0,\n sceneGameModeIndex: 0,\n\n markedCourses: new Set<number>(),\n markedToys: new Set<number>(),\n markedDownloads: new Set<number>(),\n markedProjects: new Set<number>(),\n\n courses: init.courses,\n toys: init.toys,\n downloads: init.downloads,\n projects: init.projects,\n availableComponents: [],\n availableGameModes: [],\n installedGameModes: [],\n\n theme: init.theme,\n animations: init.animations,\n mouse: init.mouse,\n\n componentBrowserActive: false,\n gameModeBrowserActive: false,\n sceneCreatorActive: false,\n\n editingProjectsDir: false,\n projectsDirInput: '',\n projectsDirError: '',\n projectsDirSuccess: '',\n\n editingLibraryPath: false,\n libraryPathInput: '',\n libraryPathError: '',\n libraryPathSuccess: '',\n\n syncingLibrary: false,\n librarySyncMessage: '',\n librarySyncError: '',\n librarySyncProgress: '',\n\n sceneNameInput: '',\n sceneCreatorMessage: '',\n sceneCreatorSuccess: false,\n\n componentInstallMessage: '',\n componentInstallSuccess: false,\n gameModeInstallMessage: '',\n gameModeInstallSuccess: false,\n\n errorPopupVisible: false,\n };\n}\n\n// ── Actions (input intents) ───────────────────────────────────────────────────\n\n/** The highest settings list index (Migrate from arcade-ref). */\nexport const SETTINGS_MAX_INDEX = 11;\n/** Number of theme rows at the top of the settings list (indices 0..5). */\nexport const SETTINGS_THEME_COUNT = 6;\n\nexport type Action =\n // Navigation within lists\n | { type: 'MoveUp' }\n | { type: 'MoveDown' }\n | { type: 'MoveLeft' } // scene-creator game-mode selector\n | { type: 'MoveRight' }\n // View changes\n | { type: 'ChangeView'; view: View }\n | { type: 'Back' }\n // Marking\n | { type: 'ToggleMark' }\n // Settings toggles (the pure part — persistence is an effect)\n | { type: 'SettingsActivate' } // ENTER/SPACE on the currently-selected settings row\n // Library browser panels (projects view)\n | { type: 'ToggleComponentBrowser' }\n | { type: 'ToggleGameModeBrowser' }\n | { type: 'ToggleSceneCreator' }\n | { type: 'CloseLibraryPanels' }\n // Inline text input\n | { type: 'InputChar'; char: string }\n | { type: 'InputBackspace' }\n | { type: 'InputSet'; value: string } // used by TAB autocomplete (effect computes value)\n | { type: 'StartEditProjectsDir'; value: string }\n | { type: 'StartEditLibraryPath'; value: string }\n | { type: 'CancelEdit' }\n // Data setters (effects fetch, then dispatch these)\n | { type: 'SetCourses'; courses: Course[] }\n | { type: 'SetDownloads'; downloads: Download[] }\n | { type: 'SetProjects'; projects: ProjectLike[] }\n | { type: 'SetAvailableComponents'; components: ComponentLike[] }\n | { type: 'SetAvailableGameModes'; gameModes: GameModeLike[] }\n | { type: 'SetInstalledGameModes'; gameModes: string[] }\n | { type: 'SetLibraryData'; components: ComponentLike[]; gameModes: GameModeLike[]; installed: string[] }\n // Theme / settings (direct sets, used by the settings ENTER effect)\n | { type: 'SetTheme'; theme: Theme }\n | { type: 'ToggleAnimations' }\n | { type: 'ToggleMouse' }\n // Messages (effects set these after async ops)\n | { type: 'SetProjectsDirResult'; error?: string; success?: string }\n | { type: 'SetLibraryPathResult'; error?: string; success?: string }\n | { type: 'SetSyncState'; syncing?: boolean; message?: string; error?: string; progress?: string }\n | { type: 'SetSceneCreatorResult'; message: string; success: boolean }\n | { type: 'SetComponentInstallResult'; message: string; success: boolean }\n | { type: 'SetGameModeInstallResult'; message: string; success: boolean }\n | { type: 'ClearSceneNameInput' }\n // Error popup\n | { type: 'ShowError' }\n | { type: 'DismissError' };\n\n// ── Helpers ────────────────────────────────────────────────────────────────────\n\nfunction toggle(set: Set<number>, index: number): Set<number> {\n const next = new Set(set);\n if (next.has(index)) next.delete(index);\n else next.add(index);\n return next;\n}\n\n/** True when any library sub-panel is open in the projects view. */\nfunction anyLibraryPanelActive(s: BbsState): boolean {\n return s.componentBrowserActive || s.gameModeBrowserActive || s.sceneCreatorActive;\n}\n\n// ── Reducer ────────────────────────────────────────────────────────────────────\n\nexport function reduce(state: BbsState, action: Action): BbsState {\n switch (action.type) {\n // ── Up / Down navigation ──────────────────────────────────────────────\n case 'MoveUp': {\n const s = state;\n if (s.currentView === 'projects' && s.componentBrowserActive) {\n if (s.componentSelectedIndex > 0) {\n return { ...s, componentSelectedIndex: s.componentSelectedIndex - 1, componentInstallMessage: '' };\n }\n return s;\n }\n if (s.currentView === 'projects' && s.gameModeBrowserActive) {\n if (s.gameModeSelectedIndex > 0) {\n return { ...s, gameModeSelectedIndex: s.gameModeSelectedIndex - 1, gameModeInstallMessage: '' };\n }\n return s;\n }\n if (s.currentView === 'courses' && s.selectedIndex > 0) {\n return { ...s, selectedIndex: s.selectedIndex - 1 };\n }\n if (s.currentView === 'toys' && s.toysSelectedIndex > 0) {\n return { ...s, toysSelectedIndex: s.toysSelectedIndex - 1 };\n }\n if (s.currentView === 'projects' && s.projectsSelectedIndex > 0) {\n return { ...s, projectsSelectedIndex: s.projectsSelectedIndex - 1 };\n }\n if (s.currentView === 'downloads' && s.downloadsSelectedIndex > 0) {\n return { ...s, downloadsSelectedIndex: s.downloadsSelectedIndex - 1 };\n }\n if (s.currentView === 'settings' && s.settingsSelectedIndex > 0) {\n return { ...s, settingsSelectedIndex: s.settingsSelectedIndex - 1 };\n }\n return s;\n }\n\n case 'MoveDown': {\n const s = state;\n if (s.currentView === 'projects' && s.componentBrowserActive) {\n if (s.componentSelectedIndex < s.availableComponents.length - 1) {\n return { ...s, componentSelectedIndex: s.componentSelectedIndex + 1, componentInstallMessage: '' };\n }\n return s;\n }\n if (s.currentView === 'projects' && s.gameModeBrowserActive) {\n if (s.gameModeSelectedIndex < s.availableGameModes.length - 1) {\n return { ...s, gameModeSelectedIndex: s.gameModeSelectedIndex + 1, gameModeInstallMessage: '' };\n }\n return s;\n }\n if (s.currentView === 'courses' && s.selectedIndex < s.courses.length - 1) {\n return { ...s, selectedIndex: s.selectedIndex + 1 };\n }\n if (s.currentView === 'toys' && s.toysSelectedIndex < s.toys.length - 1) {\n return { ...s, toysSelectedIndex: s.toysSelectedIndex + 1 };\n }\n if (s.currentView === 'projects' && s.projectsSelectedIndex < s.projects.length - 1) {\n return { ...s, projectsSelectedIndex: s.projectsSelectedIndex + 1 };\n }\n if (s.currentView === 'downloads' && s.downloadsSelectedIndex < s.downloads.length - 1) {\n return { ...s, downloadsSelectedIndex: s.downloadsSelectedIndex + 1 };\n }\n if (s.currentView === 'settings' && s.settingsSelectedIndex < SETTINGS_MAX_INDEX) {\n return { ...s, settingsSelectedIndex: s.settingsSelectedIndex + 1 };\n }\n return s;\n }\n\n case 'MoveLeft': {\n const s = state;\n if (s.currentView === 'projects' && s.sceneCreatorActive && s.sceneGameModeIndex > 0) {\n return { ...s, sceneGameModeIndex: s.sceneGameModeIndex - 1, sceneCreatorMessage: '' };\n }\n return s;\n }\n\n case 'MoveRight': {\n const s = state;\n if (\n s.currentView === 'projects' &&\n s.sceneCreatorActive &&\n s.sceneGameModeIndex < s.installedGameModes.length - 1\n ) {\n return { ...s, sceneGameModeIndex: s.sceneGameModeIndex + 1, sceneCreatorMessage: '' };\n }\n return s;\n }\n\n // ── View changes ──────────────────────────────────────────────────────\n case 'ChangeView': {\n const s = state;\n if (s.currentView === action.view) return s;\n const next: BbsState = {\n ...s,\n navigationHistory: [...s.navigationHistory, s.currentView],\n currentView: action.view,\n };\n // The monolith resets selection on switching to projects/downloads/settings.\n if (action.view === 'projects') next.projectsSelectedIndex = 0;\n if (action.view === 'downloads') next.downloadsSelectedIndex = 0;\n if (action.view === 'settings') next.settingsSelectedIndex = 0;\n return next;\n }\n\n case 'Back': {\n const s = state;\n // In projects, ESC first closes any open library sub-panel.\n if (s.currentView === 'projects' && anyLibraryPanelActive(s)) {\n return {\n ...s,\n componentBrowserActive: false,\n gameModeBrowserActive: false,\n sceneCreatorActive: false,\n componentSelectedIndex: 0,\n gameModeSelectedIndex: 0,\n componentInstallMessage: '',\n gameModeInstallMessage: '',\n sceneNameInput: '',\n sceneCreatorMessage: '',\n };\n }\n if (s.navigationHistory.length > 0) {\n const history = [...s.navigationHistory];\n const view = history.pop() as View;\n return { ...s, navigationHistory: history, currentView: view };\n }\n if (s.currentView !== 'home') {\n return { ...s, currentView: 'home' };\n }\n return s;\n }\n\n // ── Marking ─────────────────────────────────────────────────────────────\n case 'ToggleMark': {\n const s = state;\n if (s.currentView === 'courses' && s.courses[s.selectedIndex]) {\n return { ...s, markedCourses: toggle(s.markedCourses, s.selectedIndex) };\n }\n if (s.currentView === 'toys' && s.toys[s.toysSelectedIndex]) {\n return { ...s, markedToys: toggle(s.markedToys, s.toysSelectedIndex) };\n }\n if (s.currentView === 'downloads' && s.downloads[s.downloadsSelectedIndex]) {\n return { ...s, markedDownloads: toggle(s.markedDownloads, s.downloadsSelectedIndex) };\n }\n return s;\n }\n\n // ── Library browser panels ────────────────────────────────────────────\n case 'ToggleComponentBrowser': {\n const s = state;\n if (s.componentBrowserActive) {\n return { ...s, componentBrowserActive: false, componentSelectedIndex: 0, componentInstallMessage: '' };\n }\n return {\n ...s,\n componentBrowserActive: true,\n gameModeBrowserActive: false,\n sceneCreatorActive: false,\n componentSelectedIndex: 0,\n componentInstallMessage: '',\n };\n }\n\n case 'ToggleGameModeBrowser': {\n const s = state;\n if (s.gameModeBrowserActive) {\n return { ...s, gameModeBrowserActive: false, gameModeSelectedIndex: 0, gameModeInstallMessage: '' };\n }\n return {\n ...s,\n gameModeBrowserActive: true,\n componentBrowserActive: false,\n sceneCreatorActive: false,\n gameModeSelectedIndex: 0,\n gameModeInstallMessage: '',\n };\n }\n\n case 'ToggleSceneCreator': {\n const s = state;\n if (s.sceneCreatorActive) {\n return { ...s, sceneCreatorActive: false, sceneNameInput: '', sceneCreatorMessage: '' };\n }\n return {\n ...s,\n sceneCreatorActive: true,\n componentBrowserActive: false,\n gameModeBrowserActive: false,\n sceneNameInput: '',\n sceneCreatorMessage: '',\n sceneGameModeIndex: 0,\n };\n }\n\n case 'CloseLibraryPanels':\n return {\n ...state,\n componentBrowserActive: false,\n gameModeBrowserActive: false,\n sceneCreatorActive: false,\n componentSelectedIndex: 0,\n gameModeSelectedIndex: 0,\n componentInstallMessage: '',\n gameModeInstallMessage: '',\n sceneNameInput: '',\n sceneCreatorMessage: '',\n };\n\n // ── Inline text input ──────────────────────────────────────────────────\n case 'InputChar': {\n const s = state;\n if (s.editingProjectsDir) {\n return { ...s, projectsDirInput: s.projectsDirInput + action.char, projectsDirError: '' };\n }\n if (s.editingLibraryPath) {\n return { ...s, libraryPathInput: s.libraryPathInput + action.char, libraryPathError: '' };\n }\n if (s.sceneCreatorActive && s.currentView === 'projects' && /[a-zA-Z0-9_-]/.test(action.char)) {\n return { ...s, sceneNameInput: s.sceneNameInput + action.char, sceneCreatorMessage: '' };\n }\n return s;\n }\n\n case 'InputBackspace': {\n const s = state;\n if (s.editingProjectsDir) {\n return { ...s, projectsDirInput: s.projectsDirInput.slice(0, -1), projectsDirError: '' };\n }\n if (s.editingLibraryPath) {\n return { ...s, libraryPathInput: s.libraryPathInput.slice(0, -1), libraryPathError: '' };\n }\n if (s.sceneCreatorActive && s.currentView === 'projects') {\n return { ...s, sceneNameInput: s.sceneNameInput.slice(0, -1), sceneCreatorMessage: '' };\n }\n return s;\n }\n\n case 'InputSet': {\n const s = state;\n if (s.editingProjectsDir) {\n return { ...s, projectsDirInput: action.value, projectsDirError: '' };\n }\n if (s.editingLibraryPath) {\n return { ...s, libraryPathInput: action.value, libraryPathError: '' };\n }\n return s;\n }\n\n case 'StartEditProjectsDir':\n return {\n ...state,\n editingProjectsDir: true,\n projectsDirInput: action.value,\n projectsDirError: '',\n projectsDirSuccess: '',\n };\n\n case 'StartEditLibraryPath':\n return {\n ...state,\n editingLibraryPath: true,\n libraryPathInput: action.value,\n libraryPathError: '',\n libraryPathSuccess: '',\n };\n\n case 'CancelEdit': {\n const s = state;\n if (s.editingProjectsDir) {\n return {\n ...s,\n editingProjectsDir: false,\n projectsDirInput: '',\n projectsDirError: '',\n projectsDirSuccess: '',\n };\n }\n if (s.editingLibraryPath) {\n return {\n ...s,\n editingLibraryPath: false,\n libraryPathInput: '',\n libraryPathError: '',\n libraryPathSuccess: '',\n };\n }\n return s;\n }\n\n // ── Data setters ─────────────────────────────────────────────────────────\n case 'SetCourses':\n return { ...state, courses: action.courses };\n\n case 'SetDownloads':\n return { ...state, downloads: action.downloads };\n\n case 'SetProjects':\n return { ...state, projects: action.projects, projectsSelectedIndex: 0 };\n\n case 'SetAvailableComponents': {\n const s = state;\n // Keep the selected index in range after a refresh (install path).\n let idx = s.componentSelectedIndex;\n if (idx >= action.components.length) idx = Math.max(0, action.components.length - 1);\n return { ...s, availableComponents: action.components, componentSelectedIndex: idx };\n }\n\n case 'SetAvailableGameModes': {\n const s = state;\n let idx = s.gameModeSelectedIndex;\n if (idx >= action.gameModes.length) idx = Math.max(0, action.gameModes.length - 1);\n return { ...s, availableGameModes: action.gameModes, gameModeSelectedIndex: idx };\n }\n\n case 'SetInstalledGameModes':\n return { ...state, installedGameModes: action.gameModes };\n\n case 'SetLibraryData':\n return {\n ...state,\n availableComponents: action.components,\n availableGameModes: action.gameModes,\n installedGameModes: action.installed,\n };\n\n // ── Theme / settings ───────────────────────────────────────────────────\n case 'SetTheme':\n return { ...state, theme: action.theme };\n\n case 'ToggleAnimations':\n return { ...state, animations: !state.animations };\n\n case 'ToggleMouse':\n return { ...state, mouse: !state.mouse };\n\n // ── Result messages ────────────────────────────────────────────────────\n case 'SetProjectsDirResult':\n return {\n ...state,\n projectsDirError: action.error ?? '',\n projectsDirSuccess: action.success ?? '',\n };\n\n case 'SetLibraryPathResult':\n return {\n ...state,\n libraryPathError: action.error ?? '',\n libraryPathSuccess: action.success ?? '',\n };\n\n case 'SetSyncState':\n return {\n ...state,\n ...(action.syncing !== undefined ? { syncingLibrary: action.syncing } : {}),\n ...(action.message !== undefined ? { librarySyncMessage: action.message } : {}),\n ...(action.error !== undefined ? { librarySyncError: action.error } : {}),\n ...(action.progress !== undefined ? { librarySyncProgress: action.progress } : {}),\n };\n\n case 'SetSceneCreatorResult':\n return { ...state, sceneCreatorMessage: action.message, sceneCreatorSuccess: action.success };\n\n case 'SetComponentInstallResult':\n return { ...state, componentInstallMessage: action.message, componentInstallSuccess: action.success };\n\n case 'SetGameModeInstallResult':\n return { ...state, gameModeInstallMessage: action.message, gameModeInstallSuccess: action.success };\n\n case 'ClearSceneNameInput':\n return { ...state, sceneNameInput: '' };\n\n // ── Error popup ────────────────────────────────────────────────────────\n case 'ShowError':\n return { ...state, errorPopupVisible: true };\n\n case 'DismissError':\n return { ...state, errorPopupVisible: false };\n\n // SettingsActivate is handled as an effect in the orchestrator (it needs\n // AuthManager / library calls), so the pure reducer leaves state unchanged.\n case 'SettingsActivate':\n return state;\n\n default:\n return state;\n }\n}\n","/**\n * Pure key → intent mapping for the BBS.\n *\n * Translates a terminal-kit key name (plus current state) into either:\n * - a pure `Action` (handled by the reducer), or\n * - an `Effect` intent (a side-effecting command the orchestrator runs:\n * downloads, browser opens, spawning editors, async fetches, persistence).\n *\n * No terminal I/O, no fs, no network — entirely deterministic, so the whole\n * key-routing table is unit-testable. The original monolith interleaved state\n * mutation and effects inside one giant `switch`; here the routing is pure and\n * the effects are named, leaving execution to bbs.ts.\n */\n\nimport type { Action, BbsState, View } from './state.js';\nimport { SETTINGS_THEME_COUNT } from './state.js';\n\n/** Side-effecting commands the orchestrator must execute (kept out of the reducer). */\nexport type Effect =\n // Settings row activation (ENTER/SPACE): theme/anim/mouse/dir/lib/sync/migrate.\n | { type: 'ActivateSettings'; index: number; viaSpace: boolean }\n // Inline-edit commits + autocomplete.\n | { type: 'CommitProjectsDir' }\n | { type: 'CommitLibraryPath' }\n | { type: 'AutocompleteProjectsDir' }\n | { type: 'AutocompleteLibraryPath' }\n // Library browser ENTER actions.\n | { type: 'InstallComponent' }\n | { type: 'InstallGameMode' }\n | { type: 'CreateScene' }\n // Courses/toys/projects ENTER.\n | { type: 'OpenCourse' } // owned → detail view; unowned → browser purchase\n | { type: 'ShowToyInfo' }\n | { type: 'OpenProjectInEditor' }\n // Downloads / D key.\n | { type: 'Download' } // current item in courses/toys/downloads\n | { type: 'DevServer' } // D in projects\n | { type: 'DownloadAllMarked' } // A in downloads\n // Browser open (B).\n | { type: 'BuyInBrowser' }\n // Project lifecycle.\n | { type: 'NewProject' } // N\n | { type: 'RescanProjects' } // R\n | { type: 'InstallLibraryDeps' } // I\n // Quit / debug.\n | { type: 'Quit' }\n | { type: 'TestError' }; // E (DEBUG only)\n\nexport type Intent =\n | { kind: 'action'; action: Action }\n | { kind: 'effect'; effect: Effect };\n\nconst act = (action: Action): Intent => ({ kind: 'action', action });\nconst eff = (effect: Effect): Intent => ({ kind: 'effect', effect });\n\n/**\n * Map a key to an intent. Returns null when the key is a no-op in the current\n * context (mirrors the monolith's `break` with no work done).\n *\n * NOTE: The original handler had several *pre-switch* gates (error popup,\n * inline editing modes, scene-creator text input, course-detail input,\n * action-in-progress debounce). Those gates are honored here in the same order\n * so the routing is faithful. Debounce timing and course-detail delegation are\n * handled in the orchestrator (they need wall-clock time / the viewer), so this\n * function assumes it is only called when input should be routed normally —\n * except for the editing/error/scene-input gates, which it resolves because\n * they are pure given the key name.\n */\nexport function keyToAction(name: string, state: BbsState): Intent | null {\n const s = state;\n\n // ── Gate 0: error popup. ESC dismisses; everything else is swallowed. ──\n if (s.errorPopupVisible) {\n if (name === 'ESCAPE') return act({ type: 'DismissError' });\n return null;\n }\n\n // ── Gate 1: inline projects-directory editing. ──\n if (s.editingProjectsDir) {\n if (name === 'ESCAPE') return act({ type: 'CancelEdit' });\n if (name === 'ENTER') return eff({ type: 'CommitProjectsDir' });\n if (name === 'BACKSPACE') return act({ type: 'InputBackspace' });\n if (name === 'TAB') return eff({ type: 'AutocompleteProjectsDir' });\n if (name.length === 1) return act({ type: 'InputChar', char: name });\n return null;\n }\n\n // ── Gate 2: inline library-path editing. ──\n if (s.editingLibraryPath) {\n if (name === 'ESCAPE') return act({ type: 'CancelEdit' });\n if (name === 'ENTER') return eff({ type: 'CommitLibraryPath' });\n if (name === 'BACKSPACE') return act({ type: 'InputBackspace' });\n if (name === 'TAB') return eff({ type: 'AutocompleteLibraryPath' });\n if (name.length === 1) return act({ type: 'InputChar', char: name });\n return null;\n }\n\n // ── Gate 3: scene-creator text input. BACKSPACE + valid chars are consumed\n // here; ENTER/ESC/LEFT/RIGHT fall through to the main switch below. ──\n if (s.sceneCreatorActive && s.currentView === 'projects') {\n if (name === 'BACKSPACE') return act({ type: 'InputBackspace' });\n if (name.length === 1 && /[a-zA-Z0-9_-]/.test(name)) {\n return act({ type: 'InputChar', char: name });\n }\n // else fall through\n }\n\n // ── Main key switch ──\n switch (name) {\n case 'ESCAPE':\n return act({ type: 'Back' });\n\n case 'UP':\n case 'k':\n return act({ type: 'MoveUp' });\n\n case 'DOWN':\n case 'j':\n return act({ type: 'MoveDown' });\n\n case 'LEFT':\n return act({ type: 'MoveLeft' });\n\n case 'RIGHT':\n return act({ type: 'MoveRight' });\n\n case 'ENTER':\n return enterIntent(s);\n\n case 'd':\n case 'D':\n if (s.currentView === 'projects' && s.projects[s.projectsSelectedIndex]) {\n return eff({ type: 'DevServer' });\n }\n if (\n (s.currentView === 'courses' && s.courses[s.selectedIndex]) ||\n (s.currentView === 'toys' && s.toys[s.toysSelectedIndex]) ||\n (s.currentView === 'downloads' && s.downloads[s.downloadsSelectedIndex])\n ) {\n return eff({ type: 'Download' });\n }\n return null;\n\n case 'a':\n case 'A':\n if (s.currentView === 'downloads' && s.markedDownloads.size > 0) {\n return eff({ type: 'DownloadAllMarked' });\n }\n return null;\n\n case 'm':\n case 'M':\n case ' ':\n // Space/M mark in list views; Space additionally activates settings rows.\n if (s.currentView === 'settings') {\n return eff({ type: 'ActivateSettings', index: s.settingsSelectedIndex, viaSpace: true });\n }\n return act({ type: 'ToggleMark' });\n\n case 'n':\n case 'N':\n if (s.currentView === 'projects') return eff({ type: 'NewProject' });\n return null;\n\n case 'r':\n case 'R':\n if (s.currentView === 'projects') return eff({ type: 'RescanProjects' });\n return null;\n\n case 'i':\n case 'I':\n if (s.currentView === 'projects' && s.projects[s.projectsSelectedIndex]) {\n return eff({ type: 'InstallLibraryDeps' });\n }\n return null;\n\n case 'b':\n case 'B':\n if (\n (s.currentView === 'courses' && s.courses[s.selectedIndex]) ||\n (s.currentView === 'toys' && s.toys[s.toysSelectedIndex])\n ) {\n return eff({ type: 'BuyInBrowser' });\n }\n // Debounce still applies in the orchestrator, but with nothing to open\n // the monolith just consumed the key. Returning the effect is harmless\n // since the effect re-checks; preserve original by returning null.\n return null;\n\n case 'c':\n case 'C':\n if (s.currentView === 'projects' && s.projects[s.projectsSelectedIndex]) {\n return act({ type: 'ToggleComponentBrowser' });\n }\n if (s.currentView !== 'courses') {\n return act({ type: 'ChangeView', view: 'courses' });\n }\n return null;\n\n case 'g':\n case 'G':\n if (s.currentView === 'projects' && s.projects[s.projectsSelectedIndex]) {\n return act({ type: 'ToggleGameModeBrowser' });\n }\n return null;\n\n case '+':\n case '=':\n if (s.currentView === 'projects' && s.projects[s.projectsSelectedIndex]) {\n return act({ type: 'ToggleSceneCreator' });\n }\n return null;\n\n case 't':\n case 'T':\n if (s.currentView !== 'toys') return act({ type: 'ChangeView', view: 'toys' });\n return null;\n\n case 'p':\n case 'P':\n if (s.currentView !== 'projects') return act({ type: 'ChangeView', view: 'projects' });\n return null;\n\n case 'f':\n case 'F':\n if (s.currentView !== 'downloads') return act({ type: 'ChangeView', view: 'downloads' });\n return null;\n\n case 's':\n case 'S':\n if (s.currentView !== 'settings') return act({ type: 'ChangeView', view: 'settings' });\n return null;\n\n case 'e':\n case 'E':\n if (process.env.DEBUG) return eff({ type: 'TestError' });\n return null;\n\n case 'q':\n case 'Q':\n case 'CTRL_C':\n return eff({ type: 'Quit' });\n\n default:\n return null;\n }\n}\n\n/** ENTER routing — depends on view + active sub-panel. */\nfunction enterIntent(s: BbsState): Intent | null {\n if (s.currentView === 'projects' && s.componentBrowserActive) {\n return eff({ type: 'InstallComponent' });\n }\n if (s.currentView === 'projects' && s.gameModeBrowserActive) {\n return eff({ type: 'InstallGameMode' });\n }\n if (s.currentView === 'projects' && s.sceneCreatorActive) {\n return eff({ type: 'CreateScene' });\n }\n if (s.currentView === 'settings') {\n return eff({ type: 'ActivateSettings', index: s.settingsSelectedIndex, viaSpace: false });\n }\n if (s.currentView === 'courses' && s.courses[s.selectedIndex]) {\n return eff({ type: 'OpenCourse' });\n }\n if (s.currentView === 'toys' && s.toys[s.toysSelectedIndex]) {\n return eff({ type: 'ShowToyInfo' });\n }\n if (s.currentView === 'projects' && s.projects[s.projectsSelectedIndex]) {\n return eff({ type: 'OpenProjectInEditor' });\n }\n return null;\n}\n\n/** Whether a settings index toggles a theme (0..5) vs another row. */\nexport function isThemeIndex(index: number): boolean {\n return index < SETTINGS_THEME_COUNT;\n}\n","/**\n * Pure formatting helpers for the BBS — string/data transforms with no terminal\n * I/O, so they're unit-testable in isolation. Extracted from the bbs.ts monolith\n * as the first step toward a renderer-agnostic BBS core.\n */\n\n/** Relative time label, e.g. \"just now\", \"5m ago\", \"3h ago\", \"2d ago\", or a date. */\nexport function getTimeAgo(date: Date, now: number = Date.now()): string {\n const seconds = Math.floor((now - date.getTime()) / 1000)\n if (seconds < 60) return 'just now'\n if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`\n if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`\n if (seconds < 604800) return `${Math.floor(seconds / 86400)}d ago`\n return date.toLocaleDateString()\n}\n\nexport interface CourseStatusInput {\n isOwned?: boolean\n /** Completion percentage (0–100) for owned courses. */\n progress?: number\n /** Display price for unowned courses, e.g. \"$29.99\". */\n price?: string\n}\n\nexport interface CourseStatus {\n status: 'IN PROGRESS' | 'OWNED' | 'AVAILABLE'\n /** Progress % for owned courses, price for unowned. */\n value: string\n}\n\n/** Ownership/status label + value column for a course row. */\nexport function courseStatus(course: CourseStatusInput): CourseStatus {\n if (course.isOwned) {\n if (course.progress && course.progress > 0) {\n return { status: 'IN PROGRESS', value: `${course.progress}%` }\n }\n return { status: 'OWNED', value: '0%' }\n }\n return { status: 'AVAILABLE', value: course.price || '$29.99' }\n}\n\n/** Truncate a title to `max` chars, with an ellipsis when clipped. */\nexport function truncateTitle(title: string, max = 40): string {\n return title.length > max ? `${title.substring(0, max - 3)}...` : title\n}\n","/**\n * Pure layout/scroll math for the BBS list views — no terminal I/O. Extracted\n * from the repeated windowing logic in bbs.ts (courses, projects, components,\n * game-modes all used the same `Math.max(0, selected - maxVisible + 1)` slice).\n */\n\nexport interface RowWindow<T> {\n /** Index of the first visible row within `rows`. */\n offset: number\n /** The slice of rows currently on screen. */\n visible: T[]\n /** True if there are rows scrolled off the top (show a ↑ indicator). */\n hasAbove: boolean\n /** True if there are rows scrolled off the bottom (show a ↓ indicator). */\n hasBelow: boolean\n}\n\n/**\n * Window a list to `maxVisible` rows, keeping `selectedIndex` in view by pinning\n * it to the bottom of the window once it scrolls past the fold (preserves the\n * original BBS behavior). `selectedIndex` within the window is `selected - offset`.\n */\nexport function windowRows<T>(rows: T[], selectedIndex: number, maxVisible: number): RowWindow<T> {\n const offset = Math.max(0, selectedIndex - maxVisible + 1)\n const visible = rows.slice(offset, offset + maxVisible)\n return {\n offset,\n visible,\n hasAbove: offset > 0,\n hasBelow: offset + maxVisible < rows.length,\n }\n}\n","/**\n * Pure view-model selectors for the BBS.\n *\n * Each `build*` turns `(state, { width, height })` into a plain-data render\n * model — rows, columns, cursor index, marked flags, scroll indicators, status\n * lines — with no terminal coupling. The terminal renderer (render.ts) consumes\n * these; tests assert on them directly (no TTY needed).\n *\n * Reuses the already-tested pure utils:\n * - getTimeAgo / courseStatus / truncateTitle from ./format\n * - windowRows from ./layout\n */\n\nimport type { BbsState, Course, Download, ProjectLike } from './state.js';\nimport { courseStatus, truncateTitle, getTimeAgo } from './format.js';\nimport { windowRows } from './layout.js';\n\nexport interface Dimensions {\n width: number;\n height: number;\n}\n\n// ── Home ─────────────────────────────────────────────────────────────────────\n\nexport interface MenuItem {\n key: string;\n label: string;\n desc: string;\n}\n\nexport interface HomeModel {\n view: 'home';\n items: MenuItem[];\n /** Centered menu box geometry. */\n box: { x: number; y: number; width: number; height: number };\n}\n\nconst HOME_ITEMS: MenuItem[] = [\n { key: 'C', label: 'Courses', desc: 'Browse available courses' },\n { key: 'T', label: 'Toys', desc: '3D models and assets' },\n { key: 'P', label: 'Projects', desc: 'Manage game projects' },\n { key: 'F', label: 'Files', desc: 'Course downloads' },\n { key: 'S', label: 'Settings', desc: 'Configure BBS' },\n { key: 'Q', label: 'Quit', desc: 'Disconnect from BBS' },\n];\n\nexport function buildHome(_state: BbsState, dim: Dimensions): HomeModel {\n const width = 50;\n const height = 14;\n return {\n view: 'home',\n items: HOME_ITEMS,\n box: {\n x: Math.floor((dim.width - width) / 2),\n y: Math.floor((dim.height - height) / 2),\n width,\n height,\n },\n };\n}\n\n// ── Courses ──────────────────────────────────────────────────────────────────\n\nexport interface CourseRow {\n num: string;\n title: string;\n status: string;\n value: string;\n}\n\nexport interface CoursesModel {\n view: 'courses';\n rows: CourseRow[];\n /** Cursor index *within the visible window*. */\n cursor: number;\n hasAbove: boolean;\n hasBelow: boolean;\n tableWidth: number;\n titleWidth: number;\n /** Y of the scroll-down indicator (relative to content top). */\n maxVisibleRows: number;\n}\n\nexport function buildCourses(state: BbsState, dim: Dimensions): CoursesModel {\n const titleWidth = Math.min(45, dim.width - 35);\n const allRows: CourseRow[] = state.courses.map((course: Course, index) => {\n const { status, value } = courseStatus(course);\n return {\n num: state.markedCourses.has(index) ? `[${index + 1}]` : ` ${index + 1} `,\n title: truncateTitle(course.title, 40),\n status,\n value,\n };\n });\n\n const maxVisibleRows = Math.min(dim.height - 15, 20);\n const win = windowRows(allRows, state.selectedIndex, maxVisibleRows);\n const tableWidth = 5 + titleWidth + 12 + 14 + 8;\n\n return {\n view: 'courses',\n rows: win.visible,\n cursor: state.selectedIndex - win.offset,\n hasAbove: win.hasAbove,\n hasBelow: win.hasBelow,\n tableWidth,\n titleWidth,\n maxVisibleRows,\n };\n}\n\n// ── Toys ─────────────────────────────────────────────────────────────────────\n\nexport interface ToyRow {\n num: string;\n name: string;\n size: string;\n downloads: number;\n type: string;\n format: string;\n}\n\nexport interface ToysModel {\n view: 'toys';\n rows: ToyRow[];\n cursor: number;\n tableWidth: number;\n}\n\nexport function buildToys(state: BbsState, dim: Dimensions): ToysModel {\n const rows: ToyRow[] = state.toys.map((toy, index) => ({\n num: state.markedToys.has(index) ? `[${index + 1}]` : ` ${index + 1} `,\n name: toy.name,\n size: toy.size,\n downloads: toy.downloads,\n type: toy.modeltype,\n format: toy.filetype,\n }));\n return {\n view: 'toys',\n rows,\n cursor: state.toysSelectedIndex,\n tableWidth: dim.width - 2,\n };\n}\n\n// ── Downloads ──────────────────────────────────────────────────────────────\n\nexport interface DownloadRow {\n num: string;\n fileName: string;\n product: string;\n size: string;\n type: string;\n downloads: number;\n lastDL: string;\n}\n\nexport interface DownloadsModel {\n view: 'downloads';\n empty: boolean;\n rows: DownloadRow[];\n cursor: number;\n hasAbove: boolean;\n hasBelow: boolean;\n tableWidth: number;\n scrollIndicatorX: number;\n maxVisibleRows: number;\n}\n\nexport function buildDownloads(state: BbsState, dim: Dimensions): DownloadsModel {\n if (state.downloads.length === 0) {\n return {\n view: 'downloads',\n empty: true,\n rows: [],\n cursor: 0,\n hasAbove: false,\n hasBelow: false,\n tableWidth: 0,\n scrollIndicatorX: 0,\n maxVisibleRows: 0,\n };\n }\n\n const allRows: DownloadRow[] = state.downloads.map((download: Download, index) => ({\n num: state.markedDownloads.has(index) ? `[${index + 1}]` : ` ${index + 1} `,\n fileName: download.fileName.length > 30 ? download.fileName.substring(0, 27) + '...' : download.fileName,\n product: download.productTitle.length > 25 ? download.productTitle.substring(0, 22) + '...' : download.productTitle,\n size: download.fileSize,\n type: download.fileType,\n downloads: download.totalDownloads,\n lastDL: download.lastDownloaded ? new Date(download.lastDownloaded).toLocaleDateString() : 'Never',\n }));\n\n const maxVisibleRows = Math.min(dim.height - 15, 20);\n const win = windowRows(allRows, state.downloadsSelectedIndex, maxVisibleRows);\n\n return {\n view: 'downloads',\n empty: false,\n rows: win.visible,\n cursor: state.downloadsSelectedIndex - win.offset,\n hasAbove: win.hasAbove,\n hasBelow: win.hasBelow,\n tableWidth: Math.min(dim.width - 2, 110),\n scrollIndicatorX: Math.min(dim.width - 2, 112),\n maxVisibleRows,\n };\n}\n\n// ── Projects ─────────────────────────────────────────────────────────────────\n\nexport interface ProjectListRow {\n name: string;\n selected: boolean;\n}\n\nexport interface ProjectsModel {\n view: 'projects';\n empty: boolean;\n /** When empty: whether a projects dir is configured (drives the message). */\n hasProjectsDir?: boolean;\n projectsDir?: string;\n // Non-empty:\n listRows?: ProjectListRow[];\n listHasAbove?: boolean;\n listHasBelow?: boolean;\n selected?: ProjectLike;\n /** Which library sub-panel (if any) is active. */\n panel?: 'components' | 'gameModes' | 'sceneCreator' | 'default';\n}\n\n/**\n * `projectsDir` is supplied by the orchestrator (it comes from AuthManager,\n * which is not pure). Selectors stay pure by taking it as input.\n */\nexport function buildProjects(\n state: BbsState,\n dim: Dimensions,\n ctx: { projectsDir?: string },\n): ProjectsModel {\n if (state.projects.length === 0) {\n return {\n view: 'projects',\n empty: true,\n hasProjectsDir: !!ctx.projectsDir,\n projectsDir: ctx.projectsDir,\n };\n }\n\n const listWidth = 32;\n const detailX = listWidth + 4;\n const detailWidth = Math.min(dim.width - detailX - 2, 50);\n const panelHeight = Math.min(dim.height - 6 - 6, 18);\n const maxVisibleProjects = panelHeight - 2;\n\n const win = windowRows(state.projects, state.projectsSelectedIndex, maxVisibleProjects);\n const listRows: ProjectListRow[] = win.visible.map((p, i) => ({\n name: p.name,\n selected: i + win.offset === state.projectsSelectedIndex,\n }));\n\n let panel: ProjectsModel['panel'] = 'default';\n if (state.componentBrowserActive) panel = 'components';\n else if (state.gameModeBrowserActive) panel = 'gameModes';\n else if (state.sceneCreatorActive) panel = 'sceneCreator';\n\n return {\n view: 'projects',\n empty: false,\n listRows,\n listHasAbove: win.hasAbove,\n listHasBelow: win.hasBelow,\n selected: state.projects[state.projectsSelectedIndex],\n panel,\n };\n}\n\n// ── Settings ─────────────────────────────────────────────────────────────────\n\nexport interface SettingsModel {\n view: 'settings';\n themes: string[];\n /** Selected settings list index (0..5 themes, 6 anim, 7 mouse, …). */\n cursor: number;\n currentTheme: string;\n animations: boolean;\n mouse: boolean;\n // Projects dir\n editingProjectsDir: boolean;\n projectsDirInput: string;\n projectsDirError: string;\n projectsDirSuccess: string;\n projectsDirDisplay: string; // current saved value (from ctx)\n // Library path\n editingLibraryPath: boolean;\n libraryPathInput: string;\n libraryPathError: string;\n libraryPathSuccess: string;\n libraryPathDisplay: string;\n libraryInitialized: boolean;\n // Sync\n syncingLibrary: boolean;\n librarySyncMessage: string;\n librarySyncError: string;\n librarySyncProgress: string;\n lastSyncLabel: string; // e.g. \"Last sync: 5m ago\" / \"Never synced\"\n}\n\n/**\n * Pulls auth/library facts from `ctx` so the selector stays pure. `lastSyncAt`\n * is a Date | null; when present the label uses the (pure) getTimeAgo helper.\n */\nexport function buildSettings(\n state: BbsState,\n ctx: {\n projectsDir?: string;\n libraryPath: string;\n libraryInitialized: boolean;\n lastSyncAt: Date | null;\n now?: number;\n },\n): SettingsModel {\n const projectsDirSaved = ctx.projectsDir || 'Not set';\n const lastSyncLabel = ctx.lastSyncAt\n ? `Last sync: ${getTimeAgo(ctx.lastSyncAt, ctx.now)}`\n : 'Never synced';\n\n return {\n view: 'settings',\n themes: ['classic', 'desert', 'matrix', 'commando', 'sandiego', 'ed209'],\n cursor: state.settingsSelectedIndex,\n currentTheme: state.theme,\n animations: state.animations,\n mouse: state.mouse,\n\n editingProjectsDir: state.editingProjectsDir,\n projectsDirInput: state.projectsDirInput,\n projectsDirError: state.projectsDirError,\n projectsDirSuccess: state.projectsDirSuccess,\n projectsDirDisplay: projectsDirSaved,\n\n editingLibraryPath: state.editingLibraryPath,\n libraryPathInput: state.libraryPathInput,\n libraryPathError: state.libraryPathError,\n libraryPathSuccess: state.libraryPathSuccess,\n libraryPathDisplay: ctx.libraryPath,\n libraryInitialized: ctx.libraryInitialized,\n\n syncingLibrary: state.syncingLibrary,\n librarySyncMessage: state.librarySyncMessage,\n librarySyncError: state.librarySyncError,\n librarySyncProgress: state.librarySyncProgress,\n lastSyncLabel,\n };\n}\n\n// ── Header / footer status ───────────────────────────────────────────────────\n\n/** Count of marked items for the current view (drives the header badge). */\nexport function markedCount(state: BbsState): number {\n switch (state.currentView) {\n case 'courses':\n return state.markedCourses.size;\n case 'toys':\n return state.markedToys.size;\n case 'downloads':\n return state.markedDownloads.size;\n case 'projects':\n return state.markedProjects.size;\n default:\n return 0;\n }\n}\n\n/** Navigation footer text per view (verbatim from the monolith). */\nexport function navFooter(state: BbsState): string {\n switch (state.currentView) {\n case 'home':\n return '[C]ourses [T]oys [P]rojects [F]iles [S]ettings [Q]uit';\n case 'courses':\n return '[↑↓] Navigate [Enter] View Details [D]ownload [M]ark [B]uy [Space] Select [ESC] Back [Q]uit';\n case 'toys':\n return '[↑↓] Navigate [Enter] View [D]ownload [M]ark [B]uy [Space] Select [ESC] Back [Q]uit';\n case 'projects':\n return '[↑↓] Navigate [N] New Project [I] Install Lib [Enter] Manage [ESC] Back [Q]uit';\n case 'downloads':\n return '[↑↓] Navigate [D]ownload [M]ark [A]ll Downloads [Space] Select [ESC] Back [Q]uit';\n case 'settings':\n return '[↑↓] Navigate [Enter] Toggle [Space] Select [ESC] Back [Q]uit';\n default:\n return '';\n }\n}\n","/**\n * Thin terminal-kit renderer for the BBS.\n *\n * Takes pre-computed view models (from viewmodel.ts) plus the BufferedBBS draw\n * surface and draws them. This is the ONLY terminal-coupled view code; all\n * layout math + data shaping lives in the pure selectors. The per-view draw\n * branches are ported verbatim from the bbs.ts monolith to preserve pixel\n * behavior.\n *\n * Some panels (the projects library browser, settings input fields) read\n * derived data that the model intentionally leaves to state, so this module\n * receives `state` alongside the models — but it never *mutates* state.\n */\n\nimport type { BufferedBBS } from '../../utils/buffered-bbs.js';\nimport type { BbsState } from './state.js';\nimport {\n type Dimensions,\n type HomeModel,\n type CoursesModel,\n type ToysModel,\n type DownloadsModel,\n type ProjectsModel,\n type SettingsModel,\n navFooter,\n} from './viewmodel.js';\n\n/** Context the projects/settings panels need from the (impure) AuthManager etc. */\nexport interface RenderContext {\n componentCatalogLength: number;\n gameModeCatalogLength: number;\n /** Scenes in the selected project (from getProjectScenes). */\n projectScenesCount: number;\n /** Sync comparison summary for the settings panel. */\n syncUpdates?: number;\n serverManifest?: { unlockedFiles: number; totalFiles: number } | null;\n}\n\nconst CONTENT_Y = 6;\n\nexport function renderHome(bbs: BufferedBBS, model: HomeModel): void {\n const { box, items } = model;\n bbs.drawBox(box.x, box.y, box.width, box.height, 'MAIN MENU');\n items.forEach((item, i) => {\n const y = box.y + 3 + i * 2;\n bbs.put(box.x + 4, y, `[${item.key}]`, bbs.getTheme().accent, true);\n bbs.put(box.x + 8, y, item.label, 'white', true);\n bbs.put(box.x + 20, y, item.desc, bbs.getTheme().dim);\n });\n}\n\nexport function renderCourses(bbs: BufferedBBS, model: CoursesModel): void {\n bbs.drawTable(2, CONTENT_Y, {\n data: model.rows,\n columns: [\n { key: 'num', label: ' # ', width: 5 },\n { key: 'title', label: 'Course Title', width: model.titleWidth },\n { key: 'status', label: 'Status', width: 12 },\n { key: 'value', label: 'Progress/Price', width: 14 },\n ],\n selectedIndex: model.cursor,\n width: model.tableWidth,\n });\n\n if (model.hasAbove) {\n bbs.put(model.tableWidth + 1, CONTENT_Y, '↑', bbs.getTheme().accent);\n }\n if (model.hasBelow) {\n bbs.put(model.tableWidth + 1, CONTENT_Y + model.maxVisibleRows + 1, '↓', bbs.getTheme().accent);\n }\n}\n\nexport function renderToys(bbs: BufferedBBS, model: ToysModel): void {\n bbs.drawTable(2, CONTENT_Y, {\n data: model.rows,\n columns: [\n { key: 'num', label: ' # ', width: 5 },\n { key: 'name', label: 'Name' },\n { key: 'size', label: 'Size', width: 10 },\n { key: 'downloads', label: 'DLs', width: 8 },\n { key: 'type', label: 'Type', width: 10 },\n { key: 'format', label: 'Format', width: 8 },\n ],\n selectedIndex: model.cursor,\n width: model.tableWidth,\n });\n}\n\nexport function renderDownloads(bbs: BufferedBBS, model: DownloadsModel, dim: Dimensions): void {\n if (model.empty) {\n bbs.drawBox(Math.floor((dim.width - 50) / 2), CONTENT_Y + 2, 50, 5, 'NO DOWNLOADS');\n const msgX = Math.floor((dim.width - 40) / 2);\n bbs.put(msgX, CONTENT_Y + 4, 'No course downloads available yet.', bbs.getTheme().dim);\n return;\n }\n\n bbs.drawTable(2, CONTENT_Y, {\n data: model.rows,\n columns: [\n { key: 'num', label: ' # ', width: 5 },\n { key: 'fileName', label: 'File Name', width: 30 },\n { key: 'product', label: 'Course', width: 25 },\n { key: 'size', label: 'Size', width: 10 },\n { key: 'type', label: 'Type', width: 6 },\n { key: 'downloads', label: 'DLs', width: 5 },\n { key: 'lastDL', label: 'Last Downloaded', width: 15 },\n ],\n selectedIndex: model.cursor,\n width: model.tableWidth,\n });\n\n if (model.hasAbove) {\n bbs.put(model.scrollIndicatorX, CONTENT_Y, '↑', bbs.getTheme().accent);\n }\n if (model.hasBelow) {\n bbs.put(model.scrollIndicatorX, CONTENT_Y + model.maxVisibleRows + 1, '↓', bbs.getTheme().accent);\n }\n}\n\nexport function renderProjects(\n bbs: BufferedBBS,\n model: ProjectsModel,\n state: BbsState,\n dim: Dimensions,\n ctx: RenderContext,\n): void {\n if (model.empty) {\n bbs.drawBox(Math.floor((dim.width - 60) / 2), CONTENT_Y + 2, 60, 11, 'NO PROJECTS FOUND');\n const msgX = Math.floor((dim.width - 55) / 2);\n if (!model.hasProjectsDir) {\n bbs.put(msgX, CONTENT_Y + 4, 'Projects directory not configured.', bbs.getTheme().dim);\n bbs.put(msgX, CONTENT_Y + 6, 'Press [S] to go to Settings and set your', bbs.getTheme().primary);\n bbs.put(msgX, CONTENT_Y + 7, 'projects directory.', bbs.getTheme().primary);\n } else {\n const projDir = model.projectsDir as string;\n bbs.put(msgX, CONTENT_Y + 4, 'No game projects found in:', bbs.getTheme().dim);\n bbs.put(msgX, CONTENT_Y + 5, projDir.length > 54 ? '...' + projDir.slice(-51) : projDir, 'yellow');\n bbs.put(msgX, CONTENT_Y + 7, 'Press [N] to create a new project', bbs.getTheme().primary);\n bbs.put(msgX, CONTENT_Y + 8, 'or [S] to change the projects directory', bbs.getTheme().dim);\n }\n return;\n }\n\n const listWidth = 32;\n const detailX = listWidth + 4;\n const detailWidth = Math.min(dim.width - detailX - 2, 50);\n const panelHeight = Math.min(dim.height - CONTENT_Y - 6, 18);\n const maxVisibleProjects = panelHeight - 2;\n const scrollOffset = Math.max(0, state.projectsSelectedIndex - maxVisibleProjects + 1);\n\n // Project list box\n bbs.drawBox(1, CONTENT_Y, listWidth, panelHeight, 'PROJECTS');\n for (let i = 0; i < maxVisibleProjects && i + scrollOffset < state.projects.length; i++) {\n const idx = i + scrollOffset;\n const project = state.projects[idx];\n const isSelected = idx === state.projectsSelectedIndex;\n const y = CONTENT_Y + 1 + i;\n if (isSelected) bbs.put(2, y, '▶', bbs.getTheme().accent);\n const displayName =\n project.name.length > listWidth - 6 ? project.name.substring(0, listWidth - 9) + '...' : project.name;\n bbs.put(4, y, displayName, isSelected ? bbs.getTheme().accent : 'white', isSelected);\n }\n if (scrollOffset > 0) bbs.put(listWidth - 1, CONTENT_Y, '↑', bbs.getTheme().accent);\n if (scrollOffset + maxVisibleProjects < state.projects.length) {\n bbs.put(listWidth - 1, CONTENT_Y + panelHeight - 1, '↓', bbs.getTheme().accent);\n }\n\n // Detail panel\n const selectedProject = state.projects[state.projectsSelectedIndex];\n if (selectedProject) {\n bbs.drawBox(detailX, CONTENT_Y, detailWidth, panelHeight, 'DETAILS');\n let detailY = CONTENT_Y + 1;\n const labelColor = bbs.getTheme().dim;\n const valueColor = bbs.getTheme().primary;\n\n bbs.put(detailX + 2, detailY, 'Name:', labelColor);\n bbs.put(detailX + 8, detailY, selectedProject.name.substring(0, detailWidth - 10), valueColor);\n detailY += 2;\n\n bbs.put(detailX + 2, detailY, 'Engine:', labelColor);\n const engineColor =\n selectedProject.engine === 'BabylonJS' ? 'cyan' : selectedProject.engine === 'ThreeJS' ? 'green' : 'gray';\n bbs.put(detailX + 10, detailY, selectedProject.engine, engineColor);\n detailY += 1;\n\n bbs.put(detailX + 2, detailY, 'Genre:', labelColor);\n bbs.put(detailX + 10, detailY, selectedProject.genre, 'yellow');\n detailY += 2;\n\n bbs.put(detailX + 2, detailY, 'Components:', labelColor);\n detailY += 1;\n\n const maxComponents = panelHeight - 9;\n if (selectedProject.components.length === 0) {\n bbs.put(detailX + 4, detailY, '(none found)', bbs.getTheme().dim);\n } else {\n for (let i = 0; i < Math.min(selectedProject.components.length, maxComponents); i++) {\n const comp = selectedProject.components[i];\n const displayComp = comp.length > detailWidth - 8 ? comp.substring(0, detailWidth - 11) + '...' : comp;\n bbs.put(detailX + 4, detailY + i, '• ' + displayComp, 'white');\n }\n if (selectedProject.components.length > maxComponents) {\n bbs.put(\n detailX + 4,\n detailY + maxComponents,\n `+${selectedProject.components.length - maxComponents} more...`,\n bbs.getTheme().dim,\n );\n }\n }\n }\n\n // Library panel\n const libraryY = CONTENT_Y + panelHeight + 1;\n const libraryPanelHeight = Math.min(dim.height - libraryY - 4, 10);\n const fullWidth = Math.min(dim.width - 2, listWidth + detailWidth + 4);\n\n if (libraryPanelHeight >= 5) {\n let panelTitle: string;\n if (state.componentBrowserActive) {\n panelTitle = '► COMPONENTS [C] Game Modes [G] New Scene [+]';\n } else if (state.gameModeBrowserActive) {\n panelTitle = 'Components [C] ► GAME MODES [G] New Scene [+]';\n } else if (state.sceneCreatorActive) {\n panelTitle = 'Components [C] Game Modes [G] ► NEW SCENE [+]';\n } else {\n panelTitle = '[C] Components [G] Game Modes [+] New Scene';\n }\n bbs.drawBox(1, libraryY, fullWidth, libraryPanelHeight, panelTitle);\n\n if (state.componentBrowserActive) {\n if (state.availableComponents.length > 0) {\n const compListWidth = 28;\n const compDescX = compListWidth + 2;\n const maxVisibleComps = libraryPanelHeight - 2;\n const compScrollOffset = Math.max(0, state.componentSelectedIndex - maxVisibleComps + 1);\n\n for (let i = 0; i < maxVisibleComps && i + compScrollOffset < state.availableComponents.length; i++) {\n const idx = i + compScrollOffset;\n const comp = state.availableComponents[idx];\n const isSelected = idx === state.componentSelectedIndex;\n const y = libraryY + 1 + i;\n if (isSelected) bbs.put(2, y, '▶', bbs.getTheme().accent);\n const displayName =\n comp.name.length > compListWidth - 4 ? comp.name.substring(0, compListWidth - 7) + '...' : comp.name;\n bbs.put(4, y, displayName, isSelected ? bbs.getTheme().accent : 'white', isSelected);\n }\n\n if (state.availableComponents[state.componentSelectedIndex]) {\n const comp = state.availableComponents[state.componentSelectedIndex];\n const descWidth = fullWidth - compDescX - 2;\n bbs.put(compDescX, libraryY + 1, comp.category, 'cyan');\n bbs.put(compDescX, libraryY + 2, comp.description.substring(0, descWidth), bbs.getTheme().primary);\n if (comp.hasDataFile) bbs.put(compDescX, libraryY + 3, '+ Includes data definition', 'green');\n if (state.componentInstallMessage) {\n bbs.put(\n compDescX,\n libraryY + libraryPanelHeight - 2,\n state.componentInstallMessage,\n state.componentInstallSuccess ? 'green' : 'red',\n );\n } else {\n bbs.put(compDescX, libraryY + libraryPanelHeight - 2, 'ENTER to install', bbs.getTheme().dim);\n }\n }\n\n if (compScrollOffset > 0) bbs.put(compListWidth - 1, libraryY, '↑', bbs.getTheme().accent);\n if (compScrollOffset + maxVisibleComps < state.availableComponents.length) {\n bbs.put(compListWidth - 1, libraryY + libraryPanelHeight - 1, '↓', bbs.getTheme().accent);\n }\n } else {\n bbs.put(3, libraryY + 1, 'All components already installed!', 'green');\n }\n } else if (state.gameModeBrowserActive) {\n if (state.availableGameModes.length > 0) {\n const modeListWidth = 20;\n const modeDescX = modeListWidth + 2;\n const maxVisibleModes = libraryPanelHeight - 2;\n const modeScrollOffset = Math.max(0, state.gameModeSelectedIndex - maxVisibleModes + 1);\n\n for (let i = 0; i < maxVisibleModes && i + modeScrollOffset < state.availableGameModes.length; i++) {\n const idx = i + modeScrollOffset;\n const mode = state.availableGameModes[idx];\n const isSelected = idx === state.gameModeSelectedIndex;\n const y = libraryY + 1 + i;\n if (isSelected) bbs.put(2, y, '▶', bbs.getTheme().accent);\n bbs.put(4, y, mode.name, isSelected ? bbs.getTheme().accent : 'white', isSelected);\n }\n\n if (state.availableGameModes[state.gameModeSelectedIndex]) {\n const mode = state.availableGameModes[state.gameModeSelectedIndex];\n const descWidth = fullWidth - modeDescX - 2;\n bbs.put(modeDescX, libraryY + 1, mode.description.substring(0, descWidth), bbs.getTheme().primary);\n const includes: string[] = [];\n if (mode.hasScenes) includes.push('Scenes');\n if (mode.hasScreens) includes.push('Screens');\n if (mode.hasShared) includes.push('Shared');\n if (includes.length > 0) {\n bbs.put(modeDescX, libraryY + 2, 'Includes: ' + includes.join(', '), 'cyan');\n }\n if (state.gameModeInstallMessage) {\n bbs.put(\n modeDescX,\n libraryY + libraryPanelHeight - 2,\n state.gameModeInstallMessage,\n state.gameModeInstallSuccess ? 'green' : 'red',\n );\n } else {\n bbs.put(modeDescX, libraryY + libraryPanelHeight - 2, 'ENTER to install data directory', bbs.getTheme().dim);\n }\n }\n } else {\n bbs.put(3, libraryY + 1, 'All game modes already installed!', 'green');\n if (state.installedGameModes.length > 0) {\n bbs.put(3, libraryY + 2, 'Installed: ' + state.installedGameModes.join(', '), 'cyan');\n }\n }\n } else if (state.sceneCreatorActive) {\n if (state.installedGameModes.length === 0) {\n bbs.put(3, libraryY + 1, 'No game modes installed!', 'red');\n bbs.put(3, libraryY + 2, 'Press [G] to install a game mode first', bbs.getTheme().dim);\n } else {\n bbs.put(3, libraryY + 1, 'Game Mode:', bbs.getTheme().dim);\n const selectedMode = state.installedGameModes[state.sceneGameModeIndex] || state.installedGameModes[0];\n bbs.put(14, libraryY + 1, `◄ ${selectedMode} ►`, 'cyan');\n bbs.put(14 + selectedMode.length + 5, libraryY + 1, '(←/→ to change)', bbs.getTheme().dim);\n\n bbs.put(3, libraryY + 3, 'Scene Name:', bbs.getTheme().dim);\n const cursorVisible = Math.floor(Date.now() / 500) % 2 === 0;\n const inputDisplay = state.sceneNameInput + (cursorVisible ? '▌' : ' ');\n bbs.put(15, libraryY + 3, inputDisplay, 'cyan');\n\n if (state.sceneCreatorMessage) {\n bbs.put(\n 3,\n libraryY + libraryPanelHeight - 2,\n state.sceneCreatorMessage,\n state.sceneCreatorSuccess ? 'green' : 'red',\n );\n } else {\n bbs.put(3, libraryY + libraryPanelHeight - 2, 'Type scene name, ENTER to create', bbs.getTheme().dim);\n }\n }\n } else {\n bbs.put(\n 3,\n libraryY + 1,\n `${ctx.componentCatalogLength} components • ${ctx.gameModeCatalogLength} game modes`,\n bbs.getTheme().dim,\n );\n bbs.put(3, libraryY + 2, `${ctx.projectScenesCount} scenes in this project`, bbs.getTheme().dim);\n bbs.put(3, libraryY + 4, '[C] Components [G] Game Modes [+] New Scene', bbs.getTheme().primary);\n }\n }\n\n // Helpful footer\n const helpY = libraryY + libraryPanelHeight + 1;\n let helpText = '[N] New [I] Install [ENTER] Editor [D] Dev [R] Rescan';\n if (state.componentBrowserActive || state.gameModeBrowserActive) {\n helpText = '[↑↓] Select [ENTER] Install [ESC] Close [C/G/+] Switch';\n } else if (state.sceneCreatorActive) {\n helpText = '[←→] Mode [ENTER] Create [ESC] Close [C/G] Switch';\n }\n bbs.put(2, helpY, helpText, bbs.getTheme().dim);\n}\n\nexport function renderSettings(\n bbs: BufferedBBS,\n model: SettingsModel,\n dim: Dimensions,\n ctx: RenderContext,\n): void {\n const settingsWidth = 70;\n const settingsX = Math.floor((dim.width - settingsWidth) / 2);\n\n bbs.drawBox(settingsX, CONTENT_Y, settingsWidth, 22, 'SETTINGS');\n\n bbs.put(settingsX + 2, CONTENT_Y + 2, 'Theme:', bbs.getTheme().primary, true);\n model.themes.forEach((t, i) => {\n const y = CONTENT_Y + 3 + i;\n const isSelected = model.cursor === i;\n const isCurrent = model.currentTheme === t;\n if (isSelected) bbs.put(settingsX + 4, y, '▶', bbs.getTheme().accent);\n bbs.put(\n settingsX + 6,\n y,\n t.charAt(0).toUpperCase() + t.slice(1),\n isCurrent ? bbs.getTheme().accent : 'white',\n isCurrent,\n );\n });\n\n // Animations (6)\n const animY = CONTENT_Y + 10;\n if (model.cursor === 6) bbs.put(settingsX + 4, animY, '▶', bbs.getTheme().accent);\n bbs.put(settingsX + 6, animY, `Animations: ${model.animations ? 'ON' : 'OFF'}`, model.animations ? 'green' : 'red');\n\n // Mouse (7)\n const mouseY = CONTENT_Y + 12;\n if (model.cursor === 7) bbs.put(settingsX + 4, mouseY, '▶', bbs.getTheme().accent);\n bbs.put(settingsX + 6, mouseY, `Mouse: ${model.mouse ? 'ON' : 'OFF'}`, model.mouse ? 'green' : 'red');\n\n // Projects dir (8)\n const projectsDirY = CONTENT_Y + 14;\n if (model.cursor === 8) bbs.put(settingsX + 4, projectsDirY, '▶', bbs.getTheme().accent);\n bbs.put(settingsX + 6, projectsDirY, 'Projects Directory:', bbs.getTheme().primary);\n\n if (model.editingProjectsDir) {\n const inputWidth = settingsWidth - 10;\n const inputLine =\n model.projectsDirInput.length > inputWidth - 2\n ? '...' + model.projectsDirInput.slice(-(inputWidth - 5))\n : model.projectsDirInput;\n const cursorVisible = Math.floor(Date.now() / 500) % 2 === 0;\n const displayWithCursor = inputLine + (cursorVisible ? '▌' : ' ');\n bbs.put(settingsX + 6, projectsDirY + 1, displayWithCursor, 'cyan');\n const clearLen = inputWidth - displayWithCursor.length;\n if (clearLen > 0) {\n bbs.put(settingsX + 6 + displayWithCursor.length, projectsDirY + 1, ' '.repeat(clearLen), 'white');\n }\n if (model.projectsDirError) {\n bbs.put(settingsX + 6, projectsDirY + 2, model.projectsDirError.slice(0, inputWidth), 'red');\n } else if (model.projectsDirSuccess) {\n bbs.put(settingsX + 6, projectsDirY + 2, model.projectsDirSuccess.slice(0, inputWidth), 'green');\n } else {\n bbs.put(settingsX + 6, projectsDirY + 2, 'TAB: autocomplete ENTER: save ESC: cancel', bbs.getTheme().dim);\n }\n } else {\n const currentProjDir = model.projectsDirDisplay;\n const displayDir = currentProjDir.length > 50 ? '...' + currentProjDir.slice(-47) : currentProjDir;\n bbs.put(settingsX + 6, projectsDirY + 1, displayDir, currentProjDir === 'Not set' ? 'yellow' : 'green');\n }\n\n // Library path (9)\n const libraryPathY = CONTENT_Y + 17;\n if (model.cursor === 9) bbs.put(settingsX + 4, libraryPathY, '>', bbs.getTheme().accent);\n bbs.put(settingsX + 6, libraryPathY, 'Library Path:', bbs.getTheme().primary);\n\n if (model.editingLibraryPath) {\n const inputWidth = settingsWidth - 10;\n const inputLine =\n model.libraryPathInput.length > inputWidth - 2\n ? '...' + model.libraryPathInput.slice(-(inputWidth - 5))\n : model.libraryPathInput;\n const cursorVisible = Math.floor(Date.now() / 500) % 2 === 0;\n const displayWithCursor = inputLine + (cursorVisible ? '▌' : ' ');\n bbs.put(settingsX + 6, libraryPathY + 1, displayWithCursor, 'cyan');\n if (model.libraryPathError) {\n bbs.put(settingsX + 6, libraryPathY + 2, model.libraryPathError.slice(0, inputWidth), 'red');\n } else if (model.libraryPathSuccess) {\n bbs.put(settingsX + 6, libraryPathY + 2, model.libraryPathSuccess.slice(0, inputWidth), 'green');\n } else {\n bbs.put(settingsX + 6, libraryPathY + 2, 'TAB: autocomplete ENTER: save ESC: cancel', bbs.getTheme().dim);\n }\n } else {\n const currentLibPath = model.libraryPathDisplay;\n const displayPath = currentLibPath.length > 50 ? '...' + currentLibPath.slice(-47) : currentLibPath;\n bbs.put(settingsX + 6, libraryPathY + 1, displayPath, model.libraryInitialized ? 'green' : 'yellow');\n if (!model.libraryInitialized) {\n bbs.put(settingsX + 6, libraryPathY + 2, 'Press ENTER to initialize Library', bbs.getTheme().dim);\n }\n }\n\n // Sync Library (10)\n const syncLibY = CONTENT_Y + 20;\n const isSyncLibSelected = model.cursor === 10;\n if (isSyncLibSelected) bbs.put(settingsX + 4, syncLibY, '>', bbs.getTheme().accent);\n\n if (model.syncingLibrary) {\n bbs.put(settingsX + 6, syncLibY, '[Syncing Library...]', isSyncLibSelected ? bbs.getTheme().accent : bbs.getTheme().primary);\n if (model.librarySyncProgress) {\n bbs.put(settingsX + 6, syncLibY + 1, model.librarySyncProgress.slice(0, 40), bbs.getTheme().dim);\n }\n } else {\n bbs.put(settingsX + 6, syncLibY, '[Sync Library]', isSyncLibSelected ? bbs.getTheme().accent : bbs.getTheme().primary);\n if (ctx.serverManifest) {\n const updates = ctx.syncUpdates ?? 0;\n if (updates > 0) {\n bbs.put(settingsX + 6, syncLibY + 1, `${updates} file${updates !== 1 ? 's' : ''} to sync`, 'yellow');\n } else {\n bbs.put(settingsX + 6, syncLibY + 1, 'Up to date', 'green');\n }\n bbs.put(\n settingsX + 6,\n syncLibY + 2,\n `${ctx.serverManifest.unlockedFiles}/${ctx.serverManifest.totalFiles} files unlocked`,\n bbs.getTheme().dim,\n );\n } else {\n bbs.put(settingsX + 6, syncLibY + 1, model.lastSyncLabel, bbs.getTheme().dim);\n }\n }\n\n if (model.librarySyncMessage) {\n bbs.put(settingsX + 6, syncLibY + 3, model.librarySyncMessage.slice(0, 40), 'green');\n } else if (model.librarySyncError) {\n bbs.put(settingsX + 6, syncLibY + 3, model.librarySyncError.slice(0, 40), 'red');\n }\n\n // Migrate (11)\n const migrateY = CONTENT_Y + 24;\n if (model.cursor === 11) bbs.put(settingsX + 4, migrateY, '>', bbs.getTheme().accent);\n bbs.put(settingsX + 6, migrateY, '[Migrate from arcade-ref]', model.cursor === 11 ? bbs.getTheme().accent : bbs.getTheme().primary);\n\n const helpText =\n model.editingProjectsDir || model.editingLibraryPath ? 'Type path, TAB for autocomplete' : 'Press ENTER to select/toggle';\n bbs.put(settingsX + 2, CONTENT_Y + 27, helpText, bbs.getTheme().dim);\n}\n\n/** Draw the centered navigation footer (verbatim positioning from the monolith). */\nexport function renderFooter(bbs: BufferedBBS, state: BbsState, dim: Dimensions): void {\n const navY = dim.height - 1;\n const navText = navFooter(state);\n if (!navText) return;\n\n for (let x = 1; x <= dim.width; x++) {\n bbs.put(x, navY, ' ', 'black');\n }\n const textLen = navText.replace(/\\[|\\]/g, '').length + Math.floor(navText.match(/\\[/g)?.length || 0);\n const startX = textLen < dim.width ? Math.floor((dim.width - textLen) / 2) : 2;\n bbs.put(startX, navY, navText, bbs.getTheme().dim);\n}\n","import { Command } from 'commander';\nimport { mkdtempSync, existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\nimport { tmpdir } from 'os';\nimport { AuthManager } from '../utils/auth.js';\nimport { applyTheme } from '../utils/theme-colors.js';\nimport { API_URL } from '../config/constants.js';\nimport { getVersion } from '../utils/version.js';\nimport { inject as injectEngine, type InjectCollectResult } from '../lib/inject/index.js';\n\nexport const injectCommand = new Command('inject')\n .description('Submit a component or system to BabylonJS Market for curator review')\n .argument('[names...]', 'Component / system name(s) to submit')\n .option('--target <target>', 'arcade | viz (skip auto-detection; legacy arcade-pro/viz-pro accepted)')\n .option('--source <path>', 'override <cwd>/src/components/<Name>/')\n .option('--layer <layer>', 'viz only; skip per-file layer detection (core|solid|ecs)')\n .option('--force', 'allow overwriting an existing target')\n .option('--dry-run', 'print the plan, write nothing, do not submit')\n .allowUnknownOption(false)\n .action(async (names: string[], options) => {\n const auth = new AuthManager();\n const theme = applyTheme();\n\n // ── Auth gate (matches whoami / download conventions) ─────────────────\n if (!auth.isAuthenticated()) {\n console.log(theme.error('You must be logged in to submit an injection.'));\n console.log(theme.dim('Run \"bjs login\" first.'));\n process.exit(1);\n }\n\n if (!names || names.length === 0) {\n console.log(theme.error('No component names given. Pass at least one, e.g. `bjs inject Foo`.'));\n process.exit(1);\n }\n\n // ── Build a tmpdir workRoot for engine-internal scratch (the engine itself\n // does not write anything in collect mode; the workRoot is reserved for any\n // future side-buffer the engine might want and to give us a clean parent if\n // we ever extend collect to spill).\n const workRoot = mkdtempSync(join(tmpdir(), 'bjs-inject-'));\n\n // ── Forward flags to the engine as positional argv ────────────────────\n const engineArgs: string[] = [...names];\n if (options.target) engineArgs.push('--target', options.target);\n if (options.source) engineArgs.push('--source', options.source);\n if (options.layer) engineArgs.push('--layer', options.layer);\n if (options.force) engineArgs.push('--force');\n if (options.dryRun) engineArgs.push('--dry-run');\n\n let result: InjectCollectResult | void;\n try {\n result = await injectEngine(engineArgs, {\n mode: 'collect',\n projectDir: process.cwd(),\n cwd: process.cwd(),\n });\n } catch (err) {\n // The engine calls process.exit(1) on validation errors; if it threw for\n // some other reason, surface it.\n console.error(theme.error('Inject failed:'), (err as Error).message);\n process.exit(1);\n }\n\n if (!result) {\n // Engine emitted only help text or hit a validation path that already exited.\n return;\n }\n\n if (options.dryRun) {\n console.log(theme.dim(`Dry run — ${result.files.length} file(s), ${result.patches.length} patch(es). No submission made.`));\n return;\n }\n\n // ── Build submission payload (plan §B.3) ──────────────────────────────\n const meta = readSeedMeta(process.cwd(), names[0]);\n const payload = {\n target: result.target,\n componentNames: names,\n files: result.files,\n patches: result.patches,\n cli: { version: getVersion() },\n ...(meta ? { meta } : {}),\n };\n\n // ── Submit ────────────────────────────────────────────────────────────\n // POSTs the diff payload to the marketplace's `/api/auth/submissions`\n // endpoint; success returns 201 with `{ id, status, createdAt }`.\n let response: Response;\n try {\n response = await auth.makeAuthenticatedRequest(\n `${API_URL}/api/auth/submissions`,\n {\n method: 'POST',\n body: JSON.stringify(payload),\n },\n );\n } catch (err) {\n console.log(theme.error('Submission failed; try again later.'));\n console.log(theme.dim((err as Error).message));\n process.exit(1);\n }\n\n if (response.status === 401) {\n console.log(theme.error('Your session is invalid or expired.'));\n console.log(theme.dim('Run \"bjs login\" to refresh.'));\n process.exit(1);\n }\n\n if (response.status >= 500) {\n console.log(theme.error('Submission failed; try again later.'));\n try {\n const text = await response.text();\n if (text) console.log(theme.dim(text.slice(0, 500)));\n } catch {\n /* ignore */\n }\n process.exit(1);\n }\n\n if (response.status === 413) {\n console.log(theme.error('Payload too large.'));\n console.log(theme.dim('Keep total payload under 2 MB and each file under 256 KB. Strip binaries before submitting.'));\n process.exit(1);\n }\n\n let body: any = null;\n try {\n body = await response.json();\n } catch {\n /* tolerate empty body */\n }\n\n if (!response.ok) {\n const msg = (body && body.error) || `HTTP ${response.status}`;\n console.log(theme.error(`Submission rejected: ${msg}`));\n process.exit(1);\n }\n\n const id = body?.id;\n const status = body?.status ?? 'pending';\n console.log(theme.success(`Submitted! id=${id} status=${status}`));\n if (id !== undefined) {\n console.log(theme.dim(`${API_URL}/account/submissions/${id}`));\n }\n // Keep workRoot around for caller inspection during the local session; it\n // lives in the system tmpdir and gets reaped on reboot.\n void workRoot;\n });\n\n/**\n * Read the seed component's meta.json (if present) so we can attach the\n * marketplace-facing description / dependencies to the submission payload.\n */\nfunction readSeedMeta(projectDir: string, seedName: string): Record<string, unknown> | undefined {\n const metaPath = join(projectDir, 'src', 'components', seedName, 'meta.json');\n if (!existsSync(metaPath)) return undefined;\n try {\n return JSON.parse(readFileSync(metaPath, 'utf-8'));\n } catch {\n return undefined;\n }\n}\n","import { readFileSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport function getVersion(): string {\n try {\n const packagePath = join(__dirname, '../../package.json');\n const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));\n return packageJson.version;\n } catch {\n return '1.0.0';\n }\n}","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport mri from \"mri\";\nimport colors from \"picocolors\";\nimport { INJECT_HELP } from \"./inject-options.js\";\nimport {\n detectTarget,\n detectLayer,\n type Target,\n type VizLayer,\n type SeedFile,\n} from \"./detect-target.js\";\nimport { findMonorepoRoot } from \"./monorepo-root.js\";\n\nconst { cyan, green, yellow, dim, bold } = colors;\n\n// ─── Public collect-mode result shape ────────────────────────────────────────\n\nexport interface InjectPatch {\n /** Path of the file being patched, relative to the target package root. */\n file: string;\n kind: \"registry-append\" | \"barrel-append\";\n /** The line that would be appended/inserted. */\n line: string;\n}\n\nexport interface InjectFile {\n /** Path relative to the target package root (e.g. `src/Components/Foo/Foo.ts`). */\n path: string;\n contents: string;\n}\n\nexport interface InjectCollectResult {\n target: Target;\n files: InjectFile[];\n patches: InjectPatch[];\n warnings: string[];\n}\n\n// ─── Filesystem helpers (mirrors eject.ts) ────────────────────────────────────\n\n/** Every .ts/.tsx file inside a project component folder. */\nfunction componentFiles(dir: string): string[] {\n const out: string[] = [];\n const walk = (d: string) => {\n for (const e of fs.readdirSync(d, { withFileTypes: true })) {\n const p = path.join(d, e.name);\n if (e.isDirectory()) walk(p);\n else if (/\\.(ts|tsx)$/.test(e.name)) out.push(p);\n }\n };\n if (fs.existsSync(dir)) walk(dir);\n return out;\n}\n\n/** Every file (including non-ts assets like meta.json) inside a component folder. */\nfunction allComponentFiles(dir: string): string[] {\n const out: string[] = [];\n const walk = (d: string) => {\n for (const e of fs.readdirSync(d, { withFileTypes: true })) {\n const p = path.join(d, e.name);\n if (e.isDirectory()) walk(p);\n else out.push(p);\n }\n };\n if (fs.existsSync(dir)) walk(dir);\n return out;\n}\n\n/** All top-level project component names = `<project>/src/components/*` (minus `_shared`). */\nfunction projectComponentNames(projectDir: string): string[] {\n const dir = path.join(projectDir, \"src\", \"components\");\n if (!fs.existsSync(dir)) return [];\n return fs\n .readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory() && e.name !== \"_shared\")\n .map((e) => e.name);\n}\n\n/** Component names a given seed imports via `../Sibling/`, `~/components/Sibling/`, or its meta.json deps. */\nfunction directDeps(\n name: string,\n componentsDir: string,\n allNames: Set<string>,\n): Set<string> {\n const deps = new Set<string>();\n const metaPath = path.join(componentsDir, name, \"meta.json\");\n if (fs.existsSync(metaPath)) {\n try {\n const meta = JSON.parse(fs.readFileSync(metaPath, \"utf8\")) as { dependencies?: string[] };\n for (const d of meta.dependencies ?? []) if (allNames.has(d)) deps.add(d);\n } catch {\n /* tolerate malformed meta.json — import scan is the safety net */\n }\n }\n const relRe = /['\"]\\.\\.\\/([A-Z][A-Za-z0-9_]*)\\//g;\n const aliasRe = /['\"]~\\/components\\/([A-Z][A-Za-z0-9_]*)\\//g;\n for (const file of componentFiles(path.join(componentsDir, name))) {\n const src = fs.readFileSync(file, \"utf8\");\n let m: RegExpExecArray | null;\n while ((m = relRe.exec(src))) if (allNames.has(m[1])) deps.add(m[1]);\n while ((m = aliasRe.exec(src))) if (allNames.has(m[1])) deps.add(m[1]);\n }\n return deps;\n}\n\n/** Expand a seed set to its transitive sibling closure. */\nfunction resolveClosure(\n seed: Set<string>,\n componentsDir: string,\n allNames: string[],\n): Set<string> {\n const all = new Set(allNames);\n const out = new Set(seed);\n const queue = [...seed];\n while (queue.length) {\n const next = queue.pop()!;\n for (const dep of directDeps(next, componentsDir, all)) {\n if (!out.has(dep)) {\n out.add(dep);\n queue.push(dep);\n }\n }\n }\n return out;\n}\n\n/**\n * Reverse of eject's rewriteImports:\n *\n * `'@babylonjsmarket/arcade/<Sibling>'` → `'../<Sibling>/<Sibling>'`\n * `'@babylonjsmarket/arcade-pro/<Sibling>'` → `'../<Sibling>/<Sibling>'`\n *\n * …but only when <Sibling> is co-injected for the same target package. Other\n * package subpaths (including ecs / babylon / solid-js / etc.) are left alone.\n *\n * For arcade-pro, components share a parent (`src/Components/`), so the\n * relative path is always `../<Sibling>/<Sibling>`. For viz-pro the caller\n * supplies a `layerMap` and the originating file's layer; the relative path\n * resolves through the per-file layer routing.\n */\nfunction rewriteArcadeImports(src: string, injected: Set<string>): string {\n return src.replace(\n /(['\"])@babylonjsmarket\\/(?:arcade|arcade-pro)\\/([A-Z][A-Za-z0-9_]*)\\1/g,\n (whole, quote, sibling) => {\n if (injected.has(sibling)) {\n return `${quote}../${sibling}/${sibling}${quote}`;\n }\n return whole;\n },\n );\n}\n\n/**\n * viz variant. Rewrites `@babylonjsmarket/viz/<Sibling>` (the canonical name),\n * the legacy `@babylonjsmarket/viz-pro/<Sibling>`, or\n * `@babylonjsmarket/arcade/<Sibling>` referencing a viz sibling) to the\n * correct flat-layer relative path: `../<targetLayer>/<Sibling>`. Same-layer\n * siblings collapse to `./<Sibling>`. Both `viz` and `viz-pro` prefixes are\n * matched so seeds ejected against either package name still rewrite.\n */\nfunction rewriteVizImports(\n src: string,\n injected: Set<string>,\n layerOf: (name: string) => VizLayer | undefined,\n fromLayer: VizLayer,\n): string {\n return src.replace(\n /(['\"])@babylonjsmarket\\/(?:viz-pro|viz|arcade|arcade-pro)\\/([A-Z][A-Za-z0-9_]*)\\1/g,\n (whole, quote, sibling) => {\n if (!injected.has(sibling)) return whole;\n const dest = layerOf(sibling);\n if (!dest) return whole;\n const rel = dest === fromLayer ? `./${sibling}` : `../${dest}/${sibling}`;\n return `${quote}${rel}${quote}`;\n },\n );\n}\n\n// ─── Registry / barrel patchers ───────────────────────────────────────────────\n\n/**\n * Append lazy resolver lines into ARCADE_PRO_COMPONENT_REGISTRY. Pure decision\n * step: returns what to add without touching disk.\n *\n * `existingRegistry` is the current registry.ts contents, or `undefined` when\n * the file isn't present (apply mode missing the marker emits a warning; in\n * collect mode we always assume the marker is present).\n */\nfunction planArcadeProRegistry(\n existingRegistry: string | undefined,\n names: string[],\n registryRelPath = \"src/registry.ts\",\n): { lines: string[]; added: string[]; warnings: string[]; markerFound: boolean } {\n const warnings: string[] = [];\n if (existingRegistry === undefined) {\n warnings.push(\n `! packages/arcade/${registryRelPath} not found — add resolvers manually for: ${names.join(\", \")}`,\n );\n return { lines: [], added: [], warnings, markerFound: false };\n }\n const marker = /ARCADE_PRO_COMPONENT_REGISTRY:\\s*Record<string,\\s*LazyComponentResolver>\\s*=\\s*\\{/;\n if (!marker.test(existingRegistry)) {\n warnings.push(\n `! Could not find 'ARCADE_PRO_COMPONENT_REGISTRY' marker — add resolvers manually for: ${names.join(\", \")}`,\n );\n return { lines: [], added: [], warnings, markerFound: false };\n }\n const added: string[] = [];\n const lines: string[] = [];\n for (const name of names) {\n if (existingRegistry.includes(`./Components/${name}/${name}`)) continue; // already wired\n lines.push(` ${name}: () => import('./Components/${name}/${name}'),`);\n added.push(name);\n }\n return { lines, added, warnings, markerFound: true };\n}\n\n/** Append a lazy resolver line into ARCADE_PRO_COMPONENT_REGISTRY (idempotent, on-disk). */\nfunction patchArcadeProRegistry(\n arcadeProRoot: string,\n names: string[],\n dryRun: boolean,\n): string[] {\n const registryPath = path.join(arcadeProRoot, \"src\", \"registry.ts\");\n const existing = fs.existsSync(registryPath) ? fs.readFileSync(registryPath, \"utf8\") : undefined;\n const plan = planArcadeProRegistry(existing, names);\n if (plan.warnings.length) return plan.warnings;\n if (plan.added.length && !dryRun) {\n const marker = /ARCADE_PRO_COMPONENT_REGISTRY:\\s*Record<string,\\s*LazyComponentResolver>\\s*=\\s*\\{/;\n const next = (existing as string).replace(marker, (m) => `${m}\\n${plan.lines.join(\"\\n\")}`);\n fs.writeFileSync(registryPath, next);\n }\n return plan.added.map((n) => ` patched registry: ${n}`);\n}\n\n/**\n * Pure planner for the viz-pro layer barrel: returns the line to append if any.\n */\nfunction planVizProBarrel(\n existingBarrel: string | undefined,\n layer: VizLayer,\n fileName: string,\n): { line: string | null; warnings: string[] } {\n if (existingBarrel === undefined) {\n return {\n line: null,\n warnings: [\n `! packages/viz-pro/src/${layer}/index.ts not found — add the barrel re-export manually for ${fileName}`,\n ],\n };\n }\n const needle = `from './${fileName}'`;\n if (existingBarrel.includes(needle)) return { line: null, warnings: [] };\n return { line: `export * from './${fileName}';`, warnings: [] };\n}\n\n/** Append `export * from './<FileName>';` to a viz-pro layer barrel (idempotent, on-disk). */\nfunction patchVizProBarrel(\n vizProRoot: string,\n layer: VizLayer,\n fileName: string,\n dryRun: boolean,\n): string[] {\n const barrelPath = path.join(vizProRoot, \"src\", layer, \"index.ts\");\n const existing = fs.existsSync(barrelPath) ? fs.readFileSync(barrelPath, \"utf8\") : undefined;\n const plan = planVizProBarrel(existing, layer, fileName);\n if (plan.warnings.length) return plan.warnings;\n if (plan.line === null) return [];\n if (!dryRun) {\n const next = existing!.endsWith(\"\\n\")\n ? existing + plan.line + \"\\n\"\n : existing + \"\\n\" + plan.line + \"\\n\";\n fs.writeFileSync(barrelPath, next);\n }\n return [` patched ${layer}/index.ts: ${fileName}`];\n}\n\n/**\n * Strip a lazy-resolver line of the form\n * ` Foo: () => import('./components/Foo/Foo'),`\n * from `<project>/src/registry.ts`. Returns the list of names actually removed.\n */\nfunction stripProjectRegistry(\n projectDir: string,\n names: string[],\n dryRun: boolean,\n): string[] {\n const registryPath = path.join(projectDir, \"src\", \"registry.ts\");\n if (!fs.existsSync(registryPath)) return [];\n let text = fs.readFileSync(registryPath, \"utf8\");\n const removed: string[] = [];\n for (const name of names) {\n const re = new RegExp(\n `^\\\\s*${name}\\\\s*:\\\\s*\\\\(\\\\)\\\\s*=>\\\\s*import\\\\(\\\\s*['\"]\\\\.\\\\/components\\\\/${name}\\\\/${name}['\"]\\\\s*\\\\)\\\\s*,?\\\\s*\\\\r?\\\\n`,\n \"m\",\n );\n if (re.test(text)) {\n text = text.replace(re, \"\");\n removed.push(name);\n }\n }\n if (removed.length && !dryRun) fs.writeFileSync(registryPath, text);\n return removed;\n}\n\n// ─── Plan + main entry ────────────────────────────────────────────────────────\n\ninterface ResolvedSeed {\n /** Name as the operator typed it (and as it lives under `src/components/`). */\n name: string;\n /** Absolute path to the seed's source directory (post `--source` override). */\n sourceDir: string;\n}\n\nexport interface InjectOptions {\n /**\n * What the engine does with the resolved file list:\n * - 'apply' → writes into the resolved packageRoot/vizProRoot (operator mode).\n * - 'collect' → returns the file map + patch plan without touching disk\n * (member mode; payload goes to the marketplace endpoint).\n */\n mode?: \"apply\" | \"collect\";\n /** Tmpdir-friendly: the arcade-pro package root (the dir containing `src/registry.ts`). Apply mode only. */\n packageRoot?: string;\n /** Tmpdir-friendly: the viz-pro package root (the dir containing `src/{core,solid,ecs}/index.ts`). Apply mode only. */\n vizProRoot?: string;\n /** The project we're injecting FROM. Defaults to `cwd`. */\n projectDir?: string;\n /** Override for `process.cwd()`. Tests use this; the CLI entry passes `process.cwd()`. */\n cwd?: string;\n}\n\nexport async function inject(\n args: string[],\n opts: InjectOptions = {},\n): Promise<InjectCollectResult | void> {\n if (args.includes(\"-h\") || args.includes(\"--help\")) {\n console.log(INJECT_HELP);\n return;\n }\n\n const argv = mri(args, {\n boolean: [\"dry-run\", \"move\", \"confirm\", \"force\"],\n string: [\"target\", \"source\", \"layer\"],\n });\n\n const mode: \"apply\" | \"collect\" = opts.mode ?? \"apply\";\n const dryRun = Boolean(argv[\"dry-run\"]);\n const move = Boolean(argv.move);\n const confirm = Boolean(argv.confirm);\n const force = Boolean(argv.force);\n // Normalize the legacy package-name target aliases to the canonical target\n // names early, so existing user scripts passing `--target arcade-pro` or\n // `--target viz-pro` keep working:\n // arcade-pro → arcade (mirrors the original arcade alias)\n // viz-pro → viz\n const rawTarget = argv.target as string | undefined;\n const explicitTarget = (\n rawTarget === \"arcade-pro\" ? \"arcade\" : rawTarget === \"viz-pro\" ? \"viz\" : rawTarget\n ) as Target | undefined;\n const sourceOverride = argv.source as string | undefined;\n const layerOverride = argv.layer as VizLayer | undefined;\n const names = argv._.map(String);\n\n const cwd = opts.cwd ?? process.cwd();\n const projectDir = opts.projectDir ?? cwd;\n\n // ─── Arg validation ───\n if (names.length === 0) {\n console.error(yellow(\"No component names given. Pass at least one, e.g. `bjs inject Foo`.\"));\n process.exit(1);\n return;\n }\n // --move / --confirm are operator-only knobs. In collect mode they're\n // meaningless (no project to mutate); flag and bail.\n if (mode === \"collect\" && (move || confirm)) {\n console.error(yellow(\"--move and --confirm are not available in member submission mode.\"));\n process.exit(1);\n return;\n }\n if (move && !confirm) {\n console.error(yellow(\"--move requires --confirm (it deletes project files). Pass --move --confirm.\"));\n process.exit(1);\n return;\n }\n if (move && dryRun) {\n console.error(yellow(\"--move and --dry-run are mutually exclusive. Drop one.\"));\n process.exit(1);\n return;\n }\n if (explicitTarget && explicitTarget !== \"arcade\" && explicitTarget !== \"viz\") {\n console.error(yellow(`Unknown --target ${rawTarget}. Use arcade or viz.`));\n process.exit(1);\n return;\n }\n if (layerOverride && layerOverride !== \"core\" && layerOverride !== \"solid\" && layerOverride !== \"ecs\") {\n console.error(yellow(`Unknown --layer ${layerOverride}. Use core, solid, or ecs.`));\n process.exit(1);\n return;\n }\n if (sourceOverride && names.length > 1) {\n console.error(yellow(\"--source applies to a single seed; pass one NAME with --source.\"));\n process.exit(1);\n return;\n }\n\n // ─── Phase 0: resolve roots (apply mode only) ───\n let packageRoot = opts.packageRoot;\n let vizProRoot = opts.vizProRoot;\n if (mode === \"apply\" && (!packageRoot || !vizProRoot)) {\n try {\n const monorepo = findMonorepoRoot();\n packageRoot ??= monorepo.arcadeProRoot;\n vizProRoot ??= monorepo.vizProRoot;\n } catch (e) {\n console.error(yellow((e as Error).message));\n process.exit(1);\n return;\n }\n }\n\n // ─── Phase 1: locate seeds + walk closure ───\n const componentsDir = path.join(projectDir, \"src\", \"components\");\n const allProjectNames = projectComponentNames(projectDir);\n\n const seeds: ResolvedSeed[] = [];\n for (const name of names) {\n const sourceDir = sourceOverride\n ? path.resolve(cwd, sourceOverride)\n : path.join(componentsDir, name);\n if (!fs.existsSync(sourceDir)) {\n console.error(\n yellow(\n `Could not find source for \"${name}\". Looked at ${sourceDir}. ` +\n `Use --source <path> to point at the seed explicitly.`,\n ),\n );\n process.exit(1);\n return;\n }\n seeds.push({ name, sourceDir });\n }\n\n // Run the closure walk in the project's components dir (only when seeds live\n // under <project>/src/components/, which is the default and the case we can\n // reason about transitively). With --source we still inject the seed itself\n // but skip the transitive walk — caller is in unusual territory.\n const seedNames = new Set(seeds.map((s) => s.name));\n const closure: Set<string> = sourceOverride\n ? seedNames\n : resolveClosure(seedNames, componentsDir, allProjectNames);\n\n // ─── Phase 2: target detection ───\n const closureFiles: SeedFile[] = [];\n for (const name of closure) {\n const dir = sourceOverride && seedNames.has(name)\n ? seeds.find((s) => s.name === name)!.sourceDir\n : path.join(componentsDir, name);\n for (const f of componentFiles(dir)) {\n closureFiles.push({ path: f, source: fs.readFileSync(f, \"utf8\") });\n }\n }\n\n const target: Target = explicitTarget ?? detectTarget(closureFiles);\n\n // For multi-seed inputs, every seed individually must agree with `target`.\n if (!explicitTarget && seeds.length > 1) {\n for (const seed of seeds) {\n const dir = seed.sourceDir;\n const files: SeedFile[] = componentFiles(dir).map((f) => ({\n path: f,\n source: fs.readFileSync(f, \"utf8\"),\n }));\n const perSeed = detectTarget(files);\n if (perSeed !== target) {\n console.error(\n yellow(\n `Auto-detect disagrees across seeds: \"${seed.name}\" → ${perSeed}, ` +\n `others → ${target}. Pass --target explicitly or split into separate runs.`,\n ),\n );\n process.exit(1);\n return;\n }\n }\n }\n\n // ─── Apply-mode root checks ───\n let chosenRoot: string | undefined;\n if (mode === \"apply\") {\n try {\n if (target === \"arcade\") {\n if (!fs.existsSync(packageRoot!)) {\n throw new Error(\n `packages/arcade is not checked out at ${packageRoot}. Run \\`git submodule update --init packages/arcade\\` and retry.`,\n );\n }\n chosenRoot = packageRoot!;\n } else {\n if (!fs.existsSync(vizProRoot!)) {\n throw new Error(\n `packages/viz-pro is not checked out at ${vizProRoot}. Run \\`git submodule update --init packages/viz-pro\\` and retry.`,\n );\n }\n chosenRoot = vizProRoot!;\n }\n } catch (e) {\n console.error(yellow((e as Error).message));\n process.exit(1);\n return;\n }\n }\n\n // ─── Plan logging header ───\n console.log(\n bold(dryRun ? \"\\nInject plan (dry run — nothing written):\" : \"\\nInjecting:\"),\n );\n console.log(` target: ${cyan(target)}`);\n console.log(` components: ${cyan([...closure].sort().join(\", \"))}`);\n\n // ─── Phase 3: copy files ───\n if (mode === \"collect\") {\n const result =\n target === \"arcade\"\n ? collectArcadePro({ seeds, closure, componentsDir, sourceOverride })\n : collectVizPro({ seeds, closure, componentsDir, sourceOverride, layerOverride });\n for (const f of result.files) console.log(green(` + packages/${target}/${f.path}`));\n for (const w of result.warnings) console.log(yellow(w));\n console.log(\n dryRun\n ? dim(\"\\nRe-run without --dry-run to submit.\\n\")\n : dim(\"\\nCollect-mode plan ready (no submission performed by the library).\\n\"),\n );\n return { ...result, target };\n }\n\n // mode === 'apply'\n if (target === \"arcade\") {\n await injectArcadePro({\n seeds,\n closure,\n componentsDir,\n sourceOverride,\n arcadeProRoot: chosenRoot!,\n dryRun,\n force,\n });\n } else {\n await injectVizPro({\n seeds,\n closure,\n componentsDir,\n sourceOverride,\n vizProRoot: chosenRoot!,\n dryRun,\n force,\n layerOverride,\n });\n }\n\n // ─── Phase 6 (optional): source cleanup ───\n if (move) {\n if (sourceOverride) {\n console.log(\n yellow(\n \" ! --move with --source: only the source dir is removed; cannot reliably patch a foreign project's registry.\",\n ),\n );\n }\n for (const seed of seeds) {\n if (fs.existsSync(seed.sourceDir)) {\n if (!dryRun) fs.rmSync(seed.sourceDir, { recursive: true, force: true });\n console.log(dim(` - ${path.relative(projectDir, seed.sourceDir)}/ (project copy removed)`));\n }\n }\n const removed = stripProjectRegistry(\n projectDir,\n seeds.map((s) => s.name),\n dryRun,\n );\n for (const name of removed) {\n console.log(dim(` - project registry entry: ${name}`));\n }\n }\n\n console.log(\n dryRun\n ? dim(\"\\nRe-run without --dry-run to apply.\\n\")\n : green(`\\nDone. Components landed in packages/${target}/.\\n`),\n );\n}\n\n// ─── arcade-pro injection (apply mode) ───────────────────────────────────────\n\nasync function injectArcadePro(args: {\n seeds: ResolvedSeed[];\n closure: Set<string>;\n componentsDir: string;\n sourceOverride: string | undefined;\n arcadeProRoot: string;\n dryRun: boolean;\n force: boolean;\n}): Promise<void> {\n const { seeds, closure, componentsDir, sourceOverride, arcadeProRoot, dryRun, force } = args;\n const destComponents = path.join(arcadeProRoot, \"src\", \"Components\");\n if (!dryRun) fs.mkdirSync(destComponents, { recursive: true });\n\n const sourceOf = (name: string): string => {\n const seed = seeds.find((s) => s.name === name);\n return seed && sourceOverride ? seed.sourceDir : path.join(componentsDir, name);\n };\n\n for (const name of [...closure].sort()) {\n const src = sourceOf(name);\n const dest = path.join(destComponents, name);\n if (fs.existsSync(dest) && !force) {\n console.log(\n yellow(` ! packages/arcade/src/Components/${name}/ already exists — pass --force to overwrite.`),\n );\n continue;\n }\n if (!dryRun) {\n if (fs.existsSync(dest)) fs.rmSync(dest, { recursive: true, force: true });\n fs.cpSync(src, dest, { recursive: true });\n }\n console.log(green(` + packages/arcade/src/Components/${name}/`));\n }\n\n // Phase 4: import rewriting across each copied folder.\n if (!dryRun) {\n for (const name of closure) {\n const dest = path.join(destComponents, name);\n if (!fs.existsSync(dest)) continue;\n rewriteTree(dest, (text) => rewriteArcadeImports(text, closure));\n }\n }\n\n // Phase 5: arcade-pro registry patch.\n for (const line of patchArcadeProRegistry(\n arcadeProRoot,\n [...closure].sort(),\n dryRun,\n )) {\n console.log(line.startsWith(\"!\") ? yellow(line) : dim(line));\n }\n}\n\n// ─── arcade-pro collection (collect mode) ────────────────────────────────────\n\nfunction collectArcadePro(args: {\n seeds: ResolvedSeed[];\n closure: Set<string>;\n componentsDir: string;\n sourceOverride: string | undefined;\n}): { files: InjectFile[]; patches: InjectPatch[]; warnings: string[] } {\n const { seeds, closure, componentsDir, sourceOverride } = args;\n const sourceOf = (name: string): string => {\n const seed = seeds.find((s) => s.name === name);\n return seed && sourceOverride ? seed.sourceDir : path.join(componentsDir, name);\n };\n\n const files: InjectFile[] = [];\n const warnings: string[] = [];\n\n for (const name of [...closure].sort()) {\n const src = sourceOf(name);\n if (!fs.existsSync(src)) {\n warnings.push(` ! source for ${name} missing at ${src}`);\n continue;\n }\n for (const abs of allComponentFiles(src)) {\n const rel = path.relative(src, abs);\n const baseRel = path.posix.join(\"src\", \"Components\", name, rel.split(path.sep).join(\"/\"));\n const isText = /\\.(ts|tsx)$/i.test(abs);\n const raw = fs.readFileSync(abs, \"utf8\");\n const contents = isText ? rewriteArcadeImports(raw, closure) : raw;\n files.push({ path: baseRel, contents });\n }\n }\n\n // Plan the registry patch — but submit the *desired* added lines, not the\n // raw existing+new file. The server applies the patch against whatever the\n // pro package looks like at merge time.\n const patches: InjectPatch[] = [];\n for (const name of [...closure].sort()) {\n patches.push({\n file: \"src/registry.ts\",\n kind: \"registry-append\",\n line: ` ${name}: () => import('./Components/${name}/${name}'),`,\n });\n }\n\n return { files, patches, warnings };\n}\n\n// ─── viz-pro injection (apply mode) ──────────────────────────────────────────\n\ninterface ViewFile {\n src: string;\n base: string;\n owner: string;\n source: string;\n layer: VizLayer;\n destBase: string;\n}\n\nfunction classifyVizFiles(args: {\n seeds: ResolvedSeed[];\n closure: Set<string>;\n componentsDir: string;\n sourceOverride: string | undefined;\n layerOverride: VizLayer | undefined;\n}): { files: ViewFile[]; primaryLayer: Map<string, VizLayer> } {\n const { seeds, closure, componentsDir, sourceOverride, layerOverride } = args;\n\n const sourceOf = (name: string): string => {\n const seed = seeds.find((s) => s.name === name);\n return seed && sourceOverride ? seed.sourceDir : path.join(componentsDir, name);\n };\n\n const files: ViewFile[] = [];\n\n // Pass A — non-tests\n for (const name of closure) {\n const dir = sourceOf(name);\n for (const abs of componentFiles(dir)) {\n const base = path.basename(abs);\n if (/\\.test\\.tsx?$/.test(base)) continue;\n const source = fs.readFileSync(abs, \"utf8\");\n const layer = layerOverride ?? detectLayer(abs, source);\n files.push({ src: abs, base, owner: name, source, layer, destBase: base });\n }\n }\n // Pass B — tests (look up their subject's layer)\n for (const name of closure) {\n const dir = sourceOf(name);\n for (const abs of componentFiles(dir)) {\n const base = path.basename(abs);\n if (!/\\.test\\.tsx?$/.test(base)) continue;\n const source = fs.readFileSync(abs, \"utf8\");\n const subjectBase = base.replace(/\\.test(\\.tsx?)$/, \"$1\");\n const subjectAlt = base.replace(/\\.test\\.tsx?$/, \".tsx\");\n const subject = files.find((f) => f.owner === name && (f.base === subjectBase || f.base === subjectAlt));\n const layer = layerOverride ?? detectLayer(abs, source, subject?.layer);\n files.push({ src: abs, base, owner: name, source, layer, destBase: base });\n }\n }\n\n const primaryLayer = new Map<string, VizLayer>();\n for (const f of files) {\n if (/\\.test\\.tsx?$/.test(f.base)) continue;\n if (!primaryLayer.has(f.owner)) primaryLayer.set(f.owner, f.layer);\n }\n\n return { files, primaryLayer };\n}\n\nasync function injectVizPro(args: {\n seeds: ResolvedSeed[];\n closure: Set<string>;\n componentsDir: string;\n sourceOverride: string | undefined;\n vizProRoot: string;\n dryRun: boolean;\n force: boolean;\n layerOverride: VizLayer | undefined;\n}): Promise<void> {\n const { closure, vizProRoot, dryRun, force } = args;\n const { files, primaryLayer } = classifyVizFiles(args);\n const layerOf = (name: string): VizLayer | undefined => primaryLayer.get(name);\n\n for (const f of files) {\n const dest = path.join(vizProRoot, \"src\", f.layer, f.destBase);\n if (fs.existsSync(dest) && !force) {\n console.log(\n yellow(\n ` ! packages/viz-pro/src/${f.layer}/${f.destBase} already exists — pass --force to overwrite.`,\n ),\n );\n }\n }\n\n for (const f of files) {\n const destDir = path.join(vizProRoot, \"src\", f.layer);\n const dest = path.join(destDir, f.destBase);\n if (fs.existsSync(dest) && !force) continue;\n if (!dryRun) {\n fs.mkdirSync(destDir, { recursive: true });\n const rewritten = rewriteVizImports(f.source, closure, layerOf, f.layer);\n fs.writeFileSync(dest, rewritten);\n }\n console.log(green(` + packages/viz-pro/src/${f.layer}/${f.destBase}`));\n }\n\n // Phase 5 — patch the layer barrels.\n const barrelNames = new Set<string>();\n for (const f of files) {\n if (/\\.test\\.tsx?$/.test(f.base)) continue;\n const stem = f.destBase.replace(/\\.tsx?$/, \"\");\n const key = `${f.layer}:${stem}`;\n if (barrelNames.has(key)) continue;\n barrelNames.add(key);\n for (const line of patchVizProBarrel(vizProRoot, f.layer, stem, dryRun)) {\n console.log(line.startsWith(\"!\") ? yellow(line) : dim(line));\n }\n }\n\n console.log(\n dim(\n \" hint: if you want named re-exports from the package root, edit packages/viz-pro/src/index.ts by hand.\",\n ),\n );\n}\n\n// ─── viz-pro collection (collect mode) ───────────────────────────────────────\n\nfunction collectVizPro(args: {\n seeds: ResolvedSeed[];\n closure: Set<string>;\n componentsDir: string;\n sourceOverride: string | undefined;\n layerOverride: VizLayer | undefined;\n}): { files: InjectFile[]; patches: InjectPatch[]; warnings: string[] } {\n const { closure } = args;\n const { files: classified, primaryLayer } = classifyVizFiles(args);\n const layerOf = (name: string): VizLayer | undefined => primaryLayer.get(name);\n\n const files: InjectFile[] = [];\n const warnings: string[] = [];\n\n for (const f of classified) {\n const rel = path.posix.join(\"src\", f.layer, f.destBase);\n const contents = rewriteVizImports(f.source, closure, layerOf, f.layer);\n files.push({ path: rel, contents });\n }\n\n const patches: InjectPatch[] = [];\n const barrelKeys = new Set<string>();\n for (const f of classified) {\n if (/\\.test\\.tsx?$/.test(f.base)) continue;\n const stem = f.destBase.replace(/\\.tsx?$/, \"\");\n const key = `${f.layer}:${stem}`;\n if (barrelKeys.has(key)) continue;\n barrelKeys.add(key);\n patches.push({\n file: `src/${f.layer}/index.ts`,\n kind: \"barrel-append\",\n line: `export * from './${stem}';`,\n });\n }\n\n return { files, patches, warnings };\n}\n\n/** Run a rewriter over every .ts/.tsx file under a directory tree. */\nfunction rewriteTree(dir: string, rewrite: (text: string) => string): void {\n for (const e of fs.readdirSync(dir, { withFileTypes: true })) {\n const p = path.join(dir, e.name);\n if (e.isDirectory()) rewriteTree(p, rewrite);\n else if (/\\.(ts|tsx)$/.test(e.name)) {\n const before = fs.readFileSync(p, \"utf8\");\n const after = rewrite(before);\n if (after !== before) fs.writeFileSync(p, after);\n }\n }\n}\n\n// Re-export pure classifiers + helpers so callers can pick them up from one place.\nexport { detectTarget, detectLayer };\nexport type { Target, VizLayer, SeedFile };\n","import colors from \"picocolors\";\n\nconst { cyan, bold } = colors;\n\nexport const INJECT_HELP = `\\\nUsage: bjs inject [OPTION]... NAME...\n\nSubmit a component or system from your project's ${cyan(\"src/components/<Name>/\")} to\nBabylonJS Market for curator review (reverse of ${cyan(\"arcade eject\")}).\n\nWith no ${bold(\"--target\")}, the tool auto-detects per seed:\n * any file extending ${cyan(\"PanelDebuggerSystem\")} / ${cyan(\"StateStepperSystem\")} or\n importing from ${cyan(\"@babylonjsmarket/viz\")} → ${cyan(\"viz\")},\n * otherwise → ${cyan(\"arcade\")}.\n\nMulti-seed inputs must all detect to the same target.\n\nOptions:\n --target <arcade|viz> skip auto-detection (legacy: arcade-pro, viz-pro)\n --source <path> override <cwd>/src/components/<Name>/\n --layer <core|solid|ecs> viz only; skip per-file layer detection\n --force allow overwriting an existing target\n --dry-run print the plan, write nothing, do not submit\n -h, --help print this help message\n\nExamples:\n bjs inject Foo # auto-detect target\n bjs inject Foo Bar --dry-run # multi-name, preview\n bjs inject MyPanelDebugger --target viz\n bjs inject Foo --source ./packages/demo/src/components/Foo\n`;\n","/**\n * Pure classifiers for the inject engine.\n *\n * `detectTarget` decides whether a seed of project files belongs in\n * `@babylonjsmarket/arcade` (per-component, registered) or the viz package\n * (flat per-layer barrels).\n *\n * `detectLayer` decides which viz layer (`core`, `solid`, `ecs`) owns a\n * single source file. Order matters: rules are evaluated top-down and the\n * first match wins. The order mirrors the plan.\n *\n * Target naming: the canonical user-facing target names are `arcade` and\n * `viz`. The legacy `arcade-pro` / `viz-pro` package names live on only as\n * back-compat aliases (normalized to the canonical names by callers) and as\n * import-prefix patterns we still recognize in existing seeds.\n */\n\nexport type Target = \"arcade\" | \"viz\";\nexport type VizLayer = \"core\" | \"solid\" | \"ecs\";\n\nexport interface SeedFile {\n path: string;\n source: string;\n}\n\n/**\n * Classify a closure of seed files to one of the two packages. Any single\n * file extending a viz System class or importing from `@babylonjsmarket/viz`\n * (or the legacy `@babylonjsmarket/viz-pro`) tips the whole seed to `viz`.\n */\nexport function detectTarget(seedFiles: SeedFile[]): Target {\n for (const { source } of seedFiles) {\n // Recognize BOTH the canonical `@babylonjsmarket/viz` and the legacy\n // `@babylonjsmarket/viz-pro` import prefix — existing seeds were ejected\n // against `viz-pro` and must still classify correctly.\n if (/from\\s+['\"]@babylonjsmarket\\/viz(?:-pro)?['\"]/.test(source)) return \"viz\";\n if (/extends\\s+(PanelDebuggerSystem|StateStepperSystem)\\b/.test(source)) return \"viz\";\n }\n return \"arcade\";\n}\n\n/**\n * Classify a single source file to a viz layer.\n *\n * Order is load-bearing:\n * 1. *.test.ts(x) → route alongside the subject file (re-detect on the\n * subject's source if known, else default 'core').\n * 2. *.tsx that imports from 'solid-js' → 'solid'.\n * 3. extends (PanelDebuggerSystem|StateStepperSystem|System) or filename\n * ends in 'System.ts' → 'ecs'.\n * 4. extends Component and no Solid import → 'ecs'.\n * 5. contains `definePanel(` and no Solid import → 'core'.\n * 6. fallback → 'core'.\n *\n * `subjectLayer` lets the caller pin a test file to its subject's layer; pass\n * `undefined` when the subject isn't co-injected, which falls through to\n * rule (1)'s default.\n */\nexport function detectLayer(\n filePath: string,\n source: string,\n subjectLayer?: VizLayer,\n): VizLayer {\n const base = filePath.split(/[\\\\/]/).pop() ?? filePath;\n\n // (1) test files travel with their subject\n if (/\\.test\\.tsx?$/.test(base)) {\n return subjectLayer ?? \"core\";\n }\n\n const hasSolidImport = /from\\s+['\"]solid-js['\"]/.test(source);\n\n // (2) Solid .tsx\n if (/\\.tsx$/.test(base) && hasSolidImport) return \"solid\";\n\n // (3) System subclasses or *System.ts filenames\n if (/extends\\s+(PanelDebuggerSystem|StateStepperSystem|System)\\b/.test(source)) return \"ecs\";\n if (/System\\.ts$/.test(base)) return \"ecs\";\n\n // (4) Component subclasses (no Solid)\n if (/extends\\s+Component\\b/.test(source) && !hasSolidImport) return \"ecs\";\n\n // (5) definePanel files (no Solid)\n if (/\\bdefinePanel\\s*\\(/.test(source) && !hasSolidImport) return \"core\";\n\n // (6) fallback\n return \"core\";\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport interface MonorepoPaths {\n root: string;\n arcadeProRoot: string;\n vizProRoot: string;\n}\n\n/**\n * ⚠️ DEFUNCT DESTINATIONS — apply mode is being retired.\n *\n * The `arcadeProRoot` / `vizProRoot` destinations below point at\n * `packages/arcade-pro` and `packages/viz-pro`, which have been REMOVED from\n * the monorepo. Premium components are now authored directly in the game\n * project's `src/` and delivered per-component via the CLI's `collect` mode\n * (which never touches these paths); apply mode that copies into a local\n * pro-package checkout no longer has a valid target.\n *\n * This operator-only function is kept in place (not ripped out) so the\n * walk-up-to-umbrella logic stays available, but callers should not rely on\n * `arcadeProRoot` / `vizProRoot` resolving to real directories — they won't.\n *\n * Walk up from this file (dist/lib/inject/monorepo-root.js or\n * src/lib/inject/monorepo-root.ts) looking for the umbrella `package.json`\n * whose `name === \"babylonjs-market-monorepo\"`. Returns the umbrella root plus\n * the two (now-defunct) pro-package roots.\n *\n * Only called from `apply` mode — `collect` mode never touches the local\n * monorepo because it operates against a tmpdir workRoot supplied by the\n * caller.\n *\n * Does NOT validate that the pro-package directories exist — `requireTargetRoot`\n * does that lazily so callers can run --help / classifier-only paths without\n * the submodule being present.\n */\nexport function findMonorepoRoot(): MonorepoPaths {\n const here = path.dirname(fileURLToPath(import.meta.url));\n let dir = here;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const pkgPath = path.join(dir, \"package.json\");\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf8\")) as { name?: string };\n if (pkg.name === \"babylonjs-market-monorepo\") {\n return {\n root: dir,\n arcadeProRoot: path.join(dir, \"packages\", \"arcade-pro\"),\n vizProRoot: path.join(dir, \"packages\", \"viz-pro\"),\n };\n }\n } catch {\n /* unreadable / non-JSON — keep walking */\n }\n }\n const parent = path.dirname(dir);\n if (parent === dir) {\n throw new Error(\n `Could not locate umbrella repo (no ancestor package.json with name \"babylonjs-market-monorepo\" above ${here}).`,\n );\n }\n dir = parent;\n }\n}\n\n/**\n * ⚠️ DEFUNCT — see findMonorepoRoot above. Both `packages/arcade-pro` and\n * `packages/viz-pro` have been removed, so this check can no longer succeed in\n * practice. Retained as operator-only scaffolding while apply mode is retired\n * in favor of authoring premium components in the game project's `src/`.\n *\n * Verify the requested target package's submodule directory exists on disk.\n * Throws with a precise message naming the missing path so the operator knows\n * to `git submodule update --init` the relevant repo.\n *\n * `target` uses the canonical names (`arcade` | `viz`); they map to the legacy\n * `packages/arcade-pro` / `packages/viz-pro` dirs that this defunct path used.\n */\nexport function requireTargetRoot(\n paths: MonorepoPaths,\n target: \"arcade\" | \"viz\",\n): string {\n const root = target === \"arcade\" ? paths.arcadeProRoot : paths.vizProRoot;\n const legacyPkg = target === \"arcade\" ? \"arcade-pro\" : \"viz-pro\";\n if (!fs.existsSync(root)) {\n throw new Error(\n `packages/${legacyPkg} is not checked out at ${root} (and is now defunct). ` +\n `Premium components are authored in the game project's src/ — apply mode is retired.`,\n );\n }\n return root;\n}\n","/**\n * `bjs submissions` — list, show, and withdraw marketplace submissions.\n *\n * Talks to the `/api/auth/submissions` endpoint family on babylonjsmarket.com.\n * Auth is gated through the standard `AuthManager` Bearer flow.\n *\n * Subcommands:\n * - `bjs submissions list` (also the default action)\n * - `bjs submissions show <id>`\n * - `bjs submissions withdraw <id>`\n */\n\nimport { Command } from 'commander';\nimport { createInterface } from 'readline';\nimport { AuthManager } from '../utils/auth.js';\nimport { applyTheme } from '../utils/theme-colors.js';\nimport { API_URL } from '../config/constants.js';\n\ninterface SubmissionRow {\n id: number;\n status: string;\n target: string;\n componentNames: string[];\n reviewerNotes?: string | null;\n cliVersion?: string | null;\n createdAt: string;\n updatedAt?: string;\n}\n\ninterface ListResponse {\n submissions: SubmissionRow[];\n total: number;\n hasMore: boolean;\n}\n\ninterface ListOpts {\n status?: string;\n limit?: number;\n json?: boolean;\n}\n\ninterface ShowOpts {\n json?: boolean;\n}\n\ninterface WithdrawOpts {\n yes?: boolean;\n json?: boolean;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Helpers\n// ──────────────────────────────────────────────────────────────────────────\n\n/** Small wrapper around AuthManager.makeAuthenticatedRequest. */\nasync function apiCall(\n auth: AuthManager,\n method: string,\n path: string,\n): Promise<Response> {\n return auth.makeAuthenticatedRequest(`${API_URL}${path}`, { method });\n}\n\n/** Format an ISO datetime as a compact human-readable string. */\nfunction formatDate(s: string | undefined): string {\n if (!s) return '';\n try {\n const d = new Date(s);\n if (isNaN(d.getTime())) return s;\n // YYYY-MM-DD HH:MM\n const pad = (n: number) => String(n).padStart(2, '0');\n return (\n `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ` +\n `${pad(d.getHours())}:${pad(d.getMinutes())}`\n );\n } catch {\n return s;\n }\n}\n\n/** Validate id argument; on bad input prints an error and exits. */\nfunction requireValidId(idArg: string, theme: ReturnType<typeof applyTheme>): number {\n const n = Number(idArg);\n if (!Number.isInteger(n) || n <= 0 || String(n) !== String(idArg).trim()) {\n console.log(theme.error('Invalid id'));\n process.exit(1);\n }\n return n;\n}\n\n/**\n * Render an array of submissions as a column-aligned table.\n * Columns: id | status | target | components | created\n */\nfunction printTable(\n rows: SubmissionRow[],\n theme: ReturnType<typeof applyTheme>,\n): void {\n if (rows.length === 0) {\n console.log(theme.dim('No submissions.'));\n return;\n }\n const header = ['id', 'status', 'target', 'components', 'created'];\n const data = rows.map((r) => [\n String(r.id),\n r.status,\n r.target,\n (r.componentNames || []).join(','),\n formatDate(r.createdAt),\n ]);\n const widths = header.map((h, i) =>\n Math.max(h.length, ...data.map((row) => row[i].length)),\n );\n const fmt = (cells: string[]) =>\n cells.map((c, i) => c.padEnd(widths[i])).join(' ');\n\n console.log(theme.header(fmt(header)));\n console.log(theme.dim(widths.map((w) => '-'.repeat(w)).join(' ')));\n for (const row of data) {\n console.log(fmt(row));\n }\n}\n\n/** Prompt y/N on stdin. Returns true only if the user typed `y` or `Y`. */\nasync function confirm(question: string): Promise<boolean> {\n return new Promise((resolve) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question(question, (answer) => {\n rl.close();\n resolve(/^y(es)?$/i.test(answer.trim()));\n });\n });\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Actions\n// ──────────────────────────────────────────────────────────────────────────\n\nasync function listSubmissionsAction(opts: ListOpts): Promise<void> {\n const auth = new AuthManager();\n const theme = applyTheme();\n\n if (!auth.isAuthenticated()) {\n console.log(theme.error('You must be logged in to view submissions.'));\n console.log(theme.dim('Run \"bjs login\" first.'));\n process.exit(1);\n }\n\n const qsParts: string[] = [];\n if (opts.status) qsParts.push(`status=${encodeURIComponent(opts.status)}`);\n if (opts.limit !== undefined && !Number.isNaN(opts.limit)) {\n qsParts.push(`limit=${opts.limit}`);\n }\n const qs = qsParts.length ? `?${qsParts.join('&')}` : '';\n\n let response: Response;\n try {\n response = await apiCall(auth, 'GET', `/api/auth/submissions${qs}`);\n } catch (err) {\n console.log(theme.error('Failed to fetch submissions; try again later.'));\n console.log(theme.dim((err as Error).message));\n process.exit(1);\n }\n\n if (response.status === 401) {\n console.log(theme.error('Your session is invalid or expired.'));\n console.log(theme.dim('Run \"bjs login\" to refresh.'));\n process.exit(1);\n }\n\n if (response.status >= 500) {\n console.log(theme.error('Failed to fetch submissions; try again later.'));\n process.exit(1);\n }\n\n let body: any = null;\n try {\n body = await response.json();\n } catch {\n /* tolerate empty body */\n }\n\n if (response.status === 400) {\n const msg = (body && body.error) || `HTTP ${response.status}`;\n console.log(theme.error(`Submission query rejected: ${msg}`));\n process.exit(1);\n }\n\n if (!response.ok) {\n const msg = (body && body.error) || `HTTP ${response.status}`;\n console.log(theme.error(`Failed to fetch submissions: ${msg}`));\n process.exit(1);\n }\n\n const list: ListResponse = body || { submissions: [], total: 0, hasMore: false };\n\n if (opts.json) {\n console.log(JSON.stringify(list, null, 2));\n return;\n }\n\n printTable(list.submissions || [], theme);\n if (list.hasMore) {\n const shown = list.submissions?.length ?? 0;\n console.log(\n theme.dim(`(showing ${shown} of ${list.total}; pass --limit higher)`),\n );\n }\n}\n\nasync function showSubmissionAction(idArg: string, opts: ShowOpts): Promise<void> {\n const auth = new AuthManager();\n const theme = applyTheme();\n\n if (!auth.isAuthenticated()) {\n console.log(theme.error('You must be logged in to view submissions.'));\n console.log(theme.dim('Run \"bjs login\" first.'));\n process.exit(1);\n }\n\n const id = requireValidId(idArg, theme);\n\n let response: Response;\n try {\n response = await apiCall(auth, 'GET', `/api/auth/submissions/${id}`);\n } catch (err) {\n console.log(theme.error('Failed to fetch submission; try again later.'));\n console.log(theme.dim((err as Error).message));\n process.exit(1);\n }\n\n if (response.status === 401) {\n console.log(theme.error('Your session is invalid or expired.'));\n console.log(theme.dim('Run \"bjs login\" to refresh.'));\n process.exit(1);\n }\n\n if (response.status === 404) {\n console.log(theme.error('Submission not found.'));\n process.exit(1);\n }\n\n if (response.status >= 500) {\n console.log(theme.error('Failed to fetch submission; try again later.'));\n process.exit(1);\n }\n\n let body: any = null;\n try {\n body = await response.json();\n } catch {\n /* tolerate empty body */\n }\n\n if (!response.ok) {\n const msg = (body && body.error) || `HTTP ${response.status}`;\n console.log(theme.error(`Failed to fetch submission: ${msg}`));\n process.exit(1);\n }\n\n if (opts.json) {\n console.log(JSON.stringify(body, null, 2));\n return;\n }\n\n // Pretty-print each public field.\n const row: SubmissionRow = body;\n const lines: Array<[string, string]> = [\n ['id', String(row.id)],\n ['status', row.status],\n ['target', row.target],\n ['components', (row.componentNames || []).join(', ')],\n ['created', formatDate(row.createdAt)],\n ];\n if (row.updatedAt) lines.push(['updated', formatDate(row.updatedAt)]);\n if (row.cliVersion) lines.push(['cli', row.cliVersion]);\n if (row.reviewerNotes) lines.push(['reviewer notes', row.reviewerNotes]);\n\n for (const [label, value] of lines) {\n console.log(`${theme.dim(label + ':')} ${value}`);\n }\n}\n\nasync function withdrawSubmissionAction(\n idArg: string,\n opts: WithdrawOpts,\n): Promise<void> {\n const auth = new AuthManager();\n const theme = applyTheme();\n\n if (!auth.isAuthenticated()) {\n console.log(theme.error('You must be logged in to view submissions.'));\n console.log(theme.dim('Run \"bjs login\" first.'));\n process.exit(1);\n }\n\n const id = requireValidId(idArg, theme);\n\n if (!opts.yes) {\n const ok = await confirm(`Withdraw submission ${id}? (y/N) `);\n if (!ok) {\n console.log(theme.dim('Aborted.'));\n process.exit(0);\n }\n }\n\n let response: Response;\n try {\n response = await apiCall(auth, 'DELETE', `/api/auth/submissions/${id}`);\n } catch (err) {\n console.log(theme.error('Failed to withdraw submission; try again later.'));\n console.log(theme.dim((err as Error).message));\n process.exit(1);\n }\n\n if (response.status === 401) {\n console.log(theme.error('Your session is invalid or expired.'));\n console.log(theme.dim('Run \"bjs login\" to refresh.'));\n process.exit(1);\n }\n\n if (response.status === 404) {\n console.log(theme.error('Submission not found.'));\n process.exit(1);\n }\n\n if (response.status === 409) {\n console.log(theme.error(\"Already in review or finalized — can't withdraw.\"));\n process.exit(1);\n }\n\n if (response.status >= 500) {\n console.log(theme.error('Failed to withdraw submission; try again later.'));\n process.exit(1);\n }\n\n let body: any = null;\n try {\n body = await response.json();\n } catch {\n /* tolerate empty body */\n }\n\n if (!response.ok) {\n const msg = (body && body.error) || `HTTP ${response.status}`;\n console.log(theme.error(`Failed to withdraw submission: ${msg}`));\n process.exit(1);\n }\n\n if (opts.json) {\n console.log(JSON.stringify(body, null, 2));\n return;\n }\n console.log(theme.success('Withdrawn.'));\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Command wiring\n// ──────────────────────────────────────────────────────────────────────────\n\nexport const submissionsCommand = new Command('submissions')\n .description('List or inspect your marketplace submissions')\n .action(async () => {\n // Default action: behave like `bjs submissions list`.\n await listSubmissionsAction({});\n });\n\nsubmissionsCommand\n .command('list')\n .description('List your submissions')\n .option('--status <status>', 'filter: pending|reviewing|merged|rejected|withdrawn')\n .option('--limit <n>', 'max results (default 20, capped at 100 server-side)', (v) => parseInt(v, 10))\n .option('--json', 'machine-readable output')\n .action(async (opts: ListOpts) => {\n await listSubmissionsAction(opts);\n });\n\nsubmissionsCommand\n .command('show <id>')\n .description('Show detail for one submission')\n .option('--json', 'machine-readable output')\n .action(async (id: string, opts: ShowOpts) => {\n await showSubmissionAction(id, opts);\n });\n\nsubmissionsCommand\n .command('withdraw <id>')\n .description('Withdraw a pending submission')\n .option('-y, --yes', 'skip confirmation prompt')\n .option('--json', 'machine-readable output')\n .action(async (id: string, opts: WithdrawOpts) => {\n await withdrawSubmissionAction(id, opts);\n });\n"],"mappings":"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","names":["Command","chalk","fetch","join","join","fetch","Command","chalk","chalk","Command","Command","Command","Command","ora","existsSync","mkdirSync","fetch","Command","ora","Command","terminalKit","bold","markedCount","terminalKit","chalk","chalk","chalk","fetch","chalk","_","text","padding","EventEmitter","open","maxScroll","ScreenBuffer","terminalKit","EventEmitter","line","chalk","bold","isCopiedLine","open","fs","path","homedir","process","fetch","pipeline","fetch","pipeline","fs","path","fs","path","fs","path","path","fs","targetComponentDir","targetComponentPath","path","fs","componentFiles","open","fetch","reduce","dim","dim","terminalKit","ScreenBuffer","process","Command","path","fetch","open","fs","reduce","dim","homedir","intent","Command","existsSync","readFileSync","join","readFileSync","join","__dirname","fs","path","colors","fs","path","fileURLToPath","cyan","bold","colors","fs","path","confirm","Command","join","existsSync","readFileSync","Command","path","Command","Command","chalk"]}
|