fix(workspace): keep the default Workspace path language-neutral

The first-use directory name and its stored title came from the Client's
startup language, so one product decision carried two incompatible
requirements: a path addressed by shell commands, tool arguments, @path
references, and session logs, and a label a reader reads.

The controller now owns the fixed `default-workspace` directory name and
the registry titles the Workspace after that same segment, so
`workspace.initializeDefault` takes no request at all —
WorkspaceInitializeDefaultRequest and its name validation are gone, and
the registry resolver returns a path instead of a path and title. No
language reaches the Host.

Browser consumers label a Workspace through the new
`workspaceDisplayTitle`: a title still equal to the automatic one reads
as the localized default name from the `common` namespace, every other
title reads verbatim. The Workspace browser resolves it once at the store
read, so rows, hover card, search meta, and the rename and delete dialogs
inherit it; the hero picker and the Conversation chip resolve it too.
Confirming a rename stores the text on screen, which is what stops a row
following the language.
This commit is contained in:
_Kerman committed 2026-09-23 17:46:32 +08:00
1 parent 5e25475857
commit ff1c7d415f
53 files changed
+297 -195

No files matched your search

@@ -19,7 +19,7 @@ export { WorkspaceArchiveError, WorkspaceController, WorkspaceCreateError } from
export type { IWorkspaces, WorkspaceSource } from './service.ts'
export type {
SessionActivity, SessionActivityItem, SessionActivityKind, SessionActivityKindMap, WorkspaceId,
WorkspaceInitializeDefaultRequest, WorkspaceView,
WorkspaceView,
} from '../types.ts'
type WorkspaceBaselineFrame = Extract<WorkspaceFollowFrame, { type: 'baseline' }>
@@ -12,7 +12,6 @@ import type {
WorkspaceCreateValue,
WorkspaceDeleteValue,
WorkspaceInsertSessionBeforeRequest,
WorkspaceInitializeDefaultRequest,
WorkspaceOrderValue,
WorkspacePinSessionRequest,
WorkspacePinValue,
@@ -104,14 +103,11 @@ export class ClientWorkspaceModel implements WorkspaceFollowSink {
/**
* Initialize the default Workspace and merge its authoritative row.
* @param request - initial directory name and title.
* @param signal - caller lifetime.
* @returns generated Remote result.
*/
async initializeDefault(
request: WorkspaceInitializeDefaultRequest, signal?: AbortSignal,
): Promise<RemoteResult<WorkspaceValue | undefined>> {
const result = await this.remote.initializeDefault(request, signal)
async initializeDefault(signal?: AbortSignal): Promise<RemoteResult<WorkspaceValue | undefined>> {
const result = await this.remote.initializeDefault(signal)
if (result.ok && result.value !== undefined) this.upsert(result.value.workspace)
return result
}
@@ -4,7 +4,7 @@ import { Service, type Context } from '@deepseek-ai/cordis'
import type { SessionId } from '@deepseek-ai/dsh-session/types'
import type { RemoteFailure } from '@deepseek-ai/dsh-typert-protocol'
import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types'
import type { WorkspaceInitializeDefaultRequest, WorkspaceView } from '../types.ts'
import type { WorkspaceView } from '../types.ts'
import type { ClientWorkspaceModel, WorkspaceSnapshot } from './model.ts'
/** Structured create failure for callers that distinguish Host business errors. */
@@ -55,11 +55,10 @@ export interface IWorkspaces {
create(input: { path: string }): Promise<WorkspaceView>
/**
* Initialize or reuse the default Workspace.
* @param request - initial directory name and title.
* @param signal - caller lifetime.
* @returns the prepared Workspace, or undefined when first-use initialization is ineligible; rejects on preparation failure.
*/
initializeDefault(request: WorkspaceInitializeDefaultRequest, signal?: AbortSignal): Promise<WorkspaceView | undefined>
initializeDefault(signal?: AbortSignal): Promise<WorkspaceView | undefined>
/**
* Rename a Workspace.
* @param workspaceId - target Workspace.
@@ -134,8 +133,8 @@ export class WorkspaceController extends Service implements IWorkspaces {
return result.value.workspace
}
async initializeDefault(request: WorkspaceInitializeDefaultRequest, signal?: AbortSignal): Promise<WorkspaceView | undefined> {
const result = await this.model.initializeDefault(request, signal)
async initializeDefault(signal?: AbortSignal): Promise<WorkspaceView | undefined> {
const result = await this.model.initializeDefault(signal)
if (!result.ok) throw new WorkspaceCreateError(result.error)
return result.value?.workspace
}