feat(bundle): the web and one-shot apps own their own flags

dsh-web-app owns --host/--port/--dev/--workspace-root/--trusted-host and
its --help in a web-startup row; the rows it configures wait for the
webStartup service, and the client-plugin HMR receiver now ships disabled
so --dev is a row toggle rather than a runtime insert (the Loader cannot
resolve a row inserted from inside a mounting plugin).

dsh-headless owns the task positional and rejects a missing task as its own
usage error. Its runner ships disabled, not merely waiting: the schema
requires the task, and a row's config is validated when its fiber is
created, before the startup row can supply one. A composition has exactly
one command-line owner, so the patch disables the web startup row and this
one provides webStartup too, leaving the web rows on their composed
one-shot values.

The keyless web scaffold provides the same three values with no arguments,
which is what an embedding host with no command line does.
This commit is contained in:
Turtle
2026-08-06 20:52:26 +08:00
parent 788368e314
commit 82728808d4
23 changed files with 692 additions and 36 deletions

View File

@@ -3,9 +3,13 @@
# the profile's own cordis.patch.yml and any --patch overlays still to come.
#
# A patch replaces the targeted row's whole `config`, so each row below
# restates every key it owns. The `dsh web` launcher alias turns --host/--port/
# --dev/--trusted-host into further patches over these rows
# (`--dev` inserts the dsh-client-hmr row).
# restates every key it owns.
#
# Rows this app configures from flags declare `inject: [webStartup]`: they wait
# until the web-startup row has parsed --host/--port/--dev/--workspace-root/
# --trusted-host and provided that service with the resolved values.
# `dsh --profile web --help` therefore prints this app's own help and exits
# without ever binding a port.
# ── surface-specific values the base deliberately omits ─────────────────────
@@ -76,6 +80,11 @@
- id: api-gateway
name: '@deepseek-ai/dsh-host-apiproxy'
# Owns the web flag family and its --help; provides webStartup with the
# values this invocation resolved. Nothing waiting on it starts first.
- id: web-startup
name: '@deepseek-ai/dsh-web-app/startup'
# ── layer 2: transport/service ──────────────────────────────────────────────
# Plain route-registration carrier; host and port arrive as `dsh web`
@@ -83,6 +92,7 @@
# row below through the fallback seat.
- id: webserver
name: '@deepseek-ai/dsh-host-webserver'
inject: [webStartup]
config:
host: 127.0.0.1
port: 3080
@@ -96,12 +106,19 @@
# these host-owned shell variables.
- id: web-runtime
name: '@deepseek-ai/dsh-web-app'
inject: [webStartup]
config:
mode: production
printUrl: true
surfaceContext: true
# ── browser plugin roster (dsh.client rows; node halves are layer-2 hosts) ──
# The client-plugin HMR receiver ships disabled; `--dev` enables it.
- id: client-hmr
name: '@deepseek-ai/dsh-client-hmr'
inject: [webStartup]
disabled: true
# ── browser plugin roster (dshClient rows; node halves are layer-2 hosts) ──
# Dual-face: node half scans this very tree for dsh.client rows, composes
# window.__DSH_BOOT__, serves /plugins/<id>/client.js; browser half is the
@@ -114,6 +131,7 @@
# webserver under /api; browser half is the fetch/SSE client.
- id: connection
name: '@deepseek-ai/dsh-client-connection'
inject: [webStartup]
- id: api-remotes
name: '@deepseek-ai/dsh-api-remotes'