Ver Fonte

refactor(apiproxy): retire migrated unary routes

imccyu há 1 mês atrás
pai
commit
ce3391e280

+ 5 - 0
knip.json

@@ -415,6 +415,11 @@
         "tests/**/*.ts"
       ]
     },
+    "packages/llm/llm": {
+      "ignoreDependencies": [
+        "zod"
+      ]
+    },
     "packages/llm/llm-deepseek": {
       "entry": [
         "tests/**/*.spec.ts",

+ 1 - 8
packages/host/apiproxy/package.json

@@ -50,16 +50,10 @@
     "@deepseek-ai/dsh-attachment": "workspace:^",
     "@deepseek-ai/dsh-api-session-controller": "workspace:^",
     "@deepseek-ai/dsh-brand": "workspace:^",
-    "@deepseek-ai/dsh-commands": "workspace:^",
-    "@deepseek-ai/dsh-host-directory-picker": "workspace:^",
-    "@deepseek-ai/dsh-llm": "workspace:^",
     "@deepseek-ai/dsh-native-command": "workspace:^",
-    "@deepseek-ai/dsh-scope": "workspace:^",
     "@deepseek-ai/dsh-session": "workspace:^",
     "@deepseek-ai/dsh-session-persistence": "workspace:^",
     "@deepseek-ai/dsh-session-query": "workspace:^",
-    "@deepseek-ai/dsh-settings": "workspace:^",
-    "@deepseek-ai/dsh-skill": "workspace:^",
     "@deepseek-ai/dsh-util-crypto": "workspace:^",
     "@deepseek-ai/schemastery": "workspace:^",
     "fflate": "^0.8.2",
@@ -67,14 +61,13 @@
   },
   "peerDependencies": {
     "@deepseek-ai/cordis": "workspace:^",
-    "@deepseek-ai/dsh-agent-presets": "workspace:^",
     "@deepseek-ai/dsh-invariants": "workspace:^"
   },
   "devDependencies": {
     "@deepseek-ai/cordis": "workspace:^",
-    "@deepseek-ai/dsh-agent-presets": "workspace:^",
     "@deepseek-ai/dsh-credentials": "workspace:^",
     "@deepseek-ai/dsh-invariants": "workspace:^",
+    "@deepseek-ai/dsh-settings": "workspace:^",
     "@deepseek-ai/dsh-typert-protocol": "workspace:^",
     "@deepseek-ai/dsh-typert-registry": "workspace:^"
   }

+ 5 - 330
packages/host/apiproxy/src/api-proxy.ts

@@ -4,19 +4,10 @@
  */
 
 import { homedir } from 'node:os'
-import { dirname } from 'node:path'
 import type { Context } from '@deepseek-ai/cordis'
 import type { ModelSelection } from '@deepseek-ai/dsh-agent'
-import type {} from '@deepseek-ai/dsh-agent-presets/types'
-import type { SessionId } from '@deepseek-ai/dsh-session'
-import { isUserInvocable } from '@deepseek-ai/dsh-skill'
-import {
-  InvalidPresetIdError, PresetExistsError,
-  PresetNotWritableError, UnknownPresetError,
-} from '@deepseek-ai/dsh-agent-presets'
-import type { ApiProxy, ConfigurableProviderView } from './api/index.ts'
-import { buildModelCatalog } from '@deepseek-ai/dsh-api-session-controller'
-import { SessionQueryError } from '@deepseek-ai/dsh-session-query'
+import { canOpenNativePath } from '@deepseek-ai/dsh-native-command'
+import type { ApiProxy } from './api/index.ts'
 import {
   DEFAULT_SESSION_LOG_COMPRESSION_LEVEL,
   flushLiveSessionLog,
@@ -27,77 +18,30 @@ import {
   type SessionLogCompressionLevel,
 } from './session-export.ts'
 import type { SessionRawArtifact } from '@deepseek-ai/dsh-session-persistence'
-// Type-only edges: resolve the command-change stream and `ctx.get('skills')`.
-import type {} from '@deepseek-ai/dsh-commands'
-import type {} from '@deepseek-ai/dsh-skill'
-import type { ScopeKey } from '@deepseek-ai/dsh-scope'
-import type { RpcError, RpcRequest, RpcResponse } from './api/rpc.ts'
-import { canOpenNativePath, openNativePath, openNativeTextFile } from './native-path-opener.ts'
-
-/** Read live abort state across awaits without treating it as synchronously immutable. */
-function isAborted(signal: AbortSignal): boolean {
-  return signal.aborted
-}
+import type { RpcRequest, RpcResponse } from './api/rpc.ts'
 
 /** Wrap an ok result echoing the request's rpcId. */
 function ok<T>(request: RpcRequest<unknown>, value: T): RpcResponse<T> {
   return { rpcId: request.rpcId, result: { ok: true, value } }
 }
 
-/** Wrap an error result echoing the request's rpcId. */
-function err<T>(request: RpcRequest<unknown>, error: RpcError): RpcResponse<T> {
-  return { rpcId: request.rpcId, result: { ok: false, error } }
-}
-
 /** Deployment metadata and Host integrations consumed by the API implementation. */
 export interface ApiProxyDefaults {
   /** Current deployment model selection reported by `host.describe`. */
   defaultModelSelection: () => ModelSelection
   /** Project hint reported by `host.describe`; must match Session Controller's default cwd. */
   cwd: string
-  /** Native open-with-default-application; injectable for carrier tests. */
-  openPath?: (path: string, signal: AbortSignal) => Promise<void>
-  /** Native text-editor handoff; injectable for settings-document tests. */
-  openTextFile?: (path: string, signal: AbortSignal) => Promise<void>
   /** Validated DEFLATE level for session-log ZIP entries; defaults to 6. */
   sessionExportCompressionLevel?: SessionLogCompressionLevel
   /**
    * Whether handing a path to the native opener can work at all — the
    * `hasDocument` capability the preset roster reports, and the switch
    * between opening a preset directory and answering its path as text.
-   * Absent, an injected `openPath` counts as openable and everything else
-   * falls back to platform detection ({@link canOpenNativePath}).
+   * Absent, platform detection decides ({@link canOpenNativePath}).
    */
   canOpenPath?: () => boolean
 }
 
-/** The roster is absent: this deployment composes no agent presets at all. */
-function noRoster(agentPreset: string): RpcError {
-  return {
-    code: 'agent-preset-not-found',
-    message: 'this deployment composes no agent presets',
-    details: { agentPreset, available: [] },
-  }
-}
-
-/** Map one authoring/roster failure onto its wire code. */
-function presetError(agentPreset: string, error: unknown): RpcError {
-  if (error instanceof UnknownPresetError) {
-    return {
-      code: 'agent-preset-not-found',
-      message: error.message,
-      details: { agentPreset: error.presetId, available: [...error.available] },
-    }
-  }
-  if (error instanceof PresetNotWritableError) {
-    return { code: 'agent-preset-read-only', message: error.message, details: { agentPreset, reason: error.message } }
-  }
-  if (error instanceof InvalidPresetIdError || error instanceof PresetExistsError) {
-    return { code: 'agent-preset-invalid', message: error.message, details: { agentPreset, reason: error.message } }
-  }
-  return { code: 'internal', message: `agent preset "${agentPreset}": ${String(error)}`, details: {} }
-}
-
 /**
  * Implement ApiProxy over a composed host context.
  * @param ctx - a context with the Host spine mounted.
@@ -107,75 +51,10 @@ function presetError(agentPreset: string, error: unknown): RpcError {
 export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiProxy {
   const sessionExportCompressionLevel = defaults.sessionExportCompressionLevel
     ?? DEFAULT_SESSION_LOG_COMPRESSION_LEVEL
-  /** Resolve a Session's live or standing preset scope without resuming it. */
-  async function sessionScopeFor(
-    sessionId: SessionId,
-    agentPreset: string | undefined,
-  ): Promise<ScopeKey | undefined> {
-    const live = ctx.get('agents')?.get(sessionId)
-    if (live !== undefined) return live
-    const presets = ctx.get('agentPresets')
-    if (presets === undefined) return undefined
-    try {
-      return await presets.standingKeyFor(agentPreset)
-    } catch {
-      // An unknown or unusable recorded preset falls back to the global registry.
-      return undefined
-    }
-  }
-
-  /** Missing-service report shared by the settings domain (skills-domain stance). */
-  function settingsAbsent(): RpcError {
-    return { code: 'internal', message: 'settings service is absent: this deployment does not mount a settings provider (e.g. @deepseek-ai/dsh-settings-file) in its composition', details: {} }
-  }
-
-  /** Open one Host-resolved target and map native failures onto the wire vocabulary. */
-  async function openTarget(
-    request: RpcRequest<unknown>, path: string, signal: AbortSignal,
-    open: (path: string, signal: AbortSignal) => Promise<void>,
-  ): Promise<RpcResponse<{ opened: true }>> {
-    try {
-      await open(path, signal)
-      return ok(request, { opened: true as const })
-    } catch (error: unknown) {
-      if (signal.aborted) {
-        return err(request, {
-          code: 'cancelled',
-          message: 'path open was aborted',
-          details: {},
-        })
-      }
-      return err(request, {
-        code: 'internal',
-        message: `path open failed: ${error instanceof Error ? error.message : String(error)}`,
-        details: {},
-      })
-    }
-  }
-
-  /** Open one Host-resolved path with its default application. */
-  function openPath(
-    request: RpcRequest<unknown>, path: string, signal: AbortSignal,
-  ): Promise<RpcResponse<{ opened: true }>> {
-    const open = defaults.openPath
-      ?? ((target: string, openSignal: AbortSignal) => openNativePath(target, openSignal))
-    return openTarget(request, path, signal, open)
-  }
-
-  /** Open one Host-resolved text document in a native editor. */
-  function openTextFile(
-    request: RpcRequest<unknown>, path: string, signal: AbortSignal,
-  ): Promise<RpcResponse<{ opened: true }>> {
-    const open = defaults.openTextFile
-      ?? ((target: string, openSignal: AbortSignal) => openNativeTextFile(target, openSignal))
-    return openTarget(request, path, signal, open)
-  }
-
   /** Whether this deployment can hand a path to a native opener at all. */
   function canOpenPaths(): boolean {
     if (defaults.canOpenPath !== undefined) return defaults.canOpenPath()
-    // An injected opener is by definition usable; otherwise ask the platform.
-    return defaults.openPath !== undefined || canOpenNativePath()
+    return canOpenNativePath()
   }
 
   return {
@@ -198,210 +77,6 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
         }))
       },
 
