@deepseek-ai/dsh-cmdline 0.0.1-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +28 -0
- package/README.i18n.yaml +6 -0
- package/README.md +74 -0
- package/README.zh.md +74 -0
- package/lib/index.js +104 -0
- package/lib/invariant.js +25 -0
- package/lib/types/index.d.ts +110 -0
- package/lib/types/invariant.d.ts +16 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, DeepSeek
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/boot/cmdline/README.md
|
|
5
|
+
README.md: 98335e901bdf8fe33e14c1ad4c1a320d77f30c96
|
|
6
|
+
README.zh.md: 28ea749943c60089c6b4725cb61e121f82aa0114
|
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# `@deepseek-ai/dsh-cmdline`
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
The command line a dsh launcher hands to the app it boots. The launcher parses only its own flags (`--profile`, `--patch`, the config dumps) and hands **everything after them** to the tree verbatim, so an app owns its flag family, its `--help` text, and its parse errors instead of the launcher knowing them.
|
|
6
|
+
|
|
7
|
+
## The launcher values
|
|
8
|
+
|
|
9
|
+
A launcher calls `provideCmdline(ctx, host)` before any tree entry mounts, which provides:
|
|
10
|
+
|
|
11
|
+
- `ctx.cmdlineArgs` — the invocation's inner arguments. `get()` is the whole interface, and it returns a snapshot: `dsh --profile tui --resume abc` yields `['--resume', 'abc']`.
|
|
12
|
+
- `ctx.appExit` — a bounded process-exit request, wired to the launcher's shutdown controller.
|
|
13
|
+
|
|
14
|
+
An embedding host with no command line provides an empty list; that is the honest answer, not a missing value.
|
|
15
|
+
|
|
16
|
+
## Ordinary providers and injected config
|
|
17
|
+
|
|
18
|
+
Any app plugin may inject `cmdlineArgs`, parse it, and publish an ordinary app-owned service. `parseCmdline(ctx, program, plan)` is only a commander adapter; the caller owns the returned value and service:
|
|
19
|
+
|
|
20
|
+
```ts ignore
|
|
21
|
+
export const name = 'web-startup'
|
|
22
|
+
export const inject = ['cmdlineArgs']
|
|
23
|
+
|
|
24
|
+
export function apply(ctx: Context): void {
|
|
25
|
+
const values = parseCmdline(ctx, webCommand(), planWebStartup)
|
|
26
|
+
if (values !== undefined) ctx.provide('webStartup', values)
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Its Loader row carries no launcher marker or special kind:
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
- id: web-startup
|
|
34
|
+
name: '@deepseek-ai/dsh-web-app/startup'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Every row configured from those values uses ordinary service injection and direct lazy config access:
|
|
38
|
+
|
|
39
|
+
```yaml
|
|
40
|
+
- id: webserver
|
|
41
|
+
name: '@deepseek-ai/dsh-host-webserver'
|
|
42
|
+
inject: [webStartup]
|
|
43
|
+
config:
|
|
44
|
+
host: !!js ctx.webStartup.host ?? '127.0.0.1'
|
|
45
|
+
port: !!js ctx.webStartup.port ?? 3080
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`parseCmdline` parses the immutable arguments and asks `plan` for the app-owned value. On `--help`, `--version`, a parse error, or a `program.error(...)` from the plan, it writes commander's text, requests exit, and returns `undefined`; the provider publishes nothing, so dependent rows never activate.
|
|
49
|
+
|
|
50
|
+
### How injection orders config
|
|
51
|
+
|
|
52
|
+
Loader defers a row's `!!js` interpolation until that row's declared injections are active, then evaluates against the row's plugin context. The example above can therefore read `ctx.webStartup` directly: Cordis has already populated that injected service before Loader asks for `webserver`'s config. Include trees preserve nested expression nodes until each target row reaches this point. Provider replacement and live patch reload repeat interpolation against the current injected services, so a launch flag cannot be silently reset.
|
|
53
|
+
|
|
54
|
+
`enableRow(ctx, id)` turns on a row a bundle ships disabled because only some invocations want it (`dsh web --dev` and its client-plugin reload chain). The activation is an in-memory override: it does not rewrite the row's configured `disabled` value and survives config reapplication for that mounted entry. Loader applies the enabled row's ordinary injection ordering.
|
|
55
|
+
|
|
56
|
+
### Shared immutable arguments
|
|
57
|
+
|
|
58
|
+
`get()` does not consume or mutate argv. Multiple plugins can parse the same snapshot and independently provide services. The launcher does not inspect the composition for a command-line owner; a profile with no reader simply ignores its app arguments.
|
|
59
|
+
|
|
60
|
+
An out-of-tree plugin brings its own commander copy, so commander's control-flow errors are detected structurally rather than by class identity; an identity check would rethrow a printed help as a fatal load failure.
|
|
61
|
+
|
|
62
|
+
## Model Experience
|
|
63
|
+
|
|
64
|
+
None, as this package resolves the process's own command line before any session exists.
|
|
65
|
+
|
|
66
|
+
#### KV Cache effect
|
|
67
|
+
|
|
68
|
+
None; this package neither assembles nor sends a provider request.
|
|
69
|
+
|
|
70
|
+
## Known Limitations and Deferred Work
|
|
71
|
+
|
|
72
|
+
- **Launcher flags must precede app arguments.** The split is positional: the first token the launcher does not recognize starts the inner arguments, so `--patch` placed after an app flag belongs to the app. The launcher's parser consumes one `--`, so an app argument that must survive as a literal `--` needs `-- --`.
|
|
73
|
+
- **An app-owned service has no statically declared provider.** Consumer rows name it through ordinary injection; a bundle that omits its provider fails at settlement with pending entries naming the service rather than at load.
|
|
74
|
+
- **A user patch that replaces a row's whole `config` drops its expressions.** A flag beats the value written beside it, not a literal a user wrote in place of the expression; keeping the expression is what keeps the flag winning.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# `@deepseek-ai/dsh-cmdline`
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
dsh 启动器交给它所引导应用的那条命令行。启动器只解析属于自己的 flag(`--profile`、`--patch`、配置 dump),并把**其后的一切**原样交给配置树,因此 flag 家族、`--help` 文本和解析错误都由应用自己持有,启动器不必知道它们。
|
|
6
|
+
|
|
7
|
+
## 启动器提供的值
|
|
8
|
+
|
|
9
|
+
启动器在任何配置树条目挂载之前调用 `provideCmdline(ctx, host)`,它提供:
|
|
10
|
+
|
|
11
|
+
- `ctx.cmdlineArgs`:本次调用的内层参数。`get()` 就是它的全部接口,返回一份快照:`dsh --profile tui --resume abc` 得到 `['--resume', 'abc']`。
|
|
12
|
+
- `ctx.appExit`:一个有边界的进程退出请求,接到启动器的关停控制器上。
|
|
13
|
+
|
|
14
|
+
没有命令行的嵌入宿主提供空列表;这是诚实的答案,而不是缺失的值。
|
|
15
|
+
|
|
16
|
+
## 普通提供方与注入配置
|
|
17
|
+
|
|
18
|
+
任何应用插件都可以注入 `cmdlineArgs`、解析它,再发布一个普通的应用自有服务。`parseCmdline(ctx, program, plan)` 只适配 commander;返回值与服务都归调用方持有:
|
|
19
|
+
|
|
20
|
+
```ts ignore
|
|
21
|
+
export const name = 'web-startup'
|
|
22
|
+
export const inject = ['cmdlineArgs']
|
|
23
|
+
|
|
24
|
+
export function apply(ctx: Context): void {
|
|
25
|
+
const values = parseCmdline(ctx, webCommand(), planWebStartup)
|
|
26
|
+
if (values !== undefined) ctx.provide('webStartup', values)
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
它的 Loader 行不携带启动器标记,也没有特殊类型:
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
- id: web-startup
|
|
34
|
+
name: '@deepseek-ai/dsh-web-app/startup'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
所有由这些取值配置的行都使用普通服务注入,并在惰性配置中直接访问该服务:
|
|
38
|
+
|
|
39
|
+
```yaml
|
|
40
|
+
- id: webserver
|
|
41
|
+
name: '@deepseek-ai/dsh-host-webserver'
|
|
42
|
+
inject: [webStartup]
|
|
43
|
+
config:
|
|
44
|
+
host: !!js ctx.webStartup.host ?? '127.0.0.1'
|
|
45
|
+
port: !!js ctx.webStartup.port ?? 3080
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`parseCmdline` 解析不可变参数,再向 `plan` 索取应用自有取值。遇到 `--help`、`--version`、解析错误,或 `plan` 发出的 `program.error(...)` 时,它输出 commander 文本、请求退出并返回 `undefined`;提供方什么也不发布,因此依赖行不会激活。
|
|
49
|
+
|
|
50
|
+
### 注入如何排列配置求值
|
|
51
|
+
|
|
52
|
+
Loader 会把一行的 `!!js` 插值推迟到该行声明的注入全部激活之后,再基于该行的插件上下文求值。所以上例可以直接读取 `ctx.webStartup`:Loader 索取 `webserver` 的配置之前,Cordis 已经填入了这个注入服务。Include 树会保留嵌套表达式节点,直到各个目标行到达这一时点。提供方替换与活动 patch 重载都会针对当前注入服务重新插值,因此启动 flag 不会被悄悄重置。
|
|
53
|
+
|
|
54
|
+
`enableRow(ctx, id)` 打开某个组合包以禁用状态交付、只有部分调用才需要的行(`dsh web --dev` 及其客户端插件重载链路)。该激活是内存中的覆盖:它不会改写行所配置的 `disabled` 值,并会在已挂载条目的配置重新应用后继续生效。Loader 会对启用后的行应用普通的注入顺序。
|
|
55
|
+
|
|
56
|
+
### 共享不可变参数
|
|
57
|
+
|
|
58
|
+
`get()` 不会消费或修改 argv。多个插件可以解析同一份快照,并分别提供服务。启动器不会检查组合中的命令行所有者;没有读取方的 profile 只会忽略自己的应用参数。
|
|
59
|
+
|
|
60
|
+
树外插件会带来自己的一份 commander 副本,因此 commander 的控制流错误按结构识别,而不是按类身份识别;按身份判断会把已经打印出来的 help 重新抛成致命的加载失败。
|
|
61
|
+
|
|
62
|
+
## 模型体验
|
|
63
|
+
|
|
64
|
+
无。本包在任何会话存在之前解析进程自身的命令行。
|
|
65
|
+
|
|
66
|
+
#### KV Cache 影响
|
|
67
|
+
|
|
68
|
+
无;本包既不组装也不发送提供方请求。
|
|
69
|
+
|
|
70
|
+
## 已知限制与延期工作
|
|
71
|
+
|
|
72
|
+
- **启动器的 flag 必须写在应用参数之前**:切分按位置进行,启动器不认识的第一个 token 就是内层参数的起点,因此写在某个应用 flag 之后的 `--patch` 属于应用。启动器的解析器会消耗掉一个 `--`,因此必须以字面量 `--` 存活到应用的参数需要写成 `-- --`。
|
|
73
|
+
- **应用自有服务没有静态声明的提供方**:消费行通过普通注入点名它;缺少提供方的组合包会在结算时失败,由待处理条目点名该服务,而不是在加载时失败。
|
|
74
|
+
- **用户 patch 若整体替换某行的 `config`,会连同其中的表达式一起丢掉**:flag 胜过的是表达式旁写着的那个值,而不是用户用字面量替换掉表达式之后的结果;保留表达式才能保留 flag 的优先级。
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
//#region lib/types/index.js
|
|
2
|
+
/**
|
|
3
|
+
* @deepseek-ai/dsh-cmdline — the command line a dsh launcher hands to the app
|
|
4
|
+
* it boots.
|
|
5
|
+
*
|
|
6
|
+
* The launcher parses only its own flags (`--profile`, `--patch`, the config
|
|
7
|
+
* dumps) and hands everything after them to the tree verbatim through the
|
|
8
|
+
* {@link CmdlineArgs} service, so an app owns its flag family, its `--help`
|
|
9
|
+
* text, and its parse errors instead of the launcher knowing them.
|
|
10
|
+
*
|
|
11
|
+
* Any app plugin can inject `cmdlineArgs` and call {@link parseCmdline}. A
|
|
12
|
+
* provider may publish the parsed values as its own service, and ordinary rows
|
|
13
|
+
* can inject that service and read it from lazily resolved config —
|
|
14
|
+
* `port: !!js ctx.webStartup.port ?? 3080` — so a flag beats the value written
|
|
15
|
+
* beside it. No row has launcher-level command-line status.
|
|
16
|
+
* @module @deepseek-ai/dsh-cmdline
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Provide the command line and the exit request on a host context before any
|
|
20
|
+
* tree entry mounts. Both are launcher facts, not config: an embedding host
|
|
21
|
+
* with no command line provides an empty argument list.
|
|
22
|
+
* @param ctx - the host context the tree will mount under.
|
|
23
|
+
* @param host - the invocation's arguments and its exit request.
|
|
24
|
+
*/
|
|
25
|
+
function provideCmdline(ctx, host) {
|
|
26
|
+
const snapshot = Object.freeze([...host.args]);
|
|
27
|
+
ctx.provide("cmdlineArgs", { get: () => snapshot });
|
|
28
|
+
ctx.provide("appExit", host.exit);
|
|
29
|
+
}
|
|
30
|
+
/** The process streams commander output is written to; production writes to the process. */
|
|
31
|
+
const internals = {
|
|
32
|
+
stdout: process.stdout,
|
|
33
|
+
stderr: process.stderr
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Parse the launcher's immutable argument snapshot with an app's commander
|
|
37
|
+
* program. The caller decides whether and how to publish the returned value;
|
|
38
|
+
* this helper has no Loader-row or service ownership semantics.
|
|
39
|
+
*
|
|
40
|
+
* Help, version, and rejected arguments are terminal for the process: commander
|
|
41
|
+
* writes the text, the helper requests `ctx.appExit`, and it returns
|
|
42
|
+
* `undefined` so the caller publishes nothing.
|
|
43
|
+
* @param ctx - plugin context carrying `cmdlineArgs` and `appExit`.
|
|
44
|
+
* @param program - the app's commander program, with its flags and description already declared.
|
|
45
|
+
* @param plan - this invocation's resolved value; omitted returns an empty object.
|
|
46
|
+
* @returns the resolved value, or `undefined` when the app asked to exit.
|
|
47
|
+
* @throws when the launcher did not provide the command line and exit request.
|
|
48
|
+
*/
|
|
49
|
+
function parseCmdline(ctx, program, plan = (() => ({}))) {
|
|
50
|
+
const args = ctx.get("cmdlineArgs");
|
|
51
|
+
const exit = ctx.get("appExit");
|
|
52
|
+
if (args === void 0 || exit === void 0) throw new Error(`${program.name()}: the launcher must provide ctx.cmdlineArgs and ctx.appExit before the tree mounts`);
|
|
53
|
+
program.exitOverride().configureOutput({
|
|
54
|
+
writeOut: (text) => void internals.stdout.write(text),
|
|
55
|
+
writeErr: (text) => void internals.stderr.write(text)
|
|
56
|
+
});
|
|
57
|
+
try {
|
|
58
|
+
program.parse(args.get(), { from: "user" });
|
|
59
|
+
return plan(program, ctx);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (!isCommanderError(error)) throw error;
|
|
62
|
+
exit(error.exitCode);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Turn on a row this composition ships disabled, because this invocation asked
|
|
68
|
+
* for it (`dsh web --dev` and its client-plugin reload chain).
|
|
69
|
+
*
|
|
70
|
+
* A row cannot be inserted from inside a mounting plugin — the Loader returns a
|
|
71
|
+
* prefixed id it then fails to resolve — so a conditional row ships disabled
|
|
72
|
+
* and a row mounted beside it enables it after startup resolves the invocation.
|
|
73
|
+
* The Loader keeps that activation in memory, separate from serialized options,
|
|
74
|
+
* so reapplying the composition cannot restore the invocation's row to disabled.
|
|
75
|
+
* @param ctx - plugin context whose Loader tree carries the row.
|
|
76
|
+
* @param id - the row id.
|
|
77
|
+
* @returns nothing once the row has started or is waiting for its dependencies.
|
|
78
|
+
* @throws when the Loader or named row is absent.
|
|
79
|
+
*/
|
|
80
|
+
async function enableRow(ctx, id) {
|
|
81
|
+
const loader = ctx.get("loader");
|
|
82
|
+
if (loader === void 0) throw new Error("dsh-cmdline: enabling a row requires the Loader service");
|
|
83
|
+
const entry = [...loader.entries()].find((candidate) => candidate.options.id === id);
|
|
84
|
+
if (entry === void 0) throw new Error(`dsh-cmdline: the composition has no ${JSON.stringify(id)} row to enable`);
|
|
85
|
+
await entry.enableRuntime();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Whether a thrown value is commander's own control-flow error (help, version,
|
|
89
|
+
* a parse error, or `program.error`).
|
|
90
|
+
*
|
|
91
|
+
* Detected structurally, not with `instanceof`: an out-of-tree plugin brings
|
|
92
|
+
* its own commander copy, whose `CommanderError` class is a different identity
|
|
93
|
+
* from this package's, and an identity check there would rethrow a printed
|
|
94
|
+
* help as a fatal load failure.
|
|
95
|
+
* @param error - the thrown value.
|
|
96
|
+
* @returns true when the value carries commander's error code and exit code.
|
|
97
|
+
*/
|
|
98
|
+
function isCommanderError(error) {
|
|
99
|
+
if (typeof error !== "object" || error === null) return false;
|
|
100
|
+
const candidate = error;
|
|
101
|
+
return typeof candidate.code === "string" && candidate.code.startsWith("commander.") && typeof candidate.exitCode === "number";
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { enableRow, internals, parseCmdline, provideCmdline };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for `@deepseek-ai/dsh-cmdline`.
|
|
4
|
+
* @module @deepseek-ai/dsh-cmdline/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@deepseek-ai/dsh-cmdline";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "cmdline-invariant";
|
|
9
|
+
/** Service required before the companion can register. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/**
|
|
12
|
+
* No runtime invariant: `cmdlineArgs` is an immutable launcher fact that any
|
|
13
|
+
* number of ordinary plugins may read. App-owned providers and consumers use
|
|
14
|
+
* normal Cordis service injection, whose missing dependencies are already
|
|
15
|
+
* reported by Loader settlement.
|
|
16
|
+
*/
|
|
17
|
+
const install = () => {};
|
|
18
|
+
/**
|
|
19
|
+
* Register this package's invariant companion.
|
|
20
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
21
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
22
|
+
*/
|
|
23
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
24
|
+
//#endregion
|
|
25
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deepseek-ai/dsh-cmdline — the command line a dsh launcher hands to the app
|
|
3
|
+
* it boots.
|
|
4
|
+
*
|
|
5
|
+
* The launcher parses only its own flags (`--profile`, `--patch`, the config
|
|
6
|
+
* dumps) and hands everything after them to the tree verbatim through the
|
|
7
|
+
* {@link CmdlineArgs} service, so an app owns its flag family, its `--help`
|
|
8
|
+
* text, and its parse errors instead of the launcher knowing them.
|
|
9
|
+
*
|
|
10
|
+
* Any app plugin can inject `cmdlineArgs` and call {@link parseCmdline}. A
|
|
11
|
+
* provider may publish the parsed values as its own service, and ordinary rows
|
|
12
|
+
* can inject that service and read it from lazily resolved config —
|
|
13
|
+
* `port: !!js ctx.webStartup.port ?? 3080` — so a flag beats the value written
|
|
14
|
+
* beside it. No row has launcher-level command-line status.
|
|
15
|
+
* @module @deepseek-ai/dsh-cmdline
|
|
16
|
+
*/
|
|
17
|
+
import type { Command } from 'commander';
|
|
18
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
19
|
+
/**
|
|
20
|
+
* The invocation's inner arguments: everything after the launcher's own flags,
|
|
21
|
+
* verbatim and in argv order. `dsh --profile tui --resume abc` yields
|
|
22
|
+
* `['--resume', 'abc']`.
|
|
23
|
+
*/
|
|
24
|
+
export interface CmdlineArgs {
|
|
25
|
+
/**
|
|
26
|
+
* Read the inner arguments.
|
|
27
|
+
* @returns the arguments in argv order; empty when the invocation carried none.
|
|
28
|
+
*/
|
|
29
|
+
get(): readonly string[];
|
|
30
|
+
}
|
|
31
|
+
/** Request bounded process exit; the launcher wires it to its shutdown controller. */
|
|
32
|
+
export interface AppExit {
|
|
33
|
+
/**
|
|
34
|
+
* Request exit once the tree has been disposed.
|
|
35
|
+
* @param code - the process exit code.
|
|
36
|
+
*/
|
|
37
|
+
(code: number): void;
|
|
38
|
+
}
|
|
39
|
+
declare module '@deepseek-ai/cordis' {
|
|
40
|
+
interface Context {
|
|
41
|
+
/** The invocation's inner arguments; provided by a launcher before the tree mounts. */
|
|
42
|
+
cmdlineArgs?: CmdlineArgs;
|
|
43
|
+
/** Bounded process-exit request; provided by a launcher before the tree mounts. */
|
|
44
|
+
appExit?: AppExit;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** The launcher facts an app needs. */
|
|
48
|
+
export interface CmdlineHost {
|
|
49
|
+
/** The invocation's inner arguments, in argv order. */
|
|
50
|
+
args: readonly string[];
|
|
51
|
+
/** Bounded process-exit request. */
|
|
52
|
+
exit: AppExit;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Provide the command line and the exit request on a host context before any
|
|
56
|
+
* tree entry mounts. Both are launcher facts, not config: an embedding host
|
|
57
|
+
* with no command line provides an empty argument list.
|
|
58
|
+
* @param ctx - the host context the tree will mount under.
|
|
59
|
+
* @param host - the invocation's arguments and its exit request.
|
|
60
|
+
*/
|
|
61
|
+
export declare function provideCmdline(ctx: Context, host: CmdlineHost): void;
|
|
62
|
+
/** The process streams commander output is written to; production writes to the process. */
|
|
63
|
+
export declare const internals: {
|
|
64
|
+
stdout: {
|
|
65
|
+
write(chunk: string): unknown;
|
|
66
|
+
};
|
|
67
|
+
stderr: {
|
|
68
|
+
write(chunk: string): unknown;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Resolve parsed arguments into an app-owned value. Call
|
|
73
|
+
* `program.error(...)` to reject the invocation with a usage message instead
|
|
74
|
+
* of throwing.
|
|
75
|
+
* @param program - the parsed commander program.
|
|
76
|
+
* @param ctx - the plugin context that received the command line.
|
|
77
|
+
* @returns the value an ordinary provider plugin may publish.
|
|
78
|
+
*/
|
|
79
|
+
export type CmdlinePlan<T = unknown> = (program: Command, ctx: Context) => T;
|
|
80
|
+
/**
|
|
81
|
+
* Parse the launcher's immutable argument snapshot with an app's commander
|
|
82
|
+
* program. The caller decides whether and how to publish the returned value;
|
|
83
|
+
* this helper has no Loader-row or service ownership semantics.
|
|
84
|
+
*
|
|
85
|
+
* Help, version, and rejected arguments are terminal for the process: commander
|
|
86
|
+
* writes the text, the helper requests `ctx.appExit`, and it returns
|
|
87
|
+
* `undefined` so the caller publishes nothing.
|
|
88
|
+
* @param ctx - plugin context carrying `cmdlineArgs` and `appExit`.
|
|
89
|
+
* @param program - the app's commander program, with its flags and description already declared.
|
|
90
|
+
* @param plan - this invocation's resolved value; omitted returns an empty object.
|
|
91
|
+
* @returns the resolved value, or `undefined` when the app asked to exit.
|
|
92
|
+
* @throws when the launcher did not provide the command line and exit request.
|
|
93
|
+
*/
|
|
94
|
+
export declare function parseCmdline<T>(ctx: Context, program: Command, plan?: CmdlinePlan<T>): T | undefined;
|
|
95
|
+
/**
|
|
96
|
+
* Turn on a row this composition ships disabled, because this invocation asked
|
|
97
|
+
* for it (`dsh web --dev` and its client-plugin reload chain).
|
|
98
|
+
*
|
|
99
|
+
* A row cannot be inserted from inside a mounting plugin — the Loader returns a
|
|
100
|
+
* prefixed id it then fails to resolve — so a conditional row ships disabled
|
|
101
|
+
* and a row mounted beside it enables it after startup resolves the invocation.
|
|
102
|
+
* The Loader keeps that activation in memory, separate from serialized options,
|
|
103
|
+
* so reapplying the composition cannot restore the invocation's row to disabled.
|
|
104
|
+
* @param ctx - plugin context whose Loader tree carries the row.
|
|
105
|
+
* @param id - the row id.
|
|
106
|
+
* @returns nothing once the row has started or is waiting for its dependencies.
|
|
107
|
+
* @throws when the Loader or named row is absent.
|
|
108
|
+
*/
|
|
109
|
+
export declare function enableRow(ctx: Context, id: string): Promise<void>;
|
|
110
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@deepseek-ai/dsh-cmdline`.
|
|
3
|
+
* @module @deepseek-ai/dsh-cmdline/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "cmdline-invariant";
|
|
8
|
+
/** Service required before the companion can register. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@deepseek-ai/dsh-cmdline",
|
|
3
|
+
"description": "Immutable command-line handoff from a dsh launcher to any app plugin that injects cmdlineArgs",
|
|
4
|
+
"version": "0.0.1-rc.1",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "restricted"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/boot/cmdline"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./invariant": {
|
|
22
|
+
"types": "./lib/types/invariant.d.ts",
|
|
23
|
+
"default": "./lib/invariant.js"
|
|
24
|
+
},
|
|
25
|
+
"./src/*": "./src/*",
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"lib/index.js",
|
|
30
|
+
"lib/invariant.js",
|
|
31
|
+
"lib/types/**/*.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"license": "BSD-3-Clause",
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@deepseek-ai/dsh-invariants": "^0.0.1-rc.1",
|
|
36
|
+
"@deepseek-ai/cordis": "^4.0.1-rc.1",
|
|
37
|
+
"@deepseek-ai/cordis-plugin-loader": "^1.0.1-rc.1"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"commander": "^15.0.0",
|
|
41
|
+
"@deepseek-ai/cordis-plugin-include": "^1.0.5-rc.1",
|
|
42
|
+
"@deepseek-ai/cordis-plugin-loader": "^1.0.1-rc.1",
|
|
43
|
+
"@deepseek-ai/dsh-invariants": "^0.0.1-rc.1",
|
|
44
|
+
"@deepseek-ai/cordis": "^4.0.1-rc.1"
|
|
45
|
+
}
|
|
46
|
+
}
|