diff --git a/web/src/server/fwd.ts b/web/src/server/fwd.ts index c8e36688..6194acfc 100755 --- a/web/src/server/fwd.ts +++ b/web/src/server/fwd.ts @@ -17,6 +17,7 @@ import chalk from 'chalk'; import { PtyManager } from './pty/index.js'; import { VERSION, BUILD_DATE, GIT_COMMIT } from './version.js'; import { createLogger, closeLogger } from './utils/logger.js'; +import { generateSessionName } from './utils/session-naming.js'; const logger = createLogger('fwd'); @@ -79,8 +80,8 @@ export async function startVibeTunnelForward(args: string[]) { const ptyManager = new PtyManager(controlPath); try { - // Create the session - const sessionName = `fwd_${command[0]}_${Date.now()}`; + // Create a human-readable session name + const sessionName = generateSessionName(command, cwd); // Pre-generate session ID if not provided const finalSessionId = sessionId || `fwd_${Date.now()}`; diff --git a/web/src/server/routes/sessions.ts b/web/src/server/routes/sessions.ts index 04fddf87..6c0de36a 100644 --- a/web/src/server/routes/sessions.ts +++ b/web/src/server/routes/sessions.ts @@ -7,6 +7,7 @@ import { RemoteRegistry } from '../services/remote-registry.js'; import { ActivityMonitor } from '../services/activity-monitor.js'; import { cellsToText } from '../../shared/terminal-text-formatter.js'; import { createLogger } from '../utils/logger.js'; +import { generateSessionName } from '../utils/session-naming.js'; import chalk from 'chalk'; import * as fs from 'fs'; import * as path from 'path'; @@ -186,7 +187,8 @@ export function createSessionRoutes(config: SessionRoutesConfig): Router { try { // Generate session ID const sessionId = generateSessionId(); - const sessionName = name || `session_${Date.now()}`; + const sessionName = + name || generateSessionName(command, resolvePath(workingDir, process.cwd())); // Request Mac app to spawn terminal logger.log( @@ -227,9 +229,8 @@ export function createSessionRoutes(config: SessionRoutesConfig): Router { } // Create local session - const sessionName = - name || `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const cwd = resolvePath(workingDir, process.cwd()); + const sessionName = name || generateSessionName(command, cwd); logger.log(chalk.blue(`creating session: ${command.join(' ')} in ${cwd}`)); diff --git a/web/src/server/utils/session-naming.ts b/web/src/server/utils/session-naming.ts new file mode 100644 index 00000000..58cefa87 --- /dev/null +++ b/web/src/server/utils/session-naming.ts @@ -0,0 +1,49 @@ +import * as path from 'path'; +import * as os from 'os'; + +/** + * Abbreviate a file path to make it more readable + * Examples: + * /Users/john/Projects/myproject -> ~/Projects/myproject + * /Users/john/Development/vibetunnel/web -> ~/Dev/vibetunnel/web + * /very/long/path/to/some/directory -> …/some/directory + */ +export function abbreviatePath(fullPath: string): string { + if (!fullPath) return ''; + + const homedir = os.homedir(); + let abbreviated = fullPath; + + // Replace home directory with ~ + if (fullPath.startsWith(homedir)) { + abbreviated = '~' + fullPath.slice(homedir.length); + } + + // Common abbreviations + abbreviated = abbreviated + .replace('/Development/', '/Dev/') + .replace('/Documents/', '/Docs/') + .replace('/Applications/', '/Apps/'); + + // If still long, show only last 2 path components + const parts = abbreviated.split('/').filter((p) => p); + if (parts.length > 3) { + return '…/' + parts.slice(-2).join('/'); + } + + return abbreviated; +} + +/** + * Generate a human-readable session name + * Format: commandName (abbreviatedPath) + * Examples: + * claude (~/Dev/vibetunnel/web) + * bash (~/Projects/myapp) + * python3 (~) + */ +export function generateSessionName(command: string[], workingDir: string): string { + const commandName = path.basename(command[0]); + const abbrevCwd = abbreviatePath(workingDir); + return abbrevCwd ? `${commandName} (${abbrevCwd})` : commandName; +}