-      async openPath(request, signal) {
-        return openPath(request, request.payload.path, signal)
-      },
-    },
-
-    agentPresets: {
-      // Only the desktop opener remains here: the roster, selection, and
-      // authoring calls are the AgentPresets service's own Remote namespace.
-      async openDocument(request, signal) {
-        const { agentPreset } = request.payload
-        const presets = ctx.get('agentPresets')
-        if (presets === undefined) return err(request, noRoster(agentPreset))
-        try {
-          const preset = await presets.resolve(agentPreset)
-          // Same line as copy/remove draw: the shipped install is not the
-          // user's to manage, and pointing an editor into it invites edits an
-          // upgrade will silently overwrite.
-          if (preset.trust !== 'user') {
-            throw new PresetNotWritableError(preset.id, 'it ships with the deployment')
-          }
-          // The id resolved against the Host's own roots is what selects the
-          // directory — no browser payload carries a path in either direction
-          // unless the deployment has no opener to hand it to.
-          const directory = dirname(preset.path)
-          if (!canOpenPaths()) return ok(request, { opened: false as const, path: directory })
-          return await openPath(request, directory, signal)
-        } catch (error: unknown) {
-          return err(request, presetError(agentPreset, error))
-        }
-      },
-    },
-
-    skills: {
-      // Skill lookup never creates or resumes an agent: the session address
-      // resolves to a canonical cwd from the host-resident session header, and
-      // the view scope is the live agent or the preset's standing key.
-      async list(request) {
-        const { sessionId } = request.payload
-        let cwd: string | undefined
-        let agentPreset: string | undefined
-        try {
-          using observation = await ctx.sessionQuery.observeSession(sessionId)
-          if (observation.projections === undefined) {
-            throw new Error('skill catalog requires a projected Session observation')
-          }
-          cwd = observation.header.cwd
-          agentPreset = observation.projections.values.agentPreset ?? undefined
-        } catch (error: unknown) {
-          if (error instanceof SessionQueryError
-            && error.code === 'SESSION_QUERY_SESSION_NOT_FOUND') {
-            return err(request, {
-              code: 'session-not-found',
-              message: `session "${sessionId}" not found`,
-              details: { sessionId },
-            })
-          }
-          return err(request, {
-            code: 'internal',
-            message: `session "${sessionId}" could not be inspected: ${String(error)}`,
-            details: {},
-          })
-        }
-        if (cwd === undefined) {
-          // Every served session records its project at create time; a
-          // cwd-less header is a pre-project legacy log (not served).
-          return err(request, { code: 'internal', message: `session "${sessionId}" has no project cwd`, details: {} })
-        }
-        // The host registry is layered per scope and serves every session. A
-        // composition may still realm-mount its own registry instead; that
-        // instance is invisible to host contexts, so address it through the
-        // live agent (`agents.get` keeps the no-side-effect stance above).
-        const live = ctx.agents.get(sessionId)
-        const presets = ctx.get('agentPresets')
-        const scoped = live === undefined ? undefined : presets?.serviceFor(live, 'skills')
-        // A missing service means no composition mounts dsh-skill, not an
-        // empty catalog. `ctx.get` also
-        // keeps this handler independent of the gateway plugin's inject list
-        // (an undeclared `ctx.skills` property read fails the reflect proxy).
-        const skillRegistry = scoped ?? ctx.get('skills')
-        if (skillRegistry === undefined) {
-          return err(request, { code: 'internal', message: 'skill registry is absent: neither this session\'s agent preset nor the host composition mounts @deepseek-ai/dsh-skill', details: {} })
-        }
-        // Resolve the live or recorded preset scope so the catalog matches the
-        // Session composition without resuming its Agent.
-        const scope = await sessionScopeFor(sessionId, agentPreset)
-        try {
-          const skills = (await skillRegistry.list({ cwd, scope })).filter(isUserInvocable)
-          return ok(request, {
-            skills: skills.map(skill => ({
-              name: skill.name,
-              description: skill.description,
-              ...skill.whenToUse === undefined ? {} : { whenToUse: skill.whenToUse },
-              modelInvocable: skill.invocation.modelInvocable,
-            })),
-          })
-        } catch (error: unknown) {
-          return err(request, { code: 'internal', message: `skill listing failed: ${String(error)}`, details: {} })
-        }
-      },
-    },
-
-    settings: {
-      async openDocument(request, signal) {
-        const settings = ctx.get('settings')
-        if (settings === undefined) return err(request, settingsAbsent())
-        if (isAborted(signal)) {
-          return err(request, {
-            code: 'cancelled',
-            message: 'settings document open was aborted',
-            details: {},
-          })
-        }
-        let path: string | undefined
-        try {
-          path = await settings.prepareDocument()
-        } catch (error: unknown) {
-          if (isAborted(signal)) {
-            return err(request, {
-              code: 'cancelled',
-              message: 'settings document preparation was aborted',
-              details: {},
-            })
-          }
-          return err(request, {
-            code: 'internal',
-            message: `settings document preparation failed: ${error instanceof Error ? error.message : String(error)}`,
-            details: {},
-          })
-        }
-        if (path === undefined) {
-          return err(request, {
-            code: 'internal',
-            message: 'settings provider has no local document to open',
-            details: {},
-          })
-        }
-        if (isAborted(signal)) {
-          return err(request, {
-            code: 'cancelled',
-            message: 'settings document open was aborted',
-            details: {},
-          })
-        }
-        return openTextFile(request, path, signal)
-      },
-    },
-
-    llm: {
-      providers(request) {
-        const registered = ctx.llm.listProviders()
-        const active = new Set(registered.map(provider => provider.id))
-        const directory = ctx.llm.listConfigurableProviders()
-        const declared = new Set(directory.map(entry => entry.provider))
-        const views: ConfigurableProviderView[] = directory.map(entry => ({
-          provider: entry.provider,
-          displayName: entry.displayName,
-          settingsNs: entry.settingsNs,
-          settingsPath: [...entry.settingsPath],
-          active: active.has(entry.provider),
-          ...entry.declared === undefined ? {} : { declared: entry.declared },
-        }))
-        // Routes registered without a directory declaration still appear —
-        // they exist and serve models — just with no settings address. No
-        // adapter claimed them, so nothing can say whether they are shipped.
-        for (const provider of registered) {
-          if (declared.has(provider.id)) continue
-          views.push({
-            provider: provider.id,
-            displayName: provider.name,
-            settingsNs: '',
-            settingsPath: [],
-            active: true,
-          })
-        }
-        return Promise.resolve(ok(request, { providers: views }))
-      },
-
-      async models(request) {
-        return ok(request, await buildModelCatalog(ctx, defaults.defaultModelSelection()))
-      },
-
-      async discoverModels(request, signal) {
-        const { settingsNs, provider, baseURL, api, apiKey } = request.payload
-        try {
-          const models = await ctx.llm.discoverModels(settingsNs, {
-            ...provider === undefined ? {} : { provider },
-            ...baseURL === undefined ? {} : { baseURL },
-            ...api === undefined ? {} : { api },
-            ...apiKey === undefined ? {} : { apiKey },
-            ...signal === undefined ? {} : { signal },
-          })
-          return ok(request, { models })
-        } catch (error: unknown) {
-          // Every failure here is the user's next move, not a transport fault:
-          // a wrong endpoint, a rejected key, or a protocol with no listing all
-          // end at the same place — fill the models in by hand. The details
-          // repeat only what the caller already sent, never the credential.
-          return err(request, {
-            code: 'model-discovery-failed',
-            message: error instanceof Error ? error.message : String(error),
-            details: { settingsNs, ...baseURL === undefined ? {} : { baseURL } },
-          })
-        }
-      },
     },
 
     downloads: {

+ 0 - 19
packages/host/apiproxy/src/api/agent-presets.schema.ts

@@ -1,19 +0,0 @@
-/**
- * agent-presets domain zod schemas (names derived from map keys:
- * agentPresetOpenDocumentRequestSchema / agentPresetOpenDocumentValueSchema).
- */
-
-import { z } from 'zod'
-import type { RequestPayload, ResponseValue } from './rpc-map.ts'
-import type { Wire } from './rpc.schema.ts'
-
-/** agentPreset.openDocument request payload. */
-export const agentPresetOpenDocumentRequestSchema = z.object({
-  agentPreset: z.string().min(1),
-}) satisfies z.ZodType<Wire<RequestPayload<'agentPreset.openDocument'>>>
-
-/** agentPreset.openDocument response value. */
-export const agentPresetOpenDocumentValueSchema = z.union([
-  z.object({ opened: z.literal(true) }),
-  z.object({ opened: z.literal(false), path: z.string() }),
-]) satisfies z.ZodType<Wire<ResponseValue<'agentPreset.openDocument'>>>

+ 0 - 25
packages/host/apiproxy/src/api/agent-presets.ts

@@ -1,25 +0,0 @@
-/**
- * agent-presets domain contract: handing one preset's directory to the
- * platform opener, which is the only agent-preset call still carried here.
- *
- * The roster and its authoring calls are the AgentPresets service's own Remote
- * namespace. This one stays because the opener is a Host desktop integration
- * rather than a preset operation.
- */
-
-import type { RpcRequest, RpcResponse } from './rpc.ts'
-
-/** agent-preset-domain unary methods (the map key agentPreset.* of RpcMethodMap). */
-export interface AgentPresetsApi {
-  /**
-   * Hand one locally authored preset's DIRECTORY to the platform opener, for
-   * editing the files, which are the only composition editor. The request
-   * carries an id, never a path — the Host resolves it — so no browser
-   * payload can select an arbitrary filesystem target. Where the deployment
-   * has no native opener (`canOpenPath: false` on `host.describe`), the reply
-   * carries the resolved directory for the surface to show as text instead.
-   * Shipped presets are refused: their install is not the user's to manage.
-   */
-  openDocument(request: RpcRequest<{ agentPreset: string }>, signal: AbortSignal):
-  Promise<RpcResponse<{ opened: true } | { opened: false; path: string }>>
-}

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

@@ -19,13 +19,3 @@ export const hostDescribeValueSchema = z.object({
   home: z.string(),
   canOpenPath: z.boolean(),
 }) satisfies z.ZodType<Wire<ResponseValue<'host.describe'>>>
-
-/** host.openPath request payload. */
-export const hostOpenPathRequestSchema = z.object({
-  path: z.string().min(1),
-}) satisfies z.ZodType<Wire<RequestPayload<'host.openPath'>>>
-
-/** host.openPath response value. */
-export const hostOpenPathValueSchema = z.object({
-  opened: z.literal(true),
-}) satisfies z.ZodType<Wire<ResponseValue<'host.openPath'>>>

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

@@ -27,14 +27,4 @@ export interface HostApi {
     canOpenPath: boolean
   }>>
 
-  /**
-   * Open a filesystem path with the operating system's default application
-   * (Finder / Explorer / xdg-open hand-off). The browser carrier's
-   * prefix-wide trust and authentication checks cover this method like every
-   * other `/api` request.
-   */
-  openPath(
-    request: RpcRequest<{ path: string }>,
-    signal: AbortSignal,
-  ): Promise<RpcResponse<{ opened: true }>>
 }

