dsh-loop-engine-allinone 0.0.0-stage → 0.4.0

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.
Files changed (143) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/CONTRIBUTING.md +78 -0
  3. package/LICENSE +23 -0
  4. package/NOTICE +45 -0
  5. package/README.md +221 -2
  6. package/README.zh.md +89 -0
  7. package/SECURITY.md +39 -0
  8. package/cordis.patch.yml +3 -0
  9. package/lib/client.js +2166 -0
  10. package/lib/index.js +11621 -0
  11. package/lib/invariant.js +453 -0
  12. package/lib/types/agent-preset-ids.d.ts +276 -0
  13. package/lib/types/client/LoopEngineBadge.d.ts +71 -0
  14. package/lib/types/client/LoopEngineComposerSelect.d.ts +126 -0
  15. package/lib/types/client/LoopEngineSection.d.ts +35 -0
  16. package/lib/types/client/engine-marks.d.ts +87 -0
  17. package/lib/types/client/index.d.ts +39 -0
  18. package/lib/types/client/locales.d.ts +182 -0
  19. package/lib/types/client/reload.d.ts +135 -0
  20. package/lib/types/client/session-engine.d.ts +508 -0
  21. package/lib/types/client/store.d.ts +103 -0
  22. package/lib/types/client/turn-status.d.ts +234 -0
  23. package/lib/types/client/use-session-engine.d.ts +74 -0
  24. package/lib/types/commands.d.ts +77 -0
  25. package/lib/types/compat.d.ts +25 -0
  26. package/lib/types/driver-acp/agent.d.ts +289 -0
  27. package/lib/types/driver-acp/approval.d.ts +27 -0
  28. package/lib/types/driver-acp/capabilities.d.ts +200 -0
  29. package/lib/types/driver-acp/client.d.ts +297 -0
  30. package/lib/types/driver-acp/executable.d.ts +53 -0
  31. package/lib/types/driver-acp/mapping.d.ts +76 -0
  32. package/lib/types/driver-acp/profile.d.ts +126 -0
  33. package/lib/types/driver-acp/runtime.d.ts +45 -0
  34. package/lib/types/driver-acp/subprocess.d.ts +19 -0
  35. package/lib/types/driver-acp/terminal.d.ts +98 -0
  36. package/lib/types/driver-acp/transport.d.ts +43 -0
  37. package/lib/types/driver-acp/types.d.ts +152 -0
  38. package/lib/types/driver-cli/capability.d.ts +42 -0
  39. package/lib/types/driver-cli/cli-agent.d.ts +258 -0
  40. package/lib/types/driver-cli/cli-loop.d.ts +46 -0
  41. package/lib/types/driver-cli/flatten.d.ts +35 -0
  42. package/lib/types/driver-cli/frames.d.ts +128 -0
  43. package/lib/types/driver-cli/ndjson.d.ts +106 -0
  44. package/lib/types/driver-cli/session-sink.d.ts +333 -0
  45. package/lib/types/driver-cli/stream-json.d.ts +61 -0
  46. package/lib/types/driver-cli/text.d.ts +66 -0
  47. package/lib/types/driver-cli/transport.d.ts +84 -0
  48. package/lib/types/driver-core/agents-md-skill-provider.d.ts +72 -0
  49. package/lib/types/driver-core/assistant-stream.d.ts +68 -0
  50. package/lib/types/driver-core/context-files.d.ts +62 -0
  51. package/lib/types/driver-core/host-servers.d.ts +119 -0
  52. package/lib/types/driver-core/hosted-engine-runtime.d.ts +190 -0
  53. package/lib/types/driver-core/hosted-tool-vocabulary.d.ts +78 -0
  54. package/lib/types/driver-core/idle-child.d.ts +57 -0
  55. package/lib/types/driver-core/image-access.d.ts +25 -0
  56. package/lib/types/driver-core/inbox.d.ts +104 -0
  57. package/lib/types/driver-core/model-handover.d.ts +134 -0
  58. package/lib/types/driver-core/ownership.d.ts +41 -0
  59. package/lib/types/driver-core/permission-knobs.d.ts +26 -0
  60. package/lib/types/driver-core/prompt.d.ts +64 -0
  61. package/lib/types/driver-core/session-lifetime.d.ts +62 -0
  62. package/lib/types/driver-core/session-model.d.ts +128 -0
  63. package/lib/types/driver-core/skill-inject.d.ts +59 -0
  64. package/lib/types/driver-core/step-close.d.ts +49 -0
  65. package/lib/types/driver-core/step-images.d.ts +62 -0
  66. package/lib/types/driver-core/step-tools.d.ts +43 -0
  67. package/lib/types/driver-core/system-head.d.ts +43 -0
  68. package/lib/types/engine-agy/agent.d.ts +67 -0
  69. package/lib/types/engine-agy/frames.d.ts +90 -0
  70. package/lib/types/engine-agy/loop.d.ts +64 -0
  71. package/lib/types/engine-agy/process.d.ts +173 -0
  72. package/lib/types/engine-claude/agent.d.ts +186 -0
  73. package/lib/types/engine-claude/loop.d.ts +73 -0
  74. package/lib/types/engine-claude/mapping.d.ts +108 -0
  75. package/lib/types/engine-claude/permission.d.ts +41 -0
  76. package/lib/types/engine-claude/process.d.ts +59 -0
  77. package/lib/types/engine-claude/sdk.d.ts +67 -0
  78. package/lib/types/engine-claude/types.d.ts +28 -0
  79. package/lib/types/engine-codex/agent.d.ts +216 -0
  80. package/lib/types/engine-codex/appserver/client.d.ts +80 -0
  81. package/lib/types/engine-codex/appserver/mapping.d.ts +67 -0
  82. package/lib/types/engine-codex/appserver/thread.d.ts +66 -0
  83. package/lib/types/engine-codex/appserver/types.d.ts +225 -0
  84. package/lib/types/engine-codex/loop.d.ts +75 -0
  85. package/lib/types/engine-codex/model-handover.d.ts +56 -0
  86. package/lib/types/engine-codex/permission.d.ts +126 -0
  87. package/lib/types/engine-codex/skills.d.ts +28 -0
  88. package/lib/types/engine-codex/types.d.ts +36 -0
  89. package/lib/types/engine-drivers.d.ts +132 -0
  90. package/lib/types/engine-grok/agent.d.ts +24 -0
  91. package/lib/types/engine-grok/loop.d.ts +61 -0
  92. package/lib/types/engine-grok/process.d.ts +46 -0
  93. package/lib/types/engine-grok/profile.d.ts +82 -0
  94. package/lib/types/engine-hermes/agent.d.ts +47 -0
  95. package/lib/types/engine-hermes/loop.d.ts +56 -0
  96. package/lib/types/engine-hermes/process.d.ts +92 -0
  97. package/lib/types/engine-kimi/acp/client.d.ts +123 -0
  98. package/lib/types/engine-kimi/acp/mapping.d.ts +73 -0
  99. package/lib/types/engine-kimi/acp/types.d.ts +143 -0
  100. package/lib/types/engine-kimi/agent.d.ts +24 -0
  101. package/lib/types/engine-kimi/commands.d.ts +44 -0
  102. package/lib/types/engine-kimi/loop.d.ts +62 -0
  103. package/lib/types/engine-kimi/model-handover.d.ts +32 -0
  104. package/lib/types/engine-kimi/permission.d.ts +28 -0
  105. package/lib/types/engine-kimi/process.d.ts +47 -0
  106. package/lib/types/engine-kimi/profile.d.ts +19 -0
  107. package/lib/types/engine-kimi/skills.d.ts +52 -0
  108. package/lib/types/engine-kimi/types.d.ts +25 -0
  109. package/lib/types/engine-minimaxcode/agent.d.ts +24 -0
  110. package/lib/types/engine-minimaxcode/loop.d.ts +83 -0
  111. package/lib/types/engine-minimaxcode/process.d.ts +53 -0
  112. package/lib/types/engine-minimaxcode/profile.d.ts +72 -0
  113. package/lib/types/engine-of-session.d.ts +97 -0
  114. package/lib/types/engine-pi/agent.d.ts +230 -0
  115. package/lib/types/engine-pi/loop.d.ts +72 -0
  116. package/lib/types/engine-pi/model-handover.d.ts +84 -0
  117. package/lib/types/engine-pi/permission.d.ts +47 -0
  118. package/lib/types/engine-pi/rpc/client.d.ts +107 -0
  119. package/lib/types/engine-pi/rpc/mapping.d.ts +37 -0
  120. package/lib/types/engine-pi/rpc/types.d.ts +249 -0
  121. package/lib/types/engine-pi/skills.d.ts +47 -0
  122. package/lib/types/engine-pi/types.d.ts +36 -0
  123. package/lib/types/engine-qoderclicn/agent.d.ts +59 -0
  124. package/lib/types/engine-qoderclicn/loop.d.ts +51 -0
  125. package/lib/types/engine-qoderclicn/process.d.ts +113 -0
  126. package/lib/types/engine-registry.d.ts +584 -0
  127. package/lib/types/engine-remote.d.ts +192 -0
  128. package/lib/types/engine-surface.d.ts +36 -0
  129. package/lib/types/engine-zcode/agent.d.ts +50 -0
  130. package/lib/types/engine-zcode/loop.d.ts +47 -0
  131. package/lib/types/engine-zcode/process.d.ts +111 -0
  132. package/lib/types/index.d.ts +205 -0
  133. package/lib/types/invariant.d.ts +26 -0
  134. package/lib/types/model-selection-reset.d.ts +271 -0
  135. package/lib/types/namespace.d.ts +25 -0
  136. package/lib/types/patch-manager.d.ts +104 -0
  137. package/lib/types/preset.d.ts +254 -0
  138. package/lib/types/provider-route.d.ts +245 -0
  139. package/lib/types/router-loop.d.ts +458 -0
  140. package/lib/types/session-engine-store.d.ts +138 -0
  141. package/lib/types/settings.d.ts +60 -0
  142. package/lib/types/skills.d.ts +85 -0
  143. package/package.json +150 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,100 @@
