mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-11-09 20:07:43 +08:00
feat(cli): generate the CLI help reference and add dsh plugin help
`scripts/gen-cli-help.ts` runs the source `dsh` launcher with temporary Harness and Agents homes and captures the launcher, `dsh plugin`, and every shipped profile's text help (profile names come from `PROFILE_TEMPLATES`). It recursively discovers subcommands from each page's `Commands:` section, shows identical alias help once with every invocation, and writes `docs/cli-help.md`, its Chinese page, and their pairing record. The record resolves links between the two pages as written, so a first run already matches `verify-translation-pairing`. `verify-cli-help` checks all three files and runs as the `cli-help` doc-sync leaf, which the static CI lane also runs on an unbuilt tree. `dsh plugin` now owns `-h`/`--help` and reads its own options only before the forwarded pnpm arguments: `dsh plugin --help` prints its help instead of failing on the missing `--profile`, while everything after the pnpm command (including `-h`, `--help`, and `--profile`) reaches pnpm verbatim. A `--profile` placed after the pnpm command is no longer accepted; the v0.2.1-alpha.1 upgrade guide covers the migration. Refs #4114
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
# Bilingual-pair consistency record for 2026-09-14-generated-cli-help-reference.md (docs/i18n/README.md): per heading
|
||||
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
||||
# After editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/process/2026-09-14-generated-cli-help-reference.md
|
||||
/agent-note-generate-the-cli-reference-from-command-help:
|
||||
en: 618bafe3fd2afdb9
|
||||
zh: 433df2a8d0530c41
|
||||
/agent-note-generate-the-cli-reference-from-command-help/problem:
|
||||
en: 2ad571458d5d8191
|
||||
zh: 4db6bddbad65bf5c
|
||||
/agent-note-generate-the-cli-reference-from-command-help/decision:
|
||||
en: d99a93133c460385
|
||||
zh: 0f710ecf6e7137f2
|
||||
/agent-note-generate-the-cli-reference-from-command-help/alternatives-considered:
|
||||
en: df2f7f07b3e84418
|
||||
zh: 2dd87333d9d460c3
|
||||
/agent-note-generate-the-cli-reference-from-command-help/consequences:
|
||||
en: aada6686406c892e
|
||||
zh: 9a30b6b1c5ab6d55
|
||||
@@ -0,0 +1,25 @@
|
||||
# Agent Note: Generate the CLI reference from command help
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-09-14-generated-cli-help-reference.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
Launcher flags, profile options, and nested commands have separate owners. A manually maintained command reference can omit subcommands or retain obsolete defaults.
|
||||
|
||||
## Decision
|
||||
|
||||
The CLI reference captures the supported `dsh` launcher's help, the plugin forwarder's help, and each shipped profile's help, then recursively discovers the subcommands listed in each page's `Commands:` section. Shipped profile names come from `PROFILE_TEMPLATES`. Every page retains its complete help text; identical alias help appears once with all invocation forms.
|
||||
|
||||
Generation uses temporary Harness and Agents homes. Help exits before application work starts and requires no server or model. The plugin forwarder exposes its own help before pnpm arguments; flags after the pnpm command remain pnpm input.
|
||||
|
||||
The generated bilingual pages retain CLI output in its original language. `verify-cli-help` compares the complete pages and pairing record and runs with the documentation checks.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
A second command inventory or help-specific runtime API would duplicate the parser's definitions. Reading actual help keeps the reference tied to the same descriptions, options, defaults, and examples users receive.
|
||||
|
||||
## Consequences
|
||||
|
||||
Command changes update the reference through the same generator. Reviewers can compare complete help without assembling separate command invocations.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Agent Note: 从命令帮助生成 CLI 参考
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-09-14-generated-cli-help-reference.md) | 中文
|
||||
|
||||
## Problem
|
||||
|
||||
启动器选项、profile 选项和嵌套命令由不同部分负责。手工维护的命令参考可能遗漏子命令或保留过时的默认值。
|
||||
|
||||
## Decision
|
||||
|
||||
CLI 参考采集受支持的 `dsh` 启动器帮助、插件转发器帮助和各随附 profile 的帮助,并递归发现每页 `Commands:` 段落列出的子命令。随附 profile 的名称来自 `PROFILE_TEMPLATES`。每页都保留完整的帮助文本;相同的别名帮助只展示一次,并列出所有调用形式。
|
||||
|
||||
生成过程使用临时 Harness home 和 Agents home。帮助在应用开始工作前退出,不需要服务器或模型。插件转发器在 pnpm 参数之前提供自己的帮助;pnpm 命令之后的选项仍作为 pnpm 输入。
|
||||
|
||||
生成的双语页面保留 CLI 输出的原始语言。`verify-cli-help` 比较完整页面和配对记录,并随文档检查一起运行。
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
另一份命令清单或专供帮助使用的运行时 API 会重复解析器的定义。读取实际帮助,可以让参考文档始终对应用户收到的说明、选项、默认值和示例。
|
||||
|
||||
## Consequences
|
||||
|
||||
命令变化通过同一个生成器更新参考文档。审阅者可以直接比较完整帮助,无需自行拼接各个命令的调用结果。
|
||||
@@ -3,8 +3,8 @@
|
||||
# After editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write apps/cli/reference/README.md
|
||||
/dsh-cli-behavior-reference:
|
||||
en: d25712a65d21ab45
|
||||
zh: b1c57b706bc64085
|
||||
en: 5a4f43756dae900e
|
||||
zh: d58c479481cfa5fe
|
||||
/dsh-cli-behavior-reference/profile-boot:
|
||||
en: e3a159750f5f9ed3
|
||||
zh: e02d9004fcc239f9
|
||||
@@ -18,8 +18,8 @@
|
||||
en: d6368bf97a02bd57
|
||||
zh: 2ab7888a108961ce
|
||||
/dsh-cli-behavior-reference/plugin-management:
|
||||
en: 9980ff1600fa9460
|
||||
zh: cc66ba45e27b5540
|
||||
en: 142404f01a747121
|
||||
zh: a6a5edbb0614bc62
|
||||
/dsh-cli-behavior-reference/web-profile:
|
||||
en: 42f0b9349cf1574b
|
||||
zh: a3cc6e352e71badb
|
||||
|
||||
@@ -4,6 +4,8 @@ English | [中文](README.zh.md)
|
||||
|
||||
This reference defines the profile, plugin-management, and config-dump command modes. Argv is parsed once through [`src/args.ts`](../src/args.ts), and [`src/bin.ts`](../src/bin.ts) dynamically imports only the selected runner.
|
||||
|
||||
The [generated command help](../../../docs/cli-help.md) contains complete launcher, plugin-management, and shipped-profile help. Run `pnpm run gen-cli-help` to refresh it; `pnpm run verify-cli-help` checks it against the current CLI.
|
||||
|
||||
## Profile boot
|
||||
|
||||
`dsh <name>` abbreviates `dsh --profile <name>` and boots the profile at `$DSH_HOME/profiles/<name>`. The shorthand name must immediately follow `dsh`; `plugin` remains the plugin-management command, so boot a profile with that name using `dsh --profile plugin`. The effective tree is composed over an empty root by applying, in order: each bundle patch named in the profile manifest's `dsh.profile.bundles` list, the profile's own `cordis.patch.yml`, the home-level `$DSH_HOME/cordis.patch.yml` (machine-local preferences shared by every profile, so it outranks the per-profile layer), and each `--patch <path>` overlay in argv order. Later layers win per row; a patch replaces the targeted row's complete `config` value rather than deep-merging keys, and may insert new rows. The final YAML composition controls whether `dsh-hmr` watches configuration; without HMR, changes require restart. A parse, schema, resolution, or plugin boot failure is reported and exits nonzero. SIGINT and SIGTERM dispose the mounted root before exit.
|
||||
@@ -80,6 +82,8 @@ New directories and files request modes `0700` and `0600` on POSIX. The CLI prin
|
||||
|
||||
`dsh plugin --profile <name> <args...>` initializes the profile when missing (shipped template, or `@deepseek-ai/dsh-base` alone for other names), then forwards `<args...>` to `pnpm` with the profile directory as working directory — `add`, `remove`, `why`, `update`, and every other pnpm verb work unchanged; pnpm must be on PATH. Relative path specs (`.`, `../plugin`, and their `file:`/`link:` forms) are anchored to the invoking directory first, so `add .` from a plugin checkout installs that checkout, not the profile. After every successful run, `dsh.profile.bundles` is reconciled against the installed state: each dependency resolving to a package whose manifest declares `"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }` joins the layer stack (so an `update` that gains the declaration activates it), a bundle-less dependency stays plain with a one-time warning, and a removed dependency leaves the stack.
|
||||
|
||||
`dsh plugin` reads its own options only before the forwarded arguments, so `--profile <name>` comes first. When the forwarded arguments begin with the pnpm command, everything after that command reaches pnpm verbatim, including `-h`, `--help`, and `--profile`. Otherwise `-h` or `--help` prints the forwarder's own help and exits 0.
|
||||
|
||||
The Codex and Claude Code subagent providers are separate optional Bundles. Add either package, both in one command, or remove either package independently:
|
||||
|
||||
```sh
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
本参考定义 profile 启动、插件管理和配置 dump 等命令模式。argv 由 [`src/args.ts`](../src/args.ts) 统一解析一次,[`src/bin.ts`](../src/bin.ts) 只会动态导入选中的运行器。
|
||||
|
||||
[生成的命令帮助](../../../docs/cli-help.zh.md)包含启动器、插件管理和随附 profile 的完整帮助。运行 `pnpm run gen-cli-help` 刷新,运行 `pnpm run verify-cli-help` 检查它是否与当前 CLI 一致。
|
||||
|
||||
<a id="profile-boot"></a>
|
||||
|
||||
## Profile 启动
|
||||
@@ -82,6 +84,8 @@ dsh --profile web --patch ./extra.yml --dump-config
|
||||
|
||||
`dsh plugin --profile <name> <args...>` 在 profile 缺失时先初始化它(有随附模板的用模板,其他名称只装 `@deepseek-ai/dsh-base`),然后以 profile 目录为工作目录,把 `<args...>` 转发给 `pnpm`:`add`、`remove`、`why`、`update` 及其他所有 pnpm 子命令都照常可用;pnpm 必须在 PATH 上。相对路径 spec(`.`、`../plugin` 及其 `file:`/`link:` 形式)会先锚定到调用目录,因此在插件 checkout 中执行 `add .` 安装的是该 checkout,而不是 profile。每次成功运行后,系统都会根据当前安装状态更新 `dsh.profile.bundles`:如果某项依赖解析到的包在 manifest 中声明了 `"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }`,该依赖就会加入配置层栈;如果某项依赖在 `update` 后获得该声明,也会随即激活。没有组合包声明的依赖仍作为普通依赖保留,并显示一次性警告;已移除的依赖则从配置层栈中删除。
|
||||
|
||||
`dsh plugin` 只在被转发的参数之前读取自己的选项,因此 `--profile <name>` 必须写在最前面。被转发的参数以 pnpm 命令开头时,该命令之后的所有内容都会原样交给 pnpm,包括 `-h`、`--help` 和 `--profile`。其他情况下,`-h` 或 `--help` 会打印转发器自身的帮助并以 0 退出。
|
||||
|
||||
Codex 与 Claude Code subagent 提供方是两个彼此独立的可选组合包。可以只添加一个包、在同一命令中添加两个包,或独立移除任一包:
|
||||
|
||||
```sh
|
||||
|
||||
@@ -187,6 +187,8 @@ export function parseDshArgs(argv: readonly string[], version: string, manageDes
|
||||
if (first === 'plugin') {
|
||||
const plugin = program.command('plugin').description('manage a profile\'s plugins by forwarding the remaining arguments to pnpm in the profile directory')
|
||||
plugin
|
||||
.helpOption('-h, --help', 'show this help')
|
||||
.passThroughOptions()
|
||||
.requiredOption('--profile <name>', 'the profile whose plugins to manage (initialized on first use)', selectProfile)
|
||||
.allowUnknownOption()
|
||||
.argument('[args...]', 'pnpm arguments, forwarded verbatim (add <pkg>, remove <pkg>, why <pkg>, ...)')
|
||||
|
||||
@@ -120,6 +120,21 @@ describe('parseDshArgs', () => {
|
||||
// Unknown pnpm flags forward verbatim.
|
||||
expect(parse(['plugin', '--profile', 'tui', 'add', '--save-dev', 'x']))
|
||||
.toEqual({ mode: 'plugin', profile: 'tui', args: ['add', '--save-dev', 'x'] })
|
||||
// Options after the pnpm command belong to pnpm, including the forwarder's own names.
|
||||
expect(parse(['plugin', '--profile', 'tui', 'add', '--help']))
|
||||
.toEqual({ mode: 'plugin', profile: 'tui', args: ['add', '--help'] })
|
||||
expect(parse(['plugin', '--profile', 'tui', 'add', '-h', '--profile', 'x']))
|
||||
.toEqual({ mode: 'plugin', profile: 'tui', args: ['add', '-h', '--profile', 'x'] })
|
||||
expect(exitCode(['plugin', 'add', 'x', '--profile', 'tui'])).toBe(1)
|
||||
})
|
||||
|
||||
it.each([
|
||||
['plugin', '--help'], ['plugin', '-h'], ['plugin', '--profile', 'tui', '--help'],
|
||||
['plugin', '--profile', 'tui', '--filter', 'x', 'add', '--help'],
|
||||
])('prints the plugin forwarder help for %j', (...argv: string[]) => {
|
||||
const stdout = vi.spyOn(process.stdout, 'write').mockReturnValue(true)
|
||||
expect(exitCode(argv)).toBe(0)
|
||||
expect(stdout.mock.calls.map(([chunk]) => String(chunk)).join('')).toContain('Usage: dsh plugin [options] [args...]')
|
||||
})
|
||||
|
||||
it.each(['desktop', 'Desktop', 'DESKTOP'])('permits installed Desktop plugin commands for %s', (profile) => {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Bilingual-pair consistency record for cli-help.md (docs/i18n/README.md): per heading
|
||||
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
||||
# After editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/cli-help.md
|
||||
/:
|
||||
en: 24a3ad7efe7ed273
|
||||
zh: 24a3ad7efe7ed273
|
||||
/dsh-cli-help:
|
||||
en: b7174eab3476579d
|
||||
zh: 5ddab967320e3cff
|
||||
/dsh-cli-help/contents:
|
||||
en: 00308bcc6dc90afd
|
||||
zh: 16f7442b76686a02
|
||||
/dsh-cli-help/dsh:
|
||||
en: e0695abcf7d8b521
|
||||
zh: 712c23b3c8a115ca
|
||||
/dsh-cli-help/dsh-plugin:
|
||||
en: adad99c125d0ac51
|
||||
zh: f11024971184f737
|
||||
/dsh-cli-help/dsh-acp:
|
||||
en: bcb0f84577ce5f03
|
||||
zh: 4382e617006849db
|
||||
/dsh-cli-help/dsh-headless:
|
||||
en: 878a1dd78017964d
|
||||
zh: bb43d91b4beb9bda
|
||||
/dsh-cli-help/dsh-sdk:
|
||||
en: 701f239c5157dedb
|
||||
zh: ee11be2932b05ce4
|
||||
/dsh-cli-help/dsh-sdk-minimal:
|
||||
en: 8f0d7548d299ffd3
|
||||
zh: fa2262e70d6819a0
|
||||
/dsh-cli-help/dsh-web:
|
||||
en: 5d073104e8954cc8
|
||||
zh: 91cd28f7c6ac96ac
|
||||
@@ -0,0 +1,193 @@
|
||||
<!-- Generated by scripts/gen-cli-help.ts; run pnpm run gen-cli-help to regenerate. -->
|
||||
|
||||
# dsh CLI help
|
||||
|
||||
This reference contains complete help for the launcher, subcommands, and shipped profiles. Identical help appears once with every invocation listed. Help output retains its original language.
|
||||
|
||||
Run `pnpm run gen-cli-help` to regenerate; run `pnpm run verify-cli-help` to check freshness.
|
||||
|
||||
## Contents
|
||||
|
||||
- [`dsh`](#dsh)
|
||||
- [`dsh plugin`](#dsh-plugin)
|
||||
- [`dsh acp`](#dsh-acp)
|
||||
- [`dsh headless`](#dsh-headless)
|
||||
- [`dsh sdk`](#dsh-sdk)
|
||||
- [`dsh sdk-minimal`](#dsh-sdk-minimal)
|
||||
- [`dsh web`](#dsh-web)
|
||||
|
||||
<a id="dsh"></a>
|
||||
## `dsh`
|
||||
|
||||
Invocations: `dsh --help`
|
||||
|
||||
```text
|
||||
Usage: dsh [--profile] <name> [options] [app-args...]
|
||||
dsh plugin --profile <name> <pnpm-args...>
|
||||
|
||||
dsh: boot a DeepSeek Harness profile — an ordered stack of plugin-bundle patch
|
||||
layers under your own overrides.
|
||||
|
||||
Arguments:
|
||||
args arguments for the booted profile's app (see:
|
||||
dsh --profile <name> --help)
|
||||
|
||||
Options:
|
||||
-V, --version output the version number
|
||||
--profile <name> the profile under $DSH_HOME/profiles to boot
|
||||
--from-default-profile <name> initialize a new custom profile from a shipped
|
||||
profile template
|
||||
--patch <path> extra patch-list overlay applied after the
|
||||
profile layer (repeatable)
|
||||
--dump-config print the composed profile tree and exit
|
||||
--dump-config-schema print JSON Schema for profile entries and
|
||||
patches without mounting
|
||||
--dump-default-config print the profile tree without its user layer
|
||||
or --patch overlays and exit
|
||||
|
||||
Examples:
|
||||
dsh web boot the web profile (same as: dsh --profile web)
|
||||
dsh rescue --from-default-profile web
|
||||
create rescue from the shipped web template, then boot it
|
||||
dsh headless "run the tests" answer one task, print the result, and exit
|
||||
dsh tui --patch ./extra.yml boot a custom profile with one extra overlay
|
||||
dsh tui --resume <session> arguments after the launcher flags reach the app
|
||||
dsh web --help the web app's own flags and help
|
||||
dsh plugin --profile tui add <package> install a plugin into the tui profile
|
||||
|
||||
```
|
||||
|
||||
<a id="dsh-plugin"></a>
|
||||
## `dsh plugin`
|
||||
|
||||
Invocations: `dsh plugin --help`
|
||||
|
||||
```text
|
||||
Usage: dsh plugin [options] [args...]
|
||||
|
||||
manage a profile's plugins by forwarding the remaining arguments to pnpm in the
|
||||
profile directory
|
||||
|
||||
Arguments:
|
||||
args pnpm arguments, forwarded verbatim (add <pkg>, remove <pkg>,
|
||||
why <pkg>, ...)
|
||||
|
||||
Options:
|
||||
--profile <name> the profile whose plugins to manage (initialized on first
|
||||
use)
|
||||
-h, --help show this help
|
||||
```
|
||||
|
||||
<a id="dsh-acp"></a>
|
||||
## `dsh acp`
|
||||
|
||||
Invocations: `dsh acp --help`, `dsh --profile acp --help`
|
||||
|
||||
```text
|
||||
Usage: dsh --profile acp [options]
|
||||
|
||||
Serve automation clients over Agent Client Protocol stdio.
|
||||
|
||||
Options:
|
||||
-h, --help show this help
|
||||
|
||||
Example:
|
||||
dsh --profile acp serve ACP until the client disconnects
|
||||
|
||||
```
|
||||
|
||||
<a id="dsh-headless"></a>
|
||||
## `dsh headless`
|
||||
|
||||
Invocations: `dsh headless --help`, `dsh --profile headless --help`
|
||||
|
||||
```text
|
||||
Usage: dsh --profile headless [options] [task...]
|
||||
|
||||
Answer one task and exit; the answer goes to stdout and diagnostics to stderr.
|
||||
|
||||
Arguments:
|
||||
task the task text; multiple words are joined by spaces, and `-`
|
||||
reads stdin
|
||||
|
||||
Options:
|
||||
--json write newline-delimited run events to stdout instead of the
|
||||
final message
|
||||
--session-id <id> adopt the persisted Session with this id; an unknown id is
|
||||
an error
|
||||
-h, --help show this help
|
||||
|
||||
Examples:
|
||||
dsh --profile headless "run the tests" answer one task and exit
|
||||
echo "run the tests" | dsh --profile headless read the task from stdin
|
||||
dsh --profile headless --json "run the tests" emit machine-readable run events
|
||||
dsh --profile headless --session-id session-… "continue" resume an existing Session
|
||||
|
||||
```
|
||||
|
||||
<a id="dsh-sdk"></a>
|
||||
## `dsh sdk`
|
||||
|
||||
Invocations: `dsh sdk --help`, `dsh --profile sdk --help`
|
||||
|
||||
```text
|
||||
Usage: dsh --profile sdk [options]
|
||||
|
||||
Serve DeepSeek Harness SDK clients over stdio JSON-RPC.
|
||||
|
||||
Options:
|
||||
-h, --help show this help
|
||||
|
||||
Example:
|
||||
dsh --profile sdk serve one SDK runtime until its client disconnects
|
||||
|
||||
```
|
||||
|
||||
<a id="dsh-sdk-minimal"></a>
|
||||
## `dsh sdk-minimal`
|
||||
|
||||
Invocations: `dsh sdk-minimal --help`, `dsh --profile sdk-minimal --help`
|
||||
|
||||
```text
|
||||
Usage: dsh --profile sdk-minimal [options]
|
||||
|
||||
Serve DeepSeek Harness SDK clients over stdio JSON-RPC.
|
||||
|
||||
Options:
|
||||
-h, --help show this help
|
||||
|
||||
Example:
|
||||
dsh --profile sdk-minimal serve one SDK runtime until its client disconnects
|
||||
|
||||
```
|
||||
|
||||
<a id="dsh-web"></a>
|
||||
## `dsh web`
|
||||
|
||||
Invocations: `dsh web --help`, `dsh --profile web --help`
|
||||
|
||||
```text
|
||||
Usage: dsh --profile web [options]
|
||||
|
||||
Serve the DeepSeek Harness browser UI.
|
||||
|
||||
Options:
|
||||
--host <host> bind host
|
||||
--no-open do not open the Web UI in the default browser
|
||||
--port <port> listen port; pass 0 to let the OS pick a free
|
||||
one
|
||||
--public-url <url> advertise this HTTP(S) root in the printed,
|
||||
opened, web-surface, and DSH_WEB_URL forms;
|
||||
grants no trust
|
||||
--trusted-host <authority...> extra authority the /api browser-trust fence
|
||||
accepts (host or host:port; repeatable)
|
||||
-h, --help show this help
|
||||
|
||||
Examples:
|
||||
dsh --profile web serve on the composed host and port
|
||||
dsh --profile web --no-open serve without opening a browser
|
||||
dsh --profile web --port 8080 serve on another port
|
||||
dsh --profile web --public-url https://app.example/ui/ --trusted-host app.example
|
||||
advertise a prefix-stripping HTTPS proxy entry and admit its authority
|
||||
|
||||
```
|
||||
@@ -0,0 +1,195 @@
|
||||
<!-- Generated by scripts/gen-cli-help.ts; run pnpm run gen-cli-help to regenerate. -->
|
||||
|
||||
# dsh 命令行帮助
|
||||
|
||||
[English](cli-help.md) | 中文
|
||||
|
||||
此参考收录启动器、子命令和随附 profile 的完整帮助。同一份帮助只展示一次,并列出所有调用方式。帮助输出保留原文。
|
||||
|
||||
运行 `pnpm run gen-cli-help` 重新生成;运行 `pnpm run verify-cli-help` 检查是否与当前命令一致。
|
||||
|
||||
## 目录
|
||||
|
||||
- [`dsh`](#dsh)
|
||||
- [`dsh plugin`](#dsh-plugin)
|
||||
- [`dsh acp`](#dsh-acp)
|
||||
- [`dsh headless`](#dsh-headless)
|
||||
- [`dsh sdk`](#dsh-sdk)
|
||||
- [`dsh sdk-minimal`](#dsh-sdk-minimal)
|
||||
- [`dsh web`](#dsh-web)
|
||||
|
||||
<a id="dsh"></a>
|
||||
## `dsh`
|
||||
|
||||
调用方式: `dsh --help`
|
||||
|
||||
```text
|
||||
Usage: dsh [--profile] <name> [options] [app-args...]
|
||||
dsh plugin --profile <name> <pnpm-args...>
|
||||
|
||||
dsh: boot a DeepSeek Harness profile — an ordered stack of plugin-bundle patch
|
||||
layers under your own overrides.
|
||||
|
||||
Arguments:
|
||||
args arguments for the booted profile's app (see:
|
||||
dsh --profile <name> --help)
|
||||
|
||||
Options:
|
||||
-V, --version output the version number
|
||||
--profile <name> the profile under $DSH_HOME/profiles to boot
|
||||
--from-default-profile <name> initialize a new custom profile from a shipped
|
||||
profile template
|
||||
--patch <path> extra patch-list overlay applied after the
|
||||
profile layer (repeatable)
|
||||
--dump-config print the composed profile tree and exit
|
||||
--dump-config-schema print JSON Schema for profile entries and
|
||||
patches without mounting
|
||||
--dump-default-config print the profile tree without its user layer
|
||||
or --patch overlays and exit
|
||||
|
||||
Examples:
|
||||
dsh web boot the web profile (same as: dsh --profile web)
|
||||
dsh rescue --from-default-profile web
|
||||
create rescue from the shipped web template, then boot it
|
||||
dsh headless "run the tests" answer one task, print the result, and exit
|
||||
dsh tui --patch ./extra.yml boot a custom profile with one extra overlay
|
||||
dsh tui --resume <session> arguments after the launcher flags reach the app
|
||||
dsh web --help the web app's own flags and help
|
||||
dsh plugin --profile tui add <package> install a plugin into the tui profile
|
||||
|
||||
```
|
||||
|
||||
<a id="dsh-plugin"></a>
|
||||
## `dsh plugin`
|
||||
|
||||
调用方式: `dsh plugin --help`
|
||||
|
||||
```text
|
||||
Usage: dsh plugin [options] [args...]
|
||||
|
||||
manage a profile's plugins by forwarding the remaining arguments to pnpm in the
|
||||
profile directory
|
||||
|
||||
Arguments:
|
||||
args pnpm arguments, forwarded verbatim (add <pkg>, remove <pkg>,
|
||||
why <pkg>, ...)
|
||||
|
||||
Options:
|
||||
--profile <name> the profile whose plugins to manage (initialized on first
|
||||
use)
|
||||
-h, --help show this help
|
||||
```
|
||||
|
||||
<a id="dsh-acp"></a>
|
||||
## `dsh acp`
|
||||
|
||||
调用方式: `dsh acp --help`, `dsh --profile acp --help`
|
||||
|
||||
```text
|
||||
Usage: dsh --profile acp [options]
|
||||
|
||||
Serve automation clients over Agent Client Protocol stdio.
|
||||
|
||||
Options:
|
||||
-h, --help show this help
|
||||
|
||||
Example:
|
||||
dsh --profile acp serve ACP until the client disconnects
|
||||
|
||||
```
|
||||
|
||||
<a id="dsh-headless"></a>
|
||||
## `dsh headless`
|
||||
|
||||
调用方式: `dsh headless --help`, `dsh --profile headless --help`
|
||||
|
||||
```text
|
||||
Usage: dsh --profile headless [options] [task...]
|
||||
|
||||
Answer one task and exit; the answer goes to stdout and diagnostics to stderr.
|
||||
|
||||
Arguments:
|
||||
task the task text; multiple words are joined by spaces, and `-`
|
||||
reads stdin
|
||||
|
||||
Options:
|
||||
--json write newline-delimited run events to stdout instead of the
|
||||
final message
|
||||
--session-id <id> adopt the persisted Session with this id; an unknown id is
|
||||
an error
|
||||
-h, --help show this help
|
||||
|
||||
Examples:
|
||||
dsh --profile headless "run the tests" answer one task and exit
|
||||
echo "run the tests" | dsh --profile headless read the task from stdin
|
||||
dsh --profile headless --json "run the tests" emit machine-readable run events
|
||||
dsh --profile headless --session-id session-… "continue" resume an existing Session
|
||||
|
||||
```
|
||||
|
||||
<a id="dsh-sdk"></a>
|
||||
## `dsh sdk`
|
||||
|
||||
调用方式: `dsh sdk --help`, `dsh --profile sdk --help`
|
||||
|
||||
```text
|
||||
Usage: dsh --profile sdk [options]
|
||||
|
||||
Serve DeepSeek Harness SDK clients over stdio JSON-RPC.
|
||||
|
||||
Options:
|
||||
-h, --help show this help
|
||||
|
||||
Example:
|
||||
dsh --profile sdk serve one SDK runtime until its client disconnects
|
||||
|
||||
```
|
||||
|
||||
<a id="dsh-sdk-minimal"></a>
|
||||
## `dsh sdk-minimal`
|
||||
|
||||
调用方式: `dsh sdk-minimal --help`, `dsh --profile sdk-minimal --help`
|
||||
|
||||
```text
|
||||
Usage: dsh --profile sdk-minimal [options]
|
||||
|
||||
Serve DeepSeek Harness SDK clients over stdio JSON-RPC.
|
||||
|
||||
Options:
|
||||
-h, --help show this help
|
||||
|
||||
Example:
|
||||
dsh --profile sdk-minimal serve one SDK runtime until its client disconnects
|
||||
|
||||
```
|
||||
|
||||
<a id="dsh-web"></a>
|
||||
## `dsh web`
|
||||
|
||||
调用方式: `dsh web --help`, `dsh --profile web --help`
|
||||
|
||||
```text
|
||||
Usage: dsh --profile web [options]
|
||||
|
||||
Serve the DeepSeek Harness browser UI.
|
||||
|
||||
Options:
|
||||
--host <host> bind host
|
||||
--no-open do not open the Web UI in the default browser
|
||||
--port <port> listen port; pass 0 to let the OS pick a free
|
||||
one
|
||||
--public-url <url> advertise this HTTP(S) root in the printed,
|
||||
opened, web-surface, and DSH_WEB_URL forms;
|
||||
grants no trust
|
||||
--trusted-host <authority...> extra authority the /api browser-trust fence
|
||||
accepts (host or host:port; repeatable)
|
||||
-h, --help show this help
|
||||
|
||||
Examples:
|
||||
dsh --profile web serve on the composed host and port
|
||||
dsh --profile web --no-open serve without opening a browser
|
||||
dsh --profile web --port 8080 serve on another port
|
||||
dsh --profile web --public-url https://app.example/ui/ --trusted-host app.example
|
||||
advertise a prefix-stripping HTTPS proxy entry and admit its authority
|
||||
|
||||
```
|
||||
@@ -0,0 +1,16 @@
|
||||
# Bilingual-pair consistency record for guide.md (docs/i18n/README.md): per heading
|
||||
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
||||
# After editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write docs/upgrade-guide/v0.2.1-alpha.1/plugin-option-placement/guide.md
|
||||
/:
|
||||
en: 26325999c8fa35d8
|
||||
zh: 1cee6fc8d459053c
|
||||
/dsh-plugin-option-placement:
|
||||
en: 3d717a2b7e9087d3
|
||||
zh: e6004d015e6a4829
|
||||
/dsh-plugin-option-placement/change:
|
||||
en: 27539de1a79a7eec
|
||||
zh: 3860da746b0f24a5
|
||||
/dsh-plugin-option-placement/migration:
|
||||
en: 543880bb55c786bc
|
||||
zh: 0be3793b66b0c1e6
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
kind: upgrade-guide
|
||||
description: "dsh plugin reads --profile and its own help only before the forwarded pnpm arguments."
|
||||
---
|
||||
|
||||
# `dsh plugin` option placement
|
||||
|
||||
English | [中文](guide.zh.md)
|
||||
|
||||
## Change
|
||||
|
||||
`dsh plugin` reads its own options only before the forwarded pnpm arguments. Previously it accepted `--profile <name>` anywhere on the command line, had no help of its own, and forwarded `-h` and `--help` to pnpm from any position.
|
||||
|
||||
When the forwarded arguments begin with the pnpm command, everything after that command now reaches pnpm verbatim, including `-h`, `--help`, and `--profile`. Otherwise `-h` or `--help` prints the `dsh plugin` help and exits 0. Scripts that place `--profile` after the pnpm command fail with `required option '--profile <name>' not specified`, and `dsh plugin --profile <name> --help` no longer prints pnpm's help.
|
||||
|
||||
## Migration
|
||||
|
||||
1. Move `--profile <name>` before the pnpm command: replace `dsh plugin add <package> --profile <name>` with `dsh plugin --profile <name> add <package>`.
|
||||
2. Request pnpm's help for one command after that command, as in `dsh plugin --profile <name> add --help`. For pnpm's general help, forward `help`: `dsh plugin --profile <name> help`.
|
||||
3. Confirm that `dsh plugin --help` prints `Usage: dsh plugin [options] [args...]` and that the commands from steps 1 and 2 reach pnpm.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
kind: upgrade-guide
|
||||
description: "dsh plugin 只在被转发的 pnpm 参数之前读取 --profile 和自身的帮助选项。"
|
||||
---
|
||||
|
||||
# `dsh plugin` 选项位置
|
||||
|
||||
[English](guide.md) | 中文
|
||||
|
||||
## 变更
|
||||
|
||||
`dsh plugin` 只在被转发的 pnpm 参数之前读取自己的选项。此前它接受出现在命令行任意位置的 `--profile <name>`,没有自己的帮助,并且无论 `-h` 和 `--help` 位于何处都会转发给 pnpm。
|
||||
|
||||
被转发的参数以 pnpm 命令开头时,该命令之后的所有内容现在都会原样交给 pnpm,包括 `-h`、`--help` 和 `--profile`。其他情况下,`-h` 或 `--help` 会打印 `dsh plugin` 的帮助并以 0 退出。把 `--profile` 写在 pnpm 命令之后的脚本会因 `required option '--profile <name>' not specified` 而失败,`dsh plugin --profile <name> --help` 也不再打印 pnpm 的帮助。
|
||||
|
||||
## 迁移
|
||||
|
||||
1. 把 `--profile <name>` 移到 pnpm 命令之前:将 `dsh plugin add <package> --profile <name>` 改为 `dsh plugin --profile <name> add <package>`。
|
||||
2. 查看某个 pnpm 命令的帮助时,把帮助选项写在该命令之后,例如 `dsh plugin --profile <name> add --help`。查看 pnpm 的总体帮助时转发 `help`:`dsh plugin --profile <name> help`。
|
||||
3. 确认 `dsh plugin --help` 打印 `Usage: dsh plugin [options] [args...]`,并且第 1、2 步中的命令能够到达 pnpm。
|
||||
@@ -150,6 +150,8 @@
|
||||
"verify-client-domain-graph": "tsx scripts/verify-client-domain-graph.ts",
|
||||
"gen-tsconfig-paths": "tsx scripts/gen-tsconfig-paths.ts",
|
||||
"verify-tsconfig-paths": "tsx scripts/gen-tsconfig-paths.ts --check",
|
||||
"gen-cli-help": "tsx scripts/gen-cli-help.ts",
|
||||
"verify-cli-help": "tsx scripts/gen-cli-help.ts --check",
|
||||
"gen-cordis-catalog": "tsx scripts/gen-cordis-catalog.ts",
|
||||
"verify-cordis-catalog": "tsx scripts/gen-cordis-catalog.ts --check",
|
||||
"gen-cordis-api": "tsx scripts/gen-cordis-api.ts",
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/** Command discovery and complete output preservation for the CLI reference. */
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { collectCliHelp, parseCliHelp } from './gen-cli-help.ts'
|
||||
|
||||
describe('CLI help discovery', () => {
|
||||
it('reads command rows while retaining wrapped descriptions and examples', () => {
|
||||
const help = 'Usage: dsh\r\n\r\nCommands:\r\n web [options] Serve the browser\r\n with a wrapped description\r\n plugin Manage plugins\r\n\r\nExamples:\r\n dsh web\r\n'
|
||||
const result = parseCliHelp(help)
|
||||
expect(result.commands).toEqual(['web', 'plugin'])
|
||||
expect(result.output).toBe(help.replaceAll('\r\n', '\n'))
|
||||
})
|
||||
|
||||
it('includes plugin, both profile forms, and their nested commands when launcher help has no command list', async () => {
|
||||
const visited: string[] = []
|
||||
const pages = await collectCliHelp(async (args) => {
|
||||
visited.push(args.join(' '))
|
||||
if (args.length === 0) return 'Usage: dsh [--profile] <name>\n'
|
||||
if (args[0] === 'plugin') return 'Usage: dsh plugin --profile <name> <args...>\n'
|
||||
const selected = args[0] === '--profile' ? args.slice(1) : args
|
||||
if (selected[1] === 'nested') return 'Usage: nested\n'
|
||||
return `Usage: ${selected[0]} [command]\n\nCommands:\n nested Run the nested command\n`
|
||||
}, ['web'])
|
||||
expect(visited).toEqual(['', 'plugin', 'web', 'web nested', '--profile web'])
|
||||
expect(pages.map(page => page.invocations)).toEqual([
|
||||
['dsh'], ['dsh plugin'], ['dsh web', 'dsh --profile web'],
|
||||
['dsh web nested', 'dsh --profile web nested'],
|
||||
])
|
||||
})
|
||||
|
||||
it.each(['', ' \r\n\n'])('rejects blank help %j', (help) => {
|
||||
expect(() => parseCliHelp(help)).toThrow('CLI help returned empty output')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,187 @@
|
||||
/** Generate paired CLI references by invoking the shipped launcher and profile help. */
|
||||
|
||||
import { execFile } from 'node:child_process'
|
||||
import { existsSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { promisify } from 'node:util'
|
||||
import { PROFILE_TEMPLATES } from '@deepseek-ai/dsh-app-boot'
|
||||
import {
|
||||
computeTranslationPairingRecord,
|
||||
renderTranslationPairingRecord,
|
||||
translationPairPaths,
|
||||
} from './translation-pairing-record.ts'
|
||||
import { parseTranslationPairingManifest, translationPairSourcePredicate } from './translation-pairing.ts'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
const paths = translationPairPaths('docs/cli-help.md')
|
||||
const execFileAsync = promisify(execFile)
|
||||
|
||||
/** Complete help text and the immediate subcommands it advertises. */
|
||||
export interface CliHelp {
|
||||
/** Complete help text with LF line endings. */
|
||||
output: string
|
||||
/** Immediate command names listed in the `Commands:` section, in their displayed order. */
|
||||
commands: string[]
|
||||
}
|
||||
|
||||
interface HelpPage {
|
||||
help: CliHelp
|
||||
invocations: [string, ...string[]]
|
||||
children: Map<string, HelpPage>
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover commands from actual text help while preserving every displayed line.
|
||||
* @param stdout - Successful CLI help output.
|
||||
* @returns Help text with LF line endings and the command names listed in its `Commands:` section.
|
||||
* @throws When the output is empty.
|
||||
*/
|
||||
export function parseCliHelp(stdout: string): CliHelp {
|
||||
const output = stdout.replaceAll('\r\n', '\n')
|
||||
if (output.trim() === '') throw new Error('CLI help returned empty output')
|
||||
const section = /^Commands:\n((?:[ \t][^\n]*\n|\n)*)/mu.exec(output)?.[1] ?? ''
|
||||
const commands = [...section.matchAll(/^ {2}\S+/gmu)].map(match => match[0].slice(2))
|
||||
return { output, commands }
|
||||
}
|
||||
|
||||
function addAlias(page: HelpPage, invocation: string): void {
|
||||
if (page.invocations.includes(invocation)) return
|
||||
page.invocations.push(invocation)
|
||||
for (const [name, child] of page.children) addAlias(child, `${invocation} ${name}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect launcher, plugin, and profile help even when root help lists no commands.
|
||||
* @param readHelp - run one help invocation and return its complete stdout.
|
||||
* @param profiles - shipped profile names whose explicit and shorthand forms must be documented.
|
||||
* @returns distinct help pages with every discovered invocation and nested command.
|
||||
*/
|
||||
export async function collectCliHelp(
|
||||
readHelp: (args: readonly string[]) => Promise<string>, profiles: readonly string[],
|
||||
): Promise<HelpPage[]> {
|
||||
const pages = new Map<string, HelpPage>()
|
||||
const visit = async (args: string[]): Promise<HelpPage> => {
|
||||
const invocation = ['dsh', ...args].join(' ')
|
||||
const help = parseCliHelp(await readHelp(args))
|
||||
const existing = pages.get(help.output)
|
||||
if (existing !== undefined) {
|
||||
addAlias(existing, invocation)
|
||||
return existing
|
||||
}
|
||||
const page: HelpPage = { help, invocations: [invocation], children: new Map() }
|
||||
pages.set(help.output, page)
|
||||
for (const name of help.commands) page.children.set(name, await visit([...args, name]))
|
||||
return page
|
||||
}
|
||||
await visit([])
|
||||
await visit(['plugin'])
|
||||
for (const profile of [...profiles].sort()) {
|
||||
await visit([profile])
|
||||
await visit(['--profile', profile])
|
||||
}
|
||||
return [...pages.values()]
|
||||
}
|
||||
|
||||
async function collectHelp(): Promise<HelpPage[]> {
|
||||
const directory = mkdtempSync(join(tmpdir(), 'dsh-cli-help-'))
|
||||
const environment = {
|
||||
...process.env,
|
||||
DSH_HOME: join(directory, 'harness'),
|
||||
DSH_AGENTS_HOME: join(directory, 'agents'),
|
||||
DSH_TELEMETRY_DISABLED: '1',
|
||||
NO_COLOR: '1',
|
||||
}
|
||||
for (const name of ['NODE_OPTIONS', 'FORCE_COLOR']) Reflect.deleteProperty(environment, name)
|
||||
try {
|
||||
return await collectCliHelp(async (args) => {
|
||||
const { stdout, stderr } = await execFileAsync(process.execPath, [
|
||||
'--import', 'tsx/esm', 'apps/cli/src/bin.ts', ...args, '--help',
|
||||
], {
|
||||
cwd: root, env: environment, encoding: 'utf8', timeout: 30_000,
|
||||
killSignal: 'SIGKILL', maxBuffer: 2 * 1024 * 1024,
|
||||
})
|
||||
if (stderr !== '') throw new Error(`${['dsh', ...args].join(' ')} --help wrote diagnostics: ${stderr}`)
|
||||
return stdout
|
||||
}, Object.keys(PROFILE_TEMPLATES))
|
||||
} finally {
|
||||
rmSync(directory, { recursive: true, force: true })
|
||||
}
|
||||
}
|
||||
|
||||
function anchor(page: HelpPage): string {
|
||||
return page.invocations[0].replaceAll(/[^a-zA-Z0-9]+/gu, '-').replace(/-$/u, '').toLowerCase()
|
||||
}
|
||||
|
||||
function renderHelp(pages: readonly HelpPage[], chinese: boolean): string {
|
||||
const lines = [
|
||||
'<!-- Generated by scripts/gen-cli-help.ts; run pnpm run gen-cli-help to regenerate. -->',
|
||||
'',
|
||||
chinese ? '# dsh 命令行帮助' : '# dsh CLI help',
|
||||
'',
|
||||
...(chinese ? ['[English](cli-help.md) | 中文', ''] : []),
|
||||
chinese
|
||||
? '此参考收录启动器、子命令和随附 profile 的完整帮助。同一份帮助只展示一次,并列出所有调用方式。帮助输出保留原文。'
|
||||
: 'This reference contains complete help for the launcher, subcommands, and shipped profiles. Identical help appears once with every invocation listed. Help output retains its original language.',
|
||||
'',
|
||||
chinese
|
||||
? '运行 `pnpm run gen-cli-help` 重新生成;运行 `pnpm run verify-cli-help` 检查是否与当前命令一致。'
|
||||
: 'Run `pnpm run gen-cli-help` to regenerate; run `pnpm run verify-cli-help` to check freshness.',
|
||||
'',
|
||||
chinese ? '## 目录' : '## Contents',
|
||||
'',
|
||||
...pages.map(page => `- [\`${page.invocations[0]}\`](#${anchor(page)})`),
|
||||
'',
|
||||
]
|
||||
for (const page of pages) {
|
||||
lines.push(
|
||||
`<a id="${anchor(page)}"></a>`,
|
||||
`## \`${page.invocations[0]}\``,
|
||||
'',
|
||||
`${chinese ? '调用方式' : 'Invocations'}: ${page.invocations.map(invocation => `\`${invocation} --help\``).join(', ')}`,
|
||||
'',
|
||||
`\`\`\`text\n${page.help.output}${page.help.output.endsWith('\n') ? '' : '\n'}\`\`\``,
|
||||
'',
|
||||
)
|
||||
}
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
/** Regenerate both CLI reference pages, or check their bytes with --check. @returns Nothing. */
|
||||
export async function main(): Promise<void> {
|
||||
const check = process.argv.includes('--check')
|
||||
const pages = await collectHelp()
|
||||
const source = renderHelp(pages, false)
|
||||
const zh = renderHelp(pages, true)
|
||||
const written = new Set([paths.source, paths.zh])
|
||||
const context = {
|
||||
repoRoot: root,
|
||||
isTranslationPairSource: translationPairSourcePredicate(parseTranslationPairingManifest(
|
||||
readFileSync(resolve(root, 'scripts/translation-pairing.manifest.json'), 'utf8'),
|
||||
)),
|
||||
// Resolve links between the two pages as this run writes them, so a first run
|
||||
// records the same hashes that verify-translation-pairing computes afterward.
|
||||
repositoryFileExists: (path: string) => written.has(path)
|
||||
|| existsSync(resolve(root, path)) && statSync(resolve(root, path)).isFile(),
|
||||
}
|
||||
const outputs = new Map([
|
||||
[paths.source, source],
|
||||
[paths.zh, zh],
|
||||
[paths.meta, renderTranslationPairingRecord(paths, computeTranslationPairingRecord(paths, source, zh, context))],
|
||||
])
|
||||
const changed: string[] = []
|
||||
for (const [path, content] of outputs) {
|
||||
const destination = resolve(root, path)
|
||||
if (existsSync(destination) && readFileSync(destination, 'utf8') === content) continue
|
||||
changed.push(path)
|
||||
if (!check) writeFileSync(destination, content)
|
||||
}
|
||||
if (check && changed.length > 0) {
|
||||
console.error(`gen-cli-help: stale — ${changed.join(', ')}. Run pnpm run gen-cli-help.`)
|
||||
process.exitCode = 1
|
||||
} else {
|
||||
console.log(`gen-cli-help: ${pages.length} help pages; ${check ? 'all outputs are current' : `${changed.length} files written`}.`)
|
||||
}
|
||||
}
|
||||
|
||||
if (process.argv[1] !== undefined && import.meta.filename === resolve(process.argv[1])) await main()
|
||||
@@ -284,6 +284,13 @@ describe('gate graph validation', () => {
|
||||
expect(ids).toContain('public-repository-links')
|
||||
})
|
||||
|
||||
it('checks the complete CLI reference locally and in the static CI lane', () => {
|
||||
for (const mode of ['doc-sync', 'ci-static'] as const) {
|
||||
const gates = withPnpmEntrypoint(() => gatesForMode(mode))
|
||||
expect(gates.find(gate => gate.id === 'cli-help')).toBeDefined()
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps the concrete terminology policy in the documentation gate', () => {
|
||||
const ids = withPnpmEntrypoint(() => gatesForMode('doc-sync').map(subject => subject.id))
|
||||
|
||||
@@ -360,8 +367,8 @@ describe('gate graph validation', () => {
|
||||
it('schedules the longest documentation leaves before short checks', () => {
|
||||
const ids = withPnpmEntrypoint(() => gatesForMode('doc-sync').map(subject => subject.id))
|
||||
|
||||
expect(ids.slice(0, 10)).toEqual([
|
||||
'doc-typecheck', 'docs-site-build', 'doc-graphs', 'markdown-links', 'type-equivalence',
|
||||
expect(ids.slice(0, 11)).toEqual([
|
||||
'doc-typecheck', 'docs-site-build', 'doc-graphs', 'cli-help', 'markdown-links', 'type-equivalence',
|
||||
'cordis-catalog', 'cordis-inspect-catalog', 'workflow-guest', 'mermaid', 'translation-pairing',
|
||||
])
|
||||
})
|
||||
|
||||
@@ -799,6 +799,7 @@ function docSyncLeafGates(options: {
|
||||
: [pnpmScript('doc-typecheck', options.docTypecheckScript ?? 'doc-typecheck', docTypecheckOptions)],
|
||||
pnpmScript('docs-site-build', options.docsBuildScript ?? 'docs:build', { label: 'documentation build' }),
|
||||
pnpmScript('doc-graphs', 'verify-doc-graphs', { label: 'doc graphs' }),
|
||||
pnpmScript('cli-help', 'verify-cli-help', { label: 'CLI help reference' }),
|
||||
pnpmScript('markdown-links', 'verify-md-links', { label: 'markdown links', quick: true }),
|
||||
pnpmScript('type-equivalence', 'verify-type-equiv', { label: 'type equivalence', quick: true }),
|
||||
pnpmScript('cordis-catalog', 'verify-cordis-catalog', { label: 'cordis catalog' }),
|
||||
|
||||
@@ -133,6 +133,7 @@ describe('translation pairing manifest', () => {
|
||||
|
||||
describe('translation pairing switchers', () => {
|
||||
it('exempts only paired generated English sources from reciprocal switchers', () => {
|
||||
expect(requiresSourceLanguageSwitcher('docs/cli-help.md')).toBe(false)
|
||||
expect(requiresSourceLanguageSwitcher('docs/config-catalog.md')).toBe(false)
|
||||
expect(requiresSourceLanguageSwitcher('docs/cordis-api/context.md')).toBe(false)
|
||||
expect(requiresSourceLanguageSwitcher('docs/cordis-api/inherited.md')).toBe(false)
|
||||
|
||||
@@ -311,6 +311,7 @@ export function requiresSourceLanguageSwitcher(source: string): boolean {
|
||||
return ![
|
||||
'docs/agent-lifecycle.md',
|
||||
'docs/capability-seams.md',
|
||||
'docs/cli-help.md',
|
||||
'docs/config-catalog.md',
|
||||
'docs/cordis-api/context.md',
|
||||
'docs/cordis-api/events.md',
|
||||
|
||||
Reference in New Issue
Block a user