+ 0 - 12
packages/host/apiproxy/src/api/index.ts

@@ -5,19 +5,11 @@
  */
 
 import type { HostApi } from './host.ts'
-import type { AgentPresetsApi } from './agent-presets.ts'
-import type { SkillsApi } from './skills.ts'
-import type { SettingsApi } from './settings.ts'
-import type { LlmApi } from './llm.ts'
 import type { DownloadsApi } from './downloads.ts'
 
 /** Root interface of the unified API. New client-request domain = one new file pair + one field here + one map row. */
 export interface ApiProxy {
   host: HostApi
-  skills: SkillsApi
-  agentPresets: AgentPresetsApi
-  settings: SettingsApi
-  llm: LlmApi
   /** Host-only download surfaces (GET, no wire envelope); absent from IApiClient. */
   downloads: DownloadsApi
 }
@@ -28,10 +20,6 @@ export type {
   ModelReasoningEffort, ModelSelection,
 } from '@deepseek-ai/dsh-api-session-controller/types'
 export type { HostApi } from './host.ts'
-export type { SkillsApi, SkillEntry } from './skills.ts'
-export type { AgentPresetsApi } from './agent-presets.ts'
-export type { SettingsApi } from './settings.ts'
-export type { ConfigurableProviderView, DiscoveredModelView, LlmApi } from './llm.ts'
 export type { DownloadsApi } from './downloads.ts'
 
 // ---- Message layer: narrow forms (domain-signature view) ----

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

