Skip to content

Auto-prompt workspace rename for unnamed workspaces#1151

Merged
Kitenite merged 9 commits into
mainfrom
Kitenite/auto-rename-workspace
Feb 3, 2026
Merged

Auto-prompt workspace rename for unnamed workspaces#1151
Kitenite merged 9 commits into
mainfrom
Kitenite/auto-rename-workspace

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Feb 2, 2026

Description

When a worktree workspace is created without a user-provided name, the app now automatically triggers the rename UI when the workspace becomes active for the first time. This improves the UX by prompting users to give their workspaces meaningful names right after creation.

Type of Change

  • New feature

Implementation Details

Uses a session-level Set<string> to track which workspaces have already been prompted, preventing re-triggers if the user dismisses the rename dialog. The check detects unnamed workspaces by checking !name and only applies to worktree workspaces (not branch workspaces).

Summary by CodeRabbit

  • New Features

    • Workspaces can now be automatically named based on terminal activity; unnamed workspaces are renamed when terminal titles change.
  • Database

    • Added unnamed workspace tracking field to the database schema.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 2, 2026

📝 Walkthrough

Walkthrough

This PR introduces an isUnnamed boolean field to the workspaces table to track auto-generated workspace names. The database schema is updated with a migration, backend procedures manage this flag during creation and updates, and the Terminal component integrates logic to rename unnamed workspaces when terminal titles change.

Changes

Cohort / File(s) Summary
Database Schema & Migrations
packages/local-db/src/schema/schema.ts, packages/local-db/drizzle/0017_add_is_unnamed_to_workspaces.sql, packages/local-db/drizzle/meta/_journal.json, packages/local-db/drizzle/meta/0017_snapshot.json
Added isUnnamed boolean column to workspaces table (default false). Updated Drizzle migration files and journal with new schema version 6. InsertWorkspace and SelectWorkspace types now include the isUnnamed property.
Workspace Creation
apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts
Set isUnnamed to true when creating workspaces from worktree or openWorktree paths without a provided name.
Workspace Queries
apps/desktop/src/lib/trpc/routers/workspaces/procedures/query.ts
Added isUnnamed field (default false) to workspace records in the grouped workspace view (getAllGrouped). Public API now includes isUnnamed: boolean in grouped workspace items.
Workspace Updates
apps/desktop/src/lib/trpc/routers/workspaces/procedures/status.ts, apps/desktop/src/lib/trpc/routers/workspaces/utils/db-helpers.ts
Added optional preserveUnnamedStatus field to update input. When patch.name is provided, sets isUnnamed to false unless preserveUnnamedStatus is true. Updated touchWorkspace helper to accept isUnnamed in additionalFields.
Terminal Auto-Rename Logic
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx, apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/hooks/useTerminalLifecycle.ts
Added workspace query and mutation logic to Terminal component. Implemented renameUnnamedWorkspaceRef callback that renames unnamed workspaces when terminal title changes (strips leading emoji and updates workspace name while preserving unnamed status). Propagated ref through useTerminalLifecycle hook options to trigger rename on title change.

Sequence Diagram

sequenceDiagram
    participant Terminal as Terminal Component
    participant Query as Workspace Query
    participant Lifecycle as Terminal Lifecycle Hook
    participant Mutation as Update Mutation
    participant Cache as Query Cache
    
    Terminal->>Query: useQuery(workspace.isUnnamed)
    Query-->>Terminal: isUnnamed status
    
    Lifecycle->>Lifecycle: onTitleChange(newTitle)
    Lifecycle->>Terminal: renameUnnamedWorkspaceRef.current(title)
    
    alt isUnnamed && title is valid
        Terminal->>Terminal: cleanTitle(stripEmoji)
        Terminal->>Mutation: updateWorkspace({<br/>name: cleanTitle,<br/>preserveUnnamedStatus: true})
        Mutation->>Cache: invalidateQueries
        Cache-->>Terminal: cache updated
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Terminal lifecycle refactor #1089 — Directly extends the useTerminalLifecycle hook by adding renameUnnamedWorkspaceRef parameter and integrating workspace-rename behavior into the same hook/component surface.
  • feature(desktop): manage worktrees better #407 — Touches workspace creation from worktree paths; the main PR adds isUnnamed flag to workspaces created via worktree/openWorktree, which relates to the worktree creation flow.
  • feat(desktop): auto-update tab title from terminal #495 — Modifies terminal title handling and workspace rename flow by adding logic to rename unnamed workspaces via Terminal lifecycle handlers, directly overlapping with the Terminal integration in this PR.

