From 51402ac7af148d25c2ffce7fa807c852622d67c5 Mon Sep 17 00:00:00 2001 From: creatixchu Date: Tue, 28 Jul 2026 21:25:19 +0800 Subject: [PATCH] refactor(util): extract the shared no-shell native-command runner to dsh-native-command master's toolcall-open extracted runNativeCommand inside apiproxy for the openPath opener while the picker seam had moved the native chooser (its other consumer) into directory-picker-native; after the merge the two packages each carried a verbatim copy. The runner now lives in packages/util/native-command (zero-dependency library, per the util-group contract) and both native integrations depend on it. --- docs/module-graph.md | 3 ++ packages/host/apiproxy/package.json | 1 + .../host/apiproxy/src/native-path-opener.ts | 2 +- packages/host/apiproxy/tsconfig.json | 3 ++ .../host/directory-picker-native/package.json | 3 +- .../src/native-command.ts | 38 ---------------- .../src/native-picker.ts | 2 +- .../directory-picker-native/tsconfig.json | 3 ++ packages/util/README.i18n.yaml | 6 +-- packages/util/README.md | 1 + packages/util/README.zh.md | 1 + packages/util/native-command/README.i18n.yaml | 6 +++ packages/util/native-command/README.md | 27 ++++++++++++ packages/util/native-command/README.zh.md | 27 ++++++++++++ packages/util/native-command/package.json | 37 ++++++++++++++++ .../native-command/src/index.ts} | 8 +++- packages/util/native-command/src/invariant.ts | 31 +++++++++++++ .../tests/native-command.spec.ts | 43 +++++++++++++++++++ packages/util/native-command/tsconfig.json | 15 +++++++ pnpm-lock.yaml | 15 +++++++ .../verify-package-readme-model-experience.ts | 1 + tsconfig.host.json | 1 + 22 files changed, 229 insertions(+), 45 deletions(-) delete mode 100644 packages/host/directory-picker-native/src/native-command.ts create mode 100644 packages/util/native-command/README.i18n.yaml create mode 100644 packages/util/native-command/README.md create mode 100644 packages/util/native-command/README.zh.md create mode 100644 packages/util/native-command/package.json rename packages/{host/apiproxy/src/native-command.ts => util/native-command/src/index.ts} (77%) create mode 100644 packages/util/native-command/src/invariant.ts create mode 100644 packages/util/native-command/tests/native-command.spec.ts create mode 100644 packages/util/native-command/tsconfig.json diff --git a/docs/module-graph.md b/docs/module-graph.md index ddc77f1f21..c11ca86378 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -9,6 +9,7 @@ Inter-package dependencies among the `@deepseek-ai/dsh-*` harness packages, deri flowchart TD subgraph group_util["packages/util"] pkg_brand["brand"] + pkg_native_command["native-command"] pkg_paths["paths"] pkg_retention["retention"] pkg_timeout["timeout"] @@ -244,6 +245,7 @@ flowchart TD pkg_workspace["workspace"] end pkg_brand --> pkg_invariants + pkg_native_command --> pkg_invariants pkg_paths --> pkg_invariants pkg_retention --> pkg_invariants pkg_timeout --> pkg_invariants @@ -920,6 +922,7 @@ flowchart TD | --- | --- | --- | | [`invariants`](../packages/support/invariants) | `support` | — | | [`brand`](../packages/util/brand) | `util` | [`invariants`](../packages/support/invariants) | +| [`native-command`](../packages/util/native-command) | `util` | [`invariants`](../packages/support/invariants) | | [`paths`](../packages/util/paths) | `util` | [`invariants`](../packages/support/invariants) | | [`retention`](../packages/util/retention) | `util` | [`invariants`](../packages/support/invariants) | | [`timeout`](../packages/util/timeout) | `util` | [`invariants`](../packages/support/invariants) | diff --git a/packages/host/apiproxy/package.json b/packages/host/apiproxy/package.json index d90c52816d..cc9ed2b493 100644 --- a/packages/host/apiproxy/package.json +++ b/packages/host/apiproxy/package.json @@ -45,6 +45,7 @@ "@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-session": "workspace:^", "@deepseek-ai/dsh-session-persistence": "workspace:^", "@deepseek-ai/dsh-session-projection": "workspace:^", diff --git a/packages/host/apiproxy/src/native-path-opener.ts b/packages/host/apiproxy/src/native-path-opener.ts index 15a6d7a73b..a4fbbaa72e 100644 --- a/packages/host/apiproxy/src/native-path-opener.ts +++ b/packages/host/apiproxy/src/native-path-opener.ts @@ -1,6 +1,6 @@ /** Cross-platform open-with-default-application used by the local GUI carrier. */ -import { runNativeCommand, type NativeCommandRunner } from './native-command.ts' +import { runNativeCommand, type NativeCommandRunner } from '@deepseek-ai/dsh-native-command' /** Testable command boundary; native implementations never invoke a shell. */ export type PathOpenerRunner = NativeCommandRunner diff --git a/packages/host/apiproxy/tsconfig.json b/packages/host/apiproxy/tsconfig.json index d3ba26038a..f5f5931602 100644 --- a/packages/host/apiproxy/tsconfig.json +++ b/packages/host/apiproxy/tsconfig.json @@ -55,6 +55,9 @@ }, { "path": "../../support/invariants" + }, + { + "path": "../../util/native-command" } ] } diff --git a/packages/host/directory-picker-native/package.json b/packages/host/directory-picker-native/package.json index 8db5d3a9df..72cb8a3e8a 100644 --- a/packages/host/directory-picker-native/package.json +++ b/packages/host/directory-picker-native/package.json @@ -27,7 +27,8 @@ ], "license": "BSD-3-Clause", "dependencies": { - "@deepseek-ai/dsh-host-directory-picker": "workspace:^" + "@deepseek-ai/dsh-host-directory-picker": "workspace:^", + "@deepseek-ai/dsh-native-command": "workspace:^" }, "peerDependencies": { "@deepseek-ai/dsh-invariants": "^0.0.1", diff --git a/packages/host/directory-picker-native/src/native-command.ts b/packages/host/directory-picker-native/src/native-command.ts deleted file mode 100644 index 0efe9679d8..0000000000 --- a/packages/host/directory-picker-native/src/native-command.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** Shared no-shell `execFile` runner for native host dialogs and openers. */ - -import { execFile } from 'node:child_process' - -/** Testable command boundary; native implementations never invoke a shell. */ -export type NativeCommandRunner = ( - command: string, - args: readonly string[], - signal: AbortSignal, -) => Promise<{ stdout: string; stderr: string }> - -/** - * Run a host command with utf8 stdio, abort propagation, and Windows hide. - * @param command - executable path or PATH name. - * @param args - argv (never a shell string). - * @param signal - caller/connection lifetime; abort terminates the child. - * @returns captured stdout/stderr on exit 0. - */ -export const runNativeCommand: NativeCommandRunner = (command, args, signal) => - new Promise((resolve, reject) => { - execFile( - command, - [...args], - { encoding: 'utf8', signal, windowsHide: true }, - (error, stdout, stderr) => { - if (error !== null) { - const failure = Object.assign(new Error(error.message, { cause: error }), { - code: error.code, - stdout, - stderr, - }) - reject(failure) - return - } - resolve({ stdout, stderr }) - }, - ) - }) diff --git a/packages/host/directory-picker-native/src/native-picker.ts b/packages/host/directory-picker-native/src/native-picker.ts index 0ae95dfe74..ee3d3075e5 100644 --- a/packages/host/directory-picker-native/src/native-picker.ts +++ b/packages/host/directory-picker-native/src/native-picker.ts @@ -1,6 +1,6 @@ /** Cross-platform native single-directory chooser behind the dialog backend's capability. */ -import { runNativeCommand, type NativeCommandRunner } from './native-command.ts' +import { runNativeCommand, type NativeCommandRunner } from '@deepseek-ai/dsh-native-command' /** Testable command boundary; native implementations never invoke a shell. */ export type DirectoryPickerRunner = NativeCommandRunner diff --git a/packages/host/directory-picker-native/tsconfig.json b/packages/host/directory-picker-native/tsconfig.json index 99ca673189..64a32c3441 100644 --- a/packages/host/directory-picker-native/tsconfig.json +++ b/packages/host/directory-picker-native/tsconfig.json @@ -19,6 +19,9 @@ }, { "path": "../../support/invariants" + }, + { + "path": "../../util/native-command" } ] } diff --git a/packages/util/README.i18n.yaml b/packages/util/README.i18n.yaml index 1fc811bc8b..8bd1ff35b2 100644 --- a/packages/util/README.i18n.yaml +++ b/packages/util/README.i18n.yaml @@ -1,6 +1,6 @@ # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: -# pnpm run verify-translation-pairing --write -README.md: 140df90571d84320fb4eb888508c67e60aa29a22 -README.zh.md: 4c16df2a56476c0a7c965a037389fa5ba231e273 +# pnpm run verify-translation-pairing --write packages/util/README.md +README.md: 605c3dd0beebc16109e8e6bc944ea722a60975c0 +README.zh.md: 5c66ded33a36079f80965cf466449843e07511f0 diff --git a/packages/util/README.md b/packages/util/README.md index 140df90571..605c3dd0be 100644 --- a/packages/util/README.md +++ b/packages/util/README.md @@ -10,6 +10,7 @@ Zero-dependency primitives shared across the other groups. A package lands here | `paths/` | Canonical single-root `DSH_HOME` resolution plus shared filesystem path constants and helpers for harness user data (no harness deps) | | `timeout/` | The timing/classification half of a timeout — `clampTimeout`/`deadline`/`timeoutOf`/`TimeoutReason` (pure functions, no harness deps); termination stays in each capability | | `retention/` | Bounded model-facing output — `ItemRetainer`/`TextRetainer` + neutral notice helpers (pure, no harness deps); business semantics stay in each tool | +| `native-command/` | No-shell `execFile` runner for host-native OS integrations — utf8 capture, abort propagation, Windows hide (no harness deps); command choice stays in each caller | `dsh-brand` is the canonical case: it owns ONLY the `Branded` helper, so a capability package can brand the ids it owns (`dsh-tasks`'s `TaskId`, `dsh-session`'s `SessionId`, …) by depending on `dsh-brand` alone, without pulling in an unrelated package just to reach `Branded`. diff --git a/packages/util/README.zh.md b/packages/util/README.zh.md index 4c16df2a56..5c66ded33a 100644 --- a/packages/util/README.zh.md +++ b/packages/util/README.zh.md @@ -10,6 +10,7 @@ | `paths/` | 规范的单根 `DSH_HOME` 解析,以及 harness 用户数据的共享文件系统路径常量和辅助工具(无 harness 依赖) | | `timeout/` | 超时的时序/分类部分:`clampTimeout`/`deadline`/`timeoutOf`/`TimeoutReason`(纯函数,无 harness 依赖);终止机制保留在各个功能中 | | `retention/` | 有界的面向模型输出:`ItemRetainer`/`TextRetainer` 加上中性通知辅助工具(纯工具,无 harness 依赖);业务语义保留在各个工具中 | +| `native-command/` | 宿主原生 OS 集成的免 shell `execFile` 运行器——utf8 捕获、abort 传播、Windows 窗口隐藏(无 harness 依赖);命令选择保留在各调用方 | `dsh-brand` 是规范示例:它只负责 `Branded` 辅助工具,因此功能包可以为自己拥有的 id 添加品牌(`dsh-tasks` 的 `TaskId`、`dsh-session` 的 `SessionId` 等),而只需依赖 `dsh-brand`,无需仅为使用 `Branded` 而引入不相关的包。 diff --git a/packages/util/native-command/README.i18n.yaml b/packages/util/native-command/README.i18n.yaml new file mode 100644 index 0000000000..7d711e9e28 --- /dev/null +++ b/packages/util/native-command/README.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/util/native-command/README.md +README.md: 7fc8b1f4640ef87ada62b6656854feb37080e4e6 +README.zh.md: 7c1cacb06d1d58601cc9e63c2ebd9c5f0ccb8159 diff --git a/packages/util/native-command/README.md b/packages/util/native-command/README.md new file mode 100644 index 0000000000..7fc8b1f464 --- /dev/null +++ b/packages/util/native-command/README.md @@ -0,0 +1,27 @@ +# dsh-native-command + +English | [中文](README.zh.md) + +A **zero-dependency no-shell `execFile` runner** shared by host-native OS integrations: one `runNativeCommand(command, args, signal)` call spawns the executable directly (never a shell string), captures utf8 stdout/stderr, propagates the caller's abort into child termination, and hides the transient console window on Windows. Failures reject with the exit `code` and both captured streams attached, so callers classify (missing tool, cancelled, real failure) without re-running anything. + +Its two consumers are the host-side native integrations: the [`directory-picker-native`](../../host/directory-picker-native/README.md) backend's OS chooser commands and the gateway's open-with-default-application hand-off ([`dsh-host-apiproxy`](../../host/apiproxy/README.md) `host.openPath`). The `NativeCommandRunner` type is the injectable command boundary those callers expose for deterministic tests. + +It is a **library, not a service or plugin**: no `ctx`, registers nothing, holds no state, emits no events. + +## Surface + +```ts +import { runNativeCommand, type NativeCommandRunner } from '@deepseek-ai/dsh-native-command' +``` + +## Model Experience + +None, as this is host-side subprocess plumbing; nothing here reaches a model request. + +#### KV Cache effect + +None; this package neither assembles nor sends a provider request. + +## Known Limitations and Deferred Work + +- **No output bounding** — both streams buffer unbounded in memory; every current caller invokes small native tools whose output is a path or an error line. Adopt `dsh-retention` bounding before pointing this at commands with meaningful output volume. diff --git a/packages/util/native-command/README.zh.md b/packages/util/native-command/README.zh.md new file mode 100644 index 0000000000..7c1cacb06d --- /dev/null +++ b/packages/util/native-command/README.zh.md @@ -0,0 +1,27 @@ +# dsh-native-command + +[English](README.md) | 中文 + +宿主原生 OS 集成共享的**零依赖免 shell `execFile` 运行器**:一次 `runNativeCommand(command, args, signal)` 调用直接派生可执行文件(绝不拼 shell 字符串),以 utf8 捕获 stdout/stderr,把调用方的 abort 传播为子进程终止,并在 Windows 上隐藏瞬时控制台窗口。失败时以附带退出 `code` 与两路已捕获输出的错误拒绝,调用方无需重跑即可分类(工具缺失、已取消、真实失败)。 + +它的两个消费者都是宿主侧原生集成:[`directory-picker-native`](../../host/directory-picker-native/README.zh.md) 后端的 OS 选择器命令,以及网关的按默认应用打开转交([`dsh-host-apiproxy`](../../host/apiproxy/README.zh.md) 的 `host.openPath`)。`NativeCommandRunner` 类型是这些调用方为确定性测试暴露的可注入命令边界。 + +它是**库,不是服务或插件**:没有 `ctx`、不注册任何东西、不持有状态、不发事件。 + +## Surface + +```ts +import { runNativeCommand, type NativeCommandRunner } from '@deepseek-ai/dsh-native-command' +``` + +## Model Experience + +无;这是宿主侧子进程管道,这里没有任何东西进入模型请求。 + +#### KV Cache effect + +无;该包既不组装也不发送 provider 请求。 + +## Known Limitations and Deferred Work + +- **不做输出限量**——两路流在内存中无界缓冲;当前每个调用方只运行输出为一个路径或一行错误的小型原生工具。把它指向输出量可观的命令之前,先接入 `dsh-retention` 限量。 diff --git a/packages/util/native-command/package.json b/packages/util/native-command/package.json new file mode 100644 index 0000000000..a20e61c33d --- /dev/null +++ b/packages/util/native-command/package.json @@ -0,0 +1,37 @@ +{ + "name": "@deepseek-ai/dsh-native-command", + "description": "Zero-dependency no-shell execFile runner for host-native OS integrations: utf8 stdio capture, abort propagation, Windows hide", + "version": "0.0.1", + "private": true, + "type": "module", + "main": "lib/index.js", + "types": "lib/types/index.d.ts", + "exports": { + ".": { + "types": "./lib/types/index.d.ts", + "default": "./lib/index.js" + }, + "./invariant": { + "types": "./lib/types/invariant.d.ts", + "default": "./lib/invariant.js" + }, + "./src/*": "./src/*", + "./package.json": "./package.json" + }, + "files": [ + "lib/index.js", + "lib/invariant.js", + "lib/types/**/*.d.ts", + "lib/types/**/*.d.ts.map", + "src" + ], + "license": "BSD-3-Clause", + "peerDependencies": { + "@deepseek-ai/dsh-invariants": "^0.0.1", + "cordis": "^4.0.0-rc.7" + }, + "devDependencies": { + "@deepseek-ai/dsh-invariants": "workspace:^", + "cordis": "^4.0.0-rc.7" + } +} diff --git a/packages/host/apiproxy/src/native-command.ts b/packages/util/native-command/src/index.ts similarity index 77% rename from packages/host/apiproxy/src/native-command.ts rename to packages/util/native-command/src/index.ts index 0efe9679d8..8ad8b81749 100644 --- a/packages/host/apiproxy/src/native-command.ts +++ b/packages/util/native-command/src/index.ts @@ -1,4 +1,10 @@ -/** Shared no-shell `execFile` runner for native host dialogs and openers. */ +/** + * Shared no-shell `execFile` runner for host-native OS integrations (the + * native directory chooser, the open-with-default-application hand-off): + * utf8 stdio capture, abort propagation, Windows console hide. A library, + * not a plugin — no ctx, no state, no events. + * @module @deepseek-ai/dsh-native-command + */ import { execFile } from 'node:child_process' diff --git a/packages/util/native-command/src/invariant.ts b/packages/util/native-command/src/invariant.ts new file mode 100644 index 0000000000..bec1d4b774 --- /dev/null +++ b/packages/util/native-command/src/invariant.ts @@ -0,0 +1,31 @@ +/** + * Package-owned invariant companion for `@deepseek-ai/dsh-native-command`. + * @module @deepseek-ai/dsh-native-command/invariant + */ + +/* jscpd:ignore-start */ +import type { Context } from 'cordis' +import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants' + +const PACKAGE_NAME = '@deepseek-ai/dsh-native-command' + +/** Cordis companion plugin name. */ +export const name = 'native-command-invariant' +/** Service required before the companion can reserve package ownership. */ +export const inject = ['invariants'] + +/** + * No runtime invariant: each run is one stateless child-process round trip + * with no owned event stream or mutable runtime data; behavior is enforced by + * unit tests. + */ +const install: InvariantInstaller = () => {} + +/** + * Register this package's invariant companion. + * @param ctx - Cordis context carrying the invariant service. + * @returns the installed registration's disposer after setup succeeds. + */ +export const apply = (ctx: Context): Promise<() => void> => + Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install)) +/* jscpd:ignore-end */ diff --git a/packages/util/native-command/tests/native-command.spec.ts b/packages/util/native-command/tests/native-command.spec.ts new file mode 100644 index 0000000000..4c0adc40f4 --- /dev/null +++ b/packages/util/native-command/tests/native-command.spec.ts @@ -0,0 +1,43 @@ +import { describe, expect, it } from 'vitest' +import { runNativeCommand } from '@deepseek-ai/dsh-native-command' + +const node = process.execPath + +describe('runNativeCommand', () => { + it('captures utf8 stdout and stderr on exit 0', async () => { + const result = await runNativeCommand( + node, + ['-e', 'process.stdout.write("out✓"); process.stderr.write("err")'], + new AbortController().signal, + ) + expect(result).toEqual({ stdout: 'out✓', stderr: 'err' }) + }) + + it('rejects a non-zero exit with code, stdout, and stderr attached', async () => { + const failure = await runNativeCommand( + node, + ['-e', 'process.stdout.write("partial"); process.stderr.write("boom"); process.exit(3)'], + new AbortController().signal, + ).then(() => { throw new Error('unexpected resolve') }, (error: unknown) => error) + expect(failure).toMatchObject({ code: 3, stdout: 'partial', stderr: 'boom' }) + expect((failure as Error).cause).toBeInstanceOf(Error) + }) + + it('rejects a missing executable with the spawn ENOENT code', async () => { + const failure = await runNativeCommand( + 'dsh-definitely-missing-command', + [], + new AbortController().signal, + ).then(() => { throw new Error('unexpected resolve') }, (error: unknown) => error) + expect(failure).toMatchObject({ code: 'ENOENT' }) + }) + + it('terminates the child when the signal aborts', async () => { + const abort = new AbortController() + const pending = runNativeCommand(node, ['-e', 'setTimeout(() => {}, 60_000)'], abort.signal) + abort.abort() + const failure = await pending.then(() => { throw new Error('unexpected resolve') }, (error: unknown) => error) + expect(failure).toBeInstanceOf(Error) + expect((failure as { code?: unknown }).code).toBe('ABORT_ERR') + }) +}) diff --git a/packages/util/native-command/tsconfig.json b/packages/util/native-command/tsconfig.json new file mode 100644 index 0000000000..d970a00263 --- /dev/null +++ b/packages/util/native-command/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "lib/types" + }, + "include": [ + "src" + ], + "references": [ + { + "path": "../../support/invariants" + } + ] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1059d6b02b..9b06cc5b19 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2682,6 +2682,9 @@ importers: '@deepseek-ai/dsh-llm': specifier: workspace:^ version: link:../../llm/llm + '@deepseek-ai/dsh-native-command': + specifier: workspace:^ + version: link:../../util/native-command '@deepseek-ai/dsh-session': specifier: workspace:^ version: link:../../core/session @@ -2753,6 +2756,9 @@ importers: '@deepseek-ai/dsh-host-directory-picker': specifier: workspace:^ version: link:../directory-picker + '@deepseek-ai/dsh-native-command': + specifier: workspace:^ + version: link:../../util/native-command devDependencies: '@deepseek-ai/dsh-invariants': specifier: workspace:^ @@ -4797,6 +4803,15 @@ importers: specifier: ^4.0.0-rc.7 version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5) + packages/util/native-command: + devDependencies: + '@deepseek-ai/dsh-invariants': + specifier: workspace:^ + version: link:../../support/invariants + cordis: + specifier: ^4.0.0-rc.7 + version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5) + packages/util/paths: devDependencies: '@deepseek-ai/dsh-invariants': diff --git a/scripts/verify-package-readme-model-experience.ts b/scripts/verify-package-readme-model-experience.ts index 930b99ce7f..2184f90d89 100644 --- a/scripts/verify-package-readme-model-experience.ts +++ b/scripts/verify-package-readme-model-experience.ts @@ -116,6 +116,7 @@ const SENTENCE_MODEL_EXPERIENCE: Readonly> = { 'packages/ui/user-interaction': { kind: 'indirect', reason: 'Model-facing consumers render provider answers and seam errors.' }, 'packages/util/timeout': { kind: 'indirect', reason: 'Only timeout consumers render timeout outcomes.' }, 'packages/util/retention': { kind: 'indirect', reason: 'Only retention consumers render retained content and omission metadata.' }, + 'packages/util/native-command': { kind: 'none', reason: 'The host-side subprocess runner registers no model surface.' }, 'packages/web/web': { kind: 'indirect', reason: 'The provider registry delegates model rendering to dsh-tool-web.' }, 'packages/web/web-fetch-local': { kind: 'indirect', reason: 'The provider backend delegates model rendering to dsh-tool-web.' }, 'packages/web/web-search-exa': { kind: 'indirect', reason: 'The provider backend delegates model rendering to dsh-tool-web.' }, diff --git a/tsconfig.host.json b/tsconfig.host.json index 6867ce6492..effb110c07 100644 --- a/tsconfig.host.json +++ b/tsconfig.host.json @@ -46,6 +46,7 @@ { "path": "./vendor/hmr" }, { "path": "./vendor/logger-console" }, { "path": "./packages/util/brand" }, + { "path": "./packages/util/native-command" }, { "path": "./packages/util/paths" }, { "path": "./packages/util/timeout" }, { "path": "./packages/util/retention" },