* feat(release): publish package source, declaration maps, and documentation Every release member publishes its TypeScript source and the declaration maps that resolve into it, and @deepseek-ai/dsh publishes the repository Markdown documentation staged from docs/ at prepack time. The ./src/* export most members already declared now resolves for an installed consumer, and a consumer editor follows a declaration to the implementation. Bundled JavaScript maps stay unpublished; the vendored family and the Desktop runtime file policy are unchanged. Rationale: .agents/notes/implemented/process/2026-10-08-published-source-and-docs.md * feat(release): publish JavaScript maps and compress bundles Every emitted JavaScript map ships beside the bundle it describes, and the workspace build and the client preset compress bundles without mangling identifiers. The documentation payload now mirrors the website publication manifest and is removed again by `postpack`; Desktop and the Python executable exclude the published source, documentation, and maps; `clean` removes a staged copy. Typert's publication contract gains the Remote declaration map. * fix(release): keep node bundles readable for the worker image The browser worker image lowers `yield*` only as a whole statement and rewrites `for await` loops by their source layout, so compressed node-side entries either fail that lowering or lower to unparseable code. Only the browser bundles keep compression, which removes about a third of their text. The bundle-purity assertion now matches the module-loader call regardless of the quote style compression picks, and the release-pack fixture exercises the installed package's new documentation requirement. * feat(release): publish the whole documentation tree `@deepseek-ai/dsh` copies `docs/` in full instead of the website's page set: the maintainer documents, the generated migration records, the translation guidelines, and the `*.i18n.yaml` consistency records ship with the installed package, so the documentation's own links resolve without a checkout. * feat(release): publish the upgrade guides with the documentation The staged documentation keeps the website's page set and adds every `docs/upgrade-guide/` document, which is what an installed reader consults when a released change breaks something. The rest of the maintainer tree stays out. * test(release): expect source and maps in master's new payload cases * feat(release): keep installed docs and source readable in Desktop Desktop keeps the published src/ and docs/ trees inside app.asar, and every model shell call receives DSH_INSTALL_DIR and DSH_NODE_EXECUTABLE so an agent can read them through Electron's Node mode. Staging also generates docs/upgrade-guide/README.md, an index of the upgrade guides grouped by the release they upgrade from. Minified client bundles print string literals with backticks: the worker image packer now recognizes those chunk requests, client license banners are prepended after minification so their text survives, and the affected artifact tests accept either quote. * test(desktop): read archived docs through the Windows PowerShell form Regenerate the config catalog for the shifted shell-env source line. * test(desktop): wait for the GUI-subsystem Electron process from PowerShell * build(release): publish source and maps from the message-quotes package * build(release): publish source and maps from packages new on master * build(release): publish source and maps from the tool-office package
description, kind
| description | kind |
|---|---|
| App-owned command lines for dsh app bins: your app parses its own flags, --help, and exit behavior from the launcher's remaining arguments. | package-library |
@deepseek-ai/dsh-cmdline
English | 中文
Summary
dsh-cmdline lets an app parse its own flags, --help, and errors from the arguments left unchanged after launcher flags. Parsed values can override configuration defaults without rewriting configuration. The app can also request process exit through the launcher's shutdown path. Use this package for app bins with their own command-line interface. It adds no prompt, schema, or model-visible content.
Table of Contents
- Use this package
- Understand the implementation
- Further Exploration
- Model Experience
- Known Limitations and Deferred Work
- Dev Note
Use this package
Your app reads the invocation's inner arguments at startup, and any number of its plugins can use them. The common path: a startup plugin reads the arguments, parses them, and publishes the parsed values; other rows configure themselves from those values.
The launcher values
The launcher makes three things available to your app:
ctx.cmdlineArgs— the inner arguments of your invocation. Reading them returns an immutable snapshot and never consumes or changes them:dsh --profile tui --resume abcgives your app['--resume', 'abc'].ctx.appExit— a way to ask the process to exit once the tree has shut down, wired to the launcher's shutdown controller.ctx.appReady— the successful-startup signal, committed only after the Loader tree and launcher-owned setup succeed.
An app launched with no arguments sees an empty list — that is the honest answer, not a missing value.
exitOnStdinEnd(ctx, label) binds a successfully started stdio application's EOF to ctx.appExit(0). It never reads or resumes stdin, so a protocol transport receives bytes buffered before it mounts; startup rejection wins over a racing EOF, and the owning fiber removes both pending listeners.
Parsing your flags
You bring your own commander program: declare your flags and your actions, and the package runs it against the inner arguments. Your action is the only place validation happens, and it publishes whatever your rows need. The plugin's Loader row carries no special marker:
- id: web-startup
name: '@deepseek-ai/dsh-web-app/startup'
Rows configured from the parsed values inject the published service and read it directly in their config:
- id: webserver
name: '@deepseek-ai/dsh-host-webserver'
inject: [webStartup]
config:
host: !!js ctx.webStartup.host ?? '127.0.0.1'
port: !!js ctx.webStartup.port ?? 3080
The outcomes: dsh --profile web --port 8080 starts the server on port 8080 even when the config says 3080, because the flag wins. --help prints your app's help and exits 0 without starting anything; a rejected value (for example a non-numeric port) prints your error and exits nonzero, and no row that depends on the parsed values ever starts.
How flags beat config values
The value written beside a !!js expression is the fallback: the flag wins when present, the written value is used otherwise. Resolution happens once at startup, after your parser ran, so a flag is never silently reset by a later config reload.
Reading the same arguments from several plugins
Any number of plugins can read the same arguments — reading never consumes them — and each can parse what it needs and publish its own values. The launcher does not decide who owns the command line: an app with no reader ignores its arguments.
Apps built outside this repository behave the same way: their --help prints and exits instead of crashing, even though they carry their own commander copy.
Understand the implementation
Implementation internals — click to expand
This section explains how the outcomes above are realized and points at the code that realizes them; everything here is developer-facing and not needed to use the package.
Design notes
- Launcher facts, not config.
cmdlineArgsandappExitare provided on the host context before the tree mounts; they are not Loader rows, so no composition owns or overrides them. - Positional split. The launcher recognizes no app row: the first token after its own flags starts the app's arguments, so the app owns its flag family, its
--helptext, and its parse errors. - Structural error detection.
isCommanderErrorreads commander's error code prefix instead of usinginstanceof, because an out-of-tree plugin brings its own commander copy whoseCommanderErroridentity differs;configureExitAndOutputwalks every subcommand because commander copies exit and output settings only at registration. - Injectable output streams.
internalsholds the output streams so tests can capture commander's text without touching the process.
Parsing contract
The parse path is one small family with two owners: provideCmdline freezes the host arguments and provides cmdlineArgs and appExit before any tree entry mounts, and parseCmdline runs your commander program against the immutable arguments, routing every command's help, version, and error output through the launcher. A rejected value, --help, or --version prints commander's text and requests ctx.appExit without publishing anything, so dependent rows never activate; Loader defers each row's !!js interpolation until its declared injections are active. Per-export contracts live in the code, not this README — see src/index.ts.
Source map
| File | Role |
|---|---|
src/index.ts |
CmdlineArgs/AppExit types, provideCmdline, parseCmdline, commander exit/output routing |
Further Exploration
Read these pages when the package-level contract is not enough. They move from the handoff mechanism to the apps that consume it.
- dsh-app-boot — the boot sequence that provides these launcher values.
- dsh-web-app bundle — an app that owns the Web flag family through this package.
- dsh-headless bundle — the one-shot runner that reads its task from the command line.
Model Experience
None, as this package resolves the process command line before any session exists; configured rows own every model-visible consequence.
KV Cache effect
None; this package neither assembles nor sends a provider request.
Known Limitations and Deferred Work
These limits describe where app-owned command lines are a poor fit or need special care. They are current package constraints, not a task backlog.
- Launcher flags must precede app arguments — the split is positional: the first token the launcher does not recognize starts the inner arguments, so
--patchplaced 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-- --. - 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.
- A user patch that replaces a row's whole
configdrops 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.
Dev Note
Working context for maintainers — click to expand
This Dev Note is working context for maintainers: open design questions and directions that are not decided. It is explicitly non-authoritative — shipped behavior, limits, and accepted rationale live in the sections above, the package code, and the linked Agent Notes.
Open: parser surface
parseCmdline is a commander adapter, not a command-line framework: help, version, and error output follow commander's formatting, and the exit/output routing assumes commander's control-flow model. A different parser would need its own routing and error handling; nothing in the cmdlineArgs service contract depends on commander.