@@ -1,115 +0,0 @@
-/**
- * llm domain zod schemas (names derived from map keys: llmProvidersRequestSchema /
- * llmProvidersValueSchema / llmModelsRequestSchema / llmModelsValueSchema).
- */
-
-import { z } from 'zod'
-import type { RequestPayload, ResponseValue } from './rpc-map.ts'
-import type { Wire } from './rpc.schema.ts'
-import type { ConfigurableProviderView, DiscoveredModelView } from './llm.ts'
-import type {
-  ModelCatalogFailure,
-  ModelCatalogModel,
-  ModelSelection,
-  ModelProviderGroup,
-  ModelReasoning,
-  ModelReasoningEffort,
-} from '@deepseek-ai/dsh-api-session-controller/types'
-
-/** One adapter-owned reasoning effort. */
-const modelReasoningEffortSchema = z.object({
-  id: z.string().min(1),
-  name: z.string().min(1),
-  description: z.string().optional(),
-}) satisfies z.ZodType<Wire<ModelReasoningEffort>>
-
-/** Exact-model reasoning metadata. */
-const modelReasoningSchema = z.object({
-  efforts: z.array(modelReasoningEffortSchema).min(1),
-  defaultEffort: z.string().min(1).optional(),
-}) satisfies z.ZodType<Wire<ModelReasoning>>
-
-/** One advisory model entry inside a provider group. */
-const modelCatalogModelSchema = z.object({
-  id: z.string().min(1),
-  name: z.string().min(1),
-  description: z.string().optional(),
-  reasoning: modelReasoningSchema.optional(),
-}) satisfies z.ZodType<Wire<ModelCatalogModel>>
-
-/** One successfully loaded provider group. */
-const modelProviderGroupSchema = z.object({
-  id: z.string().min(1),
-  name: z.string().min(1),
-  models: z.array(modelCatalogModelSchema),
-}) satisfies z.ZodType<Wire<ModelProviderGroup>>
-
-/** One provider-local catalog failure. */
-const modelCatalogFailureSchema = z.object({
-  id: z.string().min(1),
-  name: z.string().min(1),
-  message: z.string(),
-}) satisfies z.ZodType<Wire<ModelCatalogFailure>>
-
-/** Complete model selection used as the Host default. */
-const modelSelectionSchema = z.object({
-  provider: z.string().min(1),
-  model: z.string().min(1),
-  reasoningEffort: z.string().min(1).optional(),
-}) satisfies z.ZodType<Wire<ModelSelection>>
-
-/** ConfigurableProviderView row of llm.providers. */
-export const configurableProviderViewSchema = z.object({
-  provider: z.string().min(1),
-  displayName: z.string().min(1),
-  settingsNs: z.string(),
-  settingsPath: z.array(z.string()),
-  active: z.boolean(),
-  declared: z.boolean().optional(),
-}) satisfies z.ZodType<Wire<ConfigurableProviderView>>
-
-/** llm.providers request payload. */
-export const llmProvidersRequestSchema = z.object({}) satisfies z.ZodType<Wire<RequestPayload<'llm.providers'>>>
-
-/** llm.providers response value. */
-export const llmProvidersValueSchema = z.object({
-  providers: z.array(configurableProviderViewSchema),
-}) satisfies z.ZodType<Wire<ResponseValue<'llm.providers'>>>
-
-/** llm.models request payload. */
-export const llmModelsRequestSchema = z.object({}) satisfies z.ZodType<Wire<RequestPayload<'llm.models'>>>
-
-/** llm.models response value. */
-export const llmModelsValueSchema = z.object({
-  default: modelSelectionSchema,
-  routableProviders: z.array(z.string().min(1)),
-  groups: z.array(modelProviderGroupSchema),
-  failures: z.array(modelCatalogFailureSchema),
-}) satisfies z.ZodType<Wire<ResponseValue<'llm.models'>>>
-
-/** DiscoveredModelView row of llm.discoverModels. */
-export const discoveredModelViewSchema = z.object({
-  id: z.string().min(1),
-  name: z.string().min(1).optional(),
-  contextWindow: z.number().int().positive().optional(),
-  maxTokens: z.number().int().positive().optional(),
-}) satisfies z.ZodType<Wire<DiscoveredModelView>>
-
-/** llm.discoverModels request payload. */
-export const llmDiscoverModelsRequestSchema = z.object({
-  settingsNs: z.string().min(1),
-  provider: z.string().min(1).optional(),
-  baseURL: z.string().min(1).optional(),
-  api: z.string().min(1).optional(),
-  // Write-only at the host: used for this one interrogation, never stored and
-  // never returned. It does ride the client's outgoing envelope like every
-  // other secret-bearing payload (`settings/update`), which
-  // `subscribeEnvelopes()` observers can see — redacting that tap is a
-  // configuration-plane-wide change, not this method's to make alone.
-  apiKey: z.string().min(1).optional(),
-}) satisfies z.ZodType<Wire<RequestPayload<'llm.discoverModels'>>>
-
-/** llm.discoverModels response value. */
-export const llmDiscoverModelsValueSchema = z.object({
-  models: z.array(discoveredModelViewSchema),
-}) satisfies z.ZodType<Wire<ResponseValue<'llm.discoverModels'>>>

