dsh-loop-engine-allinone 0.4.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,6 +8,133 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
9
  Nothing yet.
10
10
 
11
+ ## [0.7.2]
12
+
13
+ ### Changed
14
+
15
+ - **Installation leads with `--profile web` again.** 0.7.1 made `<your-profile>` the
16
+ primary spelling, on the reasoning that `web` is one of several shipped templates.
17
+ That is true but the wrong shape for an install section: `dsh web` is the harness
18
+ CLI's own documented example (`dsh web` = `dsh --profile web`), and every published
19
+ plugin says `dsh plugin --profile web add ...` — dsh-market included. Forcing a
20
+ placeholder substitution before the first command is friction with no payoff for the
21
+ majority.
22
+
23
+ The non-`web` case is now a caveat section instead: `desktop`, `headless`, and
24
+ self-named profiles get both steps, plus the silent failure that follows from doing
25
+ only the first one. npm / GitHub / local-clone remain the three sources.
26
+
27
+ ## [0.7.1]
28
+
29
+ ### Fixed
30
+
31
+ - **Installation no longer assumes a `web` profile.** `web` is one of several shipped
32
+ templates; the Desktop app boots `desktop`, a CI deployment boots `headless`, and
33
+ many people run a profile they named themselves. The instructions now say
34
+ `<your-profile>` and give the three real sources: npm, GitHub, and a local clone for
35
+ plugin development.
36
+ - **A wrong `profile:` is now diagnosable.** The field defaults to `web`, so forgetting
37
+ it writes the managed block into another profile's patch file while the profile that
38
+ actually boots never reads it — the plugin mounts, the base `agent-loop` row is never
39
+ disabled, and no hosted engine is reachable, with **nothing logged**. The harness
40
+ gives a plugin no way to ask which profile is running, so `apply` now checks whether
41
+ the target directory holds a profile's `package.json` and warns with the field to set.
42
+ It is a warning, not a failure: a first boot may legitimately precede the profile's
43
+ own files.
44
+
45
+ ### Documented
46
+
47
+ - The engine picker appears in whichever profile renders a web UI, not specifically in
48
+ `web`.
49
+
50
+ ## [0.7.0]
51
+
52
+ ### Added
53
+
54
+ - **Runtime model discovery.** A vendor shipping a model no longer needs a plugin
55
+ release. Two kinds of discovery, chosen so that the plugin still starts no external
56
+ process at boot:
57
+ - **free** — Kimi Code's catalog is read from its own `~/.kimi-code/config.toml` at
58
+ boot; an ACP engine's arrives in its `session/new` response the first time a
59
+ session opens (already paid for by that session).
60
+ - **costly** — `grok models` / `agy models` would need a new child process, so they
61
+ are deliberately not run: a menu render must not spawn anything. Those stay
62
+ declared.
63
+ - The provider route reads its model list through a thunk, so a catalog discovered
64
+ after boot appears without re-registering the route or restarting the harness.
65
+ - `catalogReport()` exposes each engine's catalog with its provenance
66
+ (`discovered` / `declared`), because "the engine told me" and "the plugin assumes"
67
+ are different claims.
68
+
69
+ ### Changed
70
+
71
+ - **The per-engine "Custom Models" column is gone from both READMEs.** It listed
72
+ model ids that are now discovered, so a hardcoded list was exactly the staleness
73
+ this release removes — and a reader would have taken an old id for the plugin's
74
+ limit. MiniMax Code's region, the one fact in that column that is not a model,
75
+ moved into the requirements cell.
76
+ - The model section describes the mechanism (discovered, declared fallback, and the
77
+ settings page saying which) instead of naming engines.
78
+ - Claude Code's row no longer reads as if the bundled SDK were the only option:
79
+ `bins.claudeBin` runs an external install. (Pinning changes what executes; it does
80
+ not unload the SDK package, which the driver imports.)
81
+
82
+ ### Verified
83
+
84
+ - On the reference host, `bootCatalog('kimi')` returns `origin: discovered`,
85
+ `source: kimi-config`, with four models read from the live config file.
86
+
87
+ ## [0.6.0]
88
+
89
+ ### Added
90
+
91
+ - **Kimi Code declares its model catalog** (K3, K3-256k, K2.8 Preview, K2.7 Code
92
+ Highspeed), read out of `~/.kimi-code/config.toml` — the file the Kimi Code
93
+ desktop app writes for a signed-in account. Those are the ids the app passes as
94
+ `model`, so they are the right vocabulary for this driver's `session/set_model`.
95
+
96
+ ### Documented
97
+
98
+ - **Why ZCode has no catalog**: its GLM Coding Plan subscription has lapsed
99
+ (`[1309] 您的GLM Coding Plan套餐已到期`), and an expired account cannot enumerate
100
+ what it may use. This is an account state, not a missing CLI.
101
+ - **Why Pi has no catalog**: it refreshes its model list at runtime
102
+ (`pi update --models`) from each provider, so any list shipped here would be stale
103
+ by design.
104
+ - The model-menu section now says what a **shared** group means (the menu collapsing
105
+ engines whose catalogs this build has not measured) and that declaring a `models`
106
+ row gives an engine its own group.
107
+
108
+ ## [0.5.0]
109
+
110
+ ### Added
111
+
112
+ - **Codex declares its model catalog**, so the model menu gives it a group of its
113
+ own instead of the shared `external` one. The ids were read out of the bundled
114
+ 0.149.1 CLI binary — they are what `thread/start`'s `model` accepts, which the
115
+ driver passes straight through.
116
+
117
+ ### Changed
118
+
119
+ - **Installation is the first section of both READMEs.** It used to sit below a
120
+ ten-row requirements table, which put a gate in front of the one thing a reader
121
+ wants first. The requirements table is reference, so it now follows.
122
+ - The **local-checkout install command is gone**: it told a stranger to run
123
+ `dsh plugin add /path/to/dsh-loop-engine-allinone`, a path nobody has. npm is the
124
+ documented path.
125
+ - **`dsh web` was written as if it were the harness's name.** `dsh` is the CLI and
126
+ `web` is one of its profiles; that is now said once, where a reader meets it.
127
+ - The model-menu section explains what a **shared** group means: it is the menu
128
+ collapsing engines whose catalogs this build has not measured, not a restriction
129
+ on what an engine can run. A `models` row gives an engine its own group.
130
+
131
+ ### Notes
132
+
133
+ - **Pi deliberately has no declared catalog.** It refreshes its model list at
134
+ runtime (`pi update --models`) from each provider, so any list shipped here would
135
+ be stale by design. Kimi and ZCode have none either: neither was installed on the
136
+ machine this release was measured on, so nothing could be observed.
137
+
11
138
  ## [0.4.1]