Poem

🐰 A flag is born, isUnnamed so bright,
Workspaces auto-named now get their light,
When terminals chirp with titles brand new,
The rabbit renames, old becomes true! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main feature: auto-prompting workspace rename for unnamed workspaces, which aligns with the primary change across all modified files.
Description check ✅ Passed The description covers the key aspects: feature purpose, implementation approach, and scope limitations. However, it lacks complete template sections like Related Issues and Testing details.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch Kitenite/auto-rename-workspace

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx`:
- Around line 186-192: The code currently calls autoRenamedWorkspaces.add(id)
before the delayed rename, which marks the workspace prompted even if the
timeout is cancelled; move the autoRenamedWorkspaces.add(id) call inside the
timeout callback immediately after rename.startRename() so the id is recorded
only when the rename actually runs (update the block around the setTimeout
callback that calls rename.startRename(), and keep the existing
clearTimeout(timer) cleanup as-is).
🧹 Nitpick comments (1)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx (1)

189-191: Extract the rename delay into a named constant.

The 100ms delay is a magic number; please lift it to a module-level constant for clarity and future tuning.

♻️ Proposed refactor
+const AUTO_RENAME_DELAY_MS = 100;
-			const timer = setTimeout(() => {
+			const timer = setTimeout(() => {
 				rename.startRename();
-			}, 100);
+			}, AUTO_RENAME_DELAY_MS);

As per coding guidelines: Avoid magic numbers by extracting them to named constants at module top.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx`:
- Around line 171-194: The effect in WorkspaceListItem.tsx uses a magic number
100 for the auto-rename timeout and depends on rename.startRename which is
recreated each render; extract the delay into constants.ts as AUTO_RENAME_DELAY
and import it into WorkspaceListItem (replace the inline 100 with
AUTO_RENAME_DELAY), and modify the useWorkspaceRename hook to wrap startRename
in useCallback (so startRename is stable and won't cause the effect to re-run);
reference the symbols AUTO_RENAME_DELAY, WorkspaceListItem (the effect using
setTimeout), and useWorkspaceRename.startRename when making these changes.

Comment on lines +171 to +194
// Auto-trigger rename for unnamed workspaces (name is null/empty) when active
// Only for worktree workspaces (not branch workspaces)
const isUnnamed = !name;
useEffect(() => {
if (
isUnnamed &&
isActive &&
!isBranchWorkspace &&
!isCollapsed &&
!rename.isRenaming
) {
const timer = setTimeout(() => {
rename.startRename();
}, 100);
return () => clearTimeout(timer);
}
}, [
isUnnamed,
isActive,
isBranchWorkspace,
isCollapsed,
rename.isRenaming,
rename.startRename,
]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find and check the constants file for this component
find . -path "*WorkspaceSidebar*" -name "constants.ts" -type f

Repository: superset-sh/superset

Length of output: 245


🏁 Script executed:

# Find the useWorkspaceRename hook
find . -name "*useWorkspaceRename*" -type f

Repository: superset-sh/superset

Length of output: 151


🏁 Script executed:

# Check if AUTO_RENAME_DELAY is already defined anywhere in the workspace sidebar
rg "AUTO_RENAME_DELAY" --glob "**/WorkspaceSidebar/**"

Repository: superset-sh/superset

Length of output: 46


🏁 Script executed:

# Check the WorkspaceListItem constants file
cat -n ./apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/constants.ts

Repository: superset-sh/superset

Length of output: 615


🏁 Script executed:

# Check the parent WorkspaceSidebar constants file
cat -n ./apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/constants.ts

Repository: superset-sh/superset

Length of output: 400


🏁 Script executed:

# Check the useWorkspaceRename hook implementation
cat -n ./apps/desktop/src/renderer/screens/main/hooks/useWorkspaceRename/useWorkspaceRename.ts

Repository: superset-sh/superset

Length of output: 2042


🏁 Script executed:

# Verify the WorkspaceListItem component imports and uses these
head -100 ./apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx | grep -E "import|useWorkspaceRename"

Repository: superset-sh/superset

Length of output: 1362


🏁 Script executed:

# Check if useCallback is imported in useWorkspaceRename or if it should be
grep -n "useCallback\|import.*React" ./apps/desktop/src/renderer/screens/main/hooks/useWorkspaceRename/useWorkspaceRename.ts

Repository: superset-sh/superset

Length of output: 46


🏁 Script executed:

# Verify the full imports at the top of WorkspaceListItem to see what's imported from constants
head -80 ./apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx | grep -A 10 "from \"./constants\""

Repository: superset-sh/superset

Length of output: 351


🏁 Script executed:

# Double-check the useWorkspaceRename implementation and verify startRename is indeed not memoized
grep -E "const startRename|useCallback" ./apps/desktop/src/renderer/screens/main/hooks/useWorkspaceRename/useWorkspaceRename.ts

Repository: superset-sh/superset

Length of output: 92


🏁 Script executed:

# Get the full import statement from constants to see current imports
sed -n '24,35p' ./apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx

Repository: superset-sh/superset

Length of output: 318


🏁 Script executed:

# Search for the import statement that includes constants from "./constants"
rg "from \"./constants\"" -A 8 ./apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx

Repository: superset-sh/superset

Length of output: 313


🏁 Script executed:

# Get the complete import block from constants
rg -B 8 "from \"./constants\"" ./apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx | head -20

Repository: superset-sh/superset

Length of output: 275


Extract the timeout delay to a named constant.

The 100 ms delay is a magic number. For consistency with other constants in this component (e.g., HOVER_CARD_OPEN_DELAY), extract it to ./constants.ts.

Add to ./constants.ts:

export const AUTO_RENAME_DELAY = 100;

Then update the import in WorkspaceListItem.tsx:

import {
	GITHUB_STATUS_STALE_TIME,
	HOVER_CARD_CLOSE_DELAY,
	HOVER_CARD_OPEN_DELAY,
	MAX_KEYBOARD_SHORTCUT_INDEX,
	AUTO_RENAME_DELAY,
} from "./constants";

And replace the magic number:

const timer = setTimeout(() => {
	rename.startRename();
}, AUTO_RENAME_DELAY);

Wrap startRename in useCallback in the hook.

The startRename function in useWorkspaceRename is recreated on every render. Since it's included in the effect dependency array in WorkspaceListItem, the effect will re-run unnecessarily. Add useCallback:

import { useCallback, useEffect, useRef, useState } from "react";

export function useWorkspaceRename(workspaceId: string, workspaceName: string) {
	// ...existing state...
	
	const startRename = useCallback(() => {
		setIsRenaming(true);
	}, []);

	// ...rest of the function...
}
🤖 Prompt for AI Agents
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx`
around lines 171 - 194, The effect in WorkspaceListItem.tsx uses a magic number
100 for the auto-rename timeout and depends on rename.startRename which is
recreated each render; extract the delay into constants.ts as AUTO_RENAME_DELAY
and import it into WorkspaceListItem (replace the inline 100 with
AUTO_RENAME_DELAY), and modify the useWorkspaceRename hook to wrap startRename
in useCallback (so startRename is stable and won't cause the effect to re-run);
reference the symbols AUTO_RENAME_DELAY, WorkspaceListItem (the effect using
setTimeout), and useWorkspaceRename.startRename when making these changes.

@Kitenite Kitenite force-pushed the Kitenite/auto-rename-workspace branch from 07a4eef to dc89bb5 Compare February 3, 2026 07:00
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 3, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch
  • ✅ Electric Fly.io app

Thank you for your contribution! 🎉

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts (1)

381-388: ⚠️ Potential issue | 🟡 Minor

Normalize provided name before deriving isUnnamed.
If input.name is whitespace, name becomes blank while isUnnamed becomes false, preventing the rename prompt. Trim once and use the normalized value for both name and isUnnamed.

✅ Suggested fix (apply in both create & openWorktree paths)
-				const workspace = localDb
+				const trimmedName = input.name?.trim();
+				const workspace = localDb
 					.insert(workspaces)
 					.values({
 						projectId: input.projectId,
 						worktreeId: worktree.id,
 						type: "worktree",
 						branch,
-						name: input.name ?? branch,
-						isUnnamed: !input.name,
+						name: trimmedName || branch,
+						isUnnamed: !trimmedName,
 						tabOrder: maxTabOrder + 1,
 					})
-				const workspace = localDb
+				const trimmedName = input.name?.trim();
+				const workspace = localDb
 					.insert(workspaces)
 					.values({
 						projectId: worktree.projectId,
 						worktreeId: worktree.id,
 						type: "worktree",
 						branch: worktree.branch,
-						name: input.name ?? worktree.branch,
-						isUnnamed: !input.name,
+						name: trimmedName || worktree.branch,
+						isUnnamed: !trimmedName,
 						tabOrder: maxTabOrder + 1,
 					})

Also applies to: 590-596

🤖 Fix all issues with AI agents
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx`:
- Around line 109-129: The effect in WorkspaceListItem is re-triggering
startRename() after a cancel because there is no session-level guard; add a
session-scoped Set<string> (e.g., promptedUnnamedWorkspaces) in a parent/store
and pass it (or access it) to this component, then modify the useEffect in
WorkspaceListItem to check that the workspace id is not in
promptedUnnamedWorkspaces before scheduling rename.startRename(), and add the
workspace id to promptedUnnamedWorkspaces when the rename prompt is shown or
when rename.cancelRename() is invoked so repeated prompts are suppressed; update
any caller of rename.cancelRename() (or the rename handler) to record the id in
the session Set.

In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx`:
- Around line 38-64: The rename mutation swallows errors and the query uses a
magic number; modify electronTrpc.workspaces.update.useMutation
(updateWorkspace) to add an onError handler that logs the error with a prefixed
message like "[workspaces/update] Failed to rename workspace: <error>" and any
relevant context (workspaceId, attempted name) and keep the existing onSuccess
logic; replace the hardcoded 30_000 in electronTrpc.workspaces.get.useQuery with
a named constant (e.g., WORKSPACE_QUERY_STALE_TIME) declared at the top of the
module and reference that constant when creating the query; ensure the logging
follows the prefixed console pattern and update any references to isUnnamedRef
and renameUnnamedWorkspaceRef remain unchanged.

Comment on lines +109 to +129
useEffect(() => {
if (
isUnnamed &&
isActive &&
!isBranchWorkspace &&
!isCollapsed &&
!rename.isRenaming
) {
const timer = setTimeout(() => {
rename.startRename();
}, 100);
return () => clearTimeout(timer);
}
}, [
isUnnamed,
isActive,
isBranchWorkspace,
isCollapsed,
rename.isRenaming,
rename.startRename,
]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if session-level tracking exists
echo "=== Searching for rename tracking mechanisms ==="
rg -n "autoRenamed|promptedWorkspace|renamedWorkspace|trackedWorkspace" --type=ts --type=tsx -g '!node_modules'

echo ""
echo "=== Searching for Set-based tracking in WorkspaceSidebar ==="
rg -n "new Set|Set<" apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/ --type=ts --type=tsx

echo ""
echo "=== Checking useWorkspaceRename hook implementation ==="
fd -t f "useWorkspaceRename" apps/desktop --exec cat {}

Repository: superset-sh/superset

Length of output: 1835


🏁 Script executed:

#!/bin/bash
# Get the full WorkspaceListItem.tsx file
wc -l apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx
echo ""
echo "=== Full file content ==="
cat -n apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx

Repository: superset-sh/superset

Length of output: 25157


Implement session-level tracking to prevent repeated rename prompts.

The session-level tracking mechanism mentioned in the PR description is not implemented. When a user dismisses the rename dialog via cancelRename() (ESC key or blur), isRenaming becomes false, which re-triggers the effect condition. Since the effect depends on rename.isRenaming, it will schedule another startRename() after 100ms, creating an unwanted loop of rename prompts until the user actually submits a rename.

Add a session-level Set<string> (e.g., in a parent component or store) to track which unnamed workspaces have already been prompted, and check this set before calling startRename() in the effect.

🤖 Prompt for AI Agents
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceListItem.tsx`
around lines 109 - 129, The effect in WorkspaceListItem is re-triggering
startRename() after a cancel because there is no session-level guard; add a
session-scoped Set<string> (e.g., promptedUnnamedWorkspaces) in a parent/store
and pass it (or access it) to this component, then modify the useEffect in
WorkspaceListItem to check that the workspace id is not in
promptedUnnamedWorkspaces before scheduling rename.startRename(), and add the
workspace id to promptedUnnamedWorkspaces when the rename prompt is shown or
when rename.cancelRename() is invoked so repeated prompts are suppressed; update
any caller of rename.cancelRename() (or the rename handler) to record the id in
the session Set.

Comment on lines +38 to +64
// Query workspace to check if it's unnamed
const { data: workspaceData } = electronTrpc.workspaces.get.useQuery(
{ id: workspaceId },
{ staleTime: 30_000 },
);
const isUnnamedRef = useRef(false);
isUnnamedRef.current = workspaceData?.isUnnamed ?? false;

// Mutation to rename workspace
const utils = electronTrpc.useUtils();
const updateWorkspace = electronTrpc.workspaces.update.useMutation({
onSuccess: () => {
utils.workspaces.getAllGrouped.invalidate();
utils.workspaces.get.invalidate({ id: workspaceId });
},
});

// Callback ref to rename unnamed workspace when terminal title changes
const renameUnnamedWorkspaceRef = useRef<(title: string) => void>(() => {});
renameUnnamedWorkspaceRef.current = (title: string) => {
if (isUnnamedRef.current && title.trim()) {
updateWorkspace.mutate({
id: workspaceId,
patch: { name: title.trim() },
});
}
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Handle rename mutation errors and avoid the staleTime magic number.
The rename mutation has no error handling, so failures are silent. Also, 30_000 should be a named constant.

🔧 Suggested fix
+const WORKSPACE_QUERY_STALE_TIME_MS = 30_000;
+
 	const { data: workspaceData } = electronTrpc.workspaces.get.useQuery(
 		{ id: workspaceId },
-		{ staleTime: 30_000 },
+		{ staleTime: WORKSPACE_QUERY_STALE_TIME_MS },
 	);
@@
 	const updateWorkspace = electronTrpc.workspaces.update.useMutation({
 		onSuccess: () => {
 			utils.workspaces.getAllGrouped.invalidate();
 			utils.workspaces.get.invalidate({ id: workspaceId });
 		},
+		onError: (error) => {
+			console.error(
+				"[workspace/rename] Failed to rename workspace",
+				error,
+			);
+		},
 	});

As per coding guidelines: Never swallow errors silently; at minimum log them with context. Use prefixed console logging with pattern [domain/operation] message for all logging. Avoid magic numbers by extracting them to named constants at module top.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Query workspace to check if it's unnamed
const { data: workspaceData } = electronTrpc.workspaces.get.useQuery(
{ id: workspaceId },
{ staleTime: 30_000 },
);
const isUnnamedRef = useRef(false);
isUnnamedRef.current = workspaceData?.isUnnamed ?? false;
// Mutation to rename workspace
const utils = electronTrpc.useUtils();
const updateWorkspace = electronTrpc.workspaces.update.useMutation({
onSuccess: () => {
utils.workspaces.getAllGrouped.invalidate();
utils.workspaces.get.invalidate({ id: workspaceId });
},
});
// Callback ref to rename unnamed workspace when terminal title changes
const renameUnnamedWorkspaceRef = useRef<(title: string) => void>(() => {});
renameUnnamedWorkspaceRef.current = (title: string) => {
if (isUnnamedRef.current && title.trim()) {
updateWorkspace.mutate({
id: workspaceId,
patch: { name: title.trim() },
});
}
};
const WORKSPACE_QUERY_STALE_TIME_MS = 30_000;
// Query workspace to check if it's unnamed
const { data: workspaceData } = electronTrpc.workspaces.get.useQuery(
{ id: workspaceId },
{ staleTime: WORKSPACE_QUERY_STALE_TIME_MS },
);
const isUnnamedRef = useRef(false);
isUnnamedRef.current = workspaceData?.isUnnamed ?? false;
// Mutation to rename workspace
const utils = electronTrpc.useUtils();
const updateWorkspace = electronTrpc.workspaces.update.useMutation({
onSuccess: () => {
utils.workspaces.getAllGrouped.invalidate();
utils.workspaces.get.invalidate({ id: workspaceId });
},
onError: (error) => {
console.error(
"[workspace/rename] Failed to rename workspace",
error,
);
},
});
// Callback ref to rename unnamed workspace when terminal title changes
const renameUnnamedWorkspaceRef = useRef<(title: string) => void>(() => {});
renameUnnamedWorkspaceRef.current = (title: string) => {
if (isUnnamedRef.current && title.trim()) {
updateWorkspace.mutate({
id: workspaceId,
patch: { name: title.trim() },
});
}
};
🤖 Prompt for AI Agents
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx`
around lines 38 - 64, The rename mutation swallows errors and the query uses a
magic number; modify electronTrpc.workspaces.update.useMutation
(updateWorkspace) to add an onError handler that logs the error with a prefixed
message like "[workspaces/update] Failed to rename workspace: <error>" and any
relevant context (workspaceId, attempted name) and keep the existing onSuccess
logic; replace the hardcoded 30_000 in electronTrpc.workspaces.get.useQuery with
a named constant (e.g., WORKSPACE_QUERY_STALE_TIME) declared at the top of the
module and reference that constant when creating the query; ensure the logging
follows the prefixed console pattern and update any references to isUnnamedRef
and renameUnnamedWorkspaceRef remain unchanged.

- Add preserveUnnamedStatus flag to workspace update mutation
- Auto-rename from terminal title preserves isUnnamed: true
- Only manual rename sets isUnnamed: false
- Revert sidebar UI changes (no auto-prompt for rename)
- Add migration for is_unnamed column
Filter out leading emoji/symbol characters (e.g., "✳ Casual Greeting"
becomes "Casual Greeting") when auto-renaming workspaces from terminal
title.
The isUnnamed field was not included in the touchWorkspace
additionalFields type, preventing it from being updated.
Migration 0016 was already taken by telemetry_enabled in main.
@Kitenite Kitenite merged commit f2bed52 into main Feb 3, 2026
13 checks passed
@Kitenite Kitenite deleted the Kitenite/auto-rename-workspace branch February 3, 2026 08:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant