From 83360c3dcaf4b16efd4ae8524bf4cb61d1cdc480 Mon Sep 17 00:00:00 2001 From: Turtle Date: Thu, 30 Jul 2026 10:24:04 +0800 Subject: [PATCH] fix(cli): default session root in shipped config --- apps/cli/config/base.cordis.yml | 6 +----- apps/cli/src/app-cli-entry.ts | 7 +------ apps/cli/src/tui.ts | 16 +--------------- apps/cli/tests/sessions-root.spec.ts | 20 -------------------- packages/ui/tui/src/index.ts | 12 ------------ packages/util/paths/src/index.ts | 21 --------------------- packages/util/paths/tests/paths.spec.ts | 11 ----------- 7 files changed, 3 insertions(+), 90 deletions(-) delete mode 100644 apps/cli/tests/sessions-root.spec.ts diff --git a/apps/cli/config/base.cordis.yml b/apps/cli/config/base.cordis.yml index 9f69fcc627..a6f84d1c51 100644 --- a/apps/cli/config/base.cordis.yml +++ b/apps/cli/config/base.cordis.yml @@ -67,14 +67,10 @@ apiKey: !!js process.env.ANTHROPIC_API_KEY baseURL: !!js process.env.ANTHROPIC_BASE_URL -# The session store root is the launcher's policy, not a plugin's: `dsh` shares -# one store under the Harness home across every cwd, so `/resume` spans -# workspaces. Without a launcher the project-local fallback keeps -# an embedder's sessions beside its project. - id: session-persistence-jsonl name: '@deepseek-ai/dsh-session-persistence-jsonl' config: - root: !!js launcherSessionsRoot ?? './.sessions' + root: !!js path.join(process.env.DSH_HOME || path.join(os.homedir(), '.dsh'), 'sessions') - id: subprocess name: '@deepseek-ai/dsh-subprocess-local' diff --git a/apps/cli/src/app-cli-entry.ts b/apps/cli/src/app-cli-entry.ts index 00f3c373ad..709da4fc60 100644 --- a/apps/cli/src/app-cli-entry.ts +++ b/apps/cli/src/app-cli-entry.ts @@ -16,7 +16,7 @@ import type { FiberState } from 'cordis' import type { PatchOptions } from '@cordisjs/plugin-include' import yaml from 'js-yaml' import { boot, installFailLoud, loadEnv, loadOverlayPatches, loadPersonalPatches } from '@deepseek-ai/dsh-app-boot' -import { resolveDshHome, resolveSessionsRoot } from '@deepseek-ai/dsh-paths' +import { resolveDshHome } from '@deepseek-ai/dsh-paths' // Empty type import carries the httpServer Context merge for the port read below. import type {} from '@deepseek-ai/dsh-host-webserver' @@ -189,11 +189,6 @@ export class AppCLIEntry { overrides.set(entryId, bag) } - // Source 0: computed engineering defaults. The session store is the one - // shared root every dsh surface resolves, so history follows the user across - // working directories instead of splitting per project. The profile - // (Source 1) overwrites this same field via last-write-wins in put(). - put('session-persistence-jsonl', 'root', resolveSessionsRoot()) // Source 1: profile json (missing file = empty; unmapped key = loud). for (const [key, value] of Object.entries(this.readProfile())) { diff --git a/apps/cli/src/tui.ts b/apps/cli/src/tui.ts index 76705473a5..773d1e78e8 100644 --- a/apps/cli/src/tui.ts +++ b/apps/cli/src/tui.ts @@ -31,7 +31,7 @@ import { loadPersonalPatches, resolveConfigPath, } from '@deepseek-ai/dsh-app-boot' -import { resolveDshHome, resolveSessionsRoot } from '@deepseek-ai/dsh-paths' +import { resolveDshHome } from '@deepseek-ai/dsh-paths' import { SessionId } from '@deepseek-ai/dsh-session' import { SESSION_QUERY_SQLITE_PATH_KEY } from '@deepseek-ai/dsh-session-query-sqlite' import { CONFIGURED_AGENT_IDENTITIES_KEY } from '@deepseek-ai/dsh-agent-loop' @@ -39,7 +39,6 @@ import type { Context } from 'cordis' import { INITIAL_SKILL_KEY, MAIN_SESSION_ID_KEY, - SESSIONS_ROOT_KEY, TUI_GOODBYE_MESSAGE_KEY, type MainSessionIdentity, type TuiResumeHost, @@ -65,18 +64,6 @@ const SESSION_QUERY_DB = `session-query-${String(process.pid)}-${randomUUID()}.d // symlink, an arbitrary cwd). The agent is told where its own source lives. const SOURCE_ROOT = fileURLToPath(new URL('../../..', import.meta.url)) -/** - * The value `dsh` provides on the {@link SESSIONS_ROOT_KEY} boot slot: its - * shared session-store root, `sessions` under the Harness home. Shared-store - * policy is the launcher's alone — the app bundle treats the slot as opaque and - * keeps a project-local fallback, so only `dsh` decides that sessions are - * shared across working directories (making `/resume` span every workspace). - * @returns the absolute session-store root this launcher shares. - */ -export function launcherSessionsRoot(): string { - return resolveSessionsRoot() -} - /* v8 ignore start -- composition over the unit-tested dsh-app-boot helpers; the CLI PTY smoke drives this path end to end, personal overlay included */ /** @@ -238,7 +225,6 @@ export async function runTui( // Shared-store policy is the launcher's: sessions live in one root under // the Harness home across every cwd, so /resume sees every workspace. // The bundle treats the slot as opaque. - hostCtx.provide(SESSIONS_ROOT_KEY, launcherSessionsRoot()) // The agent-loop row reads this to bind `main`, and the tui row reads the // same id, so a personal overlay repointing the model route cannot drop // the session identity or desynchronise the two. diff --git a/apps/cli/tests/sessions-root.spec.ts b/apps/cli/tests/sessions-root.spec.ts deleted file mode 100644 index cb9982615a..0000000000 --- a/apps/cli/tests/sessions-root.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Pins the launcher side of the shared-session-store contract: `dsh` defaults - * its opaque `SESSIONS_ROOT_KEY` boot-slot value to `DSH_HOME/sessions`. The - * plugin side — the slot treated as opaque, explicit config winning, and a - * project-local fallback with no globality assumption — is pinned by - * the former bundled TUI tests. - */ - -import { join, resolve } from 'node:path' -import { afterEach, describe, expect, it, vi } from 'vitest' -import { launcherSessionsRoot } from '../src/tui.ts' - -afterEach(() => vi.unstubAllEnvs()) - -describe('launcherSessionsRoot', () => { - it('defaults the boot slot to sessions under DSH_HOME', () => { - vi.stubEnv('DSH_HOME', '/tmp/dsh-slot-home') - expect(launcherSessionsRoot()).toBe(resolve(join('/tmp/dsh-slot-home', 'sessions'))) - }) -}) diff --git a/packages/ui/tui/src/index.ts b/packages/ui/tui/src/index.ts index fc6c54c293..392cb0e356 100644 --- a/packages/ui/tui/src/index.ts +++ b/packages/ui/tui/src/index.ts @@ -182,8 +182,6 @@ declare module 'cordis' { tuiGoodbyeMessage: string | undefined /** Skill the launcher wants auto-invoked as the fresh session's first turn; absent leaves it to the user. */ tuiInitialSkill: string | undefined - /** Launcher-owned session-store root the app bundle defaults to; absent keeps the bundle's project-local default. */ - launcherSessionsRoot: string | undefined } } @@ -228,16 +226,6 @@ export const TUI_GOODBYE_MESSAGE_KEY = 'tuiGoodbyeMessage' */ export const INITIAL_SKILL_KEY = 'tuiInitialSkill' -/** - * Context key a launcher sets before any Loader entry mounts - * (`ctx.provide(SESSIONS_ROOT_KEY, root)`) to supply its session-store root as - * the app bundle's default persistence root. Shared-store policy (one store - * across every cwd) belongs to the launcher — the dsh CLI resolves it under the - * Harness home — never to a plugin; a bundle without this slot keeps its own - * project-local default, and an explicit `persistenceRoot` config still wins. - */ -export const SESSIONS_ROOT_KEY = 'launcherSessionsRoot' - /** * Optional terminal-local interaction service provided by one mounted TUI. * diff --git a/packages/util/paths/src/index.ts b/packages/util/paths/src/index.ts index 85a6c881cd..c54a5e0a5f 100644 --- a/packages/util/paths/src/index.ts +++ b/packages/util/paths/src/index.ts @@ -52,27 +52,6 @@ export function resolveDshHome(configured?: string, env: Record = process.env, -): string { - return join(resolveDshHome(configuredHome, env), SESSIONS_DIR_NAME) -} - /** * Describe a resolved harness home symbolically for user-facing display. * diff --git a/packages/util/paths/tests/paths.spec.ts b/packages/util/paths/tests/paths.spec.ts index 5d41b52c44..6e1b94b1e9 100644 --- a/packages/util/paths/tests/paths.spec.ts +++ b/packages/util/paths/tests/paths.spec.ts @@ -4,12 +4,10 @@ import { describe, expect, it } from 'vitest' import { DEFAULT_DSH_HOME_DISPLAY, DSH_HOME_DIR_NAME, - SESSIONS_DIR_NAME, defaultDshHome, dshHomeDisplay, expandHomePath, resolveDshHome, - resolveSessionsRoot, } from '@deepseek-ai/dsh-paths' describe('dsh path helpers', () => { @@ -40,15 +38,6 @@ describe('dsh path helpers', () => { expect(resolveDshHome(undefined, { DSH_HOME: ' ' })).toBe(defaultDshHome()) }) - it('resolves the session store under the home it was given, by the same precedence', () => { - expect(SESSIONS_DIR_NAME).toBe('sessions') - expect(resolveSessionsRoot('/tmp/explicit-dsh', { DSH_HOME: '~/env-dsh' })) - .toBe(join(resolve('/tmp/explicit-dsh'), 'sessions')) - expect(resolveSessionsRoot(undefined, { DSH_HOME: '~/env-dsh' })) - .toBe(join(homedir(), 'env-dsh', 'sessions')) - expect(resolveSessionsRoot(undefined, {})).toBe(join(defaultDshHome(), 'sessions')) - }) - it('labels a resolved home by whether it is the default root', () => { expect(dshHomeDisplay(resolve(defaultDshHome()))).toBe('~/.dsh') expect(dshHomeDisplay('/some/other/root')).toBe('$DSH_HOME')