Commit Graph
4 Commits
Author SHA1 Message Date
Tianyi Cui f81fcccd93 refactor(subprocess): keep terminate() as the seam's only termination verb
Delete kill(signal?) from SubprocessHandle: consumers stop a process only
through terminate()'s tree-scoped SIGTERM→graceMs→SIGKILL escalation
(idempotent, also driven by the spec's abort signal, a no-op once the tree
is gone). The single-signal verb had exactly one consumer family —
lsp-local — and what it bought there was a private re-implementation of
the same escalation. The internal kill closure stays in spawn.ts as the
dispose ladder's tier primitive; terminate() now routes through it too.

lsp-local collapses onto the seam's escalation:
- LspConnection replaces its terminate()/kill() pair with one terminate()
  that delegates to handle.terminate(). Behavior change: the
  framing-failure path terminates instead of instant SIGKILL, so a
  misbehaving server now gets SIGTERM plus the killGraceMs window to
  flush before SIGKILL.
- ConnectionSpec.pipeDrainGraceMs becomes killGraceMs: one grace, the
  spawn spec's graceMs, drives both the escalation window and post-exit
  pipe draining (the provider already passed killGraceMs for it).
- LspInstance.forceTerminate() drops its hand-rolled bounded first wait
  (LSP_KILL_GRACE) and escalateProcessTree (deleted with its export and
  unit test): the seam's escalation already commits to SIGKILL after
  killGraceMs, so only the unbounded quiescence awaits stay load-bearing.

Tests: kill()-shaped spawn specs become terminate()-shaped or fold into
the terminate() suites (group-wide delivery; the settled no-op case was
already pinned by 'terminate() after the tree died'); tree-survivor
coverage is intact. A stderr-'inherit' disposition test completes the
stdout/stderr symmetry so the scoped subprocess+lsp coverage gate stands
alone instead of leaning on subagent-acp's cross-package runs.

Docs: SubprocessHandle type-equiv block, seam/impl/group READMEs, and the
consumer-migration Agent Note lose the kill(signal?) vocabulary (zh pairs
re-recorded); cordis api/services catalogs regenerated.
2026-07-27 04:41:04 +08:00
Tianyi Cui 43d81b67ce fix(subprocess): consumers with one mixed env map split DSH_* onto the managed channel
Codex review of the acp-only fix found lsp-local carries the identical
defect: its server config's unrestricted env merges into the connection's
ordinary spawn channel, so a configured DSH_* fact crashed the spawn with
the reserved-namespace rejection. The partition now lives on the seam as
splitEnvChannels() beside the scrub it complements; the ACP run and the
LSP connection both use it, and each proves child delivery end-to-end
(MOCK_ECHO_ENV / LSP_FAKE_ECHO_ENV fixture knobs). Seam + consumer README
rows updated (en+zh, re-recorded). bash-local is already two-channel;
mcp/pty/sdk bypass the seam and only share the scrub.
2026-07-27 01:21:32 +08:00
Tianyi Cui 12a7e38417 feat(subprocess): reshape the seam Node-ward for multi-consumer use
Review direction (tianyicui, PR #660): make the interface closer to Node's
API so the other process-running places can adopt it. The spec gains
per-stream stdio dispositions — 'pipe' (raw Readable/Writable for protocol
streams), 'inherit' (diagnostics to the parent), and collect mode ({maxBytes,
spill?} — the old bounded tail-keep shape, now with spill optional for
diagnostic tails). SubprocessOutcome carries exit facts only; collected
output stays readable through handle.collected after settlement (spill fds
are sealed at the settle boundary). The handle grows Node-style kill(signal)
(single signal, tree-scoped, no-op after settlement), terminate() (the
SIGTERM→grace→SIGKILL escalation, also driven by the spec signal),
waitForExit() (tree liveness, not just the direct child), and dispose()
(the cooperative stdin-EOF→SIGTERM→SIGKILL ladder from subagent-subprocess,
graces caller-supplied). Tree semantics are platform-correct: POSIX detached
groups with direct-child fallback; Windows taskkill /T with an injectable
runner. scrubbedParentEnv/SENSITIVE_ENV_PATTERN move to the seam as the one
shared scrub definition.

bash-local maps its config onto collect modes and batch stdin and reads
results through the collected readers; its kill() maps to terminate() so
task_kill keeps escalation semantics.
2026-07-26 14:07:42 +08:00
Tianyi Cui fc566119a7 refactor(subprocess): rename the process seam to subprocess and address review
Review feedback (tianyicui): 'process' is a poor service name. The family is
now packages/subprocess/ — @deepseek-ai/dsh-subprocess (ctx.subprocess,
abstract SubprocessService, Subprocess* vocabulary) and
@deepseek-ai/dsh-subprocess-local (LocalSubprocessService) — renamed
throughout code, compositions, docs (en+zh, pairs re-recorded), catalogs,
and gates. 'subprocess' is the precise term for managed OS children (the
Python-stdlib sense), avoids colliding with Node's global process object,
and reads as one system beside dsh-subagent-subprocess.

ds-review-bot findings addressed:
- kill() on a settled handle is now a no-op (no signal to a possibly-reused
  pgid, no referenced grace timer delaying exit); pinned by a spy test.
- The moved DshEnvironmentKey/DshEnvironment/CollectedOutput types get
  drift-checked type-equiv blocks on the new subprocess.md page, restoring
  their manifest registration.
- subprocess.md is registered in the core.md sub-page index (en+zh).
2026-07-26 12:43:59 +08:00