fix(session): bind new sessions to selected project (#1708)
* fix(session): bind new sessions to selected project Fix #1521: openNewSessionDraft() always used currentDirectory even when the user selected a different project. Now prefers the selected project's path when no explicit directory is provided. * test(session): add unit test for openNewSessionDraft project binding --------- Co-authored-by: Leonid Skorobogatyy <bash@opencode.itc.local> Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
committed by
GitHub
co-authored by
Leonid Skorobogatyy
Bohdan Triapitsyn
parent
83256ba924
commit
5f3ef320d2
@@ -1,5 +1,7 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
|
import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
|
||||||
import { opencodeClient } from '@/lib/opencode/client';
|
import { opencodeClient } from '@/lib/opencode/client';
|
||||||
|
import { useProjectsStore } from '@/stores/useProjectsStore';
|
||||||
|
import { useDirectoryStore } from '@/stores/useDirectoryStore';
|
||||||
import { useSessionWorktreeStore } from './session-worktree-store';
|
import { useSessionWorktreeStore } from './session-worktree-store';
|
||||||
import { routeMessage, useSessionUIStore } from './session-ui-store';
|
import { routeMessage, useSessionUIStore } from './session-ui-store';
|
||||||
import { setActionRefs, setOptimisticRefs } from './session-actions';
|
import { setActionRefs, setOptimisticRefs } from './session-actions';
|
||||||
@@ -226,6 +228,50 @@ describe('routeMessage directory scoping', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('openNewSessionDraft project binding', () => {
|
||||||
|
const projectA = { id: 'proj-a', path: '/projects/alpha', label: 'Alpha' };
|
||||||
|
const projectB = { id: 'proj-b', path: '/projects/beta', label: 'Beta' };
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
useSessionUIStore.setState({
|
||||||
|
currentSessionId: null,
|
||||||
|
currentSessionDirectory: null,
|
||||||
|
newSessionDraft: { open: false, directoryOverride: null, parentID: null },
|
||||||
|
availableWorktreesByProject: new Map(),
|
||||||
|
});
|
||||||
|
useProjectsStore.setState({
|
||||||
|
projects: [projectA, projectB],
|
||||||
|
activeProjectId: projectA.id,
|
||||||
|
});
|
||||||
|
useDirectoryStore.getState().setDirectory(projectB.path, { showOverlay: false });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('binds draft to active project when current directory differs', () => {
|
||||||
|
useSessionUIStore.getState().openNewSessionDraft();
|
||||||
|
const draft = useSessionUIStore.getState().newSessionDraft;
|
||||||
|
|
||||||
|
expect(draft.open).toBe(true);
|
||||||
|
expect(draft.selectedProjectId).toBe(projectA.id);
|
||||||
|
expect(draft.directoryOverride).toBe(projectA.path);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('respects explicit directoryOverride over active project', () => {
|
||||||
|
useSessionUIStore.getState().openNewSessionDraft({ directoryOverride: '/projects/beta/src' });
|
||||||
|
const draft = useSessionUIStore.getState().newSessionDraft;
|
||||||
|
|
||||||
|
expect(draft.open).toBe(true);
|
||||||
|
expect(draft.directoryOverride).toBe('/projects/beta/src');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('respects explicit selectedProjectId over active project', () => {
|
||||||
|
useSessionUIStore.getState().openNewSessionDraft({ selectedProjectId: projectB.id });
|
||||||
|
const draft = useSessionUIStore.getState().newSessionDraft;
|
||||||
|
|
||||||
|
expect(draft.open).toBe(true);
|
||||||
|
expect(draft.selectedProjectId).toBe(projectB.id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('routeMessage skill invocation', () => {
|
describe('routeMessage skill invocation', () => {
|
||||||
// OpenCode registers every skill as a command (source: "skill"), so a skill
|
// OpenCode registers every skill as a command (source: "skill"), so a skill
|
||||||
// selected from the slash menu must be dispatched via session.command so its
|
// selected from the slash menu must be dispatched via session.command so its
|
||||||
|
|||||||
@@ -626,6 +626,7 @@ export const useSessionUIStore = create<SessionUIState>()((set, get) => ({
|
|||||||
if (explicitProject || explicitDirectory !== null) {
|
if (explicitProject || explicitDirectory !== null) {
|
||||||
return explicitProject ?? inferredProjectFromDir ?? fallbackProject
|
return explicitProject ?? inferredProjectFromDir ?? fallbackProject
|
||||||
}
|
}
|
||||||
|
if (activeProject) return activeProject
|
||||||
if (currentDirectory) return currentDirProject ?? fallbackProject
|
if (currentDirectory) return currentDirProject ?? fallbackProject
|
||||||
return persistedProjectByDir ?? persistedProjectById ?? fallbackProject
|
return persistedProjectByDir ?? persistedProjectById ?? fallbackProject
|
||||||
})()
|
})()
|
||||||
@@ -633,6 +634,8 @@ export const useSessionUIStore = create<SessionUIState>()((set, get) => ({
|
|||||||
const directory = (() => {
|
const directory = (() => {
|
||||||
if (explicitDirectory !== null) return explicitDirectory
|
if (explicitDirectory !== null) return explicitDirectory
|
||||||
if (explicitProject) return normalizePath(explicitProject.path ?? null)
|
if (explicitProject) return normalizePath(explicitProject.path ?? null)
|
||||||
|
const selectedProjectPath = normalizePath(selectedProject?.path ?? null)
|
||||||
|
if (selectedProjectPath && selectedProjectPath !== currentDirectory) return selectedProjectPath
|
||||||
if (currentDirectory) return currentDirectory
|
if (currentDirectory) return currentDirectory
|
||||||
if (persistedTarget?.directory) return persistedTarget.directory
|
if (persistedTarget?.directory) return persistedTarget.directory
|
||||||
return normalizePath(selectedProject?.path ?? null)
|
return normalizePath(selectedProject?.path ?? null)
|
||||||
|
|||||||
Reference in New Issue
Block a user