+ 0 - 90
packages/host/apiproxy/src/api/llm.ts

@@ -1,90 +0,0 @@
-/**
- * llm domain contract: host-scoped provider topology for configuration
- * surfaces. `llm.providers` merges the configurable-provider directory
- * (which providers CAN be configured, and where their settings live) with the
- * live route registry; `llm.models` is the session-independent model catalog.
- * Clients invalidate from the forwarded `llm/adapters-updated` and
- * `settings/document-updated` owner events.
- */
-
-import type { RpcRequest, RpcResponse } from './rpc.ts'
-import type {
-  ModelCatalog,
-} from '@deepseek-ai/dsh-api-session-controller/types'
-
-/** Wire view of one configurable provider. */
-export interface ConfigurableProviderView {
-  /** Provider route key (`deepseek-official`, `openai`, …). */
-  provider: string
-  /** Human-readable name for configuration surfaces. */
-  displayName: string
-  /** Settings namespace whose section configures this provider. */
-  settingsNs: string
-  /** Path from that section's root to the provider's profile object (empty = whole section). */
-  settingsPath: string[]
-  /** Whether the route is currently registered (its models are requestable). */
-  active: boolean
-  /**
-   * Whether the owning adapter knows this route only because configuration
-   * declared it. Absent when the adapter draws no such distinction, so a
-   * surface must treat absence as "unknown", not as "shipped".
-   */
-  declared?: boolean
-}
-
-/** Llm-domain unary methods (the map keys llm.* of RpcMethodMap). */
-export interface LlmApi {
-  /**
-   * List every configurable provider with its live/dormant state, in
-   * directory declaration order. Routes registered outside the directory
-   * (an adapter that never declared configurability) are appended with their
-   * registration identity and no settings address.
-   */
-  providers(request: RpcRequest<{}>): Promise<RpcResponse<{ providers: ConfigurableProviderView[] }>>
-
-  /**
-   * Host-scoped model catalog over every registered provider route: the
-   * settings surface's models view, needing no session. Per-provider listing
-   * failures ride `failures` without failing the sound groups.
-   */
-  models(request: RpcRequest<{}>): Promise<RpcResponse<ModelCatalog>>
-
-  /**
-   * Interrogate a provider endpoint the configuration surface is still
-   * drafting, and return the models it advertises for the user to adopt.
-   *
-   * The payload is the draft, not a stored route: `settingsNs` selects the
-   * adapter family that answers, and the rest comes from the form. `provider`
-   * names the route being edited when there is one — an adapter that already
-   * describes that route answers from its own registry, with better metadata
-   * and no network call, and needs no endpoint. A route it does not describe is
-   * asked over the wire, which is what `baseURL`, `api`, and `apiKey` are for.
-   *
-   * Nothing is written — the reply is candidates, and only a later
-   * `settings.mutate` decides what a route serves. `apiKey` is accepted here
-   * but never stored or returned; a provider whose key is already stored omits
-   * it and the endpoint answers unauthenticated or refuses.
-   */
-  discoverModels(
-    request: RpcRequest<{
-      settingsNs: string
-      provider?: string
-      baseURL?: string
-      api?: string
-      apiKey?: string
-    }>,
-    signal?: AbortSignal,
-  ): Promise<RpcResponse<{ models: DiscoveredModelView[] }>>
-}
-
-/** Wire view of one model an interrogated endpoint advertises. */
-export interface DiscoveredModelView {
-  /** Model id the endpoint accepts. */
-  id: string
-  /** Human-readable name when the endpoint supplies one. */
-  name?: string
-  /** Maximum combined request and response context, when disclosed. */
-  contextWindow?: number
-  /** Maximum output tokens, when disclosed. */
-  maxTokens?: number
-}

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

@@ -4,10 +4,6 @@
  */
 
 import type { HostApi } from './host.ts'
-import type { AgentPresetsApi } from './agent-presets.ts'
-import type { SkillsApi } from './skills.ts'
-import type { SettingsApi } from './settings.ts'
-import type { LlmApi } from './llm.ts'
 import type { RpcResponse } from './rpc.ts'
 
 /**
@@ -17,13 +13,6 @@ import type { RpcResponse } from './rpc.ts'
  */
 export interface RpcMethodMap {
   'host.describe': HostApi['describe']
-  'host.openPath': HostApi['openPath']
-  'skill.list': SkillsApi['list']
-  'agentPreset.openDocument': AgentPresetsApi['openDocument']
-  'settings.openDocument': SettingsApi['openDocument']
-  'llm.providers': LlmApi['providers']
-  'llm.models': LlmApi['models']
-  'llm.discoverModels': LlmApi['discoverModels']
 }
 
 /** Business request payload of method K (reaches through the RpcRequest narrow form to payload). */

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

@@ -41,7 +41,6 @@ export const rpcErrorSchema: z.ZodType<RpcError> = z.discriminatedUnion('code',
   z.object({ code: z.literal('agent-preset-not-found'), message: z.string(), details: z.object({ agentPreset: z.string(), available: z.array(z.string()) }) }),
   z.object({ code: z.literal('agent-preset-invalid'), message: z.string(), details: z.object({ agentPreset: z.string(), reason: z.string() }) }),
   z.object({ code: z.literal('agent-busy'), message: z.string(), details: z.object({ reason: z.string() }) }),
-  z.object({ code: z.literal('model-discovery-failed'), message: z.string(), details: z.object({ settingsNs: z.string(), baseURL: z.string().optional() }) }),
   z.object({ code: z.literal('internal'), message: z.string(), details: z.object({}) }),
 ]) as unknown as z.ZodType<RpcError>
 

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

@@ -36,15 +36,6 @@ export interface RpcErrorDetailsMap {
   'agent-preset-not-found': { agentPreset: string; available: readonly string[] }
   'agent-preset-invalid': { agentPreset: string; reason: string }
   'agent-busy': { reason: string }
-  /**
-   * Interrogating a draft provider endpoint did not produce a model listing:
-   * no adapter family serves the namespace, the protocol has no listing this
-   * build can read, or the endpoint was unreachable, refused the credential,
-   * or answered with something else. The message is the adapter's own text —
-   * it is what the form shows before falling back to hand-entry — and the
-   * details name the endpoint asked, never the credential offered.
-   */
-  'model-discovery-failed': { settingsNs: string; baseURL?: string }
   'internal': {}
 }
 

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

@@ -1,16 +0,0 @@
-/**
- * settings domain zod schemas (names derived from map keys:
- * settingsOpenDocumentRequestSchema / settingsOpenDocumentValueSchema).
- */
-
-import { z } from 'zod'
-import type { RequestPayload, ResponseValue } from './rpc-map.ts'
-import type { Wire } from './rpc.schema.ts'
-
-/** settings.openDocument request payload. */
-export const settingsOpenDocumentRequestSchema = z.object({}) satisfies z.ZodType<Wire<RequestPayload<'settings.openDocument'>>>
-
-/** settings.openDocument response value. */
-export const settingsOpenDocumentValueSchema = z.object({
-  opened: z.literal(true),
-}) satisfies z.ZodType<Wire<ResponseValue<'settings.openDocument'>>>

