Merge branch 'master' into claude/unified-environment-credentials-c8841a

Master removed the TUI package, the `meta` and `upgrade` subcommands, and
`--config-replace`, and made raw `dsh` require a `--config` overlay. Resolved
onto that shape:

- Dropped this branch's TUI edits with the surface itself, including
  `tui.cordis.yml`, `runTui`, and the TUI keyless PTY smoke.
- Dropped the `--config-replace` plumbing rather than reintroducing a flag
  master deliberately removed. The gap this branch fixed remains: `dsh -p`
  still could not name its composition, so it keeps `--config`.
- Kept this branch's deletion of the personal `$DSH_HOME/config.yaml` layer,
  which master still carried, and provided the environment snapshot in the new
  raw `runConfig` surface alongside web and headless.
- Ported the headless shutdown PTY test off the personal overlay onto a named
  `--config` file, which is what proves that flag now exists on `-p`.
This commit is contained in:
Yichen Jiang
2026-08-04 17:51:44 +08:00
668 changed files with 10527 additions and 30408 deletions

View File

@@ -1,15 +1,13 @@
# The shared `dsh` core: every row both the TUI (`tui.cordis.yml`) and the web
# surface (`web.cordis.yml`) mount identically. Neither surface includes the
# other — each is a patch list applied over THIS file at one include level, so a
# surface overlay and an explicit `--config` overlay
# all address these rows by id. Patch lists stack in that order, last write
# winning per row.
# The shared `dsh` core. Raw `dsh --config <path>` applies its required patch
# list directly over this file. Web and headless apply their shipped overlay,
# followed by an explicit `--config` layer. Every layer addresses these rows by
# id at one include level, with the last write winning per row.
#
# A patch replaces the targeted row's whole `config` rather than merging into
# it, so a row whose value differs per surface does NOT live here: it belongs to
# it, so a row whose value differs by mode does NOT live here: it belongs to
# each overlay, keeping any single row down to one overlay layer plus the user's.
# Rows with surface-specific values appear below only with shared plugin identity
# and neutral defaults; each overlay restates the complete surface configuration.
# Mode-specific rows appear below only with shared plugin identity and neutral
# defaults; each overlay restates its complete configuration.
#
# Row order carries no load semantics (activation is service-availability
# driven); the grouping is for readers.
@@ -94,15 +92,15 @@
config:
root: !!js dshHomePath('sessions')
# TUI consumes this shared session capability. Its launcher supplies a unique
# process-local path; other surfaces repoint or disable the row in their
# overlay (web patches it to an ephemeral in-memory index).
# Raw configs can supply a process-local path or disable this shared session
# capability. The neutral default is process-local and opens only when used.
- id: session-query-sqlite
name: '@deepseek-ai/dsh-session-query-sqlite'
config:
path: !!js launcherSessionQueryPath ?? './.sessions/session-query.db'
path: ':memory:'
openAt: first-search
# Session telemetry, on for every dsh surface: mirrors every session-log
# Session telemetry, on for every dsh mode: mirrors every session-log
# event (assistant/chunk projected to first-of-step) plus ops markers onto
# OTLP/HTTP log records, streaming on the batch processor's cadence
# (10s/batch here) — not at exit; a crash loses at most the last unexported
@@ -114,18 +112,19 @@
# process out (the launchers patch the row disabled; config cannot disable
# a row). Exports carry the harness home's anonymous user id ($DSH_HOME/.userid,
# random UUID; delete the file to reset the identity) as the Resource's
# user.id. The exporter/processor values bound the shutdown drain to ~1s
# against an unreachable collector: exporter.timeoutMillis is both the
# per-attempt socket timeout and the retry deadline (1s effectively
# disables the SDK's 5-try backoff), maxExportBatchSize == maxQueueSize
# (both explicit) makes the drain a single batch, and exportTimeoutMillis
# is the processor's own cap on that one export cycle — the second bound
# when the exporter's clock alone does not fire. Every surface's exit path
# drains it: web/headless dispose on SIGINT/SIGTERM, and the TUI's normal
# exit and /resume handoff both dispose the root.
# user.id. The exporter/processor values normally bound the shutdown drain
# to ~1s against an unreachable collector: exporter.timeoutMillis is both
# the per-attempt socket timeout and the retry deadline (1s effectively
# disables the SDK's 5-try backoff), while maxExportBatchSize == maxQueueSize
# (both explicit) makes the drain a single batch. The SDK awaits
# exporter.forceFlush() outside exportTimeoutMillis, so the backend's 3s
# shutdownTimeoutMillis is the load-bearing outer bound when a transport
# promise never settles. Every CLI exit path drains it by disposing the root
# on SIGINT/SIGTERM.
- id: telemetry-otel
name: '@deepseek-ai/dsh-session-telemetry-otel'
config:
shutdownTimeoutMillis: 3000
exporter:
url: !!js process.env.DSH_TELEMETRY_OTLP_URL ?? 'https://harness-telemetry.deepseeksvc.com/v1/logs'
compression: gzip
@@ -139,7 +138,7 @@
- id: subprocess
name: '@deepseek-ai/dsh-subprocess-local'
# Every shipped product surface starts with the same file-effect boundary.
# Every shipped CLI mode starts with the same file-effect boundary.
# The environment remains an explicit deployment override; otherwise fresh
# sessions pin workspace-write + ask through the permission service below.
- id: sandbox
@@ -343,7 +342,7 @@
thresholds: [3, 5, 8]
argumentsPreviewChars: 500
# Every surface enables the stable web_search model surface. DeepSeek search
# Every mode enables the stable web_search model surface. DeepSeek search
# resolves the same DEEPSEEK_API_KEY credential the Models page manages for
# chat, at each search; its Messages endpoint is separate from the
# chat-completions endpoint, so it takes its own base-URL override. Fetch stays
@@ -367,35 +366,35 @@
fetch: false
searchTimeoutMs: 60000
# ── rows every surface mounts, whose values each overlay states ──────────────
# ── rows every mode mounts, whose values each overlay may state ──────────────
# The tool registry. Presentation mode is a surface choice, so each overlay
# states it; omitting it here keeps the schema default (native).
# The tool registry. Presentation mode is a deployment choice; omitting it here
# keeps the schema default (native).
- id: tools
name: '@deepseek-ai/dsh-tools'
# The deployment persona is a surface choice; plan-mode and tool plugins own
# The deployment persona is a deployment choice; plan-mode and tool plugins own
# their own prompt sections.
- id: system-prompt
name: '@deepseek-ai/dsh-system-prompt'
config:
persona: ''
# Agents created at startup. The TUI pre-creates `main`; the web surface creates
# sessions on client request, so its overlay keeps this empty.
# Agents created at startup. The base stays empty; raw overlays may create
# agents, while Web creates sessions on client request.
- id: agent-loop
name: '@deepseek-ai/dsh-agent-loop'
config:
agents: []
# The sandboxed filesystem provider. `cwd` defaults to `process.cwd()`; the TUI
# states it explicitly because that value is also the session workspace.
# The sandboxed filesystem provider. `cwd` defaults to `process.cwd()`; an
# overlay can pin another workspace.
- id: fs-sandbox
name: '@deepseek-ai/dsh-fs-sandbox'
# The native DeepSeek adapter. No key or endpoint is inlined: both resolve per
# request from the `llm-deepseek:` settings section over this entry, with the
# key coming from the credential store below. Thinking defaults are a surface
# key coming from the credential store below. Thinking defaults are a deployment
# choice.
- id: llm-deepseek
name: '@deepseek-ai/dsh-llm-deepseek'

View File

@@ -1,99 +0,0 @@
# `dsh` (the default surface) — the full-screen TUI, as a patch list over
# `base.cordis.yml`. The launcher includes the base and applies this file, then
# any `--config` overlay, then the personal `~/.dsh/config.yaml`, as sibling
# patch lists at ONE include level: patches never cross an include boundary, so
# stacking overlays as nested includes would silently stop reaching base rows.
#
# A patch replaces the targeted row's whole `config`, so each row below restates
# every key it owns. A patch whose `id` matches no row is skipped with a Loader
# warning, which is deliberate: one personal overlay is shared across surfaces,
# so a row that exists only under `web` must not fail the TUI's boot.
#
# The launcher owns session identity and the exit line, and provides both on the
# boot context rather than through config, so no key here — and no overlay
# replacing one — can drop `--resume`.
# ── surface-specific values the base deliberately omits ─────────────────────
# `main` is the agent the TUI drives. `provider`/`model` are the route `dsh
# login` rewrites and a personal overlay repoints; `cwd` anchors the session to
# the invoking directory, which is also what scopes `/resume` to this workspace.
- id: agent-loop
config:
agents:
- id: main
provider: deepseek-official
model: deepseek-v4-pro
cwd: !!js process.cwd()
# Keep the persona to identity and behavior; tool plugins own tool guidance.
# The loop resolves {{model}} from this agent's configuration.
- id: system-prompt
config:
persona: |
You are a coding agent powered by the {{model}} model.
Verify your work by running the code or tests. Keep answers brief and
factual.
# Shipped default: full thinking at max effort on every request. Exact-model
# resolution materializes request defaults before the request header is logged.
- id: llm-deepseek
config:
thinking: enabled
reasoningEffort: max
# This single-session app resolves relative paths from the process cwd.
- id: fs-sandbox
config:
cwd: !!js process.cwd()
# The shipped TUI presents the native tool registry.
- id: tools
config:
mode: native
# ── TUI-only rows ───────────────────────────────────────────────────────────
- insert:
# Relational runtime checks over the authoritative event streams; each
# companion registers the assertions its own package owns.
- id: invariants
name: '@deepseek-ai/dsh-invariants'
- id: session-invariant
name: '@deepseek-ai/dsh-session/invariant'
- id: agent-invariant
name: '@deepseek-ai/dsh-agent/invariant'
- id: scope-invariant
name: '@deepseek-ai/dsh-scope/invariant'
- id: agent-loop-invariant
name: '@deepseek-ai/dsh-agent-loop/invariant'
# The derived query index behind `/resume`. The launcher provides a unique
# process-local path because this SQLite backend has one writer owner; the
# project-local fallback applies when no launcher sets the typed slot.
- id: session-reference
name: '@deepseek-ai/dsh-session-reference'
# Terminal-multiplexer context, mounted only where a terminal exists.
- id: tmux-context
name: '@deepseek-ai/dsh-tmux-context'
config:
refreshIntervalMs: 900000
# The keyboard-backed provider behind ask_user_question and the plan-mode
# review, and the front door it renders inside.
- id: tui-prompt
name: '@deepseek-ai/dsh-tui/prompt'
# The TUI renders exactly the agent the agent-loop row bound, so it reads the
# same launcher-owned identity rather than restating one.
- id: tui
name: '@deepseek-ai/dsh-tui'
config:
sessionId: !!js configuredAgentIdentities?.main?.id ?? 'main'
showReasoning: true
maxToolOutputLines: 6
- id: tool-ask-user
name: '@deepseek-ai/dsh-tool-ask-user'