Files
deepseek-harness/packages/boot/cmdline
Turtle 38c7a9fbf4 feat(release): publish package source, declaration maps, and documentation (#5884)
* 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
2026-11-05 00:22:36 +08:00
..

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

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 abc gives 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. cmdlineArgs and appExit are 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 --help text, and its parse errors.
  • Structural error detection. isCommanderError reads commander's error code prefix instead of using instanceof, because an out-of-tree plugin brings its own commander copy whose CommanderError identity differs; configureExitAndOutput walks every subcommand because commander copies exit and output settings only at registration.
  • Injectable output streams. internals holds 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.


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 --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 -- --.
  • 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 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.

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.