+ 0 - 22
packages/host/apiproxy/src/api/settings.ts

@@ -1,22 +0,0 @@
-/**
- * settings domain contract: what remains of the web face of the user-settings
- * seam (`ctx.settings`) once the redacted read and the path-addressed write
- * moved to the `settings` Remote namespace. Only the local-document handoff
- * stays here, because opening a Host file is a platform action rather than a
- * settings read.
- */
-
-import type { RpcRequest, RpcResponse } from './rpc.ts'
-
-/** Settings-domain unary methods (the map keys settings.* of RpcMethodMap). */
-export interface SettingsApi {
-  /**
-   * Materialize the configured local document when absent and ask the Host to
-   * hand it to the platform text-document opener. macOS forces a text editor;
-   * Linux and Windows use the desktop file association. The request carries
-   * no path, so the browser cannot choose an arbitrary Host filesystem target.
-   */
-  openDocument(
-    request: RpcRequest<{}>, signal: AbortSignal,
-  ): Promise<RpcResponse<{ opened: true }>>
-}

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

@@ -1,28 +0,0 @@
-/**
- * skills domain zod schemas (names derived from map keys: skillListRequestSchema /
- * skillListValueSchema).
- */
-
-import { z } from 'zod'
-import type { RequestPayload, ResponseValue } from './rpc-map.ts'
-import type { Wire } from './rpc.schema.ts'
-import { sessionIdSchema } from './ids.schema.ts'
-import type { SkillEntry } from './skills.ts'
-
-/** SkillEntry row of skill.list. */
-export const skillEntrySchema = z.object({
-  name: z.string().min(1),
-  description: z.string(),
-  whenToUse: z.string().optional(),
-  modelInvocable: z.boolean(),
-}) satisfies z.ZodType<Wire<SkillEntry>>
-
-/** skill.list request payload. */
-export const skillListRequestSchema = z.object({
-  sessionId: sessionIdSchema,
-}) satisfies z.ZodType<Wire<RequestPayload<'skill.list'>>>
-
-/** skill.list response value. */
-export const skillListValueSchema = z.object({
-  skills: z.array(skillEntrySchema),
-}) satisfies z.ZodType<Wire<ResponseValue<'skill.list'>>>

+ 0 - 33
packages/host/apiproxy/src/api/skills.ts

@@ -1,33 +0,0 @@
-/**
- * skills domain contract: read-only skill catalog lookup addressed by session.
- * The session's header cwd resolves to the canonical project root host-side —
- * the client never submits a raw path, and skill lookup never creates or
- * resumes an Agent.
- */
-
-import type { SessionId } from '@deepseek-ai/dsh-session/types'
-import type { RpcRequest, RpcResponse } from './rpc.ts'
-
-/** Skill catalog row (wire projection of the host SkillSummary; provider/source vocabulary stays host-side). */
-export interface SkillEntry {
-  /** Kebab-case identifier the user references as `/name` in the composer. */
-  readonly name: string
-  /** Short routing description. */
-  readonly description: string
-  /** Optional extra routing guidance. */
-  readonly whenToUse?: string
-  /** False marks a user-only skill (`disable-model-invocation`): invocable here, absent from the model catalog. */
-  readonly modelInvocable: boolean
-}
-
-/**
- * Skill-domain unary methods (the map key skill.* of RpcMethodMap). Listing
- * is the domain's only RPC: invocation uses Session Controller's ordinary
- * prompt Remote. The host recognizes its leading `/name` token at the pre-step
- * boundary (`dsh-tool-skill` injects the rendered body there), so every client
- * shares one deterministic path with no dedicated invocation method.
- */
-export interface SkillsApi {
-  /** Lists the user-invocable skill catalog for the session's project. */
-  list(request: RpcRequest<{ sessionId: SessionId }>): Promise<RpcResponse<{ skills: readonly SkillEntry[] }>>
-}

+ 1 - 57
packages/host/apiproxy/src/fetch/client.ts

@@ -12,17 +12,7 @@ import type { ClientRequest, RpcMessage, RpcResponse } from '../api/rpc.ts'
 import { RpcId } from '../api/rpc.ts'
 import type { Wire } from '../api/rpc.schema.ts'
 import { serverResponseSchema } from '../api/rpc.schema.ts'
-import {
-  hostDescribeValueSchema, hostOpenPathValueSchema,
-} from '../api/host.schema.ts'
-import { skillListValueSchema } from '../api/skills.schema.ts'
-import {
-  agentPresetOpenDocumentValueSchema,
-} from '../api/agent-presets.schema.ts'
-import {
-  settingsOpenDocumentValueSchema,
-} from '../api/settings.schema.ts'
-import { llmDiscoverModelsValueSchema, llmModelsValueSchema, llmProvidersValueSchema } from '../api/llm.schema.ts'
+import { hostDescribeValueSchema } from '../api/host.schema.ts'
 
 /**
  * Client consumption face of the contract (shape a): same domain tree as ApiProxy, but unary
@@ -39,21 +29,6 @@ import { llmDiscoverModelsValueSchema, llmModelsValueSchema, llmProvidersValueSc
 export interface IApiClient {
   host: {
     describe(payload: RequestPayload<'host.describe'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'host.describe'>>>
-    openPath(payload: RequestPayload<'host.openPath'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'host.openPath'>>>
-  }
-  skills: {
-    list(payload: RequestPayload<'skill.list'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'skill.list'>>>
-  }
-  agentPresets: {
-    openDocument(payload: RequestPayload<'agentPreset.openDocument'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'agentPreset.openDocument'>>>
-  }
-  settings: {
-    openDocument(payload: RequestPayload<'settings.openDocument'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'settings.openDocument'>>>
-  }
-  llm: {
-    providers(payload: RequestPayload<'llm.providers'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'llm.providers'>>>
-    models(payload: RequestPayload<'llm.models'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'llm.models'>>>
-    discoverModels(payload: RequestPayload<'llm.discoverModels'>, signal?: AbortSignal): Promise<RpcResponse<ResponseValue<'llm.discoverModels'>>>
   }
 }
 
@@ -63,13 +38,6 @@ export interface IApiClient {
  */
 const UNARY_VALUE_SCHEMAS: { [K in keyof RpcMethodMap]: z.ZodType<Wire<ResponseValue<K>>> } = {
   'host.describe': hostDescribeValueSchema,
-  'host.openPath': hostOpenPathValueSchema,
-  'skill.list': skillListValueSchema,
-  'agentPreset.openDocument': agentPresetOpenDocumentValueSchema,
-  'settings.openDocument': settingsOpenDocumentValueSchema,
-  'llm.providers': llmProvidersValueSchema,
-  'llm.models': llmModelsValueSchema,
-  'llm.discoverModels': llmDiscoverModelsValueSchema,
 }
 
 /** Default timeout for bounded unary calls (rpc-compare 2026-07-19: a hung host must not leave callers pending forever). */
