From 925bc129c9fbca9f1d72f8201f1175e581bdb70b Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Tue, 17 Jun 2025 23:45:55 +0200 Subject: [PATCH] Add optional session name support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add optional session name field to create form - Update Session interface to include name property - Backend now accepts and stores custom session names - Session cards and views display name when available, fallback to command - Session names are passed to tty-fwd for better identification 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- web/src/client/components/session-card.ts | 5 +++- .../client/components/session-create-form.ts | 27 ++++++++++++++++++- web/src/client/components/session-list.ts | 1 + web/src/client/components/session-view.ts | 4 +-- web/src/client/components/terminal.ts | 14 +++++----- web/src/server.ts | 5 ++-- 6 files changed, 44 insertions(+), 12 deletions(-) diff --git a/web/src/client/components/session-card.ts b/web/src/client/components/session-card.ts index 7a471ea2..3b82baea 100644 --- a/web/src/client/components/session-card.ts +++ b/web/src/client/components/session-card.ts @@ -6,6 +6,7 @@ export interface Session { id: string; command: string; workingDir: string; + name?: string; status: 'running' | 'exited'; exitCode?: number; startedAt: string; @@ -194,7 +195,9 @@ export class SessionCard extends LitElement {
-
${this.session.command}
+
+ ${this.session.name || this.session.command} +
${this.session.status === 'running' ? html` diff --git a/web/src/client/components/session-create-form.ts b/web/src/client/components/session-create-form.ts index 2f7a2e1f..96e25cca 100644 --- a/web/src/client/components/session-create-form.ts +++ b/web/src/client/components/session-create-form.ts @@ -5,6 +5,7 @@ import './file-browser.js'; export interface SessionCreateData { command: string[]; workingDir: string; + name?: string; } @customElement('session-create-form') @@ -16,6 +17,7 @@ export class SessionCreateForm extends LitElement { @property({ type: String }) workingDir = '~/'; @property({ type: String }) command = 'zsh'; + @property({ type: String }) sessionName = ''; @property({ type: Boolean }) disabled = false; @property({ type: Boolean }) visible = false; @@ -95,6 +97,11 @@ export class SessionCreateForm extends LitElement { this.command = input.value; } + private handleSessionNameChange(e: Event) { + const input = e.target as HTMLInputElement; + this.sessionName = input.value; + } + private handleBrowse() { this.showFileBrowser = true; } @@ -125,6 +132,11 @@ export class SessionCreateForm extends LitElement { workingDir: this.workingDir.trim(), }; + // Add session name if provided + if (this.sessionName.trim()) { + sessionData.name = this.sessionName.trim(); + } + try { const response = await fetch('/api/sessions', { method: 'POST', @@ -135,10 +147,11 @@ export class SessionCreateForm extends LitElement { if (response.ok) { const result = await response.json(); - // Save to localStorage before clearing the command + // Save to localStorage before clearing the fields this.saveToLocalStorage(); this.command = ''; // Clear command on success + this.sessionName = ''; // Clear session name on success this.dispatchEvent( new CustomEvent('session-created', { detail: result, @@ -225,6 +238,18 @@ export class SessionCreateForm extends LitElement {
+
+
Session Name (optional):
+ +
+
Working Directory:
diff --git a/web/src/client/components/session-list.ts b/web/src/client/components/session-list.ts index b80f8e25..3fcfc469 100644 --- a/web/src/client/components/session-list.ts +++ b/web/src/client/components/session-list.ts @@ -8,6 +8,7 @@ export interface Session { id: string; command: string; workingDir: string; + name?: string; status: 'running' | 'exited'; exitCode?: number; startedAt: string; diff --git a/web/src/client/components/session-view.ts b/web/src/client/components/session-view.ts index 4ff79584..2079a757 100644 --- a/web/src/client/components/session-view.ts +++ b/web/src/client/components/session-view.ts @@ -709,9 +709,9 @@ export class SessionView extends LitElement {
- ${this.session.command} + ${this.session.name || this.session.command}
{ // Only handle touch pointers that we have captured - if (e.pointerType !== 'touch' || !this.container!.hasPointerCapture(e.pointerId)) return; + if (e.pointerType !== 'touch' || !this.container?.hasPointerCapture(e.pointerId)) return; const currentY = e.clientY; const deltaY = lastY - currentY; // Change since last move, not since start @@ -323,7 +325,7 @@ export class Terminal extends LitElement { this.isTouchActive = false; // Release pointer capture - this.container!.releasePointerCapture(e.pointerId); + this.container?.releasePointerCapture(e.pointerId); // Add momentum scrolling if needed (only after touch scrolling) if (isScrolling && Math.abs(velocity) > 0.5) { @@ -338,7 +340,7 @@ export class Terminal extends LitElement { this.isTouchActive = false; // Release pointer capture - this.container!.releasePointerCapture(e.pointerId); + this.container?.releasePointerCapture(e.pointerId); }; // Attach pointer events to the container (touch only) diff --git a/web/src/server.ts b/web/src/server.ts index b9779655..dc0d162c 100644 --- a/web/src/server.ts +++ b/web/src/server.ts @@ -165,6 +165,7 @@ app.get('/api/sessions', async (req, res) => { id: sessionId, command: sessionInfo.cmdline.join(' '), workingDir: sessionInfo.cwd, + name: sessionInfo.name, status: sessionInfo.status, exitCode: sessionInfo.exit_code, startedAt: sessionInfo.started_at, @@ -188,13 +189,13 @@ app.get('/api/sessions', async (req, res) => { // Create new session app.post('/api/sessions', async (req, res) => { try { - const { command, workingDir } = req.body; + const { command, workingDir, name } = req.body; if (!command || !Array.isArray(command) || command.length === 0) { return res.status(400).json({ error: 'Command array is required and cannot be empty' }); } - const sessionName = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + const sessionName = name || `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const cwd = resolvePath(workingDir, process.cwd()); const args = [