From 984830c94076f2d405f0bc47761ee78bc16fd8b1 Mon Sep 17 00:00:00 2001 From: Turtle Date: Wed, 29 Jul 2026 18:21:14 +0800 Subject: [PATCH] fix(tui): isolate each process query index --- apps/cli/src/tui.ts | 12 +++++++----- apps/cli/tsconfig.json | 3 +++ apps/cli/tui.cordis.yml | 7 +++---- .../session-query/session-query-sqlite/src/index.ts | 10 ++++++++++ 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/apps/cli/src/tui.ts b/apps/cli/src/tui.ts index f4b4b18f40..6964ac9753 100644 --- a/apps/cli/src/tui.ts +++ b/apps/cli/src/tui.ts @@ -19,6 +19,7 @@ import { randomUUID } from 'node:crypto' import { join, resolve } from 'node:path' +import { tmpdir } from 'node:os' import { fileURLToPath } from 'node:url' import { addHarnessSourceSection, @@ -31,6 +32,7 @@ import { } from '@deepseek-ai/dsh-app-boot' import { resolveDshHome, resolveSessionsRoot } 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' import type { Context } from 'cordis' import { @@ -57,8 +59,8 @@ const TUI_OVERLAY = fileURLToPath(new URL('../tui.cordis.yml', import.meta.url)) // session identity by this config id. const MAIN_AGENT_ID = 'main' -/** Filename of the derived `/resume` index, kept beside the session logs. */ -const SESSION_QUERY_DB = 'session-query.db' +/** Per-process filename of the disposable `/resume` index. */ +const SESSION_QUERY_DB = `session-query-${String(process.pid)}-${randomUUID()}.db` // The harness checkout root: three hops up from apps/cli/{src,lib}, resolved // from this bin's location so it holds however `dsh` is launched (a PATH @@ -242,9 +244,9 @@ export async function runTui( // same id, so a personal overlay repointing the model route cannot drop // the session identity or desynchronise the two. hostCtx.provide(CONFIGURED_AGENT_IDENTITIES_KEY, { [MAIN_AGENT_ID]: identity }) - // The launcher owns the session store location, so it also owns the - // derived index path that must sit beside those logs. - hostCtx.provide('launcherSessionQueryPath', join(launcherSessionsRoot(), SESSION_QUERY_DB)) + // The query database is a disposable derived index with single-process + // ownership. Keep it process-local while it indexes the shared logs. + hostCtx.provide(SESSION_QUERY_SQLITE_PATH_KEY, join(tmpdir(), SESSION_QUERY_DB)) if (resumeHost !== undefined) hostCtx.provide('tuiResumeHost', resumeHost) // Seed the first turn only for a fresh session, so resuming never // re-invokes the skill. diff --git a/apps/cli/tsconfig.json b/apps/cli/tsconfig.json index ce43c0f31c..a13d015a7a 100644 --- a/apps/cli/tsconfig.json +++ b/apps/cli/tsconfig.json @@ -29,6 +29,9 @@ { "path": "../../packages/util/paths" }, + { + "path": "../../packages/session-query/session-query-sqlite" + }, { "path": "../../packages/client/connection" }, diff --git a/apps/cli/tui.cordis.yml b/apps/cli/tui.cordis.yml index 82f5e7aa9e..f71be09e85 100644 --- a/apps/cli/tui.cordis.yml +++ b/apps/cli/tui.cordis.yml @@ -82,10 +82,9 @@ - id: session-checkpoint-policy name: '@deepseek-ai/dsh-session-checkpoint-policy' - # The derived query index behind `/resume`. The launcher owns the session - # store location, so it provides the resolved index path on the boot context - # (`launcherSessionQueryPath`); the index and the logs it indexes therefore - # cannot diverge. The project-local fallback applies when no launcher sets it. + # The derived query index behind `/resume`. The launcher provides a unique + # process-local path because this SQLite backend has one writer owner; the + # project-local fallback applies when no launcher sets the typed slot. - id: session-query-sqlite name: '@deepseek-ai/dsh-session-query-sqlite' config: diff --git a/packages/session-query/session-query-sqlite/src/index.ts b/packages/session-query/session-query-sqlite/src/index.ts index 0c073ccea5..e76e0a5a43 100644 --- a/packages/session-query/session-query-sqlite/src/index.ts +++ b/packages/session-query/session-query-sqlite/src/index.ts @@ -62,6 +62,16 @@ export { type JournalMode, } from './schema.ts' +/** Boot-context slot for a launcher-owned absolute path to this process's derived query index. */ +export const SESSION_QUERY_SQLITE_PATH_KEY = 'launcherSessionQueryPath' + +declare module 'cordis' { + interface Context { + /** Launcher-owned absolute path to this process's disposable derived query index. */ + launcherSessionQueryPath?: string + } +} + /** Default result page size. */ export const SESSION_QUERY_SQLITE_DEFAULT_LIMIT = 20 /** Maximum accepted result page size. */