Merge latest master into PR 555

# Conflicts:
#	packages/host/apiproxy/README.i18n.yaml
This commit is contained in:
creatixchu
2026-07-31 19:55:58 +08:00
43 changed files with 203 additions and 135 deletions

View File

@@ -23,7 +23,7 @@ import { SessionQueryError, type SessionSearchCursor } from '@deepseek-ai/dsh-se
import type { Workspace, WorkspaceRecord } from '@deepseek-ai/dsh-workspace'
import {
workspaceDomainState, workspaceRecord, WorkspaceId as brandWorkspaceId,
WorkspaceMoveInvalidError, WorkspaceNameConflictError, WorkspaceUnknownSessionError,
WorkspaceMoveInvalidError, WorkspaceUnknownSessionError,
} from '@deepseek-ai/dsh-workspace'
// Type-only: brings the `ctx.tools` Context merge into this program (viewFor reads presenters).
import type {} from '@deepseek-ai/dsh-tools'
@@ -621,6 +621,14 @@ class SessionCwdConflict extends Error {
/** Host failed before the registry could adopt a name-created directory. */
class WorkspaceDirectoryCreationError extends Error {}
/** An explicit Host naming operation would duplicate another Workspace title. */
class WorkspaceNameConflictError extends Error {
constructor(readonly workspaceName: string) {
super(`workspace name '${workspaceName}' is already in use`)
this.name = 'WorkspaceNameConflictError'
}
}
/** Shared workspace-not-found error response of the workspace.* mutation rows. */
function workspaceNotFound<T>(request: RpcRequest<unknown>, workspaceId: string): RpcResponse<T> {
return err(request, {
@@ -669,7 +677,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
const resumes = new Map<SessionId, Promise<Agent>>()
/** Client-chosen identity creation/resume, deduplicated across concurrent retries. */
const sessionCreations = new Map<SessionId, Promise<Agent>>()
/** Serializes path ownership checks with record creation across spellings. */
/** Serializes path ownership and explicit title checks with Workspace mutations. */
let workspaceCreationChain = Promise.resolve()
const pendingQuestions = new Map<RpcId, PendingQuestion>()
const pendingApprovals = new Map<RpcId, PendingApproval>()

View File

@@ -22,7 +22,7 @@ export interface WorkspaceView {
workspaceId: WorkspaceId
/** Canonical directory path (host-side realpath canon). */
path: string
/** Unique display title (defaults to the path basename at create). */
/** Display title (defaults to the path basename at create). */
title: string
/**
* Sessions accounted under this workspace, in manually owned order
@@ -53,8 +53,8 @@ export interface WorkspaceApi {
* root before registering. Either spelling resolving to a directory already
* owned by a workspace returns that workspace (`created: false`) for the
* existing-folder spelling. Create-by-name rejects an existing title with
* `workspace-name-conflict`; a new path whose basename duplicates another
* Workspace title is rejected by the registry with the same code.
* `workspace-name-conflict`; path adoption allows distinct canonical paths
* whose basenames produce the same display title.
* A new name-created workspace uses `name` as both directory name and title;
* a path-created workspace uses the registry's basename title default.
*/