Merge remote-tracking branch 'origin/master' into refactor/subagent

This commit is contained in:
Dudu-0223 committed 2026-09-21 11:59:58 +08:00
commit b3b0cd95cc
238 files changed
+6750 -2131

No files matched your search

+52 -19
View File
@@ -8,7 +8,7 @@ import { Context } from '@deepseek-ai/cordis'
import z from '@deepseek-ai/schemastery'
import { errorChain } from '@deepseek-ai/dsh-llm'
import type {} from '@deepseek-ai/dsh-client-file-upload'
import { canOpenNativePath, nativeFileManager, openNativeAssociatedPath, revealNativePath } from '@deepseek-ai/dsh-native-command'
import { canOpenNativePath, nativeFileManager, nativeFileApplications, openNativeFileApplication, openNativeAssociatedPath, revealNativePath } from '@deepseek-ai/dsh-native-command'
import type { SessionId } from '@deepseek-ai/dsh-session'
import type { SessionInspection } from '@deepseek-ai/dsh-session-persistence'
import { SessionQueryError, type SessionObservation } from '@deepseek-ai/dsh-session-query'
@@ -29,6 +29,7 @@ import { SessionSkillCatalog } from './skill-catalog.ts'
import { SessionMediaReferences } from './media-references.ts'
import type {
ModelCatalog,
SessionWorkspacePathApplication,
SessionAttachmentRequest,
SessionAttachmentValue,
SessionCancelRequest,
@@ -83,6 +84,10 @@ export interface Config {
export interface SessionControllerInternals {
/** Native default-application handoff. */
readonly openPath?: (path: string, signal: AbortSignal) => Promise<void>
/** Native file-association query. */
readonly fileApplications?: typeof nativeFileApplications
/** Explicit registered-application handoff. */
readonly openFileApplication?: typeof openNativeFileApplication
/** Native file-manager handoff. */
readonly revealPath?: (path: string, signal: AbortSignal) => Promise<void>
/** Native handoff availability probe. */
@@ -115,6 +120,8 @@ export class SessionController extends TypertRemoteService {
private readonly history: SessionHistoryController
private readonly listState: ApiSessionList
private readonly openPath: (path: string, signal: AbortSignal) => Promise<void>
private readonly fileApplications: typeof nativeFileApplications
private readonly openFileApplication: typeof openNativeFileApplication
private readonly revealPath: (path: string, signal: AbortSignal) => Promise<void>
private readonly canOpenPath: () => boolean
private readonly promotions = new Set<Promise<void>>()
@@ -142,6 +149,8 @@ export class SessionController extends TypertRemoteService {
}, 'session-controller.promotions')
this.history = new SessionHistoryController(ctx, (observation) => { this.promote(observation) })
this.listState = new ApiSessionList(ctx)
this.fileApplications = internals.fileApplications ?? nativeFileApplications
this.openFileApplication = internals.openFileApplication ?? openNativeFileApplication
this.openPath = internals.openPath ?? openNativeAssociatedPath
this.revealPath = internals.revealPath ?? revealNativePath
this.canOpenPath = internals.canOpenPath
@@ -309,35 +318,59 @@ export class SessionController extends TypertRemoteService {
request: SessionOpenWorkspacePathRequest,
signal: AbortSignal,
): Promise<SessionOpenWorkspacePathValue> {
if (request.path.length === 0) {
throw new RemoteError(
'gateway/bad-request',
'session.openWorkspacePath requires a non-empty path',
{},
)
}
signal.throwIfAborted()
try {
const hostPath = resolve(request.path)
const { fs } = this.ctx
const mapped = fs.processPathFromHostPath(hostPath)
if (mapped === undefined || fs.processPath(await fs.resolve(mapped, { signal })) !== hostPath) {
throw new Error('Path has no verified Host path')
}
signal.throwIfAborted()
if (request.action === 'reveal') await this.revealPath(request.path, signal)
else await this.openPath(request.path, signal)
const path = await this.verifyDesktopPath(request.path, signal)
if (request.action === 'reveal') await this.revealPath(path, signal)
else if (request.application !== undefined) await this.openFileApplication(path, request.application, signal)
else await this.openPath(path, signal)
return { opened: true }
} catch (error: unknown) {
if (signal.aborted) throw new RemoteError('gateway/cancelled', 'path open was aborted', {})
if (error instanceof RemoteError) throw error
throw new RemoteError(
'gateway/internal',
`path open failed: ${error instanceof Error ? error.message : String(error)}`,
'path open failed',
{},
{ cause: error },
)
}
}
/**
* Query current file handlers on the serving desktop without activating an Agent.
* @param request - file path in Host filesystem syntax.
* @param signal - caller lifetime, propagated to filesystem and desktop queries.
* @returns OS application names, icons, and default selection; empty when desktop opening is unavailable.
* @throws RemoteError when the path is invalid, the query is cancelled, or native discovery fails.
*/
@Remote('workspacePathApplications')
async workspacePathApplications(
request: { readonly path: string }, signal: AbortSignal,
): Promise<readonly SessionWorkspacePathApplication[]> {
if (!this.canOpenPath()) return []
try {
const path = await this.verifyDesktopPath(request.path, signal)
return await this.fileApplications(path, signal)
} catch (error: unknown) {
if (signal.aborted) throw new RemoteError('gateway/cancelled', 'application query was aborted', {})
if (error instanceof RemoteError) throw error
throw new RemoteError('gateway/internal', 'file application query failed', {}, { cause: error })
}
}
private async verifyDesktopPath(path: string, signal: AbortSignal): Promise<string> {
if (path.length === 0) throw new RemoteError('gateway/bad-request', 'A non-empty file path is required', {})
signal.throwIfAborted()
const hostPath = resolve(path)
const { fs } = this.ctx
const mapped = fs.processPathFromHostPath(hostPath)
if (mapped === undefined || fs.processPath(await fs.resolve(mapped, { signal })) !== hostPath) {
throw new RemoteError('gateway/bad-request', 'Path has no verified Host path', {})
}
signal.throwIfAborted()
return hostPath
}
/**
* Rename one Session after explicitly resuming it.
* @param request - Session identity and proposed title.
@@ -1,4 +1,5 @@
/** Browser-safe request, result, and lifecycle vocabulary for the Session Remote service. */
import type { NativeFileApplication } from '@deepseek-ai/dsh-native-command/types'
import type {
AttachmentIdType, ImageAttachmentLimits, ImageAttachmentRef, ImageMediaType,
@@ -381,6 +382,8 @@ export interface SessionCancelValue {
export interface SessionOpenWorkspacePathRequest {
/** File-manager navigation when requested; omission uses the default application. */
readonly action?: 'reveal'
/** Registered application identifier; ignored for reveal. Omission preserves the operating system default. */
readonly application?: string
/** Path after best-effort Session workspace resolution, in Host filesystem syntax. */
readonly path: string
}
@@ -624,3 +627,6 @@ declare module '@deepseek-ai/cordis' {
/** JSON-compatible projection value accepted by list consumers. */
export type SessionProjectionValue = JsonValue
/** Application metadata returned by the serving desktop for one file. */
export type SessionWorkspacePathApplication = NativeFileApplication