@@ -195,30 +163,6 @@ export abstract class AbstractApiClient implements IApiClient {
 
   readonly host: IApiClient['host'] = {
     describe: (payload, signal) => this.callUnary('host.describe', payload, signal),
-    openPath: (payload, signal) => this.callUnary('host.openPath', payload, signal),
-  }
-
-  readonly skills: IApiClient['skills'] = {
-    list: (payload, signal) => this.callUnary('skill.list', payload, signal),
-  }
-
-  // Annotated like every sibling, and load-bearing rather than cosmetic:
-  // inferring this member inlines `AgentPresetEntry` into the emitted
-  // declaration by the specifier TS picks — the host `index.ts` — which drags
-  // the whole gateway, and with it the host `Context` merges, into every
-  // Client program that imports this carrier.
-  readonly agentPresets: IApiClient['agentPresets'] = {
-    openDocument: (payload, signal) => this.callUnary('agentPreset.openDocument', payload, signal),
-  }
-
-  readonly settings: IApiClient['settings'] = {
-    openDocument: (payload, signal) => this.callUnary('settings.openDocument', payload, signal),
-  }
-
-  readonly llm: IApiClient['llm'] = {
-    providers: (payload, signal) => this.callUnary('llm.providers', payload, signal),
-    models: (payload, signal) => this.callUnary('llm.models', payload, signal),
-    discoverModels: (payload, signal) => this.callUnary('llm.discoverModels', payload, signal),
   }
 
 }

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

@@ -14,17 +14,7 @@ import type { ClientRequest, RpcError, RpcRequest, RpcResponse, ServerResponse }
 import { RpcId } from '../api/rpc.ts'
 import type { Wire } from '../api/rpc.schema.ts'
 import { clientRequestSchema } from '../api/rpc.schema.ts'
-import {
-  hostDescribeRequestSchema, hostOpenPathRequestSchema,
-} from '../api/host.schema.ts'
-import { skillListRequestSchema } from '../api/skills.schema.ts'
-import {
-  agentPresetOpenDocumentRequestSchema,
-} from '../api/agent-presets.schema.ts'
-import {
-  settingsOpenDocumentRequestSchema,
-} from '../api/settings.schema.ts'
-import { llmDiscoverModelsRequestSchema, llmModelsRequestSchema, llmProvidersRequestSchema } from '../api/llm.schema.ts'
+import { hostDescribeRequestSchema } from '../api/host.schema.ts'
 
 /**
  * Unary dispatch table, keyed by (and compiler-locked to) RpcMethodMap: a map row without a
@@ -44,13 +34,6 @@ type UnaryRoutes = {
 
 const UNARY_ROUTES: UnaryRoutes = {
   'host.describe': { schema: hostDescribeRequestSchema, invoke: (api, r) => api.host.describe(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) },
-  'settings.openDocument': { schema: settingsOpenDocumentRequestSchema, invoke: (api, r, signal) => api.settings.openDocument(r, signal) },
-  'llm.providers': { schema: llmProvidersRequestSchema, invoke: (api, r) => api.llm.providers(r) },
-  'llm.models': { schema: llmModelsRequestSchema, invoke: (api, r) => api.llm.models(r) },
-  'llm.discoverModels': { schema: llmDiscoverModelsRequestSchema, invoke: (api, r, signal) => api.llm.discoverModels(r, signal) },
 }
 
 /** Route lookup that narrows an arbitrary path segment to a map key (single cast point for the string→key refinement). */

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

