Keep embedded CLI imports on the carrier module tree

This commit is contained in:
winewill
2026-11-03 12:51:08 +08:00
parent 8632896e84
commit cbe275fe99
10 changed files with 34 additions and 19 deletions
+2 -2
View File
@@ -3,8 +3,8 @@
# After editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write apps/cli/README.md
/deepseek-ai-dsh:
en: 1668d6bae782422c
zh: 5637be16a7de8740
en: ebdc75fa0da18801
zh: 5c6cd2554b8f8a98
/deepseek-ai-dsh/entry-modes:
en: a1e035a813554366
zh: b87053214afe71b6
+1 -1
View File
@@ -2,7 +2,7 @@
English | [中文](README.zh.md)
The `dsh` command is the sole supported Node application launcher: profiles are ordered stacks of plugin-bundle patch layers under the user's own overrides. SDK and ACP are profiles, not separate public bins. The Python runtime wheel packages this same command; the SDK defaults to `sdk`, and the minimal example selects `sdk-minimal`. [`src/args.ts`](src/args.ts) owns the command grammar, and [`src/bin.ts`](src/bin.ts) loads only the selected runner. The installed Windows launcher resolves short paths before loading plugins so profile settings can be saved. Invalid commands, options from another mode, and fatal configuration or boot failures exit nonzero.
The `dsh` command is the sole supported Node application launcher: profiles are ordered stacks of plugin-bundle patch layers under the user's own overrides. SDK and ACP are profiles, not separate public bins. The Python runtime wheel packages this same command; the SDK defaults to `sdk`, and the minimal example selects `sdk-minimal`. [`src/args.ts`](src/args.ts) owns the command grammar, and [`src/bin.ts`](src/bin.ts) loads only the selected runner. Invalid commands, options from another mode, and fatal configuration or boot failures exit nonzero.
## Entry modes
+1 -1
View File
@@ -2,7 +2,7 @@
[English](README.md) | 中文
`dsh` 是唯一受支持的 Node 应用启动器;profile 由多个插件组合包 patch 层按顺序叠加而成,其上再应用用户自己的覆盖配置。SDK 与 ACP(Agent Client Protocol)都是 profile,而不是独立的公开可执行命令。Python 运行时 wheel 包中也包含同一个命令;SDK 默认使用 `sdk`,极简示例选择 `sdk-minimal`。[`src/args.ts`](src/args.ts) 负责命令语法,[`src/bin.ts`](src/bin.ts) 只加载选中的运行器。Windows 安装版启动器在加载插件前解析短路径,以便保存 profile 设置。无效命令、来自其他模式的选项,以及致命的配置或启动错误都会以非零状态退出。
`dsh` 是唯一受支持的 Node 应用启动器;profile 由多个插件组合包 patch 层按顺序叠加而成,其上再应用用户自己的覆盖配置。SDK 与 ACP(Agent Client Protocol)都是 profile,而不是独立的公开可执行命令。Python 运行时 wheel 包中也包含同一个命令;SDK 默认使用 `sdk`,极简示例选择 `sdk-minimal`。[`src/args.ts`](src/args.ts) 负责命令语法,[`src/bin.ts`](src/bin.ts) 只加载选中的运行器。无效命令、来自其他模式的选项,以及致命的配置或启动错误都会以非零状态退出。
## 入口模式
+2 -2
View File
@@ -27,5 +27,5 @@
en: f40edcf903a51f3f
zh: 8a9a915451047c8b
/dsh-cli-behavior-reference/source-execution:
en: 05c2b23790f7b296
zh: 51f809020fb230a1
en: 0fd6c72ba9a7eb3b
zh: 011c0ac4008ee480
+1 -1
View File
@@ -143,4 +143,4 @@ Install external plugin bundles through `dsh plugin --profile <name> add <packag
<a id="source-execution"></a>
## Source execution
From the repository root, run `pnpm run build` separately after a fresh checkout and whenever artifacts need updating, then use `pnpm dsh <args...>`. The `package.json` script launches `apps/cli/src/bin.ts` with `node --import tsx/esm` without building and forwards every argument. Missing Typert host artifacts fail profile boot through module-resolution errors without a build instruction. Once those host artifacts exist, missing frontend or client-plugin bundles fail at startup with an instruction to run `pnpm run build`. The launcher does not check freshness, so existing stale bundles can run older browser code until rebuilt. The process inherits the launch environment, and `runProfile` resolves the outbound proxy from that snapshot before any entry mounts, so `HTTP_PROXY`/`HTTPS_PROXY` (and a proxy declared in a `.env` layer) apply without any further flag. The source entry explicitly selects linked profile resolution so tsx workspace imports and profile plugins share module identities. The installed form launches the built `apps/cli/lib/bin.js` with runtime profile resolution without rebuilding the repository.
From the repository root, run `pnpm run build` separately after a fresh checkout and whenever artifacts need updating, then use `pnpm dsh <args...>`. The `package.json` script launches `apps/cli/src/bin.ts` with `node --import tsx/esm` without building and forwards every argument. Missing Typert host artifacts fail profile boot through module-resolution errors without a build instruction. Once those host artifacts exist, missing frontend or client-plugin bundles fail at startup with an instruction to run `pnpm run build`. The launcher does not check freshness, so existing stale bundles can run older browser code until rebuilt. The process inherits the launch environment, and `runProfile` resolves the outbound proxy from that snapshot before any entry mounts, so `HTTP_PROXY`/`HTTPS_PROXY` (and a proxy declared in a `.env` layer) apply without any further flag. The source entry explicitly selects linked profile resolution so tsx workspace imports and profile plugins share module identities. On Windows, the installed command expands 8.3 paths before loading profile dependencies. The installed form launches the built `apps/cli/lib/bin.js` with runtime profile resolution without rebuilding the repository.
+1 -1
View File
@@ -145,4 +145,4 @@ Web、headless 与 SDK 继承 base bundle 的原生工具执行;使用 [PTC ov
<a id="source-execution"></a>
## 源码执行
请在仓库根目录中,于全新 checkout 之后及产物需要更新时单独运行 `pnpm run build`,然后使用 `pnpm dsh <args...>`。`package.json` 中的脚本不会构建,而是通过 `node --import tsx/esm` 启动 `apps/cli/src/bin.ts`,并转发所有参数。Typert Host 产物缺失时,profile 启动会因不含构建指引的模块解析错误而失败。这些 Host 产物存在后,如果前端或 Client plugin 组合包缺失,启动会失败并提示运行 `pnpm run build`。启动器不会检查产物是否为最新,因此已有的陈旧组合包可能继续运行旧版浏览器代码,直至重新构建。该进程会继承启动环境,且 `runProfile` 会在任何 entry 挂载之前从该快照解析出站代理,因此 `HTTP_PROXY`/`HTTPS_PROXY`(以及写在 `.env` 层中的代理)无需任何额外开关即可生效。源码入口显式选择链接式 profile 解析,使 tsx workspace 导入与 profile 插件共享模块身份。安装形式会使用 runtime profile 解析直接启动构建后的 `apps/cli/lib/bin.js`,不会重新构建仓库。
请在仓库根目录中,于全新 checkout 之后及产物需要更新时单独运行 `pnpm run build`,然后使用 `pnpm dsh <args...>`。`package.json` 中的脚本不会构建,而是通过 `node --import tsx/esm` 启动 `apps/cli/src/bin.ts`,并转发所有参数。Typert Host 产物缺失时,profile 启动会因不含构建指引的模块解析错误而失败。这些 Host 产物存在后,如果前端或 Client plugin 组合包缺失,启动会失败并提示运行 `pnpm run build`。启动器不会检查产物是否为最新,因此已有的陈旧组合包可能继续运行旧版浏览器代码,直至重新构建。该进程会继承启动环境,且 `runProfile` 会在任何 entry 挂载之前从该快照解析出站代理,因此 `HTTP_PROXY`/`HTTPS_PROXY`(以及写在 `.env` 层中的代理)无需任何额外开关即可生效。源码入口显式选择链接式 profile 解析,使 tsx workspace 导入与 profile 插件共享模块身份。在 Windows 上,安装版命令在加载 profile 依赖前展开 8.3 短路径。安装形式会使用 runtime profile 解析直接启动构建后的 `apps/cli/lib/bin.js`,不会重新构建仓库。
+23 -9
View File
@@ -1,14 +1,28 @@
#!/usr/bin/env node
/** Installed CLI entry. Resolve Windows path aliases before loading runtime dependencies. */
/**
* Installed CLI entry for disk launchers and embedded runtimes.
* @module @deepseek-ai/dsh/installed-bin
*/
import { realpathSync } from 'node:fs'
import { pathToFileURL } from 'node:url'
import type { RunCliOptions } from './bin.ts'
const implementation = new URL('./cli.js', process.platform === 'win32'
? pathToFileURL(realpathSync.native(import.meta.filename))
: import.meta.url)
const cli: typeof import('./bin.ts') = await import(implementation.href)
/**
* Run the CLI in the importing carrier's module tree.
* @param options - Installation-owned runtime options.
* @returns Settlement of the selected command.
*/
export async function runCli(options?: RunCliOptions): Promise<void> {
const cli = await import('./bin.ts')
await cli.runCli(options)
}
/** Run the installed CLI with the options supplied by the hosting application. */
export const runCli = cli.runCli
if (import.meta.main) await runCli()
if (import.meta.main) {
// Windows ESM can retain an 8.3 spelling while profile resolution expands it.
const entry = process.platform === 'win32' ? pathToFileURL(realpathSync.native(import.meta.filename)).href : import.meta.url
if (entry === import.meta.url) await runCli()
else {
const canonical: typeof import('./installed-bin.ts') = await import(entry)
await canonical.runCli()
}
}
+1 -1
View File
@@ -351,7 +351,7 @@ describe.skipIf(!existsSync(dshBin))('dsh BUILT bin (node lib/bin.js, no tsx)',
symlinkSync(join(repoRoot, 'apps/cli/lib'), alias, 'junction')
const { stdout } = await execa(process.execPath, [
'--preserve-symlinks-main', join(alias, 'bin.js'), '--version',
], { timeout: SPAWN_TIMEOUT_MS })
], { timeout: SPAWN_TIMEOUT_MS, env: { DSH_HOME: home, DSH_TELEMETRY_DISABLED: '1' } })
expect(stdout).toBe(cliVersion)
} finally {
rmSync(home, { recursive: true, force: true })
+1 -1
View File
@@ -5,7 +5,7 @@ import { defineConfig } from 'tsdown'
* Declarations come from `tsc -b` (dts: false), matching every package.
*/
export default defineConfig({
entry: { bin: 'lib/types/installed-bin.js', cli: 'lib/types/bin.js', 'profile-boot': 'lib/types/profile-boot.js' },
entry: { bin: 'lib/types/installed-bin.js', 'profile-boot': 'lib/types/profile-boot.js' },
outDir: 'lib',
format: ['esm'],
platform: 'node',
@@ -31,6 +31,7 @@ const MANIFEST_BIN_ALLOWLIST = new Map<string, ManifestBin>([
/** Every JavaScript executable in an application or packaging workspace has one explicit role. */
const EXECUTABLE_SOURCE_ALLOWLIST = new Map<string, string>([
['apps/cli/src/installed-bin.ts', 'installed dsh command entry'],
['apps/cli/src/bin.ts', 'supported dsh application launcher'],
['apps/desktop/scripts/logged-notarytool.mjs', 'build-only notarization logging wrapper'],
['packages/context/time-context/tests/fixtures/driver.ts', 'test-only subprocess driver'],