12
139
 
13
140
  ### Added
package/README.md CHANGED
@@ -3,222 +3,220 @@
3
3
  **English** · [简体中文](README.zh.md)
4
4
 
5
5
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
- [![Harness: 0.1.5 / 0.1.7 / 0.2.0](https://img.shields.io/badge/harness-0.1.5%20%7C%200.1.7%20%7C%200.2.0-6f42c1)](#version-compatibility)
7
-
8
- Pick **dsh web**'s agent loop engine **per session** — the built-in `in-process` loop (the default), or one of the hosted engines `claude-code` / `codex` / `pi` / `kimi` / `agy` / `zcode` / `qoderclicn` / `hermes` / `grok` / `minimaxcode`. Sessions are independent: one chat can run Codex while another runs Kimi. Any open, idle session can move engines — between two hosted engines the handover is **in place**, and a move involving `in-process` **reloads the page** (the `dsh web` process never restarts). Nothing in the main repository changes.
9
-
10
- > **A fork of [`kuun993/dsh-loop-engine`](https://github.com/kuun993/dsh-loop-engine).**
11
- > The upstream plugin already switched engines per session. This fork's contribution
12
- > is an **architecture** — a single data-driven engine registry plus a pluggable
13
- > driver layer — and the six engines that architecture made cheap to add.
14
- >
15
- > | | upstream | this fork |
16
- > |---|---|---|
17
- > | engine roster | hardcoded in five places | **one registry table**; everything else derives |
18
- > | adding an engine | edit five files | **one registry row + one driver** |
19
- > | engines | 4 | **10** |
20
- > | ACP engines | 1 (kimi) | **3** (kimi, grok, minimaxcode) sharing one skeleton |
21
- > | external-CLI drivers | per-engine | `driver-cli/` + `driver-acp/` |
22
- >
23
- > The four original engines' protocol code is untouched. `kimi` was migrated onto
24
- > the shared ACP skeleton **without a behavior change**, and its unchanged test
25
- > suite is the regression pin.
26
- >
27
- > Two things worth knowing before you add an engine:
28
- > - [`docs/engine-registry.md`](docs/engine-registry.md) §2 step 6 is the **entire**
29
- > recipe for an ACP engine: a profile plus four small files.
30
- > - **Probe first.** Every protocol claim in this repository came from real frames
31
- > (`scripts/probe/`), never from a specification. See [CONTRIBUTING.md](CONTRIBUTING.md).
32
-
33
- ## Engine marks
34
-
35
- Every engine has its own mark in the engine picker and its own colour + glyph on
36
- the chat's turn-status row; **only `in-process` carries the DeepSeek fish**.
37
-
38
- The three engines this fork added as external CLIs are **traced or measured from
39
- the vendors' own artwork found on this machine** — Antigravity's arch, ZCode's
40
- knocked-out `Z` (written out from measured spans, because its straight edges
41
- defeat a raster trace), and Qoder's green disc with the white crescent between its
42
- two forms. Kimi's mark was rebuilt from its app tile: a bold `K` plus the brand's
43
- blue dot, which rides an `accent` subpath because one path can only be filled one
44
- way.
45
-
46
- Hermes is the exception worth knowing about: that vendor's mark is a detailed
47
- character portrait rather than a glyph, so its mark is the portrait's own line art.
48
-
49
- The two ACP engines this fork added are traced from the artwork the user supplied:
50
- **Grok Build**'s black ring-and-slash (its slash tips are ~1px diagonals, which is
51
- why that trace is 8-connected — a 4-connected contour lops the tips off), and
52
- **MiniMax Code**'s white blob on the brand's blue tile, whose gradient is why its
53
- mask rule is "the darkest channel is still high" rather than a luminance
54
- threshold. Grok's vendor-published ACP icon is the same mark drawn about one pixel
55
- bolder; the comparison is recorded in the fork's probe report.
56
- Marks live in [`src/client/engine-marks.ts`](src/client/engine-marks.ts) as data
57
- rather than JSX, so a test can assert that every registered engine has one.
58
-
59
- Both tables are exhaustive over the hosted roster and pinned by tests — the
60
- failure this prevents is real: when four engines were first added, every one of
61
- them fell through the mark switch's `default` arm and rendered the DeepSeek fish
62
- beside its name.
63
-
64
- ## Engine registry
65
-
66
- Every engine-shaped decision derives from ONE table,
67
- [`src/engine-registry.ts`](src/engine-registry.ts): the id roster, the settings
68
- schema's union, the authored preset ids and display names, the browser half's
69
- option list and copy keys, and the driver dispatch
70
- ([`src/engine-drivers.ts`](src/engine-drivers.ts)). Both tables are total over
71
- the hosted ids, so a half-added engine fails the build rather than shipping an
72
- engine that mounts but cannot be selected.
73
-
74
- Each row declares what the surfaces need to know: human-readable label, source
75
- repo, whether the engine is an npm-bundled dependency or an external CLI, the key
76
- its executable override reads, its version/update argv, its login hint, its
77
- credential paths, and its **capabilities** (`streaming`, wire `protocol`,
78
- `sessionResume`, `permissionModes`, `images`, `reasoningLevels`). Capabilities are
79
- declarations, not discoveries: a surface never promises more than the engine was
80
- verified to do, and a driver asked for something outside its declaration refuses
81
- with the user's next action rather than degrading silently.
82
-
83
- New engines implement one method. `src/driver-cli/` supplies the rest: the
84
- turn/step lifecycle (`cli-agent.ts`), the durable-log writer
85
- (`session-sink.ts` — where the session format's "refuse to load" rules are
86
- enforced in one place), the subprocess transport, and four protocol skeletons
87
- (`ndjson`, `stream-json` for the Claude-Code dialect, `text`, plus the existing
88
- engines' ACP and JSON-RPC drivers as their templates).
89
-
90
- ## Install
6
+ [![Harness: 0.1.5 | 0.1.7 | 0.2.0](https://img.shields.io/badge/harness-0.1.5%20%7C%200.1.7%20%7C%200.2.0-6f42c1)](#version-compatibility)
7
+
8
+ **dsh-loop-engine-allinone** is an all-in-one agent loop engine switcher for **[DeepSeek Harness](https://github.com/deepseek-ai)** (`dsh`). It enables per-session engine switching across **10 hosted engines** (Claude Code, Codex, Pi, Kimi Code, Antigravity, ZCode, Qoder CN, Hermes Agent, Grok Build, MiniMax Code) alongside the built-in `in-process` loop.
9
+
10
+ > `dsh` is the harness CLI. `dsh --profile <name>` boots one of its **profiles**, and the engine picker plus this plugin's settings page appear in whichever profile renders a web UI (the shipped `web` template is one; the Desktop app uses `desktop`).
11
+
12
+ Sessions are fully independent: run Codex in one chat while another runs Kimi Code or Antigravity simultaneously. Handover between two hosted engines happens seamlessly in place; switching to or from the native `in-process` engine performs an in-browser reload without restarting the backend process. All without modifying the DeepSeek Harness core codebase.
13
+
14
+ > **Fork Note**: This project is a fork of [`kuun993/dsh-loop-engine`](https://github.com/kuun993/dsh-loop-engine).
15
+ > While the upstream plugin introduced per-session switching for 4 initial engines, this fork refactors the internals into a **unified data-driven engine registry** and **shared driver infrastructure**, expanding support to **10 distinct engines**.
16
+
17
+ ---
18
+
19
+ ### Highlights & Comparison with Upstream
20
+
21
+ | Feature | Upstream (`kuun993`) | This Fork (`allinone`) |
22
+ |---|---|---|
23
+ | **Supported Engines** | 4 engines | **10 engines** (+ native `in-process`) |
24
+ | **Engine Configuration** | Hardcoded across 5+ files | **Single registry table** (`src/engine-registry.ts`) |
25
+ | **Adding New Engines** | Modify 5 separate files | **1 registry row + 1 driver** |
26
+ | **ACP Protocol** | 1 engine (Kimi) | **3 engines** (Kimi, Grok, MiniMax) on a shared ACP skeleton |
27
+ | **CLI Drivers** | Ad-hoc implementations | Standardized `driver-cli/` & `driver-acp/` runtimes |
28
+ | **Model Selection** | Global default only | **Per-engine subscription catalogs**, discovered at runtime (no release needed when a vendor ships a model) |
29
+ | **UI Integration** | Standard labels | **Custom branded marks & status badges** for all 10 engines |
30
+
31
+ ---
32
+
33
+ ## Installation
34
+
35
+ ```sh
36
+ dsh plugin --profile web add dsh-loop-engine-allinone
37
+ ```
38
+
39
+ Restart `dsh web`, then open **Settings → Loop engine**.
40
+
41
+ ### From GitHub instead of npm
91
42
 
92
43
  ```sh
93
- # From this repository (the npm package name `dsh-loop-engine-allinone` belongs to
94
- # upstream, so installing from git names the fork explicitly):
95
44
  dsh plugin --profile web add yaliklinty/dsh-loop-engine-allinone
45
+ ```
46
+
47
+ ### From a local clone
48
+
49
+ Only when you are working on the plugin itself:
50
+
51
+ ```sh
52
+ git clone https://github.com/yaliklinty/dsh-loop-engine-allinone.git
53
+ dsh plugin --profile web add ./dsh-loop-engine-allinone
54
+ ```
96
55
 
97
- # From a local checkout:
98
- dsh plugin --profile web add /path/to/dsh-loop-engine-allinone
56
+ ### Not on the `web` profile?
57
+
58
+ `web` is the profile the harness's own CLI documents (`dsh web` is short for
59
+ `dsh --profile web`), so it is the right default. But the Desktop app boots
60
+ `desktop`, a CI deployment may boot `headless`, and you may have made your own. In
61
+ that case:
62
+
63
+ 1. install with that profile's name — `dsh plugin --profile desktop add
64
+ dsh-loop-engine-allinone`;
65
+ 2. **and** set the same name in the composition entry:
66
+
67
+ ```yaml
68
+ - id: loop-engine
69
+ config:
70
+ profile: desktop
71
+ ```
72
+
73
+ Step 2 is the one that bites. The field defaults to `web`, so omitting it makes the
74
+ plugin write its managed block into `profiles/web/cordis.patch.yml` while the profile
75
+ you actually boot never reads it: the plugin mounts, but the base `agent-loop` row is
76
+ never disabled, the router cannot take the agent-factory slot, and **no hosted engine
77
+ is reachable** — with nothing logged. This release also warns when it detects that
78
+ shape, naming the field to set.
79
+
80
+ ### Installation notes
81
+
82
+ - The installer rewrites one managed block in the profile's `cordis.patch.yml`; every
83
+ other byte you wrote there is preserved, so upgrading needs no hand edit.
84
+ - **Uninstall**: `dsh plugin --profile web remove dsh-loop-engine-allinone`, **then
85
+ delete the managed `loop-engine` block** from that profile's `cordis.patch.yml`. The
86
+ block outlives the plugin, and while it is present the profile has no agent factory,
87
+ so no session can be created.
88
+ - **pnpm 10+** may block dependency build scripts (`ERR_PNPM_IGNORED_BUILDS` naming
89
+ `esbuild`, `@google/genai`, `protobufjs`). Run `pnpm approve-builds`, or add an
90
+ `allowBuilds` entry, and retry — only the installing project can grant this.
91
+ - **Harness from source**: bridge the profile's harness peers with `file:` shims, or
92
+ session resume fails with `agent-presets: refusing to compose an unscoped context`.
93
+ Steps in [docs/source-checkout.md](docs/source-checkout.md).
94
+
95
+ ## Supported Engines
96
+
97
+ | Engine | Type / Protocol | Host Requirements & Authentication |
98
+ |---|---|---|
99
+ | **Claude Code** | Bundled SDK / `ndjson` | Nothing, by default (the SDK ships a binary); set `bins.claudeBin` to run your own install instead |
100
+ | **Codex** | Bundled / `jsonrpc` | `codex login` or `CODEX_API_KEY` |
101
+ | **Pi** | Bundled / `jsonrpc` | `~/.pi/agent/auth.json`, or the provider's API-key variable |
102
+ | **Kimi Code** | External CLI / `acp` | `kimi` CLI installed and authenticated (`kimi login`) |
103
+ | **Antigravity** | External CLI / `ndjson` | `agy` CLI installed and signed in to Google |
104
+ | **ZCode** | External CLI / `jsonrpc` | `zcode` CLI installed, with a live GLM Coding Plan subscription |
105
+ | **Qoder CN** | External CLI / `ndjson` | `qoderclicn` CLI installed and authenticated |
106
+ | **Hermes Agent** | External CLI / `text` | `hermes` CLI installed and configured (`hermes setup`) |
107
+ | **Grok Build** | External CLI / `acp` | `grok` CLI installed and signed in once (`grok login`) |
108
+ | **MiniMax Code** | External CLI / `acp` | `npm i -g @minimax-ai/code`, `mcode login --region cn\|global`, then `mcode provider use token-plan` |
109
+
110
+ > **Model lists are discovered, not listed here.** Each engine's models come from the engine itself — Kimi Code's own config file at boot, an ACP engine's `session/new` response as soon as a session opens — so a vendor shipping a model does not need a plugin release. Engines whose catalog this build cannot read fall back to a declared list, and one with neither shows the shared `external` group. The settings page shows which is which.
111
+
112
+ > **Note**: For external CLI engines (`bundled: false`), the plugin spawns your locally installed binaries; it does not download or authenticate them automatically. Please install and log in on your host machine beforehand.
113
+
114
+ ---
115
+
116
+ ---
117
+
118
+ ## Configuration
119
+
120
+ Custom settings can be configured under your profile's composition entry:
121
+
122
+ ```yaml
123
+ - id: loop-engine
124
+ config:
125
+ # 1. Custom executable paths (optional - overrides default PATH / bundled binaries)
126
+ bins:
127
+ claudeBin: 'D:/tools/claude.exe'
128
+ kimiBin: 'D:/tools/kimi.exe'
129
+ agyBin: 'D:/tools/agy.exe'
130
+ qoderclicnBin: 'D:/tools/qoderclicn.exe'
131
+ grokBin: 'C:/Users/user/.grok/bin/grok.exe'
132
+ minimaxcodeBin: 'D:/npm-global/node_modules/@minimax-ai/code/cli.js'
133
+
134
+ # 2. Region override (optional - MiniMax Code supports 'cn' or 'en')
135
+ regions:
136
+ mcodeRegion: 'cn'
137
+
138
+ # 3. Child process idle timeout in milliseconds (default: 0 = disabled)
139
+ # Applies to engines with persistent subprocesses (Kimi, Codex, Grok, MiniMax).
140
+ childIdleMs: 300000
141
+
142
+ # 4. Context window for hosted sessions (default: 262144 tokens)
143
+ # Used by dsh auto-compaction (triggers at 80% of this limit).
144
+ engineContextWindow: 262144
145
+
146
+ # 5. Summarizer model for session compaction (must be set together)
147
+ # Hosted sessions route compaction through this model.
148
+ summarizerProvider: 'deepseek-official'
149
+ summarizerModel: 'deepseek-flash'
99
150
  ```
100
151
 
101
- Boot `dsh web` once (the router retries for a bounded window while the base bundle still holds the agent-factory slot), then open **Settings → Loop engine**.
152
+ ---
102
153
 
103
- **Install notes**
154
+ ## Usage Guide
104
155
 
105
- - The install rewrites one **engine-agnostic** managed block in the profile's `cordis.patch.yml`; every other byte you wrote there is preserved. Upgrading from an older release needs no hand edit.
106
- - **Installing into any profile but `web`** — the Desktop app's `desktop`, a `headless` deployment, a renamed profile — needs `profile: <name>` in the composition entry for that profile:
107
- ```yaml
108
- - id: loop-engine
109
- config:
110
- profile: desktop
111
- ```
112
- `profile` defaults to `web`, so without it the plugin writes its managed block into `<home>/profiles/web/cordis.patch.yml` while the running profile never reads it: the plugin mounts, but the base `agent-loop` row is never disabled, so its router cannot take the factory slot and no hosted engine is reachable. (Found by installing into the Desktop app.)
113
- - **Uninstall** is `dsh plugin --profile web remove dsh-loop-engine-allinone` **plus deleting that managed block** — the block outlives the plugin, and while it is present the profile has no agent factory, so no session can be created.
114
- - **pnpm 10+** may block dependency build scripts (`ERR_PNPM_IGNORED_BUILDS`, naming `esbuild`, `@google/genai`, `protobufjs`). Run `pnpm approve-builds` (or add an `allowBuilds` entry) and retry; only the installing project can grant this.
115
- - **Booting the harness from its source checkout** additionally needs the profile's harness peers bridged with `file:` shims — otherwise session resume fails with `agent-presets: refusing to compose an unscoped context`. Steps in [docs/source-checkout.md](docs/source-checkout.md).
156
+ - **Creating Sessions**: Select an engine from the preset dropdown next to the workspace picker, or leave it as `standard` to use the native `in-process` loop. Subagents automatically inherit their parent's engine.
157
+ - **Default Engine**: Configure the default engine for new chats under **Settings → Loop engine**. Existing sessions remain unchanged.
158
+ - **Switching Engines Mid-Session**: Enable *Show the engine selector in the chat page* in settings to switch engines directly from the composer:
159
+ - **Hosted ↔ Hosted**: Handover occurs in place immediately.
160
+ - **Hosted ↔ In-Process**: Prompts for confirmation and reloads the browser tab (chat history is preserved; unsent drafts and scroll positions are reset).
161
+ - *Note*: Engine switching is permitted only when the current session is idle.
162
+ - **Header Badge**: Shows the engine actively powering the current session. Can be toggled via *Show the engine badge in the conversation header*.
163
+ - **Model Selection**:
164
+ - **A catalog is discovered, not shipped.** Kimi Code's is read from its own config file at boot; an ACP engine's arrives in its `session/new` response the first time a session opens; Codex's is static in its bundled CLI. Picking a discovered model passes its id to the engine. **A vendor shipping a model therefore needs no plugin release.**
165
+ - An engine whose catalog this build cannot read falls back to a **declared** list, and the settings page says which of the two you are looking at. **Pi** has none by design (it refreshes from each provider at runtime via `pi update --models`); **ZCode**'s could not be read because its GLM Coding Plan subscription has lapsed, and an expired account cannot enumerate what it may use.
166
+ - Other hosted engines share one `external` group holding a single `default`, which means "let the engine decide". A shared group is not a limitation on what you can run — it is the menu collapsing engines whose catalogs this build has not measured. Declaring a catalog (one `models` row in the registry) gives an engine its own group.
167
+ - Picking a **real dsh model** instead hands the engine that model's endpoint and credential as well; whether the engine can serve it is the engine's business, and a refusal is reported rather than swallowed.
168
+ - Native dsh commands (`/export`, `/feedback`, `/permission`) and context auto-compaction remain fully functional.
116
169
 
117
- ## Requirements
170
+ ---
118
171
 
119
- | Engine | Needs, on the host |
120
- |---|---|
121
- | Claude Code | the Claude Code CLI installed and logged in (or none: the SDK ships a bundled binary) |
122
- | Codex | `codex login`, or a `CODEX_API_KEY` environment entry |
123
- | Pi | whatever `pi` expects (its own `~/.pi/agent/auth.json`, or the provider's API-key variable) |
124
- | Kimi Code | the `kimi` CLI installed and logged in, on `PATH` (or pinned via `bins.kimiBin`) |
125
- | Antigravity | the `agy` CLI installed and signed in to Google |
126
- | ZCode | the ZCode CLI and a live GLM Coding Plan subscription |
127
- | Qoder CN | the `qoderclicn` CLI installed and signed in |
128
- | Hermes Agent | the `hermes` CLI installed and signed in; it reads its own `HERMES_HOME`, which the child inherits |
129
- | Grok Build | the `grok` CLI installed (`~/.grok/bin/grok.exe`, or `npx @xai-official/grok@<pinned> agent stdio`) and signed in once through `grok` / `grok login` — its ACP server refuses `session/new` until it has an account |
130
- | MiniMax Code | `npm i -g @minimax-ai/code`, then `mcode login --region cn\|global` and `mcode provider use token-plan` to spend the M Plan allowance instead of an API key |
131
-
132
- ## Usage
133
-
134
- - **New session** — pick the engine on the preset chip beside the workspace picker, or keep the deployment's default (`standard`) for the in-process loop. A child agent inherits its parent's engine.
135
- - **Settings → Loop engine** sets the default for **new** sessions. It lands immediately; running sessions are unaffected. **In-process** restores whatever default the plugin replaced.
136
- - **Move a session you are in** with the composer's engine selector (enable *Show the engine selector in the chat page*).
137
- - Hosted → hosted: in place, applies on the spot.
138
- - Anything involving `in-process`: the composer asks first, then the page reloads and reopens the same session (scroll position and unsent draft are lost; the record is not).
139
- - A mid-turn session is refused, and a subagent's session cannot be moved.
140
- - **The header chip** beside the preset label names the engine the session on screen actually runs; *Show the engine badge in the conversation header* turns it off (and the header keeps no trace of the plugin).
141
- - **Models** — two kinds of group, on purpose.
142
- - **An engine that declares its own catalog gets a group of its own**, named by the engine (today: `Antigravity`, `Grok Build`, `MiniMax Code`), holding `default` plus the models that engine's own subscription includes. Picking one hands that id to the engine — `agy --model gemini-3.8-flash-low`, or a `session/set_config_option` for the ACP engines — so you choose among the models you actually pay for instead of accepting "the engine decides". `default` still means exactly that.
143
- - **Every other engine shares the `external` group** with its single `default`. That is not a leftover: the model catalog is built per Host *generation*, not per session, so a group per engine would put eight identical `default` rows in every session's menu. A group only earns its place by carrying models the others do not.
144
- - Picking a **real dsh model** still hands it to the engine together with its endpoint and credential; whether the engine can serve it is the engine's business, and a refusal is reported rather than swallowed. A pick belonging to a *different* engine's group is refused with the mismatch named, never silently ignored.
145
- - The catalog is **declared in the engine registry**, not probed at boot — this plugin starts no external process when the harness boots. A deployment whose subscription changed updates [`src/engine-registry.ts`](src/engine-registry.ts)'s `models` row; a stale id then fails loudly at the engine, which is the honest outcome.
146
- - `in-process` sessions use dsh's models normally.
147
- - **`bins`** (composition entry, optional) — per-engine executable overrides, keyed by each engine's registry `binConfigKey`. Pointing a **bundled** engine at an external CLI is how it is unbound: `claudeBin` reaches the SDK's own `pathToClaudeCodeExecutable`, while `codexBin` / `piBin` replace the entrypoint those drivers launch. Not setting one keeps the bundled copy and its argv byte for byte:
148
- ```yaml
149
- - id: loop-engine
150
- config:
151
- bins:
152
- claudeBin: 'D:/tools/claude.exe'
153
- kimiBin: 'D:/tools/kimi.exe'
154
- qoderclicnBin: 'D:/tools/qoderclicn.exe'
155
- grokBin: 'C:/Users/me/.grok/bin/grok.exe'
156
- minimaxcodeBin: 'D:/Programs/npm-global/node_modules/@minimax-ai/code/cli.js'
157
- ```
158
- An npm-installed CLI needs no pin (the resolver finds the package entrypoint, and
159
- a Windows `.cmd` shim is launched through `cmd.exe` — node refuses a `.cmd`
160
- directly), but a pin is the way to choose among several installs.
161
- - **`regions`** (composition entry, optional) — per-engine account **region**
162
- overrides, keyed by each registry row's `region.configKey`. Today only MiniMax
163
- Code declares one (`regions.mcodeRegion`, default `cn`), because its login
164
- endpoint AND its stored credentials are region-scoped:
165
- ```yaml
166
- - id: loop-engine
167
- config:
168
- regions:
169
- mcodeRegion: 'en' # this engine's spelling of the non-China account
170
- ```
171
- The value is spelled into the child's environment as the variable that engine's
172
- CLI actually reads (`MAVIS_REGION` — measured, and NOT `MCODE_REGION`, which is
173
- inert on the `mcode acp` path). An unknown value, or a `region` that contradicts
174
- the same variable in `env`, fails the engine's construction loud rather than
175
- pointing the child at an account nobody chose.
176
- - **`childIdleMs`** (composition entry, milliseconds, default `0` = off) — Kimi and Codex keep **one child process per session** across steps; this closes it after that much idle time and respawns it on the next step. Only the child is closed, so nothing reloads. Pi and Claude Code spawn per step and are unaffected.
177
- - **`engineContextWindow`** (composition entry, tokens, default `262144`) — the context window dsh assumes for the shared hosted route. It is what dsh's auto-compaction measures a hosted session against (it fires at 80% of this by default), because a hosted engine reports no capacity of its own. Set it to the **smallest** window among the engines you run.
178
- - **`summarizerProvider` / `summarizerModel`** (composition entry, **set together or not at all**) — the real dsh model a hosted session's **compaction** summarizes through, e.g. `deepseek-official` / `deepseek-flash`. Compaction is dsh's own (its preset keeps the `compaction` group), but the summarizing *call* is an ordinary llm request, and a hosted session's routed model is the plugin's placeholder route — so without this pair a hosted session can never be folded down: every attempt logs a warning and the turn continues. The pair only serves that call; the engine still answers every user turn itself. Composing just one of the two (or an empty string) is refused at boot, not silently ignored.
179
- - **dsh's own commands** (`/export`, `/feedback`, `/permission`) keep working under a hosted engine. Its preset is a copy of `standard` with the dsh-native rows an external engine replaces stripped out (dsh's `/plan`, the goal tool and `/goal`, the skill rows). dsh's **compaction is kept**: it is what keeps the session log — and so the transcript replayed to the engine on every step — bounded, which an engine's own per-turn compaction cannot do (a fresh engine session is opened per step, so the engine's shrink is discarded while the log keeps growing). Configure `summarizerProvider` / `summarizerModel` (above) or its summarizing call has no model to run on.
180
-
181
- ## Version compatibility
182
-
183
- One release serves the **0.1.5 line** (`>=0.1.5-rc.1 <0.1.6-0`), the **0.1.7 line** (`>=0.1.7-rc.1 <0.1.8-0`) and the **0.2.0 line** (`>=0.2.0-rc.1 <0.2.1-0`): the plugin detects the running generation at load and takes the matching code path. Those union ranges are what it declares in `peerDependencies`, and a harness outside them fails loudly at boot or session resume.
184
-
185
- Read the version as `<harness line>-rcN`, where **`rcN` is this plugin's own release counter for that line** — not the harness's `rc` number. Within a covered line a new harness `rc` needs no plugin release unless an API surface moved; [docs/compatibility.md](docs/compatibility.md) §1 lists those surfaces and the diff command that decides it.
186
-
187
- | Plugin | Harness |
172
+ ## Architecture & Extending
173
+
174
+ Adding a new engine is straightforward thanks to the unified registry:
175
+
176
+ 1. **Register Descriptor**: Add the engine ID to `HOSTED_ENGINE_IDS` and define its metadata and capabilities in `src/engine-registry.ts`.
177
+ 2. **Implement Driver**: Create a driver implementing `runStep` (leveraging `src/driver-cli/` or `src/driver-acp/`).
178
+ 3. **Bind Driver**: Register the driver class in `src/engine-drivers.ts`.
179
+ 4. **UI Localization**: Add display strings in `src/client/locales.ts` and an optional SVG icon in `src/client/engine-marks.ts`.
180
+
181
+ Both tables enforce compile-time exhaustiveness checks — incomplete engine registrations fail at build time rather than runtime. Detailed instructions are in [docs/engine-registry.md](docs/engine-registry.md).
182
+
183
+ ---
184
+
185
+ ## Version Compatibility
186
+
187
+ A single release seamlessly supports multiple DeepSeek Harness generations via runtime detection:
188
+
189
+ | Plugin Release | Supported DeepSeek Harness Line |
188
190
  |---|---|
189
- | `0.2.0-rc1` | `0.2.0-rc.1`, `0.2.0-rc.2` |
190
- | `0.1.7-rc1` … `0.1.7-rc5` | `0.1.7-rc.1`, `0.1.7-rc.2` |
191
- | `0.1.5-rc3` … `0.1.5-rc5` | `0.1.5-rc.2` |
192
- | `0.1.5-rc1` / `0.1.5-rc2` | `0.1.5-rc.1` |
193
- | `1.0.0-rc8` … `1.0.0-rc15` | `0.1.2-rc.1` |
194
- | `1.0.0-rc7` and earlier | `0.1.1-rc.2` |
195
-
196
- `0.2.0-rc1` is the first release that serves three lines at once, and the first one published after the harness started enforcing a peer-range gate at boot: the plugin is still mounted alongside an incompatible one, but a harness outside the ranges above is now skipped by dsh itself rather than failing later.
197
-
198
- ## Known limitations
199
-
200
- - **It replaces the harness's agent factory.** One facade serves every session, so the plugin promises to stay out of the way: any session it cannot answer for — including sessions with nothing to do with hosted engines — degrades to the `in-process` loop instead of failing to open. See [docs/per-session-engine.md](docs/per-session-engine.md) §6.
201
- - **The engine record is a sidecar**, `$DSH_HOME/.loop-engine/engines.json`, not part of the session log: changing machine or `DSH_HOME` loses it and the session falls back to its preset. See §5.5.
202
- - **Moving a session involving `in-process` reloads the page** — the harness loop neither hands over a live session nor adopts one it did not create. See §5.2/§5.4.
203
- - **Sessions that already ran a turn** can still move, but only while idle, and the move rebuilds that session's agent. See §5.
204
- - **Old sessions with the legacy preset id `loop-engine`** read as "legacy hosted engine" until rebuilt once. See §7.
205
- - **Same-engine sessions share that CLI's own auth directory**, with no lock added by the plugin. See §6.
206
- - **Switching back to `in-process` leaves the shared `external` group in the model menu** (the catalog is not scoped per session).
207
-
208
- ## Where the details live
209
-
210
- - [docs/per-session-engine.md](docs/per-session-engine.md) — the full user-visible behavior (§ numbers above refer to it).
211
- - [docs/architecture.md](docs/architecture.md) — plugin core: the single factory slot, the managed block, routing, the provider route.
212
- - [docs/compatibility.md](docs/compatibility.md) — **start here when the harness upgrades**: every generation-dependent code site and the checklist for the next generation.
213
- - [docs/driver-core.md](docs/driver-core.md) — the shared driver infrastructure.
214
- - [docs/engine-claude.md](docs/engine-claude.md) · [engine-codex](docs/engine-codex.md) · [engine-kimi](docs/engine-kimi.md) · [engine-pi](docs/engine-pi.md) — per-engine internals. The ACP engines (`kimi` / `grok` / `minimaxcode`) share `driver-acp/`, whose per-engine surface is documented in [docs/engine-registry.md](docs/engine-registry.md) §2 step 6.
215
- - `scripts/probe/acp-handshake.mjs` · `scripts/probe/smoke-acp.ts` — dump a real ACP engine's frames, or drive one through the plugin's OWN profile (`node node_modules/tsx/dist/cli.mjs scripts/probe/smoke-acp.ts minimaxcode`).
216
- - [docs/source-checkout.md](docs/source-checkout.md) — the `file:` shims a source-launched harness needs.
217
- - [docs/optimization-backlog.md](docs/optimization-backlog.md) — known issues and the optimization list.
218
- - [docs/proposals/](docs/proposals/) — main-repo proposals.
191
+ | `0.2.0-rcX` | `0.2.0-rc.1`, `0.2.0-rc.2` |
192
+ | `0.1.7-rcX` | `0.1.7-rc.1`, `0.1.7-rc.2` |
193
+ | `0.1.5-rcX` | `0.1.5-rc.1`, `0.1.5-rc.2` |
194
+
195
+ See [docs/compatibility.md](docs/compatibility.md) for harness upgrade checklists and API surface diffs.
196
+
197
+ ---
198
+
199
+ ## Technical Notes & Limitations
200
+
201
+ - **Agent Factory Replacement**: The plugin registers a unified facade over the harness agent factory. Any session that cannot be routed to a hosted engine gracefully falls back to the native `in-process` loop.
202
+ - **Engine State Persistence**: Active session engine bindings are stored in `$DSH_HOME/.loop-engine/engines.json`. If this file is cleared, sessions revert to their preset defaults.
203
+ - **Subprocess Concurrency**: Multi-session execution shares the respective CLI's local authentication and configuration directory.
204
+ - **Grok Build Shell Execution**: Grok tools rely on the harness client terminal bridge (`ctx.shell`).
205
+
206
+ ---
207
+
208
+ ## Documentation Links
209
+
210
+ - [docs/engine-registry.md](docs/engine-registry.md) — Engine registration guide & ACP engine recipe.
211
+ - [docs/per-session-engine.md](docs/per-session-engine.md) — Detailed user-facing behaviors and handover specs.
212
+ - [docs/architecture.md](docs/architecture.md) — Core routing, factory slots, and configuration patches.
213
+ - [docs/driver-core.md](docs/driver-core.md) — Shared driver runtime and lifecycle management.
214
+ - [docs/compatibility.md](docs/compatibility.md) — Multi-version harness compatibility guide.
215
+ - [docs/source-checkout.md](docs/source-checkout.md) — Running alongside a harness source checkout.
216
+ - [CONTRIBUTING.md](CONTRIBUTING.md) — Development and probe verification workflows.
217
+
218
+ ---
219
219
 
220
220
  ## License
221
221
 
222
- MIT — see [LICENSE](LICENSE) for the full text. The upstream author's copyright
223
- notice is preserved there beside this fork's own; [NOTICE](NOTICE) records what the
224
- fork adds and what it deliberately leaves untouched.
222
+ [MIT](LICENSE) © contributors of `dsh-loop-engine-allinone` and upstream `kuun993/dsh-loop-engine`. See [NOTICE](NOTICE) for license and attribution details.