feat: task-based workspace names - #25
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New workspaces show a temporary "New Workspace" label until the first user message, which the companion server turns into a short task-derived name (markdown stripped, first line, capped at 50 chars). The chat header and workspace list pick up the rename live via the new GET /workspaces/:id endpoint; git worktree folders/branches keep their city id.
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Warning Review limit reached
Next review available in: 49 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThe server now assigns temporary workspace labels and replaces them with task-derived names after the first usable message. The iOS client retrieves updated workspace data and refreshes the chat header. The project build number changes from 12 to 18. ChangesWorkspace naming and synchronization
Release metadata
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant ChatView
participant APIClient
participant Server
participant projects.json
ChatView->>APIClient: Refresh workspace
APIClient->>Server: GET /workspaces/{id}
Server->>projects.json: Read current label
Server-->>APIClient: Return workspaceJSON
APIClient-->>ChatView: Update workspaceName
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1⚔️ Resolve merge conflicts 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@server/server.ts`:
- Around line 699-713: The taskNameFrom truncation currently allows 50 content
characters plus the ellipsis; adjust its truncation budget so the complete
returned label, including the suffix, never exceeds 50 characters. Preserve the
existing word-boundary behavior and unchanged output for labels already within
the limit.
- Around line 769-774: Restrict the task-based renaming block around
taskNameFrom and setStoredName to phone-created workspaces only. Before
persisting the derived name, validate the workspace’s phone-worktree path or
explicit workspace origin, while preserving the existing first-message and
sessionless checks for eligible workspaces; do not rename the main checkout or
/projects folders.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 54d03a00-85b6-48c1-bda4-e9e6615bdedf
📒 Files selected for processing (5)
PiMobile.xcodeproj/project.pbxprojPiMobile/APIClient.swiftPiMobile/Views/ChatView.swiftPiMobile/Views/WorkspacesView.swiftserver/server.ts
| const taskNameFrom = (text: string): string => { | ||
| // Drop fenced code blocks first, then take the first non-empty line. | ||
| const firstLine = text.replace(/```[\s\S]*?```/g, " ").split("\n").find((l) => l.trim()) ?? ""; | ||
| const cleaned = firstLine | ||
| .replace(/\[([^\]]*)\]\([^)]*\)/g, "$1") // links keep their visible text | ||
| .replace(/[#>*_`~|]/g, " ") | ||
| .replace(/\s+/g, " ") | ||
| .trim(); | ||
| if (!cleaned) return ""; | ||
| const MAX = 50; | ||
| if (cleaned.length <= MAX) return cleaned; | ||
| const cut = cleaned.slice(0, MAX + 1); | ||
| const space = cut.lastIndexOf(" "); | ||
| return (space > MAX * 0.6 ? cut.slice(0, space) : cut.slice(0, MAX)).trimEnd() + "…"; | ||
| }; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Keep the complete workspace label within 50 characters.
For an overlong task, MAX limits the text before …. The returned label can therefore contain 50 characters plus the ellipsis, for a total of 51 characters. Use a 49-character content budget when adding the suffix.
The PR objective requires a 50-character limit.
Proposed fix
const MAX = 50;
+ const suffix = "…";
+ const contentMax = MAX - suffix.length;
- if (cleaned.length <= MAX) return cleaned;
- const cut = cleaned.slice(0, MAX + 1);
+ if (cleaned.length <= MAX) return cleaned;
+ const cut = cleaned.slice(0, contentMax + 1);
const space = cut.lastIndexOf(" ");
- return (space > MAX * 0.6 ? cut.slice(0, space) : cut.slice(0, MAX)).trimEnd() + "…";
+ return (space > contentMax * 0.6 ? cut.slice(0, space) : cut.slice(0, contentMax)).trimEnd() + suffix;📝 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.
| const taskNameFrom = (text: string): string => { | |
| // Drop fenced code blocks first, then take the first non-empty line. | |
| const firstLine = text.replace(/```[\s\S]*?```/g, " ").split("\n").find((l) => l.trim()) ?? ""; | |
| const cleaned = firstLine | |
| .replace(/\[([^\]]*)\]\([^)]*\)/g, "$1") // links keep their visible text | |
| .replace(/[#>*_`~|]/g, " ") | |
| .replace(/\s+/g, " ") | |
| .trim(); | |
| if (!cleaned) return ""; | |
| const MAX = 50; | |
| if (cleaned.length <= MAX) return cleaned; | |
| const cut = cleaned.slice(0, MAX + 1); | |
| const space = cut.lastIndexOf(" "); | |
| return (space > MAX * 0.6 ? cut.slice(0, space) : cut.slice(0, MAX)).trimEnd() + "…"; | |
| }; | |
| const taskNameFrom = (text: string): string => { | |
| // Drop fenced code blocks first, then take the first non-empty line. | |
| const firstLine = text.replace(/ |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@server/server.ts` around lines 699 - 713, The taskNameFrom truncation
currently allows 50 content characters plus the ellipsis; adjust its truncation
budget so the complete returned label, including the suffix, never exceeds 50
characters. Preserve the existing word-boundary behavior and unchanged output
for labels already within the limit.
| // First message in a brand-new workspace: swap the temporary "New Workspace" | ||
| // label for a short name derived from the task itself. | ||
| if (!found && (scanned().workspaces.get(encodeCwd(cwd))?.sessionCount ?? 0) === 0) { | ||
| const name = taskNameFrom(text); | ||
| if (name) setStoredName(cwd, name); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Limit task-based renaming to phone-created workspaces.
This condition applies to every sessionless cwd. It includes the main checkout and folders registered through /projects. workspaceLabel states that those folders keep their folder names, but this block persists a task name for them after the first message.
Check the phone-worktree path, or use an explicit workspace origin, before calling setStoredName.
The PR objective scopes task-based names to phone-created workspaces.
Proposed fix
+ const isPhoneWorkspace = cwd.startsWith(`${homedir()}/pi-workspaces/`);
- if (!found && (scanned().workspaces.get(encodeCwd(cwd))?.sessionCount ?? 0) === 0) {
+ if (
+ isPhoneWorkspace &&
+ !found &&
+ (scanned().workspaces.get(encodeCwd(cwd))?.sessionCount ?? 0) === 0
+ ) {📝 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.
| // First message in a brand-new workspace: swap the temporary "New Workspace" | |
| // label for a short name derived from the task itself. | |
| if (!found && (scanned().workspaces.get(encodeCwd(cwd))?.sessionCount ?? 0) === 0) { | |
| const name = taskNameFrom(text); | |
| if (name) setStoredName(cwd, name); | |
| } | |
| // First message in a brand-new workspace: swap the temporary "New Workspace" | |
| // label for a short name derived from the task itself. | |
| const isPhoneWorkspace = cwd.startsWith(`${homedir()}/pi-workspaces/`); | |
| if ( | |
| isPhoneWorkspace && | |
| !found && | |
| (scanned().workspaces.get(encodeCwd(cwd))?.sessionCount ?? 0) === 0 | |
| ) { | |
| const name = taskNameFrom(text); | |
| if (name) setStoredName(cwd, name); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@server/server.ts` around lines 769 - 774, Restrict the task-based renaming
block around taskNameFrom and setStoredName to phone-created workspaces only.
Before persisting the derived name, validate the workspace’s phone-worktree path
or explicit workspace origin, while preserving the existing first-message and
sessionless checks for eligible workspaces; do not rename the main checkout or
/projects folders.
# Conflicts: # PiMobile.xcodeproj/project.pbxproj
Summary
Workspaces created from the phone no longer keep a random city name (Conductor-style) forever. They start with a temporary "New Workspace" label and are renamed from the task the user actually posts.
What changed
server/server.ts) — new worktrees get the temporary label; on the first user message in a fresh workspace, a short task-derived name (markdown/code fences stripped, first line, ≤50 chars) is persisted via newsetStoredName(). City id stays internal to the git worktree folder/branch. AddedGET /workspaces/:id(withworkspaceJSONrefactor) so the app can re-read the name.ChatViewtracksworkspaceNamein@Stateand refreshes it after each turn (header flips to the task name); newAPIClient.workspace(_:)method.User impact
Validation
bun buildpasses (only unrelated runtime-installedqrcode-terminaldep flagged).Follow-ups
Summary by CodeRabbit
New Features
Bug Fixes