Moving ShellEnvError onto dsh-error replaced the existing dsh-llm
devDependency, but the shell-env tests still import ToolCallId from
dsh-llm. Both are now declared.
Refs #7869
subprocessSpawnFailure() now converts only errors that carry a string
errno code and returns every other value unchanged, so an internal
failure such as a dropped collect stream is no longer reported as
cannot start / SUBPROCESS_SPAWN_FAILED. The bash and pwsh tools pass a
rejection through unchanged only when it is the call's own
cancellation reason; a spawn error that settles after the call was
cancelled is still classified. The job starter reads the failure
through an optional hooks binding instead of a definite-assignment
assertion.
Refs #7869
Renderers such as errorChain and the activation report expand
AggregateError members but otherwise follow only cause, so a cause of
just the setup failure hid the cleanup failure that may leave
resources alive. The cause is now an AggregateError of both failures.
An upgrade guide records that the class extends TerminalError instead
of AggregateError.
INIT_REJECTED is documented as the code a consumer that drives a shell
uses when the shell rejects its setup input, and the persistent bash
tool README records it.
Refs #7869
The error classes this branch adds import HarnessError from the
dependency-free @deepseek-ai/dsh-error package: Win32Error,
SubprocessError, and ShellEnvError packages depend on dsh-error instead
of the LLM runtime, and dsh-sandbox and dsh-working-directory declare it
beside their existing dsh-llm dependency. The SHELL_ENV and
WORKING_DIRECTORY code lists stay in internal modules so the plugin
entries export only the error classes and code types. Generated module,
config, and event graphs follow.
Refs #7869
A contributor that returns an undeclared key or a non-string value now
fails the shell call with ShellEnvError SHELL_ENV_CONTRIBUTION_INVALID
instead of a plain Error, with the same message.
Refs #7869
TerminalError gains SESSION_CLOSING, SESSION_EXITED, STARTUP_EXITED,
STARTUP_TIMEOUT, NO_SANDBOX, and INIT_REJECTED, following its existing
unprefixed code style. The terminal service and terminal-bash use them
for a send to a closing or exited session, a shell that exits or misses
readiness during startup, and a confined mode without a sandbox
provider; an empty confined argv is SubprocessError
SUBPROCESS_INVALID_ARGV, and a send on an aborted signal throws an
error named AbortError.
The persistent bash and pwsh tools report a missing owner as
ToolContextUnavailableError, a blank command as ToolArgsError, and a
shell that rejects its setup as TerminalError INIT_REJECTED.
Refs #7869
A foreground bash or pwsh call that waits on a job rethrew a failed
preparation as new Error(view.detail), dropping the original class and
code, so even SandboxUnavailableError reached tool/result without
error.name or error.code. processJob now keeps the original error for a
failed job and the tool rethrows it; launch and spawn rejections on
every path keep a HarnessError's identity, and a platform spawn error
becomes SubprocessError (SUBPROCESS_SPAWN_NOT_FOUND or _SPAWN_FAILED).
Argument violations are ToolArgsError, a missing sandboxing executor
for sandbox_permissions is SandboxEscalationError
SANDBOX_ESCALATION_UNAVAILABLE, a disabled background call is JobError
JOB_BACKGROUND_DISABLED, and a missing job runtime is
ToolContextUnavailableError.
Refs #7869
* 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
- tool-jobs: inline a completion notice only when the complete text fits inlineOutputBytes and the producer cap; otherwise point at job_output, whose result the spill policy bounds
- subagent: drop toolCallsThisStep; omit the closing text while the child's last logged tool call is its message to the parent
The persistent bash tool types each wrapped command into an interactive
bash, which applies history expansion before parsing. A `!` after a single
quote made bash reject the whole line with `event not found`, so neither
marker printed and the call waited for the full timeout; `!!` silently
substituted the previous history entry.
Disable history expansion when the shell is initialized, as OpenHands does
for its interactive terminal. Raw control characters other than newline and
carriage return still reach readline as typed keys; the README records that
limitation.