Skip to content

fix(desktop): auto-name workspaces after setup completes#2107

Merged
Kitenite merged 9 commits into
superset-sh:mainfrom
Kitenite:kitenite/serious-saturn
Mar 6, 2026
Merged

fix(desktop): auto-name workspaces after setup completes#2107
Kitenite merged 9 commits into
superset-sh:mainfrom
Kitenite:kitenite/serious-saturn

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Mar 6, 2026

Summary

  • move workspace auto-naming into the server-side workspace init flow so the rename happens after setup completes
  • make auto-naming use the same auth sources as chat, with Anthropic first and OpenAI fallback, and surface a non-fatal toast when naming fails
  • refactor the rename guard into a small pure helper and add focused tests for skip conditions

Testing

  • bun run --cwd apps/desktop typecheck
  • bun test apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-auto-rename.test.ts

Summary by cubic

Auto-names workspaces after setup completes with Anthropic-first and OpenAI fallback, using shared title generation and fixed Anthropic auth (API key or OAuth). Shows a one-time warning when auto-naming is skipped or fails.

  • Bug Fixes

    • Runs auto-naming after create (best‑effort) and again in workspace-init when the worktree is ready; renames only if still unnamed and equal to the branch, and skips on deletion, name already set/changed, empty prompt, missing credentials, generation failure, or missing workspace.
    • Accepts an optional naming prompt on create; passes it into init and surfaces a single warning per workspace via the create response and init progress toasts.
    • Fixes Anthropic auth by using provider options that support API key or OAuth; Anthropic is preferred with OpenAI as fallback.
  • Refactors

    • Centralizes title generation in @superset/chat and reuses it in desktop and chat-mastra; removes the generateName TRPC endpoint and client-side renaming from NewWorkspaceModal.
    • Adds a pure rename-decision helper with focused tests and reduces debug noise.

Written for commit fa39f69. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Optional AI naming prompt when creating a workspace triggers an asynchronous multi-provider auto-name attempt.
    • Workspace creation progress can include an auto-name warning; the UI shows a one-time warning toast per workspace if auto-naming is skipped or fails.
  • Tests

    • Added tests covering auto-rename decision logic and edge cases for when a generated name should or should not be applied.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 6, 2026

Caution

Review failed

Pull request was closed or merged during review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an optional AI naming prompt to workspace creation, propagates it through initialization, tries an asynchronous provider-driven auto-rename (with explicit skip reasons and warnings), surfaces warnings in init progress, and shows a one-time UI toast when auto-rename is skipped.

Changes

