Merge main into massive-terminal-upgrade

Resolves merge conflicts:
- apps/server/src/routes/terminal/common.ts: Keep randomBytes import, use @automaker/utils for createLogger
- apps/ui/eslint.config.mjs: Use main's explicit globals list with XMLHttpRequest and MediaQueryListEvent additions
- apps/ui/src/components/views/terminal-view.tsx: Keep our terminal improvements (killAllSessions, beforeunload, better error handling)
- apps/ui/src/config/terminal-themes.ts: Keep our search highlight colors for all themes
- apps/ui/src/store/app-store.ts: Keep our terminal settings persistence improvements (merge function)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
SuperComboGamer
2025-12-21 20:27:44 -05:00
393 changed files with 32473 additions and 17974 deletions

View File

@@ -2,12 +2,12 @@
* Common utilities and state for terminal routes
*/
import { randomBytes } from "crypto";
import { createLogger } from "../../lib/logger.js";
import type { Request, Response, NextFunction } from "express";
import { getTerminalService } from "../../services/terminal-service.js";
import { randomBytes } from 'crypto';
import { createLogger } from '@automaker/utils';
import type { Request, Response, NextFunction } from 'express';
import { getTerminalService } from '../../services/terminal-service.js';
const logger = createLogger("Terminal");
const logger = createLogger('Terminal');
// Read env variables lazily to ensure dotenv has loaded them
function getTerminalPassword(): string | undefined {
@@ -15,21 +15,17 @@ function getTerminalPassword(): string | undefined {
}
function getTerminalEnabledConfig(): boolean {
return process.env.TERMINAL_ENABLED !== "false"; // Enabled by default
return process.env.TERMINAL_ENABLED !== 'false'; // Enabled by default
}
// In-memory session tokens (would use Redis in production) - private
const validTokens: Map<string, { createdAt: Date; expiresAt: Date }> =
new Map();
const validTokens: Map<string, { createdAt: Date; expiresAt: Date }> = new Map();
const TOKEN_EXPIRY_MS = 24 * 60 * 60 * 1000; // 24 hours
/**
* Add a token to the valid tokens map
*/
export function addToken(
token: string,
data: { createdAt: Date; expiresAt: Date }
): void {
export function addToken(token: string, data: { createdAt: Date; expiresAt: Date }): void {
validTokens.set(token, data);
}
@@ -43,9 +39,7 @@ export function deleteToken(token: string): void {
/**
* Get token data for a given token
*/
export function getTokenData(
token: string
): { createdAt: Date; expiresAt: Date } | undefined {
export function getTokenData(token: string): { createdAt: Date; expiresAt: Date } | undefined {
return validTokens.get(token);
}
@@ -53,7 +47,7 @@ export function getTokenData(
* Generate a cryptographically secure random token
*/
export function generateToken(): string {
return `term-${randomBytes(32).toString("base64url")}`;
return `term-${randomBytes(32).toString('base64url')}`;
}
/**
@@ -106,16 +100,12 @@ export function isTerminalEnabled(): boolean {
* Terminal authentication middleware
* Checks for valid session token if password is configured
*/
export function terminalAuthMiddleware(
req: Request,
res: Response,
next: NextFunction
): void {
export function terminalAuthMiddleware(req: Request, res: Response, next: NextFunction): void {
// Check if terminal is enabled
if (!getTerminalEnabledConfig()) {
res.status(403).json({
success: false,
error: "Terminal access is disabled",
error: 'Terminal access is disabled',
});
return;
}
@@ -127,13 +117,12 @@ export function terminalAuthMiddleware(
}
// Check for session token
const token =
(req.headers["x-terminal-token"] as string) || (req.query.token as string);
const token = (req.headers['x-terminal-token'] as string) || (req.query.token as string);
if (!validateTerminalToken(token)) {
res.status(401).json({
success: false,
error: "Terminal authentication required",
error: 'Terminal authentication required',
passwordRequired: true,
});
return;
@@ -154,10 +143,7 @@ export function getTokenExpiryMs(): number {
return TOKEN_EXPIRY_MS;
}
import {
getErrorMessage as getErrorMessageShared,
createLogError,
} from "../common.js";
import { getErrorMessage as getErrorMessageShared, createLogError } from '../common.js';
// Re-export shared utilities
export { getErrorMessageShared as getErrorMessage };

View File

@@ -3,12 +3,12 @@
* POST /sessions endpoint - Create a new terminal session
*/
import type { Request, Response } from "express";
import { getTerminalService } from "../../../services/terminal-service.js";
import { getErrorMessage, logError } from "../common.js";
import { createLogger } from "../../../lib/logger.js";
import type { Request, Response } from 'express';
import { getTerminalService } from '../../../services/terminal-service.js';
import { getErrorMessage, logError } from '../common.js';
import { createLogger } from '@automaker/utils';
const logger = createLogger("Terminal");
const logger = createLogger('Terminal');
export function createSessionsListHandler() {
return (_req: Request, res: Response): void => {
@@ -41,7 +41,7 @@ export function createSessionsCreateHandler() {
logger.warn(`Session limit reached: ${currentSessions}/${maxSessions}`);
res.status(429).json({
success: false,
error: "Maximum terminal sessions reached",
error: 'Maximum terminal sessions reached',
details: `Server limit is ${maxSessions} concurrent sessions. Please close unused terminals.`,
currentSessions,
maxSessions,
@@ -59,10 +59,10 @@ export function createSessionsCreateHandler() {
},
});
} catch (error) {
logError(error, "Create terminal session failed");
logError(error, 'Create terminal session failed');
res.status(500).json({
success: false,
error: "Failed to create terminal session",
error: 'Failed to create terminal session',
details: getErrorMessage(error),
});
}