Bladeren bron

refactor(apiproxy)!: remove directory-picker RPCs

imccyu 1 maand geleden
bovenliggende
commit
6e4087626d

+ 0 - 17
packages/api/session-controller/tests/fake-api.client.ts

@@ -167,23 +167,9 @@ export class FakeApiClient implements IApiClient {
     () => Promise.resolve(ok({
       version: '0-fake', cwd: '/f', attachedSessions: 0, home: '/h', canOpenPath: true,
     }))
-  onPickDirectory: (payload: unknown) => Promise<RpcResponse<{ path: string | null }>> =
-    () => Promise.resolve(ok({ path: null }))
   onOpenPath: (payload: unknown) => Promise<RpcResponse<{ opened: true }>> =
     () => Promise.resolve(ok({ opened: true as const }))
 
-  onListDirectory: (payload: unknown) => Promise<RpcResponse<{
-    path: string
-    home: string
-    crumbs: { name: string; path: string; hidden: boolean }[]
-    entries: { name: string; path: string; hidden: boolean }[]
-    truncated: boolean
-  }>> =
-    () => Promise.resolve(ok({ path: '/home/fake', home: '/home/fake', crumbs: [{ name: '/', path: '/', hidden: false }], entries: [], truncated: false }))
-
-  onCreateDirectory: (payload: unknown) => Promise<RpcResponse<{ path: string }>> =
-    () => Promise.resolve(ok({ path: '/home/fake/new' }))
-
   private readonly followConns = new Map<SessionId, ValueStreamConn<SessionFollowFrame>[]>()
   private readonly controlConns: ValueStreamConn<SessionControlFrame>[] = []
   private readonly workspaceConns: ValueStreamConn<WorkspaceFollowFrame>[] = []
@@ -210,9 +196,6 @@ export class FakeApiClient implements IApiClient {
 
   readonly host: IApiClient['host'] = {
     describe: (payload: unknown) => this.record('host.describe', payload, this.onDescribe(payload)),
-    pickDirectory: (payload: unknown) => this.record('host.pickDirectory', payload, this.onPickDirectory(payload)),
-    listDirectory: (payload: unknown) => this.record('host.listDirectory', payload, this.onListDirectory(payload)),
-    createDirectory: (payload: unknown) => this.record('host.createDirectory', payload, this.onCreateDirectory(payload)),
     openPath: (payload: unknown) => this.record('host.openPath', payload, this.onOpenPath(payload)),
   }
 

+ 0 - 1
packages/client/connection/src/client/api.ts

@@ -7,7 +7,6 @@
 
 export type {
   ApiProxy, HostApi,
-  DirectoryEntry, DirectoryListing,
   ResponseValue,
   SkillsApi, SkillEntry,
   ModelCatalog, ModelCatalogFailure, ModelCatalogModel, ModelProviderGroup, ModelReasoning,

+ 0 - 39
packages/client/connection/src/client/fixture.ts

@@ -3314,42 +3314,6 @@ function createFixtureWorld(options: FixtureOptions): FixtureWorld {
       describe: request => ok(request, {
         version: '0.0.0-fixture', cwd: '/tmp/fixture', attachedSessions, home: FIXTURE_HOME, canOpenPath: true,
       }),
-      // Deterministic native pick: the keyless lanes drive the full
-      // pick-then-adopt path without an OS chooser (design-mock content,
-      // same tree the browse primitives serve).
-      pickDirectory: request => ok(request, { path: `${FIXTURE_HOME}/Documents/project` }),
-      listDirectory: (request) => {
-        const target = request.payload.path ?? FIXTURE_HOME
-        const children = childrenOf(target)
-        if (children === undefined) {
-          return err(request, { code: 'directory-unreadable', message: `cannot list ${target}: not in the fixture tree`, details: { path: target } })
-        }
-        return ok(request, {
-          path: target,
-          home: FIXTURE_HOME,
-          crumbs: crumbsOf(target),
-          entries: [...children].sort((a, b) => a.localeCompare(b))
-            .map(name => ({ name, path: target === '/' ? `/${name}` : `${target}/${name}`, hidden: name.startsWith('.') })),
-          // The fixture tree is tiny; no level ever reaches a backend bound.
-          truncated: false,
-        })
-      },
-      createDirectory: (request) => {
-        const parent = request.payload.path
-        const children = childrenOf(parent)
-        if (children === undefined) {
-          return err(request, { code: 'directory-create-failed', message: `missing parent ${parent}`, details: { path: parent } })
-        }
-        // Same root special case as listDirectory's entry paths: a plain join
-        // under '/' would mint '//name' and fork the tree's identity.
-        const target = parent === '/' ? `/${request.payload.name}` : `${parent}/${request.payload.name}`
-        if (children.includes(request.payload.name)) {
-          return err(request, { code: 'directory-exists', message: `${target} already exists`, details: { path: target } })
-        }
-        directoryTree.set(parent, [...children, request.payload.name])
-        directoryTree.set(target, [])
-        return ok(request, { path: target })
-      },
       openPath: request => ok(request, { opened: true as const }),
     },
     agentPresets: {
@@ -3652,9 +3616,6 @@ export class FixtureApiClient extends AbstractApiClient {
   ): Promise<RpcResponse<unknown>> {
     switch (method) {
       case 'host.describe': return this.api.host.describe(request)
-      case 'host.pickDirectory': return this.api.host.pickDirectory(request, new AbortController().signal)
-      case 'host.listDirectory': return this.api.host.listDirectory(request, new AbortController().signal)
-      case 'host.createDirectory': return this.api.host.createDirectory(request)
       case 'host.openPath': return this.api.host.openPath(request, new AbortController().signal)
       case 'skill.list': return this.api.skills.list(request)
       case 'agentPreset.openDocument': return this.api.agentPresets.openDocument(request, new AbortController().signal)

+ 0 - 1
packages/client/connection/src/client/index.ts

@@ -31,7 +31,6 @@ declare module '@deepseek-ai/cordis' {
 // ---- Contract re-exports (browser-safe apiproxy channels + core types) ----
 export type {
   ApiProxy, HostApi,
-  DirectoryEntry, DirectoryListing,
   SkillsApi, SkillEntry,
   ModelCatalog, ModelCatalogFailure, ModelCatalogModel, ModelProviderGroup, ModelReasoning,
   MessageId, ModelReasoningEffort, ModelSelection,

+ 0 - 17
packages/client/connection/tests/fake-api.client.ts

@@ -50,30 +50,13 @@ export class FakeApiClient implements IApiClient {
     () => Promise.resolve(ok({
       version: '0-fake', cwd: '/f', attachedSessions: 0, home: '/h', canOpenPath: true,
     }))
-  onPickDirectory: (payload: unknown) => Promise<RpcResponse<{ path: string | null }>> =
-    () => Promise.resolve(ok({ path: null }))
   onOpenPath: (payload: unknown) => Promise<RpcResponse<{ opened: true }>> =
     () => Promise.resolve(ok({ opened: true as const }))
 
-  onListDirectory: (payload: unknown) => Promise<RpcResponse<{
-    path: string
-    home: string
-    crumbs: { name: string; path: string; hidden: boolean }[]
-    entries: { name: string; path: string; hidden: boolean }[]
-    truncated: boolean
-  }>> =
-    () => Promise.resolve(ok({ path: '/home/fake', home: '/home/fake', crumbs: [{ name: '/', path: '/', hidden: false }], entries: [], truncated: false }))
-
-  onCreateDirectory: (payload: unknown) => Promise<RpcResponse<{ path: string }>> =
-    () => Promise.resolve(ok({ path: '/home/fake/new' }))
-
   private readonly generationConns: StreamConn[] = []
 
   readonly host: IApiClient['host'] = {
     describe: payload => this.record('host.describe', payload, this.onDescribe(payload)),
-    pickDirectory: payload => this.record('host.pickDirectory', payload, this.onPickDirectory(payload)),
-    listDirectory: payload => this.record('host.listDirectory', payload, this.onListDirectory(payload)),
-    createDirectory: payload => this.record('host.createDirectory', payload, this.onCreateDirectory(payload)),
     openPath: payload => this.record('host.openPath', payload, this.onOpenPath(payload)),
   }
 

+ 2 - 2
packages/client/connection/tests/node-half.host.spec.ts

@@ -174,7 +174,7 @@ describe('connection node half', () => {
   it('requires the same browser session for every method on every trusted authority', async () => {
     const { routes, connection, dispose } = await mounted({ trustedHosts: ['harness.example'] })
     const methods = [
-      'host.pickDirectory', 'host.openPath',
+      'host.openPath',
       'settings.describe', 'settings.update', 'credentials.describe', 'credentials.set',
       'llm.discoverModels', 'llm.models', 'agentPreset.openDocument',
     ]
@@ -503,7 +503,7 @@ describe('connection node half over a real HTTP server', () => {
       const methods = [
         'settings.describe', 'settings.openDocument', 'settings.update', 'settings.replace', 'settings.mutate',
         'credentials.describe', 'credentials.set', 'credentials.unset',
-        'host.pickDirectory', 'host.openPath',
+        'host.openPath',
         'llm.discoverModels',
         'agentPreset.openDocument',
         'llm.providers', 'llm.models',

+ 0 - 75
packages/host/apiproxy/src/api-proxy.ts

@@ -41,7 +41,6 @@ import type { SettingsDescriptor, SettingsNamespace, SettingsPathOp } from '@dee
 import { credentialRef } from '@deepseek-ai/dsh-credentials'
 import type { ScopeKey } from '@deepseek-ai/dsh-scope'
 import type { RpcError, RpcRequest, RpcResponse } from './api/rpc.ts'
-import { DirectoryPickerError } from '@deepseek-ai/dsh-host-directory-picker'
 import { canOpenNativePath, openNativePath, openNativeTextFile } from './native-path-opener.ts'
 
 /** Read live abort state across awaits without treating it as synchronously immutable. */
@@ -59,14 +58,6 @@ function err<T>(request: RpcRequest<unknown>, error: RpcError): RpcResponse<T> {
   return { rpcId: request.rpcId, result: { ok: false, error } }
 }
 
-/** Map a browse-primitive failure onto the wire error vocabulary (unknown throws stay internal). */
-function directoryError(error: unknown): RpcError {
-  if (error instanceof DirectoryPickerError) {
-    return { code: error.code, message: error.message, details: { path: error.path } }
-  }
-  return { code: 'internal', message: error instanceof Error ? error.message : String(error), details: {} }
-}
-
 /** Deployment metadata and Host integrations consumed by the API implementation. */
 export interface ApiProxyDefaults {
   /** Current deployment model selection reported by `host.describe`. */
@@ -290,72 +281,6 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
         }))
       },
 
-      async pickDirectory(request, signal) {
-        const capability = ctx.directoryPicker.capability()
-        if (capability.kind !== 'native') {
-          return err(request, {
-            code: 'directory-picker-unavailable',
-            message: `host.pickDirectory needs the native capability; the composed picker serves "${capability.kind}"`,
-            details: { capability: capability.kind },
-          })
-        }
-        try {
-          const path = await capability.pick(signal)
-          return ok(request, { path })
-        } catch (error: unknown) {
-          if (signal.aborted) {
-            return err(request, {
-              code: 'cancelled',
-              message: 'directory picker was aborted',
-              details: {},
-            })
-          }
-          return err(request, {
-            code: 'internal',
-            message: `directory picker failed: ${error instanceof Error ? error.message : String(error)}`,
-            details: {},
-          })
-        }
-      },
-
-      async listDirectory(request, signal) {
-        const capability = ctx.directoryPicker.capability()
-        if (capability.kind !== 'browse') {
-          return err(request, {
-            code: 'directory-picker-unavailable',
-            message: `host.listDirectory needs the browse capability; the composed picker serves "${capability.kind}"`,
-            details: { capability: capability.kind },
-          })
-        }
-        try {
-          // The carrier's signal follows the caller: a disconnect or timeout
-          // stops the backend's directory scan instead of outliving it.
-          return ok(request, await capability.list(request.payload.path, signal))
-        } catch (error: unknown) {
-          // An abort is the caller's own timeout/disconnect, not a server failure.
-          if (signal.aborted) {
-            return err(request, { code: 'cancelled', message: 'directory listing was aborted', details: {} })
-          }
-          return err(request, directoryError(error))
-        }
-      },
-
-      async createDirectory(request) {
-        const capability = ctx.directoryPicker.capability()
-        if (capability.kind !== 'browse') {
-          return err(request, {
-            code: 'directory-picker-unavailable',
-            message: `host.createDirectory needs the browse capability; the composed picker serves "${capability.kind}"`,
-            details: { capability: capability.kind },
-          })
-        }
-        try {
-          return ok(request, { path: await capability.createDirectory(request.payload.path, request.payload.name) })
-        } catch (error: unknown) {
-          return err(request, directoryError(error))
-        }
-      },
-
       async openPath(request, signal) {
         return openPath(request, request.payload.path, signal)
       },

+ 0 - 44
packages/host/apiproxy/src/api/host.schema.ts

@@ -3,7 +3,6 @@
  */
 
 import { z } from 'zod'
-import type { DirectoryEntry } from './host.ts'
 import type { RequestPayload, ResponseValue } from './rpc-map.ts'
 import type { Wire } from './rpc.schema.ts'
 
@@ -21,49 +20,6 @@ export const hostDescribeValueSchema = z.object({
   canOpenPath: z.boolean(),
 }) satisfies z.ZodType<Wire<ResponseValue<'host.describe'>>>
 
-/** host.pickDirectory request payload (empty object literal). */
-export const hostPickDirectoryRequestSchema = z.object({}) satisfies z.ZodType<Wire<RequestPayload<'host.pickDirectory'>>>
-
-/** host.pickDirectory response value; null means the user cancelled. */
-export const hostPickDirectoryValueSchema = z.object({
-  path: z.string().nullable(),
-}) satisfies z.ZodType<Wire<ResponseValue<'host.pickDirectory'>>>
-
-/** Directory row shared by listing entries and breadcrumb crumbs. */
-export const directoryEntrySchema = z.object({
-  name: z.string(),
-  path: z.string(),
-  hidden: z.boolean(),
-}) satisfies z.ZodType<Wire<DirectoryEntry>>
-
-/** host.listDirectory request payload; an absent path lists the home directory. */
-export const hostListDirectoryRequestSchema = z.object({
-  path: z.string().optional(),
-}) satisfies z.ZodType<Wire<RequestPayload<'host.listDirectory'>>>
-
-/** host.listDirectory response value. */
-export const hostListDirectoryValueSchema = z.object({
-  path: z.string(),
-  home: z.string(),
-  crumbs: z.array(directoryEntrySchema),
-  entries: z.array(directoryEntrySchema),
-  truncated: z.boolean(),
-}) satisfies z.ZodType<Wire<ResponseValue<'host.listDirectory'>>>
-
-/** host.createDirectory request payload: name must be one plain path segment. */
-export const hostCreateDirectoryRequestSchema = z.object({
-  path: z.string(),
-  name: z.string(),
-}).refine(
-  payload => payload.name.trim() !== '' && payload.name !== '.' && payload.name !== '..'
-    && !/[/\\]/.test(payload.name),
-  { message: 'host.createDirectory requires a single non-blank path segment name' },
-) satisfies z.ZodType<Wire<RequestPayload<'host.createDirectory'>>>
-
-/** host.createDirectory response value: the created directory's absolute path. */
-export const hostCreateDirectoryValueSchema = z.object({
-  path: z.string(),
-}) satisfies z.ZodType<Wire<ResponseValue<'host.createDirectory'>>>
 /** host.openPath request payload. */
 export const hostOpenPathRequestSchema = z.object({
   path: z.string().min(1),

+ 0 - 58
packages/host/apiproxy/src/api/host.ts

@@ -5,33 +5,6 @@
 
 import type { RpcRequest, RpcResponse } from './rpc.ts'
 
-/** One directory row of a listing: a child entry or a breadcrumb ancestor. */
-export interface DirectoryEntry {
-  /** Base name shown in a browser row (a root crumb carries its full path). */
-  name: string
-  /** Absolute host path — the client never joins path segments itself. */
-  path: string
-  /** Hidden by the host platform's convention (dot-prefixed on POSIX); the client owns whether to show it. */
-  hidden: boolean
-}
-
-/** host.listDirectory response value: one directory level plus its ancestry. */
-export interface DirectoryListing {
-  /** Absolute path of the listed directory. */
-  path: string
-  /** The host account's home directory (breadcrumb "Home" rooting). */
-  home: string
-  /**
-   * Ancestor chain from the filesystem root to the listed directory
-   * inclusive; every crumb is a jump target (crumb `hidden` is always false).
-   */
-  crumbs: DirectoryEntry[]
-  /** Direct child directories, name-sorted; symlinks to directories included. */
-  entries: DirectoryEntry[]
-  /** True when the backend cut `entries` at its complete-result bound (the name-sorted tail is absent). */
-  truncated: boolean
-}
-
 /** Host-level unary methods. */
 export interface HostApi {
   /**
@@ -54,37 +27,6 @@ export interface HostApi {
     canOpenPath: boolean
   }>>
 
-  /**
-   * Open the operating system's single-directory picker; cancellation returns
-   * null. Only served under the `native` capability.
-   */
-  pickDirectory(
-    request: RpcRequest<{}>,
-    signal: AbortSignal,
-  ): Promise<RpcResponse<{ path: string | null }>>
-
-  /**
-   * List one directory level for the in-app browser; an absent path lists the
-   * host account's home directory. Only served under the `browse` capability;
-   * unreadable or missing targets fail with `directory-unreadable`. The
-   * carrier's request signal follows the caller, stopping the backend's scan
-   * on disconnect or timeout.
-   */
-  listDirectory(
-    request: RpcRequest<{ path?: string }>,
-    signal: AbortSignal,
-  ): Promise<RpcResponse<DirectoryListing>>
-
-  /**
-   * Create one child directory under an existing parent (the browser's
-   * "New folder"). Only served under the `browse` capability; an existing
-   * child fails with `directory-exists`, every other filesystem failure with
-   * `directory-create-failed`.
-   */
-  createDirectory(
-    request: RpcRequest<{ path: string; name: string }>,
-  ): Promise<RpcResponse<{ path: string }>>
-
   /**
    * Open a filesystem path with the operating system's default application
    * (Finder / Explorer / xdg-open hand-off). The browser carrier's

+ 1 - 1
packages/host/apiproxy/src/api/index.ts

@@ -29,7 +29,7 @@ export type {
   ModelCatalog, ModelCatalogFailure, ModelCatalogModel, ModelProviderGroup, ModelReasoning,
   ModelReasoningEffort, ModelSelection,
 } from '@deepseek-ai/dsh-api-session-controller/types'
-export type { DirectoryEntry, DirectoryListing, HostApi } from './host.ts'
+export type { HostApi } from './host.ts'
 export type { SkillsApi, SkillEntry } from './skills.ts'
 export type { AgentPresetsApi } from './agent-presets.ts'
 export type { SettingsApi, SettingsNamespaceView, SettingsPathOpView, SettingsSecretView } from './settings.ts'

+ 0 - 3
packages/host/apiproxy/src/api/rpc-map.ts

@@ -18,9 +18,6 @@ import type { RpcResponse } from './rpc.ts'
  */
 export interface RpcMethodMap {
   'host.describe': HostApi['describe']
-  'host.pickDirectory': HostApi['pickDirectory']
-  'host.listDirectory': HostApi['listDirectory']
-  'host.createDirectory': HostApi['createDirectory']
   'host.openPath': HostApi['openPath']
   'skill.list': SkillsApi['list']
   'agentPreset.openDocument': AgentPresetsApi['openDocument']

+ 0 - 4
packages/host/apiproxy/src/api/rpc.schema.ts

@@ -36,10 +36,6 @@ export const rpcErrorSchema: z.ZodType<RpcError> = z.discriminatedUnion('code',
   z.object({ code: z.literal('cancelled'), message: z.string(), details: z.object({}) }),
   z.object({ code: z.literal('session-not-found'), message: z.string(), details: z.object({ sessionId: z.string() }) }),
   z.object({ code: z.literal('invalid-time-zone'), message: z.string(), details: z.object({ value: z.string() }) }),
-  z.object({ code: z.literal('directory-unreadable'), message: z.string(), details: z.object({ path: z.string() }) }),
-  z.object({ code: z.literal('directory-exists'), message: z.string(), details: z.object({ path: z.string() }) }),
-  z.object({ code: z.literal('directory-create-failed'), message: z.string(), details: z.object({ path: z.string() }) }),
-  z.object({ code: z.literal('directory-picker-unavailable'), message: z.string(), details: z.object({ capability: z.string() }) }),
   z.object({ code: z.literal('agent-preset-read-only'), message: z.string(), details: z.object({ agentPreset: z.string(), reason: z.string() }) }),
   z.object({ code: z.literal('agent-preset-locked'), message: z.string(), details: z.object({ sessionId: z.string(), agentPreset: z.string() }) }),
   z.object({ code: z.literal('agent-preset-not-found'), message: z.string(), details: z.object({ agentPreset: z.string(), available: z.array(z.string()) }) }),

+ 0 - 4
packages/host/apiproxy/src/api/rpc.ts

@@ -31,10 +31,6 @@ export interface RpcErrorDetailsMap {
   'cancelled': {}
   'session-not-found': { sessionId: SessionId }
   'invalid-time-zone': { value: string }
-  'directory-unreadable': { path: string }
-  'directory-exists': { path: string }
-  'directory-create-failed': { path: string }
-  'directory-picker-unavailable': { capability: string }
   'agent-preset-read-only': { agentPreset: string; reason: string }
   'agent-preset-locked': { sessionId: SessionId; agentPreset: string }
   'agent-preset-not-found': { agentPreset: string; available: readonly string[] }

+ 8 - 29
packages/host/apiproxy/src/fetch/client.ts

@@ -13,8 +13,7 @@ import { RpcId } from '../api/rpc.ts'
 import type { Wire } from '../api/rpc.schema.ts'
 import { serverResponseSchema } from '../api/rpc.schema.ts'
 import {
-  hostCreateDirectoryValueSchema, hostDescribeValueSchema,
-  hostListDirectoryValueSchema, hostOpenPathValueSchema, hostPickDirectoryValueSchema,
+  hostDescribeValueSchema, hostOpenPathValueSchema,
 } from '../api/host.schema.ts'
 import { skillListValueSchema } from '../api/skills.schema.ts'
 import {
@@ -44,9 +43,6 @@ import { llmDiscoverModelsValueSchema, llmModelsValueSchema, llmProvidersValueSc
 export interface IApiClient {
   host: {
     describe(payload: RequestPayload<'host.describe'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'host.describe'>>>
-    pickDirectory(payload: RequestPayload<'host.pickDirectory'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'host.pickDirectory'>>>
-    listDirectory(payload: RequestPayload<'host.listDirectory'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'host.listDirectory'>>>
-    createDirectory(payload: RequestPayload<'host.createDirectory'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'host.createDirectory'>>>
     openPath(payload: RequestPayload<'host.openPath'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'host.openPath'>>>
   }
   skills: {
@@ -80,9 +76,6 @@ export interface IApiClient {
  */
 const UNARY_VALUE_SCHEMAS: { [K in keyof RpcMethodMap]: z.ZodType<Wire<ResponseValue<K>>> } = {
   'host.describe': hostDescribeValueSchema,
-  'host.pickDirectory': hostPickDirectoryValueSchema,
-  'host.listDirectory': hostListDirectoryValueSchema,
-  'host.createDirectory': hostCreateDirectoryValueSchema,
   'host.openPath': hostOpenPathValueSchema,
   'skill.list': skillListValueSchema,
   'agentPreset.openDocument': agentPresetOpenDocumentValueSchema,
@@ -102,9 +95,6 @@ const UNARY_VALUE_SCHEMAS: { [K in keyof RpcMethodMap]: z.ZodType<Wire<ResponseV
 /** Default timeout for bounded unary calls (rpc-compare 2026-07-19: a hung host must not leave callers pending forever). */
 const DEFAULT_TIMEOUT_MS = 30_000
 
-/** Whether a unary call uses the transport health deadline or only caller/connection cancellation. */
-type UnaryTimeoutPolicy = 'default' | 'caller-signal-only'
-
 /** URL base for in-process handler injection (fake authority, opencode precedent). */
 const INTERNAL_BASE = 'http://dsh.internal'
 
@@ -122,7 +112,7 @@ export abstract class AbstractApiClient implements IApiClient {
   private flushScheduled = false
   private readonly envelopeListeners = new Set<(batch: readonly RpcMessage[]) => void>()
 
-  /** @param timeoutMs - timeout for bounded unary calls; user-paced calls do not use it. */
+  /** @param timeoutMs - timeout for unary calls. */
   constructor(protected readonly timeoutMs: number = DEFAULT_TIMEOUT_MS) {}
 
   /** Transport aspect: browser fetch, injected handler.fetch, IPC bridge, ... */
@@ -178,24 +168,21 @@ export abstract class AbstractApiClient implements IApiClient {
 
   /**
    * Shared POST leg of unary calls: JSON body,
-   * optional default timeout merged with the caller's external signal, non-2xx → transport throw.
+   * default timeout merged with the caller's external signal, non-2xx → transport throw.
    */
   private async postJson(
     path: string,
     body: ClientRequest,
     signal: AbortSignal | undefined,
-    timeoutPolicy: UnaryTimeoutPolicy = 'default',
   ): Promise<Response> {
-    const requestSignal = timeoutPolicy === 'default'
-      ? signal === undefined
-        ? AbortSignal.timeout(this.timeoutMs)
-        : AbortSignal.any([AbortSignal.timeout(this.timeoutMs), signal])
-      : signal
+    const requestSignal = signal === undefined
+      ? AbortSignal.timeout(this.timeoutMs)
+      : AbortSignal.any([AbortSignal.timeout(this.timeoutMs), signal])
     const response = await this.doFetch(new URL(path, this.resolveBase()), {
       method: 'POST',
       headers: { 'content-type': 'application/json' },
       body: JSON.stringify(body),
-      ...requestSignal === undefined ? {} : { signal: requestSignal },
+      signal: requestSignal,
     })
     if (!response.ok) throw new Error(`transport failure for ${path}: HTTP ${response.status}`)
     return response
@@ -210,11 +197,10 @@ export abstract class AbstractApiClient implements IApiClient {
     method: K,
     payload: RequestPayload<K>,
     signal?: AbortSignal,
-    timeoutPolicy: UnaryTimeoutPolicy = 'default',
   ): Promise<RpcResponse<ResponseValue<K>>> {
     const message: ClientRequest = { type: 'client-request', rpcId: this.mintRpcId(), method, payload }
     this.onEnvelope(message)
-    const response = await this.postJson(`/api/${method}`, message, signal, timeoutPolicy)
+    const response = await this.postJson(`/api/${method}`, message, signal)
     const full = serverResponseSchema.parse(await response.json())
     this.onEnvelope(full)
     if (full.rpcId !== message.rpcId) throw new Error(`rpcId mismatch for ${method}: sent ${message.rpcId}, got ${full.rpcId}`)
@@ -229,13 +215,6 @@ export abstract class AbstractApiClient implements IApiClient {
 
   readonly host: IApiClient['host'] = {
     describe: (payload, signal) => this.callUnary('host.describe', payload, signal),
-    // A native system dialog is user-paced and may legitimately stay open
-    // longer than the normal unary deadline. Caller/connection aborts remain.
-    pickDirectory: (payload, signal) => this.callUnary(
-      'host.pickDirectory', payload, signal, 'caller-signal-only',
-    ),
-    listDirectory: (payload, signal) => this.callUnary('host.listDirectory', payload, signal),
-    createDirectory: (payload, signal) => this.callUnary('host.createDirectory', payload, signal),
     openPath: (payload, signal) => this.callUnary('host.openPath', payload, signal),
   }
 

+ 1 - 6
packages/host/apiproxy/src/fetch/handler.ts

@@ -15,9 +15,7 @@ import { RpcId } from '../api/rpc.ts'
 import type { Wire } from '../api/rpc.schema.ts'
 import { clientRequestSchema } from '../api/rpc.schema.ts'
 import {
-  hostCreateDirectoryRequestSchema, hostDescribeRequestSchema,
-  hostListDirectoryRequestSchema, hostOpenPathRequestSchema,
-  hostPickDirectoryRequestSchema,
+  hostDescribeRequestSchema, hostOpenPathRequestSchema,
 } from '../api/host.schema.ts'
 import { skillListRequestSchema } from '../api/skills.schema.ts'
 import {
@@ -50,9 +48,6 @@ type UnaryRoutes = {
 
 const UNARY_ROUTES: UnaryRoutes = {
   'host.describe': { schema: hostDescribeRequestSchema, invoke: (api, r) => api.host.describe(r) },
-  'host.pickDirectory': { schema: hostPickDirectoryRequestSchema, invoke: (api, r, signal) => api.host.pickDirectory(r, signal) },
-  'host.listDirectory': { schema: hostListDirectoryRequestSchema, invoke: (api, r, signal) => api.host.listDirectory(r, signal) },
-  'host.createDirectory': { schema: hostCreateDirectoryRequestSchema, invoke: (api, r) => api.host.createDirectory(r) },
   'host.openPath': { schema: hostOpenPathRequestSchema, invoke: (api, r, signal) => api.host.openPath(r, signal) },
   'skill.list': { schema: skillListRequestSchema, invoke: (api, r) => api.skills.list(r) },
   'agentPreset.openDocument': { schema: agentPresetOpenDocumentRequestSchema, invoke: (api, r, signal) => api.agentPresets.openDocument(r, signal) },

+ 1 - 0
packages/host/apiproxy/src/index.ts

@@ -15,6 +15,7 @@ import { Context, Service } from '@deepseek-ai/cordis'
 import z from '@deepseek-ai/schemastery'
 import type {} from '@deepseek-ai/dsh-agent-default-model'
 import type {} from '@deepseek-ai/dsh-api-session-controller'
+import type {} from '@deepseek-ai/dsh-host-directory-picker'
 import type { ApiProxy } from './api/index.ts'
 import { createApiProxy } from './api-proxy.ts'
 import {

+ 4 - 133
packages/host/apiproxy/tests/api-proxy-host.spec.ts

@@ -2,8 +2,6 @@ import { homedir } from 'node:os'
 import { afterEach, describe, expect, it } from 'vitest'
 import { Context } from '@deepseek-ai/cordis'
 import AgentRegistry from '@deepseek-ai/dsh-agent'
-import { DirectoryPickerError } from '@deepseek-ai/dsh-host-directory-picker'
-import type { DirectoryPickerCapability } from '@deepseek-ai/dsh-host-directory-picker'
 import type { RpcRequest } from '@deepseek-ai/dsh-host-apiproxy/api/rpc'
 import { RpcId } from '@deepseek-ai/dsh-host-apiproxy/api/rpc'
 import { createApiProxy } from '../src/api-proxy.ts'
@@ -26,7 +24,6 @@ function expectOk<T>(response: { readonly result: { readonly ok: true; readonly
 }
 
 async function harness(
-  picker: DirectoryPickerCapability = { kind: 'native', pick: async () => null },
   extras: {
     openPath?: (path: string, signal: AbortSignal) => Promise<void>
     canOpenPath?: () => boolean
@@ -35,7 +32,6 @@ async function harness(
   const ctx = new Context()
   contexts.push(ctx)
   await ctx.plugin(AgentRegistry)
-  ctx.provide('directoryPicker', { capability: () => picker } as never)
   const api = createApiProxy(ctx, {
     defaultModelSelection: () => ({ provider: 'test', model: 'test-model' }),
     cwd: '/tmp/dsh-apiproxy-host',
@@ -45,135 +41,10 @@ async function harness(
   return { api }
 }
 
-describe('host.pickDirectory', () => {
-  it('returns a selected path or explicit cancellation from the native capability', async () => {
-    const selected = await harness({ kind: 'native', pick: async () => '/tmp/project' })
-    expect((await selected.api.host.pickDirectory(request({}), new AbortController().signal)).result)
-      .toEqual({ ok: true, value: { path: '/tmp/project' } })
-
-    const cancelled = await harness({ kind: 'native', pick: async () => null })
-    expect((await cancelled.api.host.pickDirectory(request({}), new AbortController().signal)).result)
-      .toEqual({ ok: true, value: { path: null } })
-  })
-
-  it('propagates abort into the native capability as a cancelled RPC error', async () => {
-    const { api } = await harness({
-      kind: 'native',
-      pick: signal => new Promise((_resolve, reject) => {
-        signal.addEventListener('abort', () => { reject(new Error('aborted')) }, { once: true })
-      }),
-    })
-    const abort = new AbortController()
-    const pending = api.host.pickDirectory(request({}), abort.signal)
-    abort.abort()
-    expect((await pending).result).toMatchObject({ ok: false, error: { code: 'cancelled' } })
-  })
-
-  it('folds a non-abort native-chooser failure into an internal error', async () => {
-    const { api } = await harness({
-      kind: 'native',
-      pick: async () => { throw new Error('no chooser installed') },
-    })
-    const response = await api.host.pickDirectory(request({}), new AbortController().signal)
-    expect(response.result).toMatchObject({ ok: false, error: { code: 'internal' } })
-  })
-
-  it('refuses the native RPC under a browse composition', async () => {
-    const { api } = await harness(BROWSE_STUB)
-    const response = await api.host.pickDirectory(request({}), new AbortController().signal)
-    expect(response.result).toMatchObject({
-      ok: false,
-      error: { code: 'directory-picker-unavailable', details: { capability: 'browse' } },
-    })
-  })
-})
-
-const BROWSE_STUB: DirectoryPickerCapability = {
-  kind: 'browse',
-  list: async (path) => {
-    if (path === '/denied') {
-      throw new DirectoryPickerError('directory-unreadable', '/denied', 'cannot list /denied')
-    }
-    const target = path ?? '/home/user'
-    return {
-      path: target,
-      home: '/home/user',
-      crumbs: [{ name: '/', path: '/', hidden: false }],
-      entries: [{ name: 'projects', path: `${target}/projects`, hidden: false }],
-      truncated: false,
-    }
-  },
-  createDirectory: async (path, name) => {
-    if (name === 'taken') {
-      throw new DirectoryPickerError('directory-exists', `${path}/${name}`, 'already exists')
-    }
-    if (name === 'unwritable') throw new Error('disk detached')
-    return `${path}/${name}`
-  },
-}
-
-describe('host.listDirectory / host.createDirectory', () => {
-  it('serves listings and creation through the browse capability, defaulting to home', async () => {
-    const { api } = await harness(BROWSE_STUB)
-    const home = await api.host.listDirectory(request({}), new AbortController().signal)
-    expect(home.result).toMatchObject({ ok: true, value: { path: '/home/user', home: '/home/user' } })
-    const listed = await api.host.listDirectory(
-      request({ path: '/home/user/projects' }),
-      new AbortController().signal,
-    )
-    expect(listed.result).toMatchObject({ ok: true, value: { path: '/home/user/projects' } })
-    const created = await api.host.createDirectory(request({ path: '/home/user', name: 'fresh' }))
-    expect(created.result).toEqual({ ok: true, value: { path: '/home/user/fresh' } })
-  })
-
-  it('maps typed picker failures onto wire errors and folds unknown throws to internal', async () => {
-    const { api } = await harness(BROWSE_STUB)
-    expect((await api.host.listDirectory(
-      request({ path: '/denied' }),
-      new AbortController().signal,
-    )).result).toMatchObject({
-      ok: false,
-      error: { code: 'directory-unreadable', details: { path: '/denied' } },
-    })
-    expect((await api.host.createDirectory(request({ path: '/home/user', name: 'taken' }))).result)
-      .toMatchObject({ ok: false, error: { code: 'directory-exists' } })
-    expect((await api.host.createDirectory(request({ path: '/home/user', name: 'unwritable' }))).result)
-      .toMatchObject({ ok: false, error: { code: 'internal' } })
-  })
-
-  it('reports an aborted listing as cancelled', async () => {
-    const { api } = await harness({
-      kind: 'browse',
-      list: (_path, signal) => new Promise((_resolve, reject) => {
-        signal?.addEventListener('abort', () => { reject(new Error('scan aborted')) }, { once: true })
-      }),
-      createDirectory: async () => '/never',
-    })
-    const abort = new AbortController()
-    const pending = api.host.listDirectory(request({}), abort.signal)
-    abort.abort()
-    expect((await pending).result).toMatchObject({ ok: false, error: { code: 'cancelled' } })
-  })
-
-  it('refuses the browse RPCs under a native composition', async () => {
-    const { api } = await harness()
-    expect((await api.host.listDirectory(request({}), new AbortController().signal)).result)
-      .toMatchObject({
-        ok: false,
-        error: { code: 'directory-picker-unavailable', details: { capability: 'native' } },
-      })
-    expect((await api.host.createDirectory(request({ path: '/x', name: 'y' }))).result)
-      .toMatchObject({
-        ok: false,
-        error: { code: 'directory-picker-unavailable', details: { capability: 'native' } },
-      })
-  })
-})
-
 describe('host.openPath', () => {
   it('describes whether the deployment can reach a native desktop', async () => {
-    const visible = await harness(undefined, { canOpenPath: () => true })
-    const headless = await harness(undefined, { canOpenPath: () => false })
+    const visible = await harness({ canOpenPath: () => true })
+    const headless = await harness({ canOpenPath: () => false })
     expect(expectOk(await visible.api.host.describe(request({}))).canOpenPath).toBe(true)
     expect(expectOk(await headless.api.host.describe(request({}))).canOpenPath).toBe(false)
     expect(expectOk(await visible.api.host.describe(request({}))).home).toBe(homedir())
@@ -181,7 +52,7 @@ describe('host.openPath', () => {
 
   it('opens through the injected native boundary', async () => {
     const opened: string[] = []
-    const { api } = await harness(undefined, {
+    const { api } = await harness({
       openPath: async (path) => { opened.push(path) },
     })
     expect((await api.host.openPath(
@@ -192,7 +63,7 @@ describe('host.openPath', () => {
   })
 
   it('propagates abort into the native boundary as a cancelled RPC error', async () => {
-    const { api } = await harness(undefined, {
+    const { api } = await harness({
       openPath: (_path, signal) => new Promise((_resolve, reject) => {
         signal.addEventListener('abort', () => { reject(new Error('aborted')) }, { once: true })
       }),

+ 0 - 3
packages/host/apiproxy/tests/client-handler.spec.ts

@@ -29,9 +29,6 @@ function scriptedApi(overrides: {
       describe: r => ok(r, {
         version: '0-test', cwd: '/t', attachedSessions: 0, home: '/h', canOpenPath: true,
       }),
-      pickDirectory: r => ok(r, { path: null }),
-      listDirectory: r => ok(r, { path: '/t', home: '/t', crumbs: [], entries: [], truncated: false }),
-      createDirectory: r => ok(r, { path: '/t/new' }),
       openPath: r => ok(r, { opened: true as const }),
       ...overrides.host,
     },

+ 7 - 70
packages/host/apiproxy/tests/fetch-carrier.spec.ts

@@ -18,15 +18,6 @@ function fakeApi(overrides: Partial<{ crashOn: string }> = {}): ApiProxy {
           },
         }
       },
-      async pickDirectory(request) {
-        return { rpcId: request.rpcId, result: { ok: true, value: { path: null } } }
-      },
-      async listDirectory(request) {
-        return { rpcId: request.rpcId, result: { ok: true, value: { path: '/w', home: '/w', crumbs: [{ name: '/', path: '/', hidden: false }], entries: [], truncated: false } } }
-      },
-      async createDirectory(request) {
-        return { rpcId: request.rpcId, result: { ok: true, value: { path: '/w/new' } } }
-      },
       async openPath(request) {
         return { rpcId: request.rpcId, result: { ok: true, value: { opened: true as const } } }
       },
@@ -124,29 +115,6 @@ describe('unary round trip (handler ⇄ client, no network)', () => {
       .toEqual({ ok: true, value: { opened: true } })
   })
 
-  it('round-trips the native picker without the default unary timeout', async () => {
-    const api = fakeApi()
-    api.host.pickDirectory = async (request) => {
-      await new Promise(resolve => setTimeout(resolve, 15))
-      return { rpcId: request.rpcId, result: { ok: true, value: { path: '/tmp/project' } } }
-    }
-    const response = await client(api, 1).host.pickDirectory({})
-    expect(response.result).toEqual({ ok: true, value: { path: '/tmp/project' } })
-  })
-
-  it('round-trips the browse listing and creation calls through the wire form', async () => {
-    const c = client()
-    const listed = await c.host.listDirectory({ path: '/w' })
-    expect(listed.result).toEqual({
-      ok: true,
-      value: { path: '/w', home: '/w', crumbs: [{ name: '/', path: '/', hidden: false }], entries: [], truncated: false },
-    })
-    const home = await c.host.listDirectory({})
-    expect(home.result).toMatchObject({ ok: true, value: { home: '/w' } })
-    const created = await c.host.createDirectory({ path: '/w', name: 'fresh' })
-    expect(created.result).toEqual({ ok: true, value: { path: '/w/new' } })
-  })
-
   it('round-trips host.openPath through the wire form', async () => {
     const api = fakeApi()
     let opened: string | undefined
@@ -165,41 +133,10 @@ describe('unary round trip (handler ⇄ client, no network)', () => {
     expect(skills.result).toEqual({ ok: true, value: { skills: [{ name: 'commit-helper', description: 'Git commits', modelInvocable: true }] } })
   })
 
-  it('lets host.pickDirectory finish after the 30-second default unary deadline', async () => {
-    vi.useFakeTimers()
-    const timeoutSpy = vi.spyOn(AbortSignal, 'timeout').mockImplementation((milliseconds) => {
-      const controller = new AbortController()
-      setTimeout(() => {
-        controller.abort(new DOMException('The operation was aborted due to timeout', 'TimeoutError'))
-      }, milliseconds)
-      return controller.signal
-    })
-    try {
-      const api = fakeApi()
-      api.host.pickDirectory = async (request) => {
-        await new Promise(resolve => setTimeout(resolve, 30_001))
-        return { rpcId: request.rpcId, result: { ok: true, value: { path: '/tmp/slow' } } }
-      }
-      const execution = client(api).host.pickDirectory({})
-      const assertion = expect(execution).resolves.toMatchObject({
-        result: { ok: true, value: { path: '/tmp/slow' } },
-      })
-
-      await Promise.all([
-        vi.advanceTimersByTimeAsync(30_001),
-        assertion,
-      ])
-      expect(timeoutSpy).not.toHaveBeenCalled()
-    } finally {
-      timeoutSpy.mockRestore()
-      vi.useRealTimers()
-    }
-  })
-
-  it('keeps caller and connection aborts on a deadline-exempt unary', async () => {
+  it('keeps caller and connection aborts on a signal-taking unary', async () => {
     const api = fakeApi()
     const started = Promise.withResolvers<AbortSignal>()
-    api.host.pickDirectory = async (request, signal) => {
+    api.host.openPath = async (request, signal) => {
       started.resolve(signal)
       if (!signal.aborted) {
         await new Promise<void>((resolve) => {
@@ -212,7 +149,7 @@ describe('unary round trip (handler ⇄ client, no network)', () => {
       }
     }
     const controller = new AbortController()
-    const execution = client(api).host.pickDirectory({}, controller.signal)
+    const execution = client(api).host.openPath({ path: '/tmp/a.txt' }, controller.signal)
     const handlerSignal = await started.promise
 
     controller.abort(new Error('connection closed'))
@@ -221,9 +158,9 @@ describe('unary round trip (handler ⇄ client, no network)', () => {
     expect(handlerSignal.aborted).toBe(true)
   })
 
-  it('propagates the carrier Request signal into host.pickDirectory', async () => {
+  it('propagates the carrier Request signal into host.openPath', async () => {
     const api = fakeApi()
-    api.host.pickDirectory = async (request, signal) => {
+    api.host.openPath = async (request, signal) => {
       if (!signal.aborted) {
         await new Promise<void>((resolve) => {
           signal.addEventListener('abort', () => { resolve() }, { once: true })
@@ -236,8 +173,8 @@ describe('unary round trip (handler ⇄ client, no network)', () => {
     }
     const handler = toFetchHandler(api)
     const controller = new AbortController()
-    const body = JSON.stringify({ type: 'client-request', rpcId: 'r-picker', method: 'host.pickDirectory', payload: {} })
-    const pending = handler.fetch(new Request('http://x/api/host.pickDirectory', {
+    const body = JSON.stringify({ type: 'client-request', rpcId: 'r-opener', method: 'host.openPath', payload: { path: '/tmp/a.txt' } })
+    const pending = handler.fetch(new Request('http://x/api/host.openPath', {
       method: 'POST', headers: { 'content-type': 'application/json' }, body, signal: controller.signal,
     }))
     controller.abort()

+ 1 - 30
packages/host/apiproxy/tests/rpc-schemas.spec.ts

@@ -5,11 +5,7 @@ import {
   rpcResultSchema, serverResponseSchema,
 } from '../src/api/rpc.schema.ts'
 import { z } from 'zod'
-import {
-  hostCreateDirectoryRequestSchema, hostCreateDirectoryValueSchema,
-  hostDescribeRequestSchema, hostDescribeValueSchema,
-  hostListDirectoryRequestSchema, hostListDirectoryValueSchema,
-} from '../src/api/host.schema.ts'
+import { hostDescribeRequestSchema, hostDescribeValueSchema } from '../src/api/host.schema.ts'
 import { skillEntrySchema, skillListRequestSchema, skillListValueSchema } from '../src/api/skills.schema.ts'
 import { agentPresetOpenDocumentValueSchema } from '../src/api/agent-presets.schema.ts'
 
@@ -36,10 +32,6 @@ describe('rpcErrorSchema', () => {
     expect(rpcErrorSchema.parse({ code: 'cancelled', message: 'm', details: {} }).code).toBe('cancelled')
     expect(rpcErrorSchema.parse({ code: 'session-not-found', message: 'm', details: { sessionId: 's' } }).code).toBe('session-not-found')
     expect(rpcErrorSchema.parse({ code: 'invalid-time-zone', message: 'm', details: { value: 'CST' } }).code).toBe('invalid-time-zone')
-    expect(rpcErrorSchema.parse({ code: 'directory-unreadable', message: 'm', details: { path: '/x' } }).code).toBe('directory-unreadable')
-    expect(rpcErrorSchema.parse({ code: 'directory-exists', message: 'm', details: { path: '/x' } }).code).toBe('directory-exists')
-    expect(rpcErrorSchema.parse({ code: 'directory-create-failed', message: 'm', details: { path: '/x' } }).code).toBe('directory-create-failed')
-    expect(rpcErrorSchema.parse({ code: 'directory-picker-unavailable', message: 'm', details: { capability: 'none' } }).code).toBe('directory-picker-unavailable')
     expect(rpcErrorSchema.parse({ code: 'agent-preset-read-only', message: 'm', details: { agentPreset: 'p', reason: 'system' } }).code).toBe('agent-preset-read-only')
     expect(rpcErrorSchema.parse({ code: 'agent-preset-locked', message: 'm', details: { sessionId: 's', agentPreset: 'p' } }).code).toBe('agent-preset-locked')
     expect(rpcErrorSchema.parse({ code: 'agent-preset-not-found', message: 'm', details: { agentPreset: 'p', available: [] } }).code).toBe('agent-preset-not-found')
@@ -55,7 +47,6 @@ describe('rpcErrorSchema', () => {
 
   it('rejects a known code with missing details', () => {
     expect(() => rpcErrorSchema.parse({ code: 'agent-busy', message: 'm', details: {} })).toThrow()
-    expect(() => rpcErrorSchema.parse({ code: 'directory-unreadable', message: 'm', details: {} })).toThrow()
     expect(() => rpcErrorSchema.parse({ code: 'internal', message: 'm' })).toThrow()
     expect(() => rpcErrorSchema.parse({ code: 'nope', message: 'm', details: {} })).toThrow()
   })
@@ -109,26 +100,6 @@ describe('host domain schemas', () => {
       version: '1', cwd: '/x', attachedSessions: 0, canOpenPath: true,
     })).toThrow()
   })
-
-  it('validates the browse listing/creation payloads', () => {
-    expect(hostListDirectoryRequestSchema.parse({})).toEqual({})
-    expect(hostListDirectoryRequestSchema.parse({ path: '/x' })).toEqual({ path: '/x' })
-    const listing = hostListDirectoryValueSchema.parse({
-      path: '/home/u/p',
-      home: '/home/u',
-      crumbs: [{ name: '/', path: '/', hidden: false }, { name: 'p', path: '/home/u/p', hidden: false }],
-      entries: [{ name: '.dot', path: '/home/u/p/.dot', hidden: true }],
-      truncated: false,
-    })
-    expect(listing.entries[0]?.hidden).toBe(true)
-    // The flag is part of the wire value, not an optional decoration.
-    expect(() => hostListDirectoryValueSchema.parse({ path: '/x', home: '/x', crumbs: [], entries: [] })).toThrow()
-    expect(hostCreateDirectoryRequestSchema.parse({ path: '/x', name: 'new' })).toEqual({ path: '/x', name: 'new' })
-    for (const name of ['', ' ', '.', '..', 'a/b', 'a\\b']) {
-      expect(() => hostCreateDirectoryRequestSchema.parse({ path: '/x', name })).toThrow()
-    }
-    expect(hostCreateDirectoryValueSchema.parse({ path: '/x/new' })).toEqual({ path: '/x/new' })
-  })
 })
 
 describe('skills domain schemas', () => {