Cohort / File(s) Summary
Create procedure
apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts
Add optional prompt to create input, pass namingPrompt into init flows, attempt async auto-rename after creating/reusing worktree, and return autoRenameWarning when applicable.
AI naming engine
apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts
Add attemptWorkspaceAutoRenameFromPrompt and WorkspaceAutoRenameResult; implement provider-driven generateWorkspaceNameFromPrompt, credentials-aware model building, DB checks, logging, and detailed skip/warning handling.
Auto-rename decision & tests
apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-auto-rename.ts, .../workspace-auto-rename.test.ts
New decision types and functions (getWorkspaceAutoRenameDecision, resolveWorkspaceAutoRename) with explicit skip reasons; tests cover rename and skip scenarios.
Workspace init integration
apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts, apps/desktop/src/main/lib/workspace-init-manager.ts
Thread namingPrompt into WorkspaceInitParams/initializeWorkspaceWorktree; add completeReadyState to attempt auto-rename and capture a warning; extend updateProgress to accept warning.
Progress type
apps/desktop/src/shared/types/workspace-init.ts
Add optional warning?: string to WorkspaceInitProgress.
Renderer: modal & hooks
apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx, apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts
NewWorkspaceModal forwards prompt to create mutation (remove separate generate/update flow); on create success show one-time warning toast if autoRenameWarning present.
Renderer: layout toast
apps/desktop/src/renderer/routes/_authenticated/layout.tsx
Listen for init progress warnings and show a one-time per-workspace toast when a warning is emitted.
Chat & title infra
packages/chat*/src/host/..., packages/chat-mastra/*
Add generateTitleFromMessage and related re-exports; adapt runtime call sites to use generateTitleFromMessage; add provider option helpers and a new dependency wiring.
Misc formatting/deps
packages/chat-mastra/package.json, packages/chat/package.json, .../ChatMastraPane.tsx
Add package deps and small formatting change; no functional impact beyond dependency exports.

Sequence Diagram

sequenceDiagram
    participant User as NewWorkspaceModal (User)
    participant Server as TRPC Server (create.ts)
    participant WInit as Workspace Init (workspace-init.ts)
    participant AI as AI Naming (ai-name.ts)
    participant DB as Workspace DB
    participant UI as Layout/Toast (layout.tsx)

    User->>Server: createWorkspace(projectId, name, prompt?)
    Server->>WInit: initializeWorkspaceWorktree(params + namingPrompt)
    WInit->>WInit: create or reuse worktree/workspace
    WInit->>AI: attemptWorkspaceAutoRenameFromPrompt(workspaceId, prompt)
    AI->>AI: iterate TITLE_PROVIDERS -> generateWorkspaceNameFromPrompt(prompt)
    AI->>DB: read workspace state (getWorkspaceAutoRenameDecision)
    AI->>AI: decide rename or skip (with reason/warning)
    alt renamed
        AI->>DB: update workspace name
        AI-->>WInit: { kind: "renamed", name }
    else skipped
        AI-->>WInit: { kind: "skip", reason, warning? }
    end
    WInit->>Server: updateProgress(step, msg, warning?)
    Server->>UI: emit init progress event
    UI->>UI: if progress.warning and not shown -> toast.warning(warning)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped a prompt into the box,

The AI whispered names and clocks,
Some names took root, some chose to stay,
A gentle toast nudged those that sway.
🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% 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 change: moving workspace auto-naming into the server-side init flow so it runs after setup completes.
Description check ✅ Passed The description includes a summary, testing instructions, and a detailed breakdown of changes. All key sections from the template are addressed.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 11 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts">

<violation number="1" location="apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts:416">
P2: Unhandled promise rejection risk: `void attemptWorkspaceAutoRenameFromPrompt(...)` discards the promise without catching errors. If the DB query or rename logic throws, this becomes an unhandled rejection that can crash the Electron main process. Wrap the call with `.catch()` to match the error-safe pattern used in the `initializeWorkspaceWorktree` path.

(Based on your team's feedback about handling async calls with proper await and catch.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts">

<violation number="1" location="apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts:147">
P1: Auto-rename is not wrapped in its own try/catch, so an unexpected error (e.g. DB failure in `ai-name.ts`) will fail the entire workspace init and **delete the already-created worktree**. Since the PR intends naming to be non-fatal, wrap this in a try/catch that falls back to reporting "ready" without a rename.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts Outdated
Comment thread apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts Outdated
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: 3

🧹 Nitpick comments (3)
apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-auto-rename.ts (1)

1-6: Consider exporting the interfaces for reuse.

The WorkspaceAutoRenameState and ResolveWorkspaceAutoRenameParams interfaces are not exported, which may limit reusability if other modules need to construct these types. If these are intentionally internal, this is fine.

♻️ Optional: Export interfaces for external use
-interface WorkspaceAutoRenameState {
+export interface WorkspaceAutoRenameState {
 	branch: string;
 	name: string;
 	isUnnamed: boolean | null;
 	deletingAt?: number | null;
 }

-interface ResolveWorkspaceAutoRenameParams {
+export interface ResolveWorkspaceAutoRenameParams {
 	workspace: WorkspaceAutoRenameState | null;
 	generatedName: string | null;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-auto-rename.ts`
around lines 1 - 6, The interfaces WorkspaceAutoRenameState and
ResolveWorkspaceAutoRenameParams are declared but not exported, limiting reuse;
export them by adding the export keyword to their declarations (e.g., export
interface WorkspaceAutoRenameState and export interface
ResolveWorkspaceAutoRenameParams) so other modules can import these types;
ensure any local usages/imports still compile and update any files that should
import these interfaces accordingly.
apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts (1)

175-184: DB query correctly filters out deleting workspaces.

The query includes isNull(workspaces.deletingAt) which ensures workspaces marked for deletion are not renamed. However, this creates a potential inconsistency: the getWorkspaceAutoRenameDecision function also checks deletingAt, but if the workspace is already filtered out by the query, it will return null and trigger "missing-workspace" instead of "workspace-deleting".

This is functionally correct (rename is skipped either way) but the logged skip reason may be misleading.

♻️ Optional: Remove deletingAt filter from query for accurate skip reason
 const workspace = localDb
 	.select({
 		branch: workspaces.branch,
 		name: workspaces.name,
 		isUnnamed: workspaces.isUnnamed,
 		deletingAt: workspaces.deletingAt,
 	})
 	.from(workspaces)
-	.where(and(eq(workspaces.id, workspaceId), isNull(workspaces.deletingAt)))
+	.where(eq(workspaces.id, workspaceId))
 	.get();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts` around lines
175 - 184, The select query that fetches the workspace currently includes
isNull(workspaces.deletingAt) which causes a null result and hides the fact the
workspace is deleting, leading getWorkspaceAutoRenameDecision to report
"missing-workspace" instead of "workspace-deleting"; remove the
isNull(workspaces.deletingAt) predicate from the localDb.select/.where call (or
alternatively keep the predicate but after fetching check the
workspace.deletingAt field) so that getWorkspaceAutoRenameDecision can read
deletingAt and return the accurate "workspace-deleting" skip reason (refer to
the workspace query using localDb.select(...) .from(workspaces)
.where(eq(workspaces.id, workspaceId)) and the getWorkspaceAutoRenameDecision
function).
apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-auto-rename.test.ts (1)

7-79: Good test coverage for core auto-rename scenarios.

The tests cover the essential paths: unnamed workspace with valid name, already-named workspace, placeholder-changed scenario, and whitespace handling. The test for getWorkspaceAutoRenameDecision verifies the skip reason structure.

Consider adding tests for the remaining skip reasons ("missing-workspace", "workspace-deleting", "workspace-name-changed") to ensure complete coverage of the decision logic.

🧪 Optional: Additional test cases for complete coverage
test("reports skip reason for missing workspace", () => {
	expect(
		getWorkspaceAutoRenameDecision({
			workspace: null,
			generatedName: "Fix auth flow",
		}),
	).toEqual({
		kind: "skip",
		reason: "missing-workspace",
	});
});

test("reports skip reason for deleting workspace", () => {
	expect(
		getWorkspaceAutoRenameDecision({
			workspace: {
				branch: "feat/test-branch",
				name: "feat/test-branch",
				isUnnamed: true,
				deletingAt: Date.now(),
			},
			generatedName: "Fix auth flow",
		}),
	).toEqual({
		kind: "skip",
		reason: "workspace-deleting",
	});
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-auto-rename.test.ts`
around lines 7 - 79, Add unit tests to cover the remaining skip reasons returned
by getWorkspaceAutoRenameDecision: add one test calling
getWorkspaceAutoRenameDecision with workspace: null and generatedName "Fix auth
flow" expecting { kind: "skip", reason: "missing-workspace" }; add one test with
workspace.deletingAt set (e.g., Date.now()) and isUnnamed true expecting { kind:
"skip", reason: "workspace-deleting" }; and add one test exercising the
"workspace-name-changed" branch by providing a workspace whose branch and name
no longer match the original placeholder (e.g., branch: "feat/test-branch",
name: "Running setup", isUnnamed: true) and assert the result is { kind: "skip",
reason: "workspace-name-changed" } so getWorkspaceAutoRenameDecision is fully
covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts`:
- Around line 416-419: The call to attemptWorkspaceAutoRenameFromPrompt({
workspaceId: workspace.id, prompt: input.prompt }) is being fire-and-forget
which causes unhandled rejections and drops any returned warning/result; change
this to await the promise and wrap it in try/catch so rejections are handled,
then propagate any non-fatal naming warning into the mutation response (or
forward the outcome through the same init-progress mechanism used elsewhere) so
callers receive the warning/toast instead of it being lost.

In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts`:
- Line 72: The modelId value "gpt-4.1" is invalid and will cause OpenAI API
errors—update the modelId in the AI name request configuration (the modelId
property in this file/function) to a valid OpenAI model string such as "gpt-4",
"gpt-4-turbo", or "gpt-4o" (or a dated snapshot like "gpt-4o-2024-11-20"), then
run/fix any related callers of this config to match the chosen model id.

In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts`:
- Around line 147-163: attemptWorkspaceAutoRenameFromPrompt can throw and
currently its await is inside the outer init try so failures will bubble to the
outer catch and cause removeWorktree() to run after
manager.markWorktreeCreated(workspaceId) — convert rename failures into warnings
by wrapping the await in a local try/catch (or extract a helper like
safeAttemptWorkspaceAutoRenameFromPrompt), on error set autoRenameResult = {
status: "skipped", warning: <error message> } (or similar) and then call
manager.updateProgress(workspaceId, "ready", "Ready", undefined,
autoRenameResult.status === "skipped" ? autoRenameResult.warning : undefined);
apply the same change to the other occurrence (lines ~466-482) so both branches
remain in sync and rename errors no longer trigger removeWorktree().

---

Nitpick comments:
In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts`:
- Around line 175-184: The select query that fetches the workspace currently
includes isNull(workspaces.deletingAt) which causes a null result and hides the
fact the workspace is deleting, leading getWorkspaceAutoRenameDecision to report
"missing-workspace" instead of "workspace-deleting"; remove the
isNull(workspaces.deletingAt) predicate from the localDb.select/.where call (or
alternatively keep the predicate but after fetching check the
workspace.deletingAt field) so that getWorkspaceAutoRenameDecision can read
deletingAt and return the accurate "workspace-deleting" skip reason (refer to
the workspace query using localDb.select(...) .from(workspaces)
.where(eq(workspaces.id, workspaceId)) and the getWorkspaceAutoRenameDecision
function).

In
`@apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-auto-rename.test.ts`:
- Around line 7-79: Add unit tests to cover the remaining skip reasons returned
by getWorkspaceAutoRenameDecision: add one test calling
getWorkspaceAutoRenameDecision with workspace: null and generatedName "Fix auth
flow" expecting { kind: "skip", reason: "missing-workspace" }; add one test with
workspace.deletingAt set (e.g., Date.now()) and isUnnamed true expecting { kind:
"skip", reason: "workspace-deleting" }; and add one test exercising the
"workspace-name-changed" branch by providing a workspace whose branch and name
no longer match the original placeholder (e.g., branch: "feat/test-branch",
name: "Running setup", isUnnamed: true) and assert the result is { kind: "skip",
reason: "workspace-name-changed" } so getWorkspaceAutoRenameDecision is fully
covered.

In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-auto-rename.ts`:
- Around line 1-6: The interfaces WorkspaceAutoRenameState and
ResolveWorkspaceAutoRenameParams are declared but not exported, limiting reuse;
export them by adding the export keyword to their declarations (e.g., export
interface WorkspaceAutoRenameState and export interface
ResolveWorkspaceAutoRenameParams) so other modules can import these types;
ensure any local usages/imports still compile and update any files that should
import these interfaces accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7de30076-2f6f-4aad-ac39-a69244450b41

📥 Commits

Reviewing files that changed from the base of the PR and between d0163af and f505509.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • apps/desktop/package.json
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-auto-rename.test.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-auto-rename.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts
  • apps/desktop/src/main/lib/workspace-init-manager.ts
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/renderer/routes/_authenticated/layout.tsx
  • apps/desktop/src/shared/types/workspace-init.ts

Comment thread apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts Outdated
Comment thread apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts Outdated
Comment thread apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts Outdated
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts`:
- Around line 97-100: The logs in ai-name.ts are printing user-authored content
(prompt, promptPreview, generatedName, workspace names/state) which may contain
sensitive info; update all console.log calls (those referencing prompt,
prompt.length/prompt.slice, promptPreview, generatedName, workspace.name,
workspace.state) to avoid verbatim content by either removing the raw strings or
replacing them with redacted values or metadata only (e.g., log prompt length,
provider name, and reason), and ensure any preview uses a deterministic
redaction like "<redacted>" or a hash instead of the actual text; apply this
change to the console.log sites around the prompt logging block and the other
occurrences noted (lines ~124-127, ~157-161, ~197-202, ~216-220).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9eecbade-f3ee-4f24-9980-92c4497e3c8a

📥 Commits

Reviewing files that changed from the base of the PR and between f505509 and 3afcf15.

📒 Files selected for processing (2)
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx

Comment thread apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts Outdated
Comment thread apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts
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

♻️ Duplicate comments (2)
apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts (1)

147-159: ⚠️ Potential issue | 🔴 Critical

Keep auto-naming failures out of the init cleanup path.

These awaits still sit inside the outer try after manager.markWorktreeCreated(workspaceId). If attemptWorkspaceAutoRenameFromPrompt() rejects, the catch below will remove an otherwise healthy worktree and mark init as failed even though setup already succeeded. Catch rename errors locally, turn them into a warning, and re-check cancellation before updateProgress("ready") so a late delete doesn't resurrect the workspace.

Suggested direction
+		const completeReadyState = async () => {
+			let warning: string | undefined;
+			try {
+				const autoRenameResult = await attemptWorkspaceAutoRenameFromPrompt({
+					workspaceId,
+					prompt: namingPrompt,
+				});
+				warning =
+					autoRenameResult.status === "skipped"
+						? autoRenameResult.warning
+						: undefined;
+			} catch (error) {
+				console.warn("[workspace-init] Auto naming failed", {
+					workspaceId,
+					error: error instanceof Error ? error.message : String(error),
+				});
+				warning = "Couldn't auto-name this workspace.";
+			}
+
+			if (manager.isCancellationRequested(workspaceId)) {
+				return;
+			}
+
+			manager.updateProgress(workspaceId, "ready", "Ready", undefined, warning);
+		};
...
-		const autoRenameResult = await attemptWorkspaceAutoRenameFromPrompt({
-			workspaceId,
-			prompt: namingPrompt,
-		});
-		manager.updateProgress(
-			workspaceId,
-			"ready",
-			"Ready",
-			undefined,
-			autoRenameResult.status === "skipped"
-				? autoRenameResult.warning
-				: undefined,
-		);
+		await completeReadyState();

Also applies to: 462-474

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts` around
lines 147 - 159, The auto-rename call (attemptWorkspaceAutoRenameFromPrompt) is
inside the outer try that, if it throws, will trigger the catch that removes the
already-created worktree; change this by wrapping the
attemptWorkspaceAutoRenameFromPrompt call in its own try/catch so any rejection
is caught locally and converted into a warning string (e.g., autoRenameWarning)
rather than thrown, then re-check cancellation/state after
markWorktreeCreated(workspaceId) and before calling
manager.updateProgress(workspaceId, "ready", ...) so a late cancellation can
still abort without resurrecting the workspace; finally pass the warning into
manager.updateProgress when auto-rename was skipped/failed instead of letting
the outer catch run.
apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts (1)

143-170: ⚠️ Potential issue | 🔴 Critical

Re-check the rename preconditions in the UPDATE.

Line 151 filters deleting rows out of the read entirely, which bypasses the workspace-deleting branch in getWorkspaceAutoRenameDecision(), and Line 169 updates by id only. A manual rename or delete that lands between those statements can still be overwritten while this path returns "renamed". Fetch by id only, then carry deletingAt IS NULL, isUnnamed = true, and name === branch into the UPDATE, and only report "renamed" if that guarded write actually matches a row.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts` around lines
143 - 170, The code reads the workspace filtered by deletingAt IS NULL, then
unconditionally runs an update by id which can race and produce a false
"renamed" result; change the read to fetch by id only (use workspaceId and not
filter out deletingAt) before calling getWorkspaceAutoRenameDecision(workspace:
workspace ?? null, generatedName), then perform the UPDATE against workspaces
with a WHERE that includes eq(workspaces.id, workspaceId) AND
isNull(workspaces.deletingAt) (or NOT deleting) AND eq(workspaces.isUnnamed,
true) AND eq(workspaces.name, workspaces.branch) (to ensure name === branch) and
set name, isUnnamed=false, updatedAt; finally, inspect the update
result/affected count and only return {status: "renamed"} if a row was actually
updated, otherwise return {status: "skipped", reason: "precondition failed"} (or
forward decision.reason).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts`:
- Around line 1-11: Imports in ai-name.ts are not ordered per Biome's
import-order rule; reorder the import statements so groups follow project
convention (external packages first, then internal aliases, then relative
imports) and alphabetize within groups — specifically reorder the symbols like
Agent, createAnthropic, createOpenAI, workspaces,
getAnthropicCredentialsFromAnySource, getOpenAICredentialsFromAnySource,
and/eq/isNull, localDb, and getWorkspaceAutoRenameDecision into the correct
group order; after reordering, run the formatter/linter auto-fix (bun run
lint:fix) to apply Biome's import-order and formatting rules.

---

Duplicate comments:
In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts`:
- Around line 143-170: The code reads the workspace filtered by deletingAt IS
NULL, then unconditionally runs an update by id which can race and produce a
false "renamed" result; change the read to fetch by id only (use workspaceId and
not filter out deletingAt) before calling
getWorkspaceAutoRenameDecision(workspace: workspace ?? null, generatedName),
then perform the UPDATE against workspaces with a WHERE that includes
eq(workspaces.id, workspaceId) AND isNull(workspaces.deletingAt) (or NOT
deleting) AND eq(workspaces.isUnnamed, true) AND eq(workspaces.name,
workspaces.branch) (to ensure name === branch) and set name, isUnnamed=false,
updatedAt; finally, inspect the update result/affected count and only return
{status: "renamed"} if a row was actually updated, otherwise return {status:
"skipped", reason: "precondition failed"} (or forward decision.reason).

In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts`:
- Around line 147-159: The auto-rename call
(attemptWorkspaceAutoRenameFromPrompt) is inside the outer try that, if it
throws, will trigger the catch that removes the already-created worktree; change
this by wrapping the attemptWorkspaceAutoRenameFromPrompt call in its own
try/catch so any rejection is caught locally and converted into a warning string
(e.g., autoRenameWarning) rather than thrown, then re-check cancellation/state
after markWorktreeCreated(workspaceId) and before calling
manager.updateProgress(workspaceId, "ready", ...) so a late cancellation can
still abort without resurrecting the workspace; finally pass the warning into
manager.updateProgress when auto-rename was skipped/failed instead of letting
the outer catch run.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4a314332-be80-4cf0-b4ad-27ad7e5e0b58

📥 Commits

Reviewing files that changed from the base of the PR and between 3afcf15 and 759324e.

📒 Files selected for processing (2)
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts

Comment thread apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts Outdated
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts">

<violation number="1" location="apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts:148">
P3: This `if (!workspace)` block is unreachable because `getWorkspaceAutoRenameDecision` already returns `kind: "skip"` when workspace is null. After the skip return, workspace must be non-null, so this block is dead code. Remove it to avoid misleading control flow.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

if (decision.kind === "skip") {
return { status: "skipped", reason: decision.reason };
}
if (!workspace) {
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Mar 6, 2026

Choose a reason for hiding this comment

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

P3: This if (!workspace) block is unreachable because getWorkspaceAutoRenameDecision already returns kind: "skip" when workspace is null. After the skip return, workspace must be non-null, so this block is dead code. Remove it to avoid misleading control flow.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts, line 148:

<comment>This `if (!workspace)` block is unreachable because `getWorkspaceAutoRenameDecision` already returns `kind: "skip"` when workspace is null. After the skip return, workspace must be non-null, so this block is dead code. Remove it to avoid misleading control flow.</comment>

<file context>
@@ -128,32 +128,68 @@ export async function attemptWorkspaceAutoRenameFromPrompt({
+	if (decision.kind === "skip") {
 		return { status: "skipped", reason: decision.reason };
 	}
+	if (!workspace) {
+		return { status: "skipped", reason: "missing-workspace" };
+	}
</file context>
Fix with Cubic

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

Caution

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

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

409-425: 🛠️ Refactor suggestion | 🟠 Major

Make isUnnamed explicit for the orphaned-worktree insert.

This new immediate rename path only works when the freshly inserted workspace is still marked unnamed, but createWorkspaceFromWorktree() leaves that column implicit. On the input.name ?? branch path, that makes auto-renaming depend on the workspaces.isUnnamed default instead of the create flow, so this branch can silently skip naming. Thread isUnnamed: !input.name through the helper so it matches the other workspace insert paths.

Suggested direction
 const workspace = createWorkspaceFromWorktree({
 	projectId: input.projectId,
 	worktreeId: orphanedWorktree.id,
 	branch,
 	name: input.name ?? branch,
+	isUnnamed: !input.name,
 });

createWorkspaceFromWorktree() should then persist isUnnamed on the insert.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts` around
lines 409 - 425, The create path relies on the new workspace being marked
unnamed so the immediate rename flow runs, but createWorkspaceFromWorktree
currently omits isUnnamed so the DB default controls behavior; update the call
site to pass isUnnamed: !input.name into createWorkspaceFromWorktree (alongside
projectId, worktreeId, branch, name) and then update the
createWorkspaceFromWorktree implementation to persist that isUnnamed value on
insert (so workspaces.isUnnamed is set explicitly), ensuring the logic around
attemptWorkspaceAutoRenameFromPrompt and autoRenameResult behaves
deterministically.
apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts (1)

23-30: ⚠️ Potential issue | 🟠 Major

Persist the naming prompt across init retries.

Because naming moved to ready-time, namingPrompt now has to survive any failed first init. Right now it only lives on this in-memory init call, while the retry path in apps/desktop/src/lib/trpc/routers/workspaces/procedures/init.ts (Lines 164-176) requeues initializeWorkspaceWorktree() without it. A workspace that only reaches ready on retry will therefore never be auto-named. Persist the prompt, or persist a precomputed title request, with the workspace/init job instead of threading it only through the first call.

Also applies to: 50-79

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts` around
lines 23 - 30, The namingPrompt currently only lives in the transient
WorkspaceInitParams passed to initializeWorkspaceWorktree and is dropped when
init.ts requeues the job; persist it by adding namingPrompt (or a precomputed
title request string) to the long-lived workspace/init job payload and to the
WorkspaceInitParams interface so requeue paths (the code that calls
initializeWorkspaceWorktree in
apps/desktop/src/lib/trpc/routers/workspaces/procedures/init.ts) include it when
enqueuing/re-enqueuing; update all call sites of initializeWorkspaceWorktree and
the job serialization/deserialization to read/write namingPrompt (or
titleRequest) so a retry that reaches ready still has the prompt available for
auto-naming.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts`:
- Around line 115-146: The function attemptWorkspaceAutoRenameFromPrompt
currently calls generateWorkspaceNameFromPrompt before loading the workspace,
which can consume provider calls and return wrong skip reasons; move the localDb
select that loads the workspace (using workspaceId and
localDb/select/from/where) to run before generateWorkspaceNameFromPrompt, run
getWorkspaceAutoRenameDecision on the loaded workspace to short-circuit and
return non-"empty-generated-name" skip cases early, and only call
generateWorkspaceNameFromPrompt and the guarded UPDATE if the decision allows
renaming, keeping the existing post-generation race check that uses
generatedName and getWorkspaceAutoRenameDecision.

---

Outside diff comments:
In `@apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts`:
- Around line 409-425: The create path relies on the new workspace being marked
unnamed so the immediate rename flow runs, but createWorkspaceFromWorktree
currently omits isUnnamed so the DB default controls behavior; update the call
site to pass isUnnamed: !input.name into createWorkspaceFromWorktree (alongside
projectId, worktreeId, branch, name) and then update the
createWorkspaceFromWorktree implementation to persist that isUnnamed value on
insert (so workspaces.isUnnamed is set explicitly), ensuring the logic around
attemptWorkspaceAutoRenameFromPrompt and autoRenameResult behaves
deterministically.

In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts`:
- Around line 23-30: The namingPrompt currently only lives in the transient
WorkspaceInitParams passed to initializeWorkspaceWorktree and is dropped when
init.ts requeues the job; persist it by adding namingPrompt (or a precomputed
title request string) to the long-lived workspace/init job payload and to the
WorkspaceInitParams interface so requeue paths (the code that calls
initializeWorkspaceWorktree in
apps/desktop/src/lib/trpc/routers/workspaces/procedures/init.ts) include it when
enqueuing/re-enqueuing; update all call sites of initializeWorkspaceWorktree and
the job serialization/deserialization to read/write namingPrompt (or
titleRequest) so a retry that reaches ready still has the prompt available for
auto-naming.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 820539ae-af5c-4c3a-be01-86b012feca5f

📥 Commits

Reviewing files that changed from the base of the PR and between 759324e and 73ba31b.

📒 Files selected for processing (6)
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts
  • apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx
  • apps/desktop/src/renderer/react-query/workspaces/useCreateWorkspace.ts
  • apps/desktop/src/renderer/routes/_authenticated/layout.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/desktop/src/renderer/routes/_authenticated/layout.tsx

Comment on lines +115 to +146
const generatedName = await generateWorkspaceNameFromPrompt(cleanedPrompt);
if (!generatedName) {
const hasCredentials =
getAnthropicCredentialsFromAnySource() !== null ||
getOpenAICredentialsFromAnySource() !== null;
return {
status: "skipped",
reason: hasCredentials ? "generation-failed" : "missing-credentials",
warning: hasCredentials
? "Couldn't auto-name this workspace."
: "Couldn't auto-name this workspace because chat credentials aren't configured.",
};
}

const workspace = localDb
.select({
id: workspaces.id,
branch: workspaces.branch,
name: workspaces.name,
isUnnamed: workspaces.isUnnamed,
deletingAt: workspaces.deletingAt,
})
.from(workspaces)
.where(eq(workspaces.id, workspaceId))
.get();

const decision = getWorkspaceAutoRenameDecision({
workspace: workspace ?? null,
generatedName,
});
if (decision.kind === "skip") {
return { status: "skipped", reason: decision.reason };
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

Short-circuit skip cases before generating a title.

attemptWorkspaceAutoRenameFromPrompt() calls the provider before loading the workspace. If the workspace is already missing, deleting, or no longer eligible for rename, this still burns a provider call and can return missing-credentials / generation-failed instead of the real skip reason. Load the workspace first, return the non-empty-generated-name skip cases early, then keep the guarded UPDATE as the post-generation race check.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/ai-name.ts` around lines
115 - 146, The function attemptWorkspaceAutoRenameFromPrompt currently calls
generateWorkspaceNameFromPrompt before loading the workspace, which can consume
provider calls and return wrong skip reasons; move the localDb select that loads
the workspace (using workspaceId and localDb/select/from/where) to run before
generateWorkspaceNameFromPrompt, run getWorkspaceAutoRenameDecision on the
loaded workspace to short-circuit and return non-"empty-generated-name" skip
cases early, and only call generateWorkspaceNameFromPrompt and the guarded
UPDATE if the decision allows renaming, keeping the existing post-generation
race check that uses generatedName and getWorkspaceAutoRenameDecision.

@Kitenite Kitenite merged commit d223a62 into superset-sh:main Mar 6, 2026
12 of 15 checks passed
@Kitenite Kitenite deleted the kitenite/serious-saturn branch March 6, 2026 10:47
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