1
+ # Changelog
2
+
3
+ All notable changes to this fork. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ Nothing yet.
10
+
11
+ ## [0.4.0]
12
+
13
+ ### Added
14
+
15
+ - **Grok Build (`grok`)** — ACP engine over `grok agent stdio`.
16
+ - `session/new` refuses an unauthenticated client, so the driver answers ACP's
17
+ `authenticate` with the method id `initialize` published, retries once, and
18
+ otherwise reports the registry's login hint instead of a raw JSON-RPC error.
19
+ - Model selection is `session/set_config_option` with a **bare value**; the
20
+ `{ value }` wrapper the vendor's documentation shows is rejected `-32602`.
21
+ (Measured after signing in; the earlier "documented spelling first, fall back"
22
+ guess was wrong and is gone.)
23
+ - The model catalog is read from the signed-in agent's own
24
+ `initialize._meta.modelState` (`grok-4.7`), not from the unauthenticated
25
+ `grok models` command, which reports ids this surface refuses.
26
+ - Declares `images: false`: `promptCapabilities.image` is false, and sending an
27
+ image block would reject the whole prompt.
28
+ - **MiniMax Code (`minimaxcode`)** — ACP engine over `mcode acp`, aimed at the
29
+ M Plan **subscription** rather than an API key (`mcode login`, then
30
+ `mcode provider use token-plan`; the plugin never logs in and never reads the
31
+ credential).
32
+ - Resolves the npm package entrypoint, and launches a Windows `.cmd` shim
33
+ through the command interpreter — `spawn('mcode')` fails `ENOENT` and
34
+ `spawn('mcode.cmd')` throws `EINVAL`, both measured.
35
+ - Region travels as `MAVIS_REGION` (measured as the variable this surface
36
+ honours; `MCODE_REGION` is inert here), with the `cn|en` value domain the CLI
37
+ validates — not the login flag's `cn|global`.
38
+ - States `permissionMode` on every opened session rather than inheriting
39
+ whatever the CLI last persisted, because that default can be Full access.
40
+ - **ACP client-side capabilities** (`driver-acp/capabilities.ts`,
41
+ `driver-acp/terminal.ts`) — the other half of ACP, and what makes a
42
+ tool-using ACP engine actually work.
43
+ - `terminal/create` and its lifecycle, plus `fs/read_text_file`.
44
+ - The terminal bridge routes through the harness's own `shell` service, i.e. the
45
+ same executor dsh's `bash` tool uses, so an engine's command gets the same
46
+ sandbox, timeout policy and output caps. With no shell service it **refuses**
47
+ rather than falling back to an unconfined spawn.
48
+ - The announced `clientCapabilities` is derived from the implemented handlers, so
49
+ a declared capability is always an implemented one; a filesystem **write** is
50
+ never announced.
51
+ - `capabilities.acpProtocolVersion` — the version announced at `initialize` is
52
+ registry data now, not a constant in the shared client.
53
+ - `EngineDescriptor.region` — an engine whose CLI scopes accounts by region
54
+ declares the knob, the environment variable and the accepted values.
55
+ - `scripts/probe/acp-handshake.mjs` and `scripts/probe/smoke-acp.ts` — dump an ACP
56
+ engine's frames, or drive one through the plugin's own profile.
57
+ - `CONTRIBUTING.md`, `SECURITY.md`, this changelog.
58
+
59
+ ### Changed
60
+
61
+ - **`engine-kimi/acp/` → `driver-acp/`**, and `KimiAgent`'s turn/step machine
62
+ generalised into `AcpEngineAgent`. Kimi keeps its class names and constructor
63
+ shapes; its entire suite passes unchanged, which is the regression pin for the
64
+ move.
65
+ - An ACP engine is now a **profile** (argv, protocol version, model dialect,
66
+ session handshake, endpoint handover) plus four small files. Adding the fourth
67
+ one does not touch shared code.
68
+ - Tool vocabulary: MiniMax Code's measured `bash` call is a **declared identity**
69
+ (a table row meaning "read and found to agree"), and grok deliberately has no
70
+ row — its only measured tool runs through the client-side terminal bridge, and
71
+ renaming it to dsh's `bash` would dress a failing call up as a working one.
72
+
73
+ ### Fixed
74
+
75
+ - `smoke-acp.ts <engine>` skipped the engine name as if it were `--bin`'s value
76
+ when `--bin` was absent, so `smoke-acp.ts grok` silently ran minimaxcode.
77
+ - grok's `authenticate` sat outside its `try`, so a failure there (which is what a
78
+ signed-out host produces, since the call starts the vendor's browser sign-in)
79
+ surfaced "process exited unexpectedly" instead of an actionable hint.
80
+ - `.gitignore` now covers a stray CLI home directory: a relative `GROK_HOME` once
81
+ made an engine write its whole state dir — `auth.json` included — into this repo.
82
+
83
+ ### Known limitations
84
+
85
+ - **grok's tools need the harness shell service.** Its shell tools run through the
86
+ client-side terminal bridge; a composition without `ctx.shell` refuses them
87
+ rather than running them unconfined. Grok's reasoning and conversation work
88
+ either way.
89
+ - **`claudeBin` cannot unload the bundled SDK.** Pointing it at an external binary
90
+ changes what executes, but `@anthropic-ai/claude-agent-sdk` is a value import in
91
+ `engine-claude/agent.ts`, so the package stays required. `codexBin` and `piBin`
92
+ CAN fully unbind their bundled copies.
93
+ - **Bundled engines have no runtime updater** by design: their version is this
94
+ package's dependency pin, so upgrading means changing the dependency, not
95
+ rewriting it in place.
96
+
97
+ ## [0.3.0] and earlier
98
+
99
+ The upstream plugin's history. See
100
+ [`kuun993/dsh-loop-engine`](https://github.com/kuun993/dsh-loop-engine).
@@ -0,0 +1,78 @@
1
+ # Contributing
2
+
3
+ Thanks for looking. This is a fork, and it stays useful only if it is easy to
4
+ extend — so the most valuable contribution is **another engine**, not another
5
+ refactor.
6
+
7
+ ## Before you start
8
+
9
+ - Read [`docs/engine-registry.md`](docs/engine-registry.md). It is the "add an
10
+ engine" recipe, and it records the traps that cost real time.
11
+ - **Probe first.** An engine's wire protocol is recorded from real frames before a
12
+ driver is written for it. A guessed frame shape produces a driver that looks
13
+ finished and silently answers nothing. `scripts/probe/` is that record.
14
+ - Never guess a capability. `capabilities` describes what the DRIVER was verified
15
+ to do, not what the vendor's documentation claims. `images: false` for an engine
16
+ that turns out to accept images is a bug; `images: true` for one that rejects
17
+ them is a broken turn.
18
+
19
+ ## Adding an engine
20
+
21
+ The full recipe is [`docs/engine-registry.md`](docs/engine-registry.md) §2. In
22
+ short, for an ACP engine (three of them share one skeleton, so this is four small
23
+ files):
24
+
25
+ 1. add the id to `HOSTED_ENGINE_IDS` (append only — ids are persisted);
26
+ 2. add its `ENGINE_REGISTRY` row (TypeScript refuses a missing one);
27
+ 3. write `src/engine-<id>/{process,profile,agent,loop}.ts`;
28
+ 4. add its driver factory to `src/engine-drivers.ts`;
29
+ 5. add its copy to `src/client/locales.ts` and its mark to
30
+ `src/client/engine-marks.ts`.
31
+
32
+ Then:
33
+
34
+ ```sh
35
+ node node_modules/typescript/bin/tsc -p tsconfig.build.json --noEmit
36
+ node node_modules/vitest/vitest.mjs run
37
+ node build.mjs
38
+ ```
39
+
40
+ All three must pass. The suite is the contract: a new engine that lands without
41
+ tests is a new engine nobody can safely change later.
42
+
43
+ ## What a pull request needs
44
+
45
+ - **A probe artifact.** Frames dumped from the real CLI, in the PR body (not
46
+ necessarily committed — they can be large). Without it a protocol claim is a
47
+ guess.
48
+ - **A driver smoke result**, when the CLI can run on your machine:
49
+ `node node_modules/tsx/dist/cli.mjs scripts/probe/smoke-driver.ts <engine>` for
50
+ the CLI-family drivers, or `smoke-acp.ts <engine>` for an ACP one.
51
+ - **Tests for the behaviour you changed**, not just for the happy path. The
52
+ failures this codebase has actually shipped were mostly "no error, wrong data"
53
+ (a stream that never reached the durable log, a tool call split across two
54
+ messages, a config value that looked right and did nothing).
55
+ - **An honest UNKNOWN.** If something could not be measured on your machine, say
56
+ so in the docs rather than filling it in. A documented gap is worth more than a
57
+ plausible invention.
58
+
59
+ ## Style
60
+
61
+ - Comments explain **why**, and they cite the measurement or the failure that
62
+ produced the rule. "This is load-bearing because X failed" beats "this is
63
+ important".
64
+ - Every module starts with a `@module` tag and a paragraph on what it is for.
65
+ - Do not reformat code you are not changing. Diffs should be readable.
66
+
67
+ ## Reporting a bug
68
+
69
+ Include: the engine, its version (`<cli> --version`), the harness line
70
+ (0.1.5 / 0.1.7 / 0.2.0), the profile, and what you expected vs what happened. If
71
+ the bug is protocol-shaped, the probe output is the single most useful thing you
72
+ can attach.
73
+
74
+ ## Security
75
+
76
+ Engine credentials are the engines' own business: this plugin never reads, writes
77
+ or refreshes them, and a profile should never contain one. If you find a path where
78
+ that is not true, treat it as a security report — see [SECURITY.md](SECURITY.md).
package/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kuun993 (original author, https://github.com/kuun993/dsh-loop-engine)
4
+
5
+ Copyright (c) 2026 dsh-loop-engine-allinone fork contributors
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/NOTICE ADDED
@@ -0,0 +1,45 @@
1
+ dsh-loop-engine-allinone
2
+ ========================
3
+
4
+ This project is a fork of **dsh-loop-engine** by kuun993:
5
+
6
+ https://github.com/kuun993/dsh-loop-engine
7
+
8
+ The original work is MIT-licensed. Its copyright notice is preserved in the
9
+ `LICENSE` file, alongside this fork's own.
10
+
11
+ ## What the fork adds
12
+
13
+ The upstream plugin already switches the agent loop engine per session. This fork
14
+ contributes an ARCHITECTURE and the engines it made cheap to add:
15
+
16
+ - **A single data-driven engine registry** (`src/engine-registry.ts`). The engine
17
+ roster, its capability declarations, its model catalogs and its display copy are
18
+ declared once; the settings schema, the preset ids, the driver dispatch and the
19
+ browser half all derive from that table. Upstream restated the roster in five
20
+ places, so adding an engine meant finding all five.
21
+ - **A pluggable driver layer**: `driver-cli/` for line-delimited CLI protocols and
22
+ `driver-acp/` for the Agent Client Protocol. An ACP engine is a profile plus four
23
+ small files, and adding the fourth does not touch shared code.
24
+ - **Six additional engines**: Antigravity, ZCode, Qoder CN, Hermes, Grok Build and
25
+ MiniMax Code.
26
+ - **Client-side ACP capabilities** (`terminal/*`, `fs/read_text_file`), routed
27
+ through the harness's own shell and filesystem services, which is what lets an
28
+ engine that drives its tools through the client actually use them.
29
+
30
+ ## What the fork does NOT change
31
+
32
+ The four original engines' protocol code is untouched. `kimi` was migrated onto the
33
+ shared ACP skeleton without a behavior change, and its unchanged test suite is the
34
+ regression pin for that move.
35
+
36
+ ## Third-party artwork
37
+
38
+ The engine marks in `src/client/engine-marks.ts` are traced or measured from each
39
+ vendor's own published artwork, and remain the trademarks of their respective
40
+ owners. They are used here only to identify the engine a user selected.
41
+
42
+ ## Modifications
43
+
44
+ Modifications made by this fork are licensed under the same MIT terms as the
45
+ original. See `LICENSE`.
package/README.md CHANGED
@@ -1,3 +1,222 @@
1
- # Temporary Holding Version
1
+ # dsh-loop-engine-allinone
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
4
+ [![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)
5
+
6
+ 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.
7
+
8
+ > **A fork of [`kuun993/dsh-loop-engine`](https://github.com/kuun993/dsh-loop-engine).**
9
+ > The upstream plugin already switched engines per session. This fork's contribution
10
+ > is an **architecture** — a single data-driven engine registry plus a pluggable
11
+ > driver layer — and the six engines that architecture made cheap to add.
12
+ >
13
+ > | | upstream | this fork |
14
+ > |---|---|---|
15
+ > | engine roster | hardcoded in five places | **one registry table**; everything else derives |
16
+ > | adding an engine | edit five files | **one registry row + one driver** |
17
+ > | engines | 4 | **10** |
18
+ > | ACP engines | 1 (kimi) | **3** (kimi, grok, minimaxcode) sharing one skeleton |
19
+ > | external-CLI drivers | per-engine | `driver-cli/` + `driver-acp/` |
20
+ >
21
+ > The four original engines' protocol code is untouched. `kimi` was migrated onto
22
+ > the shared ACP skeleton **without a behavior change**, and its unchanged test
23
+ > suite is the regression pin.
24
+ >
25
+ > Two things worth knowing before you add an engine:
26
+ > - [`docs/engine-registry.md`](docs/engine-registry.md) §2 step 6 is the **entire**
27
+ > recipe for an ACP engine: a profile plus four small files.
28
+ > - **Probe first.** Every protocol claim in this repository came from real frames
29
+ > (`scripts/probe/`), never from a specification. See [CONTRIBUTING.md](CONTRIBUTING.md).
30
+
31
+ ## Engine marks
32
+
33
+ Every engine has its own mark in the engine picker and its own colour + glyph on
34
+ the chat's turn-status row; **only `in-process` carries the DeepSeek fish**.
35
+
36
+ The three engines this fork added as external CLIs are **traced or measured from
37
+ the vendors' own artwork found on this machine** — Antigravity's arch, ZCode's
38
+ knocked-out `Z` (written out from measured spans, because its straight edges
39
+ defeat a raster trace), and Qoder's green disc with the white crescent between its
40
+ two forms. Kimi's mark was rebuilt from its app tile: a bold `K` plus the brand's
41
+ blue dot, which rides an `accent` subpath because one path can only be filled one
42
+ way.
43
+
44
+ Hermes is the exception worth knowing about: that vendor's mark is a detailed
45
+ character portrait rather than a glyph, so its mark is the portrait's own line art.
46
+
47
+ The two ACP engines this fork added are traced from the artwork the user supplied:
48
+ **Grok Build**'s black ring-and-slash (its slash tips are ~1px diagonals, which is
49
+ why that trace is 8-connected — a 4-connected contour lops the tips off), and
50
+ **MiniMax Code**'s white blob on the brand's blue tile, whose gradient is why its
51
+ mask rule is "the darkest channel is still high" rather than a luminance
52
+ threshold. Grok's vendor-published ACP icon is the same mark drawn about one pixel
53
+ bolder; the comparison is recorded in the fork's probe report.
54
+ Marks live in [`src/client/engine-marks.ts`](src/client/engine-marks.ts) as data
55
+ rather than JSX, so a test can assert that every registered engine has one.
56
+
57
+ Both tables are exhaustive over the hosted roster and pinned by tests — the
58
+ failure this prevents is real: when four engines were first added, every one of
59
+ them fell through the mark switch's `default` arm and rendered the DeepSeek fish
60
+ beside its name.
61
+
62
+ ## Engine registry
63
+
64
+ Every engine-shaped decision derives from ONE table,
65
+ [`src/engine-registry.ts`](src/engine-registry.ts): the id roster, the settings
66
+ schema's union, the authored preset ids and display names, the browser half's
67
+ option list and copy keys, and the driver dispatch
68
+ ([`src/engine-drivers.ts`](src/engine-drivers.ts)). Both tables are total over
69
+ the hosted ids, so a half-added engine fails the build rather than shipping an
70
+ engine that mounts but cannot be selected.
71
+
72
+ Each row declares what the surfaces need to know: human-readable label, source
73
+ repo, whether the engine is an npm-bundled dependency or an external CLI, the key
74
+ its executable override reads, its version/update argv, its login hint, its
75
+ credential paths, and its **capabilities** (`streaming`, wire `protocol`,
76
+ `sessionResume`, `permissionModes`, `images`, `reasoningLevels`). Capabilities are
77
+ declarations, not discoveries: a surface never promises more than the engine was
78
+ verified to do, and a driver asked for something outside its declaration refuses
79
+ with the user's next action rather than degrading silently.
80
+
81
+ New engines implement one method. `src/driver-cli/` supplies the rest: the
82
+ turn/step lifecycle (`cli-agent.ts`), the durable-log writer
83
+ (`session-sink.ts` — where the session format's "refuse to load" rules are
84
+ enforced in one place), the subprocess transport, and four protocol skeletons
85
+ (`ndjson`, `stream-json` for the Claude-Code dialect, `text`, plus the existing
86
+ engines' ACP and JSON-RPC drivers as their templates).
87
+
88
+ ## Install
89
+
90
+ ```sh
91
+ # From this repository (the npm package name `dsh-loop-engine-allinone` belongs to
92
+ # upstream, so installing from git names the fork explicitly):
93
+ dsh plugin --profile web add yaliklinty/dsh-loop-engine-allinone
94
+
95
+ # From a local checkout:
96
+ dsh plugin --profile web add /path/to/dsh-loop-engine-allinone
97
+ ```
98
+
99
+ 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**.
100
+
101
+ **Install notes**
102
+
103
+ - 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.
104
+ - **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:
105
+ ```yaml
106
+ - id: loop-engine
107
+ config:
108
+ profile: desktop
109
+ ```
110
+ `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.)
111
+ - **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.
112
+ - **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.
113
+ - **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).
114
+
115
+ ## Requirements
116
+
117
+ | Engine | Needs, on the host |
118
+ |---|---|
119
+ | Claude Code | the Claude Code CLI installed and logged in (or none: the SDK ships a bundled binary) |
120
+ | Codex | `codex login`, or a `CODEX_API_KEY` environment entry |
121
+ | Pi | whatever `pi` expects (its own `~/.pi/agent/auth.json`, or the provider's API-key variable) |
122
+ | Kimi Code | the `kimi` CLI installed and logged in, on `PATH` (or pinned via `bins.kimiBin`) |
123
+ | Antigravity | the `agy` CLI installed and signed in to Google |
124
+ | ZCode | the ZCode CLI and a live GLM Coding Plan subscription |
125
+ | Qoder CN | the `qoderclicn` CLI installed and signed in |
126
+ | Hermes Agent | the `hermes` CLI installed and signed in; it reads its own `HERMES_HOME`, which the child inherits |
127
+ | 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 |
128
+ | 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 |
129
+
130
+ ## Usage
131
+
132
+ - **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.
133
+ - **Settings → Loop engine** sets the default for **new** sessions. It lands immediately; running sessions are unaffected. **In-process** restores whatever default the plugin replaced.
134
+ - **Move a session you are in** with the composer's engine selector (enable *Show the engine selector in the chat page*).
135
+ - Hosted → hosted: in place, applies on the spot.
136
+ - 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).
137
+ - A mid-turn session is refused, and a subagent's session cannot be moved.
138
+ - **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).
139
+ - **Models** — two kinds of group, on purpose.
140
+ - **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.
141
+ - **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.
142
+ - 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.
143
+ - 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.
144
+ - `in-process` sessions use dsh's models normally.
145
+ - **`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:
146
+ ```yaml
147
+ - id: loop-engine
148
+ config:
149
+ bins:
150
+ claudeBin: 'D:/tools/claude.exe'
151
+ kimiBin: 'D:/tools/kimi.exe'
152
+ qoderclicnBin: 'D:/tools/qoderclicn.exe'
153
+ grokBin: 'C:/Users/me/.grok/bin/grok.exe'
154
+ minimaxcodeBin: 'D:/Programs/npm-global/node_modules/@minimax-ai/code/cli.js'
155
+ ```
156
+ An npm-installed CLI needs no pin (the resolver finds the package entrypoint, and
157
+ a Windows `.cmd` shim is launched through `cmd.exe` — node refuses a `.cmd`
158
+ directly), but a pin is the way to choose among several installs.
159
+ - **`regions`** (composition entry, optional) — per-engine account **region**
160
+ overrides, keyed by each registry row's `region.configKey`. Today only MiniMax
161
+ Code declares one (`regions.mcodeRegion`, default `cn`), because its login
162
+ endpoint AND its stored credentials are region-scoped:
163
+ ```yaml
164
+ - id: loop-engine
165
+ config:
166
+ regions:
167
+ mcodeRegion: 'en' # this engine's spelling of the non-China account
168
+ ```
169
+ The value is spelled into the child's environment as the variable that engine's
170
+ CLI actually reads (`MAVIS_REGION` — measured, and NOT `MCODE_REGION`, which is
171
+ inert on the `mcode acp` path). An unknown value, or a `region` that contradicts
172
+ the same variable in `env`, fails the engine's construction loud rather than
173
+ pointing the child at an account nobody chose.
174
+ - **`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.
175
+ - **`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.
176
+ - **`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.
177
+ - **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.
178
+
179
+ ## Version compatibility
180
+
181
+ 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.
182
+
183
+ 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.
184
+
185
+ | Plugin | Harness |
186
+ |---|---|
187
+ | `0.2.0-rc1` | `0.2.0-rc.1`, `0.2.0-rc.2` |
188
+ | `0.1.7-rc1` … `0.1.7-rc5` | `0.1.7-rc.1`, `0.1.7-rc.2` |
189
+ | `0.1.5-rc3` … `0.1.5-rc5` | `0.1.5-rc.2` |
190
+ | `0.1.5-rc1` / `0.1.5-rc2` | `0.1.5-rc.1` |
191
+ | `1.0.0-rc8` … `1.0.0-rc15` | `0.1.2-rc.1` |
192
+ | `1.0.0-rc7` and earlier | `0.1.1-rc.2` |
193
+
194
+ `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.
195
+
196
+ ## Known limitations
197
+
198
+ - **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.
199
+ - **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.
200
+ - **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.
201
+ - **Sessions that already ran a turn** can still move, but only while idle, and the move rebuilds that session's agent. See §5.
202
+ - **Old sessions with the legacy preset id `loop-engine`** read as "legacy hosted engine" until rebuilt once. See §7.
203
+ - **Same-engine sessions share that CLI's own auth directory**, with no lock added by the plugin. See §6.
204
+ - **Switching back to `in-process` leaves the shared `external` group in the model menu** (the catalog is not scoped per session).
205
+
206
+ ## Where the details live
207
+
208
+ - [docs/per-session-engine.md](docs/per-session-engine.md) — the full user-visible behavior (§ numbers above refer to it).
209
+ - [docs/architecture.md](docs/architecture.md) — plugin core: the single factory slot, the managed block, routing, the provider route.
210
+ - [docs/compatibility.md](docs/compatibility.md) — **start here when the harness upgrades**: every generation-dependent code site and the checklist for the next generation.
211
+ - [docs/driver-core.md](docs/driver-core.md) — the shared driver infrastructure.
212
+ - [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.
213
+ - `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`).
214
+ - [docs/source-checkout.md](docs/source-checkout.md) — the `file:` shims a source-launched harness needs.
215
+ - [docs/optimization-backlog.md](docs/optimization-backlog.md) — known issues and the optimization list.
216
+ - [docs/proposals/](docs/proposals/) — main-repo proposals.
217
+
218
+ ## License
219
+
220
+ MIT — see [LICENSE](LICENSE) for the full text. The upstream author's copyright
221
+ notice is preserved there beside this fork's own; [NOTICE](NOTICE) records what the
222
+ fork adds and what it deliberately leaves untouched.
package/README.zh.md ADDED
@@ -0,0 +1,89 @@
1
+ # dsh-loop-engine-allinone
2
+
3
+ [![npm version](https://img.shields.io/npm/v/dsh-loop-engine-allinone?color=cb3837)](https://www.npmjs.com/package/dsh-loop-engine-allinone)
4
+
5
+ 像选模型一样选 **dsh web** 的 agent 循环引擎——**按会话**选:内置的 `in-process`(默认),或四个托管引擎 `claude-code`、`codex`、`pi`、`kimi`。会话之间互不影响:一个对话跑 Codex,另一个可以同时跑 Kimi。只要会话打开且空闲,任何时候都能换引擎——两个托管引擎之间是**原地换手**,有一边是 `in-process` 时会让**页面重新载入**(`dsh web` 进程本身**不重启**)。以上**无需改动主仓库**。
6
+
7
+ ## 安装
8
+
9
+ ```sh
10
+ dsh plugin --profile web add dsh-loop-engine-allinone
11
+ ```
12
+
13
+ 启动一次 `dsh web`(路由器会在有界窗口内重试,等基础 bundle 让出 factory 槽位),然后打开 **Settings → Loop engine**。
14
+
15
+ **安装须知**
16
+
17
+ - 安装会重写 profile 的 `cordis.patch.yml` 里一小段**不带引擎 id** 的受管理块;文件里你写的其它部分逐字节保留。从更早版本升级**不需要手工改文件**。
18
+ - **装到 `web` 以外的 profile**(桌面版的 `desktop`、`headless` 部署、改过名的 profile)必须在该 profile 的组合条目里写上 `profile: <名字>`:
19
+ ```yaml
20
+ - id: loop-engine
21
+ config:
22
+ profile: desktop
23
+ ```
24
+ `profile` 默认是 `web`,不写的话插件会把受管块写进 `<home>/profiles/web/cordis.patch.yml`,而正在跑的那个 profile 永远不会读它:插件挂着,但基础 `agent-loop` 行没被禁,路由器拿不到 factory 槽位,任何托管引擎都不可达。(这是装进桌面版时踩出来的。)
25
+ - **卸载**是 `dsh plugin --profile web remove dsh-loop-engine-allinone` **再加上删掉那段受管理块**——块会比插件活得久,而它还在时 profile 里没有任何 agent factory,会话一条也建不出来。
26
+ - **pnpm 10+** 可能拦下依赖的 build script(`ERR_PNPM_IGNORED_BUILDS`,列出 `esbuild`、`@google/genai`、`protobufjs`)。执行 `pnpm approve-builds`(或加一条 `allowBuilds`)后重试;只有安装方能授予这个权限。
27
+ - **用源码启动 harness** 时还要多做一步:用 `file:` shim 把 profile 的 harness peer 包桥接到 checkout 源码,否则恢复会话会报 `agent-presets: refusing to compose an unscoped context`。步骤见 [docs/source-checkout.md](docs/source-checkout.md)。
28
+
29
+ ## 环境要求
30
+
31
+ | 引擎 | 本机需要 |
32
+ |---|---|
33
+ | Claude Code | 已安装并登录 Claude Code CLI |
34
+ | Codex | 执行过 `codex login`,或配置 `CODEX_API_KEY` |
35
+ | Pi | `pi` 自己要求的认证方式(其 `~/.pi/agent/auth.json`,或提供方的 API-key 环境变量) |
36
+ | Kimi Code | 已安装并登录 `kimi` CLI,且在 `PATH` 上(或用 `kimiBin` 固定路径) |
37
+
38
+ ## 使用方法
39
+
40
+ - **新会话**——在 preset 选择器(工作区选择器旁的 chip)上选引擎;保留部署自己的默认(通常是 `standard`)则走 in-process。子 agent 沿用拉起它的那个 agent 的引擎。
41
+ - **Settings → Loop engine** 决定**新会话**的默认引擎:改完立即生效,已经在跑的会话不受影响。选 **In-process** 会把插件接手前的默认值恢复回去。
42
+ - **换当前这条会话**用对话页 composer 的引擎选择器(勾选 *在对话页显示引擎选择器*)。
43
+ - 托管 → 托管:原地换手,当场生效。
44
+ - 涉及 `in-process` 的方向:先弹确认框,确认后页面重新载入并回到同一条会话(滚动位置与未发出的草稿会丢,会话记录不丢)。
45
+ - 正在跑一轮的会话会被**拒绝**,子 agent 的会话不能换。
46
+ - **对话头部那个标记**(preset 标签旁边)写的是这条会话**实际在跑**的引擎;取消勾选 *在对话头部显示引擎标记* 即可关掉它(关掉后 header 上不留插件的任何痕迹)。
47
+ - **模型**——所有托管引擎共用 **一个** `external` 分组,里面只有一条 `default`,含义是"交给引擎自己决定"。选一条**真实的 dsh 模型**会把模型连同它的端点与凭据一起交给引擎;引擎能不能用是引擎的事,**被拒会如实报错而不是悄悄吞掉**。`in-process` 会话照常用 dsh 的模型。
48
+ - **`childIdleMs`**(组合条目,毫秒,默认 `0` = 不启用)——Kimi 与 Codex **每条会话保有一个常驻子进程**跨 step 复用;设了它就在空闲这么久之后把子进程关掉,下一步再重新拉起。只关子进程,所以不会触发任何重载。Pi 与 Claude Code 每步各起一次,不受影响。
49
+ - **dsh 自己的命令**(`/export`、`/feedback`、`/permission`)在托管引擎下照常可用。托管引擎的 preset 是 `standard` 的副本,去掉了被外部引擎接管的那几行(dsh 的 `/plan`、`/compact`、goal 工具与 `/goal`、以及技能相关行)。
50
+
51
+ ## 版本兼容
52
+
53
+ **一个发布版本同时服务两代 harness**:0.1.5 线(`>=0.1.5-rc.1 <0.1.6-0`)与 0.1.7 线(`>=0.1.7-rc.1 <0.1.8-0`)——它在加载期探测当前是哪一代、走对应分支。这两个并集范围就是它在 `peerDependencies` 里声明的范围;超出范围的 harness 会在启动或会话恢复时**响亮地失败**。
54
+
55
+ 版本读作 `<harness 线>-rcN`,其中 **`rcN` 是本插件对那条线的第 N 次发布号**,不是 harness 自己的 `rc` 号。在被覆盖的线里,新的 harness `rc` **不需要**插件跟版——除非某个 API 面动了;[docs/compatibility.md](docs/compatibility.md) §1 列出了这些面与"要不要改代码"的判定命令。
56
+
57
+ | 插件 | 目标 harness |
58
+ |---|---|
59
+ | `0.1.7-rc1` … `0.1.7-rc5` | `0.1.7-rc.1`、`0.1.7-rc.2` |
60
+ | `0.1.5-rc3` … `0.1.5-rc5` | `0.1.5-rc.2` |
61
+ | `0.1.5-rc1` / `0.1.5-rc2` | `0.1.5-rc.1` |
62
+ | `1.0.0-rc8` … `1.0.0-rc15` | `0.1.2-rc.1` |
63
+ | `1.0.0-rc7` 及更早 | `0.1.1-rc.2` |
64
+
65
+ ## 已知限制
66
+
67
+ - **它替掉了 harness 的 agent factory。** 唯一那个门面服务所有会话,所以插件对此的承诺是:它读不出引擎的会话——包括跟托管引擎毫无关系的会话——一律**降级到 `in-process`**,而不是打不开。见 [docs/per-session-engine.md](docs/per-session-engine.md) §6。
68
+ - **引擎记录是侧车文件** `$DSH_HOME/.loop-engine/engines.json`,不在会话日志里:换机器或换 `DSH_HOME` 就丢,会话回退到自己的 preset。见 §5.5。
69
+ - **涉及 `in-process` 的换引擎会重新载入页面**——harness loop 既不交出活会话,也不接受不是它建的会话。见 §5.2/§5.4。
70
+ - **已经跑过一轮的会话**仍可换引擎,但只能在空闲时,且会重建那条会话的 agent。见 §5。
71
+ - **带旧 preset id `loop-engine` 的老会话**在重建一次之前显示为"旧版托管引擎"。见 §7。
72
+ - **同引擎的多条会话共享该 CLI 自己的认证目录**,插件不加锁。见 §6。
73
+ - **切回 `in-process` 之后**,模型菜单里那个共享的 `external` 分组仍在(模型目录不按会话裁剪)。
74
+
75
+ ## 细节都在哪
76
+
77
+ - [docs/per-session-engine.md](docs/per-session-engine.md) —— 按会话选引擎的完整用户可见行为(上面引的 § 就是它)。
78
+ - [docs/architecture.md](docs/architecture.md) —— 插件核心:唯一 factory 槽位、受管理块、路由、provider 路由。
79
+ - [docs/compatibility.md](docs/compatibility.md) —— **harness 升级时先看这篇**:所有依赖代际的代码点与"加下一代"的清单。
80
+ - [docs/driver-core.md](docs/driver-core.md) —— 四个引擎共享的驱动层。
81
+ - [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) —— 逐引擎内部实现。
82
+ - [docs/source-checkout.md](docs/source-checkout.md) —— 源码启动 harness 需要的 `file:` shim。
83
+ - [docs/optimization-backlog.md](docs/optimization-backlog.md) —— 已知问题与优化清单。
84
+ - [docs/proposals/](docs/proposals/) —— 提交给主仓的提案。
85
+
86
+ ## License
87
+
88
+ MIT —— 全文见 [LICENSE](LICENSE)。上游作者的版权声明与本 fork 的声明并列保留在其中;
89
+ 本 fork 做了什么、刻意没动什么,见 [NOTICE](NOTICE)。
package/SECURITY.md ADDED
@@ -0,0 +1,39 @@
1
+ # Security policy
2
+
3
+ ## What this plugin touches
4
+
5
+ - **It does not own credentials.** Every hosted engine reads its own credentials
6
+ from its own directory (`~/.grok/auth.json`, `~/.kimi-code/…`, `~/.minimax/…`,
7
+ the Claude/Codex/Pi installs' own files). The plugin only checks whether an auth
8
+ path EXISTS, to show a signed-in/not-signed-in hint in the settings page. It
9
+ never opens one for reading its contents.
10
+ - **It spawns external processes.** Every engine's CLI runs as a child, and every
11
+ child is spawned through the harness's subprocess seam (`ctx.subprocess`), which
12
+ is the privilege boundary. ACP engines additionally declare client-side
13
+ capabilities: an engine may ask the plugin to read a file or run a command. Both
14
+ go through the harness's own services (`ctx.fs`, `ctx.shell`), so the engine's
15
+ request is subject to the same policy as the harness's own tools — and the
16
+ terminal bridge REFUSES rather than falling back to an unconfined spawn when no
17
+ shell service is present.
18
+ - **It writes to one place in your profile**: the managed block in the profile's
19
+ `cordis.patch.yml`, plus the agent presets it authors. Both are documented in the
20
+ README's install notes, and the block is what uninstall must remove.
21
+
22
+ ## Reporting
23
+
24
+ Open a private security advisory on the repository, or email the maintainer listed
25
+ in `package.json`'s `author` field. Please do not open a public issue for a
26
+ credential-handling or sandbox-bypass problem.
27
+
28
+ Include: what you expected, what happened, the profile composition (redact
29
+ credentials), and the engine involved. A reproduction that does not need your own
30
+ account is worth much more than one that does.
31
+
32
+ ## What is NOT a vulnerability
33
+
34
+ - An engine's own tool call being denied by the harness sandbox. That is the
35
+ sandbox working; the plugin's job is to route the request INTO it, not around it.
36
+ - A hosted engine reporting that it has no subscription or quota. The plugin
37
+ reports the engine's own words rather than hiding them.
38
+ - The plugin failing to start an engine whose CLI is not installed. The engine is
39
+ an external dependency by design; see the README's Requirements table.
@@ -0,0 +1,3 @@
1
+ - insert:
2
+ - id: loop-engine
3
+ name: 'dsh-loop-engine-allinone'