Skip to content

feat(chat): new chats start in the most recent chat's project#3712

Merged
BunsDev merged 1 commit into
mainfrom
feat/new-chat-recent-project
Jul 23, 2026
Merged

feat(chat): new chats start in the most recent chat's project#3712
BunsDev merged 1 commit into
mainfrom
feat/new-chat-recent-project

Conversation

@BunsDev

@BunsDev BunsDev commented Jul 23, 2026

Copy link
Copy Markdown
Member

New chats (chat composer and Home) now default to the project the most recent chat ran in, instead of the alphabetically-first project. Zero-config recency inheritance — requested as "set a default project OR let new chats start with the most recent chat's project".

Precedence (unchanged where it matters)

user pick → linked task's project → opener/session root → most recent chat's project (new) → first project

  • Explicit picks (including No project) always win.
  • Existing sessions in unregistered cwds stay No project — the 2026-07-02 regression pin (re-rooting forks the harness session) is untouched.
  • projects is familiar-grant-scoped, so a non-granted project can never be inherited.

How

  • chat-projects.ts: new recentChatProjectRoot(sessions, projects) — newest visible chat whose recorded cwd maps to a registered project; resolveChatProjectSelection gains recentProjectRoot used only in the brand-new-chat fallback.
  • chat-view.tsx: recency resolves live at render (sessions land seconds after boot; an eager seed would freeze it out). Brand-new chats keep a null draft; only switching compose targets clears a prior pick — and only while sessionId is null, so a just-minted session keeps the pick its first send used. Empty-state picker displays the resolved id.
  • home-composer.tsx / home-composer-context.ts: same fallback before projects[0]; the seeding effect no longer writes projects[0] into state (clear-only for stale picks); pickers display the resolved live default.

Verification

  • pnpm test:app — 888 test files passed
  • pnpm typecheck — clean
  • Updated pinned source-shape tests (task-chat-cwd, project-picker, home-composer) + new unit coverage for the resolver, recentChatProjectRoot, and resolveHomeComposerProject recency cases.

A brand-new chat (chat composer or Home) now defaults to the project the
most recent visible chat ran in, instead of snapping to the alphabetically
first project. Explicit picks, a linked task's project, and an opener
surface's root all still outrank the recency default; existing sessions in
unregistered cwds stay No project (regression-pinned).

- chat-projects: recentChatProjectRoot(sessions, projects) walks visible
  chats newest-first and returns the first registered project root;
  resolveChatProjectSelection takes recentProjectRoot in its brand-new-chat
  fallback, before firstProject.
- chat-view: resolves the recency default LIVE at render (sessions load
  async after boot), keeps a null project draft for brand-new chats so a
  late recency signal still applies and background refreshes can never
  clobber an explicit pick; only switching compose targets clears a pick,
  and only while sessionId is still null (a just-minted session keeps the
  pick its first send used). Empty-state picker displays the resolved id.
- home-composer: resolveHomeComposerProject takes the recent root before
  projects[0]; the composer no longer seeds state to the first project
  (clear-only effect for stale picks) and pickers display the resolved
  live default the send would use.
- tests: updated pinned source shapes, added resolver/helper unit coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 23, 2026 14:55

Copilot AI left a comment

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.

Pull request overview

This PR updates chat and Home composer project-defaulting so brand-new chats inherit the registered project of the most recent visible chat (when the user hasn’t explicitly picked a project), instead of defaulting to the alphabetically-first project—while preserving existing precedence rules for explicit picks, linked tasks, and existing sessions in unregistered directories.

Changes:

  • Added a recency-based default (recentChatProjectRoot) and threaded it into resolveChatProjectSelection for brand-new chats.
  • Updated ChatView and HomeComposer to keep “unset” project drafts null so the default resolves live as sessions load, and to display the resolved default in pickers.
  • Expanded/added unit + source-shape tests covering recency inheritance and the “don’t freeze default” regression.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/lib/home-composer-context.ts Adds recency-root fallback to home composer project resolution.
src/lib/home-composer-context.test.ts Adds tests for recency-based defaulting behavior.
src/lib/chat-projects.ts Adds recentChatProjectRoot and integrates recency-root into selection resolution.
src/lib/chat-projects.test.ts Adds coverage for recency precedence and recentChatProjectRoot behavior.
src/components/task-chat-cwd.test.ts Updates pinned-source assertions for new recentProjectRoot plumbing and null-draft behavior.
src/components/project-picker.test.ts Updates pinned-source expectation to use resolved display project id.
src/components/home-composer.tsx Computes recent project root, uses live-resolved selection for display, and stops seeding projects[0] into state.
src/components/home-composer.test.ts Updates pinned-source assertions + regression check against seeding first project.
src/components/chat-view.tsx Computes recent project root; keeps null draft for new chats; uses resolved project id for composer/empty-state.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +5187 to 5191
taskCwd: linkedContext?.task?.cwd,
projects,
}).projectId;
// Initialise when unset, or always resync on session switch.
return prev === null ? resolved : resolved ?? prev;
Comment on lines +31 to +34
return (
projects.find((project) => project.id === selectedProjectId) ??
projectForRoot(recentProjectRoot, projects.slice()) ??
projects[0] ??
@BunsDev
BunsDev merged commit 8fdead4 into main Jul 23, 2026
16 checks passed
@BunsDev
BunsDev deleted the feat/new-chat-recent-project branch July 23, 2026 15:04
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.

2 participants