An unnamed project's folder takes the name its agent gives it - #196
Conversation
The agent wrote a name into project.json but the folder stayed Untitled N. Renaming it from inside the turn breaks the next message (no such project), so the server renames it once the turn ends and moves the open page and tab. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deploying super-prototyping with
|
| Latest commit: |
22ce6d1
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c7749249.super-prototyping.pages.dev |
| Branch Preview URL: | https://project-folder-name.super-prototyping.pages.dev |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fd534605b2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| moved(from, to) { | ||
| setTabs((tabs) => |
There was a problem hiding this comment.
Refresh the project list when a folder moves
When a turn finishes while Home or Community is already open, the hidden iframe receives this event, but moved only rewrites tabs; the projects state remains stale because the listing effect depends on the boolean home, which stays true throughout. The Home card therefore continues targeting the now-missing /p/Untitled.../ address, so opening or using its menu returns “no such project” until a manual refresh or navigation forces another listing. Update the matching project or call listProjects as part of handling the move.
AGENTS.md reference: AGENTS.md:L52-L57
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in b534c3c: spShell.moved now calls listProjects().
| if ( | ||
| dir !== undefined && | ||
| code === 0 && | ||
| ![...runs.values()].some((r) => r !== run && !ended(r)) |
There was a problem hiding this comment.
Preserve deferred renames across turns in other projects
When the previous run has emitted its end event but its child has not yet closed, the server permits a queued turn to start; after the user navigates, that queued turn can target another project. This global active-run check then skips the original rename, and when the other run closes it calls named only for its own directory, leaving the first project as Untitled indefinitely unless another successful turn later runs there. Track the skipped directory as a pending rename rather than assuming the next run belongs to the same project.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in ef34d1b: runs carry their dir. The rename now waits only for a live turn on the same project.
- The old project name stays an alias: a message sent as the turn ends, a page's last save as it unloads and a stale home card all reach the new folder, and a GET on the old address redirects. - The moved event goes to every open page, so the tab moves when another project is in front, and the home list refreshes. - A name Windows can't hold, or a non-string name, leaves the folder alone; a throw while naming can no longer keep a run from ending. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3b4ff97958
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // saves its last edits there as it leaves, and a message sent as the turn ended names it. | ||
| const renamed = new Map<string, string>(); | ||
| const project = (name: string) => { | ||
| const dir = projects().get(name) ?? renamed.get(name); |
There was a problem hiding this comment.
Keep renamed aliases from being shadowed by reused names
After Untitled is renamed, the next unnamed project reuses that now-free folder name, and this lookup then selects the new folder before consulting the alias. Any stale /p/Untitled/ tab, bookmark, unload save, or chat request that the alias is intended to preserve will consequently open or write to the wrong project instead of the renamed one; reserve aliased names when creating projects or otherwise disambiguate stale requests.
AGENTS.md reference: AGENTS.md:L15-L18
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in ef34d1b: a new Untitled project skips any name still held as an alias in renamed.
| const sp = sps.get(dir); | ||
| sps.delete(dir); | ||
| sp?.unwatch(); | ||
| try { | ||
| fs.renameSync(dir, to); |
There was a problem hiding this comment.
Drain active writes before renaming the project directory
On POSIX systems, if a /__sp/canvas-file upload has already entered this project's existing sp handler when the naming turn closes, this rename moves the directory and its open .part file while the handler still retains paths under the old directory. When the upload finishes, sp.ts tries to rename the vanished old .part path, returns 500, and leaves an orphaned partial file under the new directory; buffered canvas saves can similarly return 404. Track or drain in-flight writes, or make existing handlers resolve the moved path before performing the rename.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Leaving this one. It needs an upload to be in flight at the moment the naming turn exits, and even then the upload fails loudly rather than corrupting anything. I'll revisit it if it's ever seen.
| path.basename(name) !== name || | ||
| // oxlint-disable-next-line no-control-regex | ||
| /[<>:"|?*\x00-\x1f]|[. ]$/.test(name) || |
There was a problem hiding this comment.
Reject backslashes in cross-platform folder names
On macOS and Linux, path.basename("Foo\\Bar") returns the whole string, and this invalid-character expression omits \\, so an agent-provided name containing a backslash is accepted and renamed even though Windows interprets that character as a path separator. Such a project cannot retain that folder name when transferred to the supported Windows desktop app; include backslash in the platform-independent rejection.
AGENTS.md reference: AGENTS.md:L52-L53
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in cbc46f5: backslashes are rejected, and a trailing dot or space is trimmed.
Windows drops a trailing dot or space from a folder's name, so trim them rather than leave "Acme Inc." an Untitled folder for good. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ld names A turn started in another project no longer defers the rename for good, and a new Untitled project never takes a name a renamed one still answers to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ef34d1b689
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const name = | ||
| typeof given === "string" ? given.trim().replace(/[. ]+$/, "") : ""; | ||
| if ( | ||
| !/^Untitled( \d+)?$/.test(path.basename(dir)) || |
There was a problem hiding this comment.
Distinguish user-named Untitled folders before renaming
When a person explicitly creates a project named Untitled or Untitled N, the server writes the same project.json as it does for a blank name, so this basename check later misclassifies that user-named folder as auto-generated. If its project.json already has a display name or gains one during any successful agent turn, the app unexpectedly moves the folder and changes its /p/<name>/ address despite the stated behavior that person-named folders remain fixed; persist whether the project was created unnamed and require that marker here.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 22ce6d1: a project made without a name gets "unnamed": true in project.json, and namedFolder requires it. A folder the person typed as Untitled N keeps its name.
| // Nor a name a renamed project had, which still answers for it (`renamed`). | ||
| for ( | ||
| let n = 2; | ||
| fs.existsSync(path.join(projectsDir, name)) || renamed.has(name); |
There was a problem hiding this comment.
Reject explicit names retained as aliases
Although the new reservation skips aliases while auto-generating an empty name, it only runs inside the name === "" branch, so an explicit request for Untitled after that folder was renamed can still recreate the aliased name. Because project() checks the real folder map before renamed, stale /p/Untitled/ saves or messages will then target the newly created project and can overwrite the wrong data; reject explicit names present in renamed as well. This remaining explicit-name path is fresh evidence after the earlier alias finding's auto-generated case was fixed.
AGENTS.md reference: AGENTS.md:L15-L18
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 22ce6d1: a typed name still held in renamed gets the same 409 as an existing folder.
…s an old name A project made without a name now carries "unnamed": true in project.json, and only such a folder follows its agent's name. One the person typed "Untitled" keeps it. A typed name that a renamed project still answers to is refused, as the generated ones already skip it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 22ce6d143e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| setTabs((tabs) => withTab(tabs, tab)); | ||
| }, | ||
| moved(from, to) { | ||
| listProjects(); |
There was a problem hiding this comment.
Refresh Home when a naming turn outlives its tab
If the user closes the only project tab while its initial naming turn is still running, closeTabs replaces the iframe with about:blank, so no page remains subscribed to the moved event and this listProjects() call never runs. Home retains the listing fetched before the rename; although opening that stale card follows the alias redirect, its Reveal and Delete actions post the old name, which projects.ts:362-366 looks up only in projects() and rejects with 404 until a manual refresh. The fresh evidence beyond the earlier fixed Home case is the explicit iframe teardown at AppShell.tsx:253-255.
AGENTS.md reference: AGENTS.md:L52-L57
Useful? React with 👍 / 👎.
A project started from an idea with no name was shown by its agent-given name, but its folder stayed `Untitled N`.
Why not in the prompt alone. I tested it: when the agent renamed the folder itself, the next chat message failed with "no such project". The page URL, tab, `SP_PROJECT` and the session's `projects[]` all hold the old name.
What this does
Tested on the dev server with a fresh unnamed project:
`tsc`, `oxlint` and `bun run test` pass: 233 passed, 1 skipped, plus a new `namedFolder` test.
🤖 Generated with Claude Code