@@ -14,8 +14,6 @@
 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 {
@@ -63,8 +61,7 @@ export interface Config {
  */
 export class ApiProxyService extends Service implements ApiProxy {
   static inject = [
-    'agentDefaultModel', 'agents', 'attachments', 'directoryPicker', 'llm', 'sessions', 'sessionQuery',
-    'sessionController',
+    'agentDefaultModel', 'agents', 'attachments', 'sessions', 'sessionQuery',
   ]
 
   static Config: z<Config> = z.object({
@@ -74,10 +71,6 @@ export class ApiProxyService extends Service implements ApiProxy {
   })
 
   readonly host: ApiProxy['host']
-  readonly skills: ApiProxy['skills']
-  readonly agentPresets: ApiProxy['agentPresets']
-  readonly settings: ApiProxy['settings']
-  readonly llm: ApiProxy['llm']
   readonly downloads: ApiProxy['downloads']
 
   constructor(ctx: Context, config: Config) {
@@ -91,10 +84,6 @@ export class ApiProxyService extends Service implements ApiProxy {
         : { sessionExportCompressionLevel: config.sessionExportCompressionLevel }),
     })
     this.host = api.host
-    this.skills = api.skills
-    this.agentPresets = api.agentPresets
-    this.settings = api.settings
-    this.llm = api.llm
     this.downloads = api.downloads
   }
 }

+ 0 - 202
packages/host/apiproxy/src/native-path-opener.ts

@@ -1,202 +0,0 @@
-/**
- * Cross-platform native path and text-document openers used by the local GUI
- * carrier.
- *
- * The default intent prefers the default browser for documents it renders when
- * the platform can name one, then falls back to the default application. WSL
- * translates every path for the Windows desktop instead of assuming a Linux
- * GUI. The text-editor intent never consults the browser.
- */
-
-import { release as osRelease } from 'node:os'
-import { extname } from 'node:path'
-import { runNativeCommand, type NativeCommandRunner } from '@deepseek-ai/dsh-native-command'
-
-/** Testable command boundary; native implementations never invoke a shell. */
-export type PathOpenerRunner = NativeCommandRunner
-
-/** Injectable platform facts for deterministic adapter tests. */
-export interface PathOpenerInternals {
-  platform?: NodeJS.Platform
-  /** Kernel release override used to distinguish WSL from desktop Linux. */
-  osRelease?: string
-  /** Environment used for WSL markers and the desktop Linux browser convention. */
-  env?: NodeJS.ProcessEnv
-  run?: PathOpenerRunner
-}
-
-/** Documents a browser renders, as opposed to ones an editor merely edits. */
-const BROWSER_DOCUMENTS = new Set(['.html', '.htm', '.xhtml', '.svg'])
-
-/**
- * The macOS bundle registered for `https` — the default browser, as
- * LaunchServices records it. The nested version dict is stripped first
- * because it carries its own `LSHandlerRoleAll`.
- */
-function macBundleForHttps(plist: string): string | undefined {
-  const stripped = plist.replace(/LSHandlerPreferredVersions\s*=\s*\{[^}]*\};/g, '')
-  const block = /\{[^{}]*LSHandlerURLScheme\s*=\s*"?https"?;[^{}]*\}/.exec(stripped)?.[0]
-  if (block === undefined) return undefined
-  return /LSHandlerRoleAll\s*=\s*"?([\w.-]+)"?;/.exec(block)?.[1]
-}
-
-/**
- * Open one browser-renderable document with the default browser.
- * @returns true when a browser took it; false when this platform cannot name
- * one, or naming it failed — the caller then uses the default application.
- */
-async function openInBrowser(
-  path: string, signal: AbortSignal, platform: NodeJS.Platform,
-  run: PathOpenerRunner, env: NodeJS.ProcessEnv,
-): Promise<boolean> {
-  if (platform === 'darwin') {
-    let bundle: string | undefined
-    try {
-      const { stdout } = await run(
-        'defaults', ['read', 'com.apple.LaunchServices/com.apple.launchservices.secure'], signal)
-      bundle = macBundleForHttps(stdout)
-    } catch {
-      // No LaunchServices record (a fresh account never changed a default):
-      // the content-type handler is then the system's own choice anyway.
-      return false
-    }
-    if (bundle === undefined) return false
-    await run('open', ['-b', bundle, path], signal)
-    return true
-  }
-  if (platform === 'linux') {
-    // $BROWSER is the portable convention; desktop-entry resolution through
-    // xdg-settings needs a launcher this package has no business shipping.
-    const browser = env.BROWSER
-    if (browser === undefined || browser === '') return false
-    await run(browser, [path], signal)
-    return true
-  }
-  // Windows names no browser without reading the UserChoice registry, and its
-  // .html association is the browser in the ordinary case.
-  return false
-}
-
-/** Native path-open intent; macOS distinguishes text editing from file association. */
-type PathOpenIntent = 'default' | 'text-editor'
-
-/** PowerShell single-quoted literal (doubles embedded quotes). */
-function powershellLiteral(path: string): string {
-  return `'${path.replace(/'/g, "''")}'`
-}
-
-/** Whether one environment marker is set to a non-empty value. */
-function present(value: string | undefined): boolean {
-  return value !== undefined && value !== ''
-}
-
-/** Distinguish WSL from desktop Linux using its process and kernel markers. */
-function isWsl(internals: PathOpenerInternals): boolean {
-  const env = internals.env ?? process.env
-  if (present(env.WSL_DISTRO_NAME) || present(env.WSL_INTEROP)) return true
-  return (internals.osRelease ?? osRelease()).toLowerCase().includes('microsoft')
-}
-
-/** Open one Windows-resolvable path through its registered desktop application. */
-async function openWindowsPath(path: string, signal: AbortSignal, run: PathOpenerRunner): Promise<void> {
-  await run('powershell.exe', [
-    '-NoProfile',
-    '-Command',
-    `Invoke-Item -LiteralPath ${powershellLiteral(path)}`,
-  ], signal)
-}
-
-/** Translate a WSL path before handing it to the Windows desktop. */
-async function openWslPath(path: string, signal: AbortSignal, run: PathOpenerRunner): Promise<void> {
-  const translated = await run('wslpath', ['-w', path], signal)
-  signal.throwIfAborted()
-  const windowsPath = translated.stdout.replace(/[\r\n]+$/, '')
-  if (windowsPath === '') throw new Error('wslpath returned no Windows path')
-  await openWindowsPath(windowsPath, signal, run)
-}
-
-/** Dispatch one shell-free platform command for the requested open intent. */
-async function openNativePathWithIntent(
-  path: string,
-  signal: AbortSignal,
-  intent: PathOpenIntent,
-  internals: PathOpenerInternals = {},
-): Promise<void> {
-  const platform = internals.platform ?? process.platform
-  const run = internals.run ?? runNativeCommand
-  const env = internals.env ?? process.env
-  const wsl = platform === 'linux' && isWsl(internals)
-
-  if (!wsl && intent === 'default' && BROWSER_DOCUMENTS.has(extname(path).toLowerCase())
-    && await openInBrowser(path, signal, platform, run, env)) return
-
-  if (platform === 'darwin') {
-    await run('open', intent === 'text-editor' ? ['-t', path] : [path], signal)
-    return
-  }
-
-  if (platform === 'win32') {
-    await openWindowsPath(path, signal, run)
-    return
-  }
-
-  if (platform === 'linux') {
-    if (wsl) {
-      await openWslPath(path, signal, run)
-      return
-    }
-    await run('xdg-open', [path], signal)
-    return
-  }
-
-  throw new Error(`native path opener is unsupported on ${platform}`)
-}
-
-/**
- * Whether {@link openNativePath} plausibly reaches a desktop on this host.
- *
- * macOS and Windows always carry a desktop opener; Linux does when it is WSL
- * (the Windows desktop takes the path) or a display server is announced.
- * A headless or containerised Linux host answers false, which is what lets a
- * surface show a path as text instead of offering a button that would spawn
- * `xdg-open` into nothing.
- * @param internals - platform and environment seam for deterministic tests.
- * @returns true when handing a path to the native opener can work at all.
- */
-export function canOpenNativePath(internals: PathOpenerInternals = {}): boolean {
-  const platform = internals.platform ?? process.platform
-  if (platform === 'darwin' || platform === 'win32') return true
-  if (platform !== 'linux') return false
-  const env = internals.env ?? process.env
-  return isWsl(internals) || present(env.DISPLAY) || present(env.WAYLAND_DISPLAY)
-}
-
-/**
- * Open a filesystem path with the operating system's default application, or
- * with the default browser when the path names a document a browser renders.
- * @param path - absolute or host-resolvable path (caller owns resolution).
- * @param signal - caller/connection lifetime; abort terminates the native command.
- * @param internals - Platform, environment, and runner hooks for deterministic tests.
- */
-export function openNativePath(
-  path: string,
-  signal: AbortSignal,
-  internals: PathOpenerInternals = {},
-): Promise<void> {
-  return openNativePathWithIntent(path, signal, 'default', internals)
-}
-
-/**
- * Open a text document for editing; macOS bypasses the file-type association
- * so a YAML association with a browser cannot consume the gesture.
- * @param path - absolute or host-resolvable text-document path.
- * @param signal - caller/connection lifetime; abort terminates the native command.
- * @param internals - Platform and runner hooks for deterministic tests.
- */
-export function openNativeTextFile(
-  path: string,
-  signal: AbortSignal,
-  internals: PathOpenerInternals = {},
-): Promise<void> {
-  return openNativePathWithIntent(path, signal, 'text-editor', internals)
-}

+ 0 - 21
packages/host/apiproxy/tsconfig.json

@@ -8,9 +8,6 @@
     "src"
   ],
   "references": [
-    {
-      "path": "../../settings/settings"
-    },
     {
       "path": "../../credentials/credentials"
     },
@@ -29,39 +26,21 @@
     {
       "path": "../../attachment/attachment"
     },
-    {
-      "path": "../../llm/llm"
-    },
     {
       "path": "../../core/agent"
     },
     {
       "path": "../../core/agent-default-model"
     },
-    {
-      "path": "../../preset/agent-presets"
-    },
     {
       "path": "../../core/session"
     },
-    {
-      "path": "../../core/scope"
-    },
     {
       "path": "../../session/session-persistence"
     },
     {
       "path": "../../session-query/session-query"
     },
-    {
-      "path": "../../skill/skill"
-    },
-    {
-      "path": "../../interaction/commands"
-    },
-    {
-      "path": "../directory-picker"
-    },
     {
       "path": "../../runtime-diagnostics/invariants"
     },