You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[P2] Keep bare \new in the thread's bound project #36
Bare \new ("Fresh session in this thread") uses ctx.state.defaultDir(ctx.channelId, ctx.cwd) — the global current project or a channel pin — not ctx.thread?.projectDir. Every boot resets the current project to the launch cwd, and a \cd in any other thread moves it. Other thread-scoped commands (\model, \sessions, \usage, \cmd, \restart) prefer ctx.thread?.projectDir.
Failure scenario
Thread bound to /projB; bridge restarts in /launch; \new in that thread creates the session in /launch, and subsequent file-editing prompts run in the wrong repo.
Evidence
Local probe cc_mnt/review-20261011/commands/new-and-project.test.ts prints "✨ Fresh session … in /launch" for a thread bound to /projB. Confidence medium only because intent could be argued; the help text says "in this thread".
Suggested fix
const dir = ctx.state.channelProject(ctx.channelId) ?? ctx.thread?.projectDir ?? ctx.state.defaultDir(ctx.channelId, ctx.cwd).
Acceptance
Bare \new in a thread bound to /projB (unpinned channel) creates the session in /projB.
Found in the 2026-10-11 codebase review of commit 22ce7ee (typecheck clean, 1,142/1,142 tests passing). Probe paths refer to the maintainer's local, gitignored review ledger.
Approach: Bare \new should start the fresh session in the project the thread is already bound to. This matches the rule start.ts:113-117 states ("existing threads keep their own bound dir") and the ctx.thread?.projectDir ?? defaultDir fallback every other command uses (\model, \sessions, \usage, \cmd, \restart). A channel pin still wins, because the \pin contract is "new sessions here start in it". An unbound thread keeps today's behavior.
Changes:
src/commands/handlers.ts, \new (line 640):
- const dir = ctx.state.defaultDir(ctx.channelId, ctx.cwd);+ // Same project as the thread (a pin still wins); unbound threads use the channel default.+ const dir = ctx.state.channelProject(ctx.channelId) ?? ctx.thread?.projectDir ?? ctx.state.defaultDir(ctx.channelId, ctx.cwd);
await rebindThread(ctx, dir, "✨", { teardown: false });
Help detail (line 631), so the bare form is explicit:
- detail: "`\\new /abs/path` also switches the current project. Accepts `~` paths. The previous session is kept (\\resume recovers it).",+ detail: "Bare `\\new` stays in this thread's project; `\\new /abs/path` also switches the current project. Accepts `~` paths. The previous session is kept (\\resume recovers it).",
Tests: in test/commands.test.ts, next to "\new unbinds only…":
A thread is bound to /projB and state.setCurrentProject("/launch") simulates a boot. Bare \new must produce getThread("C1:T1").projectDir === "/projB", and currentProjectDir must stay /launch. My probe cc_mnt/review-20261011/commands/new-and-project.test.ts currently shows /launch.
With state.setChannelProject("C1", "/pinned") and a thread bound to /projB, bare \new uses /pinned.
Behavior change: someone who relied on bare \new to "follow" a recent \cd from another thread now stays put. \new <path>/\cd remain the explicit way to move.
Alternatives considered:
Stop resetting currentProjectDir on boot: fixes only the restart case, not the "another thread \cd'd elsewhere" case, and reverses a deliberate design.
Effort: S. Confidence: high
Proposal only, not implemented. Sketches are against 22ce7ee.
Activity
MatthewS65537 commentedon Oct 11, 2026
Proposed fix
Approach: Bare
\newshould start the fresh session in the project the thread is already bound to. This matches the rulestart.ts:113-117states ("existing threads keep their own bound dir") and thectx.thread?.projectDir ?? defaultDirfallback every other command uses (\model,\sessions,\usage,\cmd,\restart). A channel pin still wins, because the\pincontract is "new sessions here start in it". An unbound thread keeps today's behavior.Changes:
src/commands/handlers.ts,\new(line 640):Help detail (line 631), so the bare form is explicit:
Tests: in
test/commands.test.ts, next to "\new unbinds only…":/projBandstate.setCurrentProject("/launch")simulates a boot. Bare\newmust producegetThread("C1:T1").projectDir === "/projB", andcurrentProjectDirmust stay/launch. My probecc_mnt/review-20261011/commands/new-and-project.test.tscurrently shows/launch.state.setChannelProject("C1", "/pinned")and a thread bound to/projB, bare\newuses/pinned.defaultDir(unchanged).Risks / interactions:
rebindThreadcanonicalizes the dir and keeps its rebind-race guard ([P1] Prevent an older asynchronous rebind from overwriting newer owner intent #12). The pool lease goes to the thread's dir, which is already the dir its server runs in.\newto "follow" a recent\cdfrom another thread now stays put.\new <path>/\cdremain the explicit way to move.Alternatives considered:
currentProjectDiron boot: fixes only the restart case, not the "another thread\cd'd elsewhere" case, and reverses a deliberate design.Effort: S. Confidence: high
Proposal only, not implemented. Sketches are against
22ce7ee.Harden catch-up recovery and fix small command bugs (#33, #35, #36, #37…