dsh-loop-engine-allinone 0.7.3 → 0.7.5
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 +73 -2
- package/README.md +65 -27
- package/README.zh.md +32 -8
- package/lib/index.js +47 -11
- package/lib/types/index.d.ts +38 -2
- package/package.json +161 -152
- package/lib/types/engine-kimi/acp/client.d.ts +0 -123
- package/lib/types/engine-kimi/acp/mapping.d.ts +0 -73
- package/lib/types/engine-kimi/acp/types.d.ts +0 -143
package/CHANGELOG.md
CHANGED
|
@@ -8,14 +8,85 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
8
8
|
|
|
9
9
|
Nothing yet.
|
|
10
10
|
|
|
11
|
+
## [0.7.5]
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Coverage is a ratchet now, and the ratchet is at 100%.** `scripts/coverage-gate.mjs`
|
|
16
|
+
replaces `vitest.config.ts`'s `thresholds.perFile`, which had never passed on this
|
|
17
|
+
branch: files the change touches must be at 100% per metric, every other file may not
|
|
18
|
+
fall below `.coverage-baseline.json`. The gate reads the istanbul `json` report, diffs
|
|
19
|
+
against the base commit, and refuses a lowered floor in the same change that needs it
|
|
20
|
+
(the baseline is regenerated deliberately, in its own commit, with a reason).
|
|
21
|
+
- The 38 files the old threshold flagged are all at per-file 100% now (1,613 → **1,817
|
|
22
|
+
tests**, 96 files); `.coverage-baseline.json` was rewritten to 119 × 100%, so "do not
|
|
23
|
+
regress" now means the same thing as "must be full".
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **A profile install no longer writes its managed block into `web`.** With
|
|
28
|
+
`config.profile` omitted, `resolvePatchPath()` defaulted to `web`; a market install into
|
|
29
|
+
the Desktop app's `desktop` profile therefore disabled `agent-loop` in a profile that
|
|
30
|
+
had no plugin, while `desktop` kept the base loop in the agent-factory slot and every
|
|
31
|
+
per-session engine switch answered `router-unmounted` ("the loop engine router is not
|
|
32
|
+
ready"). The profile is now resolved from the launcher's `profileContext`, then from the
|
|
33
|
+
directory the package was installed into, and only then from `web`. An explicit
|
|
34
|
+
`profile:` entry still wins (needed for a `link:`/source checkout).
|
|
35
|
+
- **Two preset-authoring tests could flake on a loaded runner.** They polled for one second while the plugin's own roster wait is bounded at two; a docs-only push (run `39118609901`) failed both. The helper now polls for the full eight-second budget, which is what the assertion means. (Tests only.)
|
|
36
|
+
- **Coverage no longer depends on the host's home directory.** `model-registry.ts` sat at
|
|
37
|
+
93.94% on a clean CI runner while reading 100% locally, because the local machine has a
|
|
38
|
+
real `~/.kimi-code/config.toml` and the tests silently relied on it. The spec now points
|
|
39
|
+
`KIMI_CODE_HOME` at a fixture for the discovered arm and at an empty directory for the
|
|
40
|
+
"not installed" arm, so both run everywhere. (Tests only; runtime behaviour unchanged.)
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- Coverage-only source edits are comments at genuinely unreachable arms (`/* v8 ignore
|
|
45
|
+
start|stop */` plus a reason: POSIX-only ternaries, registry-constant branches, the
|
|
46
|
+
production-layout early return). Runtime behaviour is unchanged.
|
|
47
|
+
|
|
48
|
+
## [0.7.4]
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- **`0.7.3` could not be installed on DeepSeek Harness `0.2.1`.** `dsh` refuses a
|
|
53
|
+
plugin whose declared peers the running version does not satisfy, and two things
|
|
54
|
+
broke at once. The union range ended at `<0.2.1-0`, so every `0.2.1-rc.N` host fell
|
|
55
|
+
outside it; and `@deepseek-ai/dsh-invariants` — declared as a hard peer — was never
|
|
56
|
+
published for that line and is not part of the `0.2.1` runtime at all. Both are
|
|
57
|
+
fixed: the last segment is now `>=0.2.0-rc.1 <0.2.2-0` (one range covers `0.2.0` and
|
|
58
|
+
`0.2.1`, which kept the same API shape), and the invariants peer is marked
|
|
59
|
+
`optional`, which is what it always was in practice — the `./invariant` companion
|
|
60
|
+
imports it for types only and the built bundle contains no runtime import of it.
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
|
|
64
|
+
- **The `0.2.1` line is a supported generation**, verified end to end: an isolated
|
|
65
|
+
`.compat/021/` dependency set plus `vitest.config.compat021.ts` run the same 1,613
|
|
66
|
+
specs, `tsconfig.compat021.json` typechecks the sources against `0.2.1`'s published
|
|
67
|
+
declarations, and a real `dsh web` on `0.2.1-rc.1` installs the plugin, writes its
|
|
68
|
+
managed block once (byte-identical on reboot), publishes all ten engine presets,
|
|
69
|
+
and serves the client bundle.
|
|
70
|
+
- `npm run test:compat` and `npm run compat:install` cover all four generations, and
|
|
71
|
+
`npm run typecheck:compat` is the `0.2.1`-against-isolated-declarations check.
|
|
72
|
+
|
|
73
|
+
### Changed
|
|
74
|
+
|
|
75
|
+
- `devDependencies` moved to the `0.2.1` line; `schemastery` to `3.18.5`,
|
|
76
|
+
`cordis` to `4.0.5`.
|
|
77
|
+
- The test suite mounts the JSONL durability backend through the new
|
|
78
|
+
`tests/helpers/jsonl-persistence.ts`. `0.2.1` replaced that package's default
|
|
79
|
+
export with named `{ name, apply }` exports, so the direct default import the specs
|
|
80
|
+
used resolved to `undefined` and cordis rejected the mount with
|
|
81
|
+
`invalid plugin, expect function or object with an "apply" method`.
|
|
82
|
+
|
|
11
83
|
## [0.7.3]
|
|
12
84
|
|
|
13
85
|
### Fixed
|
|
14
86
|
|
|
15
87
|
- **ZCode's path probe only worked on the author's machine.** The resolver and the
|
|
16
88
|
probe script both hardcoded `D:\Programs\ZCode\...` (and the probe also
|
|
17
|
-
`D:\Programs
|
|
18
|
-
pm-global`), so on any other host the "well-known location" check
|
|
89
|
+
`D:\Programs\npm-global`), so on any other host the "well-known location" check
|
|
19
90
|
silently never matched and a user with ZCode installed somewhere normal was told it
|
|
20
91
|
was not installed. Both now derive candidates from the environment:
|
|
21
92
|
`%ZCODE_HOME%` → `%LOCALAPPDATA%\Programs\ZCode` → `%ProgramFiles%\ZCode`, and
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**English** · [简体中文](README.zh.md)
|
|
4
4
|
|
|
5
5
|
[](LICENSE)
|
|
6
|
-
[](#version-compatibility)
|
|
6
|
+
[](#version-compatibility)
|
|
7
7
|
|
|
8
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
9
|
|
|
@@ -57,25 +57,32 @@ dsh plugin --profile web add ./dsh-loop-engine-allinone
|
|
|
57
57
|
|
|
58
58
|
`web` is the profile the harness's own CLI documents (`dsh web` is short for
|
|
59
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.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
60
|
+
`desktop`, a CI deployment may boot `headless`, and you may have made your own.
|
|
61
|
+
|
|
62
|
+
**Installing with `dsh plugin --profile desktop add dsh-loop-engine-allinone` is
|
|
63
|
+
enough**: the plugin resolves the profile it is actually serving — the launcher's
|
|
64
|
+
`profileContext` when the generation provides it, otherwise the profile directory
|
|
65
|
+
it was installed into (the nearest ancestor with a `dsh.profile` manifest). Only a
|
|
66
|
+
`link:`/source checkout has neither, and there the composition entry still wins:
|
|
67
|
+
|
|
68
|
+
```yaml
|
|
69
|
+
- id: loop-engine
|
|
70
|
+
config:
|
|
71
|
+
profile: desktop # only needed for a linked checkout / global install
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Before 0.7.5 the field defaulted to `web` and nothing else was consulted. A market
|
|
75
|
+
install into `desktop` then wrote the managed block into `profiles/web/`, the
|
|
76
|
+
`desktop` base `agent-loop` kept the agent-factory slot, and every per-session
|
|
77
|
+
engine switch answered `router-unmounted` ("the loop engine router is not ready")
|
|
78
|
+
— with nothing logged. The same omission could disable `agent-loop` in a `web`
|
|
79
|
+
profile that had no plugin at all. 0.7.5 fixes both ends: it finds the right
|
|
80
|
+
profile, and it warns when the resolved profile has no `package.json` beside it.
|
|
81
|
+
|
|
82
|
+
If 0.7.4 already wrote the managed block into `web` while you did not install the
|
|
83
|
+
plugin there, delete that block (from `# -- dsh-loop-engine managed block --` through
|
|
84
|
+
`# -- /dsh-loop-engine managed block --`, plus the preset block) before booting
|
|
85
|
+
`web`; otherwise that profile has no agent factory.
|
|
79
86
|
|
|
80
87
|
### Installation notes
|
|
81
88
|
|
|
@@ -85,9 +92,35 @@ shape, naming the field to set.
|
|
|
85
92
|
delete the managed `loop-engine` block** from that profile's `cordis.patch.yml`. The
|
|
86
93
|
block outlives the plugin, and while it is present the profile has no agent factory,
|
|
87
94
|
so no session can be created.
|
|
88
|
-
- **pnpm 10
|
|
89
|
-
|
|
90
|
-
`
|
|
95
|
+
- **One-time script approval.** pnpm 10+ refuses to run dependency install scripts
|
|
96
|
+
until the installing project approves them, so a fresh `dsh plugin add` can stop at
|
|
97
|
+
`ERR_PNPM_IGNORED_BUILDS` naming `@google/genai` and `protobufjs`. **This is not a
|
|
98
|
+
missing dependency and there is nothing to install by hand** — the whole tree,
|
|
99
|
+
including the bundled Pi engine, is already on disk; pnpm is only asking whether to
|
|
100
|
+
execute two scripts those packages ship:
|
|
101
|
+
|
|
102
|
+
| Package | Script | What it actually does |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| `@google/genai` | `preinstall` | `echo 'preinstall: no-op'` |
|
|
105
|
+
| `protobufjs` | `postinstall` | reads its own `package.json`, prints a version-scheme warning |
|
|
106
|
+
|
|
107
|
+
Both are no-ops, so **either answer is safe**: approving runs them, and
|
|
108
|
+
`allowBuilds: false` skips them. Verified for the second case — with both set to
|
|
109
|
+
`false`, `@google/genai` loads (145 exports), `protobufjs` loads, and Pi's
|
|
110
|
+
`dist/cli.js` is present. They arrive only through the bundled Pi engine;
|
|
111
|
+
Claude Code and Codex ship no install scripts, so this prompt never appears
|
|
112
|
+
because of them.
|
|
113
|
+
|
|
114
|
+
The question is asked **once per profile** — the answer is written into that
|
|
115
|
+
profile's `pnpm-workspace.yaml` and later installs and upgrades do not ask again.
|
|
116
|
+
To pre-answer it before the first install, add to the profile's
|
|
117
|
+
`pnpm-workspace.yaml`:
|
|
118
|
+
|
|
119
|
+
```yaml
|
|
120
|
+
allowBuilds:
|
|
121
|
+
'@google/genai': false
|
|
122
|
+
protobufjs: false
|
|
123
|
+
```
|
|
91
124
|
- **Harness from source**: bridge the profile's harness peers with `file:` shims, or
|
|
92
125
|
session resume fails with `agent-presets: refusing to compose an unscoped context`.
|
|
93
126
|
Steps in [docs/source-checkout.md](docs/source-checkout.md).
|
|
@@ -193,11 +226,16 @@ Both tables enforce compile-time exhaustiveness checks — incomplete engine reg
|
|
|
193
226
|
|
|
194
227
|
A single release seamlessly supports multiple DeepSeek Harness generations via runtime detection:
|
|
195
228
|
|
|
196
|
-
| Plugin
|
|
229
|
+
| Plugin release | Supported DeepSeek Harness |
|
|
197
230
|
|---|---|
|
|
198
|
-
| `0.
|
|
199
|
-
| `0.
|
|
200
|
-
|
|
231
|
+
| `0.7.4`+ | `0.2.0-rc.1` … `0.2.1-rc.1` |
|
|
232
|
+
| `0.7.0` – `0.7.3` | `0.1.5-rc.1` … `0.2.0-rc.2` |
|
|
233
|
+
|
|
234
|
+
The union range is `>=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0`.
|
|
235
|
+
`0.2.0` and `0.2.1` share the last segment because the harness kept the same API shape
|
|
236
|
+
across them, so one range covers both. `dsh`'s compatibility check reads these peers
|
|
237
|
+
and refuses to load a plugin that misses one, which is what made `0.7.3` uninstallable
|
|
238
|
+
on `0.2.1`.
|
|
201
239
|
|
|
202
240
|
See [docs/compatibility.md](docs/compatibility.md) for harness upgrade checklists and API surface diffs.
|
|
203
241
|
|
package/README.zh.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[English](README.md) · **简体中文**
|
|
4
4
|
|
|
5
5
|
[](LICENSE)
|
|
6
|
-
[](#版本兼容性)
|
|
6
|
+
[](#版本兼容性)
|
|
7
7
|
|
|
8
8
|
**dsh-loop-engine-allinone** 是专为 [DeepSeek Harness](https://github.com/deepseek-ai)(`dsh`)打造的 Agent 循环引擎全功能切换插件。支持**按会话独立切换** 10 家主流外部引擎与 Harness 原生 `in-process` 循环。
|
|
9
9
|
|
|
@@ -79,9 +79,30 @@ dsh plugin --profile web add ./dsh-loop-engine-allinone
|
|
|
79
79
|
- **卸载**:`dsh plugin --profile web remove dsh-loop-engine-allinone`,**然后手动删掉**
|
|
80
80
|
该 profile `cordis.patch.yml` 里的 `loop-engine` 受管块。块会比插件活得久,而它还在时
|
|
81
81
|
profile 里没有任何 agent factory,会话一条也建不出来。
|
|
82
|
-
-
|
|
83
|
-
`@google/genai
|
|
84
|
-
|
|
82
|
+
- **一次性脚本授权**。pnpm 10+ 默认不执行依赖包自带的安装脚本,要由安装方批准,
|
|
83
|
+
所以首次 `dsh plugin add` 可能停在 `ERR_PNPM_IGNORED_BUILDS`,点名 `@google/genai` 与
|
|
84
|
+
`protobufjs`。**这不是缺依赖,也没有任何东西要你手动装**——整棵树(含捆绑的 Pi 引擎)
|
|
85
|
+
已经落盘,pnpm 只是在问要不要执行这两个包自带的脚本:
|
|
86
|
+
|
|
87
|
+
| 包 | 脚本 | 实际做的事 |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `@google/genai` | `preinstall` | `echo 'preinstall: no-op'` |
|
|
90
|
+
| `protobufjs` | `postinstall` | 读自己的 `package.json`,打印一行版本方案警告 |
|
|
91
|
+
|
|
92
|
+
两个都是空操作,**所以批准或拒绝都安全**:批准就执行,`allowBuilds: false` 就跳过。
|
|
93
|
+
拒绝这条路径已实测——两者设为 `false` 后,`@google/genai` 正常加载(145 个导出)、
|
|
94
|
+
`protobufjs` 正常加载、Pi 的 `dist/cli.js` 也在。这两个包**只由捆绑的 Pi 引擎带进来**;
|
|
95
|
+
Claude Code 与 Codex 不带安装脚本,永远不会因为它们弹这个窗。
|
|
96
|
+
|
|
97
|
+
**每个 profile 只问一次**——答案写进该 profile 的 `pnpm-workspace.yaml`,
|
|
98
|
+
之后的安装与升级都不再问。想在首次安装前就预先回答,往该 profile 的
|
|
99
|
+
`pnpm-workspace.yaml` 加:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
allowBuilds:
|
|
103
|
+
'@google/genai': false
|
|
104
|
+
protobufjs: false
|
|
105
|
+
```
|
|
85
106
|
- **用源码启动 harness** 时,要用 `file:` shim 把 profile 的 harness peer 包桥接到 checkout 源码,
|
|
86
107
|
否则恢复会话会报 `agent-presets: refusing to compose an unscoped context`。
|
|
87
108
|
步骤见 [docs/source-checkout.md](docs/source-checkout.md)。
|
|
@@ -181,11 +202,14 @@ dsh plugin --profile web add ./dsh-loop-engine-allinone
|
|
|
181
202
|
|
|
182
203
|
单一版本通过动态探测,全面兼容 DeepSeek Harness 多代版本:
|
|
183
204
|
|
|
184
|
-
|
|
|
205
|
+
| 插件版本 | 兼容的 DeepSeek Harness |
|
|
185
206
|
|---|---|
|
|
186
|
-
| `0.
|
|
187
|
-
| `0.
|
|
188
|
-
|
|
207
|
+
| `0.7.4` 起 | `0.2.0-rc.1` … `0.2.1-rc.1` |
|
|
208
|
+
| `0.7.0` – `0.7.3` | `0.1.5-rc.1` … `0.2.0-rc.2` |
|
|
209
|
+
|
|
210
|
+
并集范围是 `>=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0`。
|
|
211
|
+
`0.2.0` 与 `0.2.1` 共用末段,因为 harness 在这两代之间没有改 API 形状,一段范围就够了。
|
|
212
|
+
`dsh` 的兼容性判定读的就是这些 peer,差一条就拒绝加载——这正是 `0.7.3` 在 `0.2.1` 上装不上的原因。
|
|
189
213
|
|
|
190
214
|
版本号 `<harness 线>-rcN` 中的 `rcN` 为本插件对应分支的迭代发布号。详见 [docs/compatibility.md](docs/compatibility.md)。
|
|
191
215
|
|
package/lib/index.js
CHANGED
|
@@ -92,7 +92,8 @@ var __callDispose = (stack, error, hasError) => {
|
|
|
92
92
|
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "node:fs";
|
|
93
93
|
import { mkdir as mkdir2, readFile as readFile6, rename as rename2, writeFile as writeFile2 } from "node:fs/promises";
|
|
94
94
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
95
|
-
import { dirname as dirname7, join as join22 } from "node:path";
|
|
95
|
+
import { basename, dirname as dirname7, join as join22 } from "node:path";
|
|
96
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
96
97
|
import z12 from "@deepseek-ai/schemastery";
|
|
97
98
|
import { resolveDshHome as resolveDshHome2 } from "@deepseek-ai/dsh-home-paths";
|
|
98
99
|
|
|
@@ -8548,8 +8549,10 @@ var AgyAgent = class extends CliHostedAgent {
|
|
|
8548
8549
|
stdin: agyStdinPrompt(prompt),
|
|
8549
8550
|
map: (document) => mapAgyDocument(document, accept, run)
|
|
8550
8551
|
},
|
|
8552
|
+
/* v8 ignore start -- the mapper pushes frames straight to `accept` rather than returning them, so this collector is never called; the run signature requires one */
|
|
8551
8553
|
() => {
|
|
8552
8554
|
}
|
|
8555
|
+
/* v8 ignore stop */
|
|
8553
8556
|
);
|
|
8554
8557
|
if (result.parsed === 0) {
|
|
8555
8558
|
accept({
|
|
@@ -8887,7 +8890,9 @@ function mapStreamJsonDocument(document, accept, run) {
|
|
|
8887
8890
|
const subtype = typeof frame2.subtype === "string" ? frame2.subtype : void 0;
|
|
8888
8891
|
const isError = frame2.is_error === true || subtype !== void 0 && subtype !== "success";
|
|
8889
8892
|
if (isError) {
|
|
8890
|
-
|
|
8893
|
+
let message = `the engine ended the run with "${subtype ?? "an error"}"`;
|
|
8894
|
+
if (typeof frame2.result === "string" && frame2.result !== "") message = frame2.result;
|
|
8895
|
+
else if (typeof frame2.error === "string" && frame2.error !== "") message = frame2.error;
|
|
8891
8896
|
run.reportedError = message;
|
|
8892
8897
|
accept({ kind: "error", message });
|
|
8893
8898
|
}
|
|
@@ -8984,8 +8989,10 @@ var QoderclicnAgent = class extends CliHostedAgent {
|
|
|
8984
8989
|
};
|
|
8985
8990
|
const result = await runNdjson(
|
|
8986
8991
|
{ transport, map: (document) => mapDocument(document, accept, run) },
|
|
8992
|
+
/* v8 ignore start -- the mapper pushes frames straight to `accept` rather than returning them, so this collector is never called; the run signature requires one */
|
|
8987
8993
|
() => {
|
|
8988
8994
|
}
|
|
8995
|
+
/* v8 ignore stop */
|
|
8989
8996
|
);
|
|
8990
8997
|
if (result.parsed === 0) {
|
|
8991
8998
|
this.sink.accept({
|
|
@@ -9172,9 +9179,10 @@ function resolveOnPath(name2, env = process.env) {
|
|
|
9172
9179
|
return void 0;
|
|
9173
9180
|
}
|
|
9174
9181
|
function npmPackageEntry(prefix, pkg, entry) {
|
|
9182
|
+
const slash = pkg.indexOf("/");
|
|
9175
9183
|
const scoped = pkg.startsWith("@");
|
|
9176
|
-
const scope = scoped ? pkg.slice(0,
|
|
9177
|
-
const name2 = scoped ? pkg.slice(
|
|
9184
|
+
const scope = scoped && slash > 0 ? pkg.slice(0, slash) : "";
|
|
9185
|
+
const name2 = scoped ? pkg.slice(slash + 1) : pkg;
|
|
9178
9186
|
if (name2 === "" || scoped && scope === "") return void 0;
|
|
9179
9187
|
const relative = scoped ? join10("node_modules", scope, name2, entry) : join10("node_modules", name2, entry);
|
|
9180
9188
|
for (const candidate of [join10(prefix, relative), join10(prefix, "lib", relative)]) {
|
|
@@ -11394,12 +11402,16 @@ var Config11 = z12.object({
|
|
|
11394
11402
|
// Derived from the registry's own capability declaration rather than restated:
|
|
11395
11403
|
// a permission mode an engine declares is a mode the entry accepts, so the two
|
|
11396
11404
|
// cannot drift.
|
|
11405
|
+
/* v8 ignore start -- the registry row always declares its permission modes, so the empty fallback is a type-level guard */
|
|
11397
11406
|
permissionMode: z12.union((ENGINE_REGISTRY["claude-code"].capabilities.permissionModes ?? []).map((mode) => z12.const(mode))),
|
|
11407
|
+
/* v8 ignore stop */
|
|
11398
11408
|
env: z12.dict(z12.string()),
|
|
11399
11409
|
model: z12.string(),
|
|
11400
11410
|
disposeGraceMs: z12.number(),
|
|
11401
11411
|
maxTurns: z12.number(),
|
|
11412
|
+
/* v8 ignore start -- the registry row always declares them, so the empty fallback is a type-level guard */
|
|
11402
11413
|
sandboxMode: z12.union((ENGINE_REGISTRY.codex.capabilities.permissionModes ?? []).map((mode) => z12.const(mode))),
|
|
11414
|
+
/* v8 ignore stop */
|
|
11403
11415
|
approvalPolicy: z12.union(CODEX_APPROVAL_POLICIES.map((policy) => z12.const(policy))),
|
|
11404
11416
|
piProvider: z12.string(),
|
|
11405
11417
|
piThinking: z12.string(),
|
|
@@ -11437,15 +11449,37 @@ var Config11 = z12.object({
|
|
|
11437
11449
|
showEngineBadge: LOOP_ENGINE_SHOW_ENGINE_BADGE_SCHEMA
|
|
11438
11450
|
}
|
|
11439
11451
|
});
|
|
11440
|
-
function resolvePatchPath(config) {
|
|
11452
|
+
function resolvePatchPath(config, fallbackProfile = "web") {
|
|
11441
11453
|
if (config.patchPath !== void 0 && config.patchPath !== "") return config.patchPath;
|
|
11442
11454
|
return join22(
|
|
11443
11455
|
resolveDshHome2(),
|
|
11444
11456
|
"profiles",
|
|
11445
|
-
config.profile ??
|
|
11457
|
+
config.profile ?? fallbackProfile,
|
|
11446
11458
|
config.patchFilename ?? "cordis.patch.yml"
|
|
11447
11459
|
);
|
|
11448
11460
|
}
|
|
11461
|
+
function inferProfileName(entry = fileURLToPath2(import.meta.url)) {
|
|
11462
|
+
let dir = dirname7(entry);
|
|
11463
|
+
for (; ; ) {
|
|
11464
|
+
const manifest = join22(dir, "package.json");
|
|
11465
|
+
if (existsSync8(manifest)) {
|
|
11466
|
+
try {
|
|
11467
|
+
const parsed = JSON.parse(readFileSync5(manifest, "utf8"));
|
|
11468
|
+
if (parsed.dsh?.profile !== void 0) return basename(dir);
|
|
11469
|
+
} catch {
|
|
11470
|
+
}
|
|
11471
|
+
}
|
|
11472
|
+
const parent = dirname7(dir);
|
|
11473
|
+
if (parent === dir) return void 0;
|
|
11474
|
+
dir = parent;
|
|
11475
|
+
}
|
|
11476
|
+
}
|
|
11477
|
+
function resolveProfileName(ctx, config) {
|
|
11478
|
+
if (config.profile !== void 0 && config.profile !== "") return config.profile;
|
|
11479
|
+
const fromContext = ctx.get("profileContext")?.name;
|
|
11480
|
+
if (typeof fromContext === "string" && fromContext !== "") return fromContext;
|
|
11481
|
+
return inferProfileName() ?? "web";
|
|
11482
|
+
}
|
|
11449
11483
|
function resolveSummarizerTarget(config) {
|
|
11450
11484
|
const provider = config.summarizerProvider;
|
|
11451
11485
|
const model = config.summarizerModel;
|
|
@@ -11497,18 +11531,18 @@ function readPatchFileSync(path) {
|
|
|
11497
11531
|
throw error;
|
|
11498
11532
|
}
|
|
11499
11533
|
}
|
|
11500
|
-
function warnIfProfileLooksWrong(ctx,
|
|
11534
|
+
function warnIfProfileLooksWrong(ctx, profileName, patchPath) {
|
|
11501
11535
|
const profileDir = dirname7(patchPath);
|
|
11502
11536
|
if (existsSync8(join22(profileDir, "package.json"))) return;
|
|
11503
|
-
const named = config.profile ?? "web";
|
|
11504
11537
|
ctx.logger.warn(
|
|
11505
|
-
`loop-engine: profile "${
|
|
11538
|
+
`loop-engine: profile "${profileName}" has no package.json beside "${patchPath}". If you boot a different profile, set \`profile: <that-name>\` in this plugin's composition entry - otherwise its managed block is written here, the profile you actually boot never reads it, and no hosted engine will be reachable.`
|
|
11506
11539
|
);
|
|
11507
11540
|
}
|
|
11508
11541
|
function apply(ctx, config) {
|
|
11509
11542
|
const summarizer = resolveSummarizerTarget(config);
|
|
11510
|
-
const
|
|
11511
|
-
|
|
11543
|
+
const profileName = resolveProfileName(ctx, config);
|
|
11544
|
+
const patchPath = resolvePatchPath(config, profileName);
|
|
11545
|
+
warnIfProfileLooksWrong(ctx, profileName, patchPath);
|
|
11512
11546
|
const patchText = readPatchFileSync(patchPath);
|
|
11513
11547
|
const legacyEngine = legacyBlockEngineOf(patchText);
|
|
11514
11548
|
const needsWrite = hasLegacyManagedBlock(patchText) || !hasManagedBlock(patchText);
|
|
@@ -11783,9 +11817,11 @@ function apply(ctx, config) {
|
|
|
11783
11817
|
export {
|
|
11784
11818
|
Config11 as Config,
|
|
11785
11819
|
apply,
|
|
11820
|
+
inferProfileName,
|
|
11786
11821
|
inject,
|
|
11787
11822
|
name,
|
|
11788
11823
|
resolvePatchPath,
|
|
11824
|
+
resolveProfileName,
|
|
11789
11825
|
resolveSummarizerTarget,
|
|
11790
11826
|
syncManagedBlock,
|
|
11791
11827
|
writePatchFile,
|
package/lib/types/index.d.ts
CHANGED
|
@@ -152,8 +152,44 @@ type ConfigInput = Omit<Config, 'engine' | 'showInComposer' | 'showEngineBadge'>
|
|
|
152
152
|
* entry is the engine knobs alone.
|
|
153
153
|
*/
|
|
154
154
|
export declare const Config: z<ConfigInput, Config>;
|
|
155
|
-
/**
|
|
156
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Resolve the managed patch file from configuration, defaulting to the web profile.
|
|
157
|
+
* @param config - composition entry; `patchPath` wins, then `profile` + `patchFilename`.
|
|
158
|
+
* @param fallbackProfile - profile name to use when the entry names none (the
|
|
159
|
+
* running profile, discovered by {@link resolveProfileName}); `web` when unknown.
|
|
160
|
+
* @returns the absolute patch file path.
|
|
161
|
+
*/
|
|
162
|
+
export declare function resolvePatchPath(config: Config, fallbackProfile?: string): string;
|
|
163
|
+
/**
|
|
164
|
+
* Infer the profile a plugin copy was installed into from its own location.
|
|
165
|
+
*
|
|
166
|
+
* A profile is the nearest ancestor directory holding a `package.json` with a
|
|
167
|
+
* `dsh.profile` field. Walking up (rather than assuming
|
|
168
|
+
* `<home>/profiles/<name>/node_modules`) survives pnpm's real path
|
|
169
|
+
* (`node_modules/.pnpm/<pkg>@<ver>/node_modules/<pkg>/lib`) and nested installs,
|
|
170
|
+
* and returns undefined when the plugin runs from a checkout, a global install,
|
|
171
|
+
* or a linked source tree - none of which belongs to a profile.
|
|
172
|
+
* @param entry - module path to start from; the resolved module by default.
|
|
173
|
+
* @returns the profile name, or undefined when the copy is not inside one.
|
|
174
|
+
*/
|
|
175
|
+
export declare function inferProfileName(entry?: string): string | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* The profile this process is actually serving.
|
|
178
|
+
*
|
|
179
|
+
* Precedence: the composition entry's `profile` (an explicit deployment choice),
|
|
180
|
+
* then the harness's `profileContext.name` (0.2.x launchers), then the install
|
|
181
|
+
* location, and only then `web` (the historical default, correct for a global
|
|
182
|
+
* install and for `dsh web` before profiles had names).
|
|
183
|
+
*
|
|
184
|
+
* The install-location step is what makes a market install work without hand
|
|
185
|
+
* editing: installing into `desktop` used to leave `profile` unset, so the
|
|
186
|
+
* managed block went to `web`, the base `agent-loop` kept the factory slot in
|
|
187
|
+
* `desktop`, and every per-session switch answered `router-unmounted`.
|
|
188
|
+
* @param ctx - composing context, read for `profileContext`.
|
|
189
|
+
* @param config - composition entry, read for an explicit `profile`.
|
|
190
|
+
* @returns the profile name whose patch file this plugin owns.
|
|
191
|
+
*/
|
|
192
|
+
export declare function resolveProfileName(ctx: Context, config: Config): string;
|
|
157
193
|
/**
|
|
158
194
|
* Resolve the summarization model the plugin writes into every hosted preset,
|
|
159
195
|
* or `undefined` when the deployment names none.
|
package/package.json
CHANGED
|
@@ -1,152 +1,161 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "dsh-loop-engine-allinone",
|
|
3
|
-
"description": "Web-switchable agent loop engine selection for the DeepSeek Harness - out-of-tree plugin with a data-driven engine registry and a pluggable driver layer. Ten engines: Claude Code / Codex / Pi / Kimi Code / Antigravity / ZCode / Qoder CN / Hermes / Grok Build / MiniMax Code. All-in-one fork of kuun993/dsh-loop-engine.",
|
|
4
|
-
"version": "0.7.
|
|
5
|
-
"publishConfig": {
|
|
6
|
-
"registry": "https://registry.npmjs.org/"
|
|
7
|
-
},
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/yaliklinty/dsh-loop-engine-allinone.git"
|
|
11
|
-
},
|
|
12
|
-
"type": "module",
|
|
13
|
-
"main": "lib/index.js",
|
|
14
|
-
"types": "lib/types/index.d.ts",
|
|
15
|
-
"exports": {
|
|
16
|
-
".": {
|
|
17
|
-
"types": "./lib/types/index.d.ts",
|
|
18
|
-
"default": "./lib/index.js"
|
|
19
|
-
},
|
|
20
|
-
"./invariant": {
|
|
21
|
-
"types": "./lib/types/invariant.d.ts",
|
|
22
|
-
"default": "./lib/invariant.js"
|
|
23
|
-
},
|
|
24
|
-
"./client": {
|
|
25
|
-
"types": "./lib/types/client/index.d.ts",
|
|
26
|
-
"default": "./lib/client.js"
|
|
27
|
-
},
|
|
28
|
-
"./src/*": "./src/*",
|
|
29
|
-
"./package.json": "./package.json"
|
|
30
|
-
},
|
|
31
|
-
"files": [
|
|
32
|
-
"lib/index.js",
|
|
33
|
-
"lib/invariant.js",
|
|
34
|
-
"lib/client.js",
|
|
35
|
-
"lib/types/**/*.d.ts",
|
|
36
|
-
"cordis.patch.yml",
|
|
37
|
-
"README.md",
|
|
38
|
-
"CHANGELOG.md",
|
|
39
|
-
"CONTRIBUTING.md",
|
|
40
|
-
"SECURITY.md",
|
|
41
|
-
"LICENSE",
|
|
42
|
-
"NOTICE"
|
|
43
|
-
],
|
|
44
|
-
"license": "MIT",
|
|
45
|
-
"engines": {
|
|
46
|
-
"node": "^22.19.0 || >=24.0.0"
|
|
47
|
-
},
|
|
48
|
-
"packageManager": "pnpm@11.23.0",
|
|
49
|
-
"scripts": {
|
|
50
|
-
"build": "node build.mjs",
|
|
51
|
-
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
52
|
-
"test": "vitest run",
|
|
53
|
-
"test:coverage": "vitest run --coverage",
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"@deepseek-ai/dsh-
|
|
66
|
-
"@deepseek-ai/dsh-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"@deepseek-ai/dsh-client-
|
|
73
|
-
"@deepseek-ai/dsh-
|
|
74
|
-
"@deepseek-ai/dsh-settings/
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
"@
|
|
82
|
-
"@
|
|
83
|
-
"@
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
"@deepseek-ai/
|
|
89
|
-
"@deepseek-ai/dsh-
|
|
90
|
-
"@deepseek-ai/dsh-
|
|
91
|
-
"@deepseek-ai/dsh-
|
|
92
|
-
"@deepseek-ai/dsh-
|
|
93
|
-
"@deepseek-ai/dsh-
|
|
94
|
-
"@deepseek-ai/dsh-
|
|
95
|
-
"@deepseek-ai/dsh-
|
|
96
|
-
"@deepseek-ai/dsh-
|
|
97
|
-
"@deepseek-ai/dsh-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
"@deepseek-ai/dsh-
|
|
103
|
-
"@deepseek-ai/dsh-
|
|
104
|
-
"@deepseek-ai/dsh-
|
|
105
|
-
"@deepseek-ai/dsh-
|
|
106
|
-
"@deepseek-ai/dsh-
|
|
107
|
-
"@deepseek-ai/dsh-
|
|
108
|
-
"@deepseek-ai/dsh-
|
|
109
|
-
"@deepseek-ai/dsh-
|
|
110
|
-
"@deepseek-ai/dsh-
|
|
111
|
-
"@deepseek-ai/dsh-
|
|
112
|
-
"@deepseek-ai/dsh-
|
|
113
|
-
"@deepseek-ai/dsh-client-
|
|
114
|
-
"@deepseek-ai/dsh-client-
|
|
115
|
-
"@deepseek-ai/dsh-client-ui-
|
|
116
|
-
"@deepseek-ai/dsh-client-ui-
|
|
117
|
-
"@deepseek-ai/dsh-client-ui-
|
|
118
|
-
"@deepseek-ai/dsh-
|
|
119
|
-
"@deepseek-ai/dsh-
|
|
120
|
-
"@deepseek-ai/dsh-
|
|
121
|
-
"@deepseek-ai/dsh-
|
|
122
|
-
"@deepseek-ai/dsh-
|
|
123
|
-
"@
|
|
124
|
-
"@
|
|
125
|
-
"@
|
|
126
|
-
"
|
|
127
|
-
"
|
|
128
|
-
"
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
"
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
"
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
"
|
|
144
|
-
"
|
|
145
|
-
"
|
|
146
|
-
"
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
|
|
152
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-loop-engine-allinone",
|
|
3
|
+
"description": "Web-switchable agent loop engine selection for the DeepSeek Harness - out-of-tree plugin with a data-driven engine registry and a pluggable driver layer. Ten engines: Claude Code / Codex / Pi / Kimi Code / Antigravity / ZCode / Qoder CN / Hermes / Grok Build / MiniMax Code. All-in-one fork of kuun993/dsh-loop-engine.",
|
|
4
|
+
"version": "0.7.5",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"registry": "https://registry.npmjs.org/"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/yaliklinty/dsh-loop-engine-allinone.git"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "lib/index.js",
|
|
14
|
+
"types": "lib/types/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./lib/types/index.d.ts",
|
|
18
|
+
"default": "./lib/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./invariant": {
|
|
21
|
+
"types": "./lib/types/invariant.d.ts",
|
|
22
|
+
"default": "./lib/invariant.js"
|
|
23
|
+
},
|
|
24
|
+
"./client": {
|
|
25
|
+
"types": "./lib/types/client/index.d.ts",
|
|
26
|
+
"default": "./lib/client.js"
|
|
27
|
+
},
|
|
28
|
+
"./src/*": "./src/*",
|
|
29
|
+
"./package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"lib/index.js",
|
|
33
|
+
"lib/invariant.js",
|
|
34
|
+
"lib/client.js",
|
|
35
|
+
"lib/types/**/*.d.ts",
|
|
36
|
+
"cordis.patch.yml",
|
|
37
|
+
"README.md",
|
|
38
|
+
"CHANGELOG.md",
|
|
39
|
+
"CONTRIBUTING.md",
|
|
40
|
+
"SECURITY.md",
|
|
41
|
+
"LICENSE",
|
|
42
|
+
"NOTICE"
|
|
43
|
+
],
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
47
|
+
},
|
|
48
|
+
"packageManager": "pnpm@11.23.0",
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "node build.mjs",
|
|
51
|
+
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
52
|
+
"test": "vitest run",
|
|
53
|
+
"test:coverage": "vitest run --coverage && node scripts/coverage-gate.mjs",
|
|
54
|
+
"coverage:baseline": "node scripts/coverage-gate.mjs --update",
|
|
55
|
+
"compat:install": "pnpm -C .compat/015 install --frozen-lockfile && pnpm -C .compat/017 install --frozen-lockfile && pnpm -C .compat/020 install --frozen-lockfile && pnpm -C .compat/021 install --frozen-lockfile",
|
|
56
|
+
"test:compat": "vitest run --config vitest.config.compat015.ts && vitest run --config vitest.config.compat017.ts && vitest run --config vitest.config.compat020.ts && vitest run --config vitest.config.compat021.ts",
|
|
57
|
+
"typecheck:compat": "tsc -p tsconfig.compat021.json"
|
|
58
|
+
},
|
|
59
|
+
"dsh": {
|
|
60
|
+
"bundle": {
|
|
61
|
+
"patch": "./cordis.patch.yml"
|
|
62
|
+
},
|
|
63
|
+
"client": {
|
|
64
|
+
"inject": [
|
|
65
|
+
"@deepseek-ai/dsh-client-locale",
|
|
66
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
67
|
+
"@deepseek-ai/dsh-api-remotes",
|
|
68
|
+
"@deepseek-ai/dsh-api-session-controller"
|
|
69
|
+
],
|
|
70
|
+
"platform": "web",
|
|
71
|
+
"external": [
|
|
72
|
+
"@deepseek-ai/dsh-client-locale/client",
|
|
73
|
+
"@deepseek-ai/dsh-client-store",
|
|
74
|
+
"@deepseek-ai/dsh-client-ui-settings/client",
|
|
75
|
+
"@deepseek-ai/dsh-api-remotes/client",
|
|
76
|
+
"@deepseek-ai/dsh-settings/types"
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"dependencies": {
|
|
81
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.220",
|
|
82
|
+
"@anthropic-ai/sdk": "0.93.0",
|
|
83
|
+
"@deepseek-ai/schemastery": "3.18.4",
|
|
84
|
+
"@earendil-works/pi-coding-agent": "0.84.3",
|
|
85
|
+
"@openai/codex": "0.149.1"
|
|
86
|
+
},
|
|
87
|
+
"peerDependencies": {
|
|
88
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
89
|
+
"@deepseek-ai/dsh-agent": ">=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0",
|
|
90
|
+
"@deepseek-ai/dsh-agent-loop": ">=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0",
|
|
91
|
+
"@deepseek-ai/dsh-invariants": ">=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0",
|
|
92
|
+
"@deepseek-ai/dsh-llm": ">=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0",
|
|
93
|
+
"@deepseek-ai/dsh-scope": ">=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0",
|
|
94
|
+
"@deepseek-ai/dsh-session": ">=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0",
|
|
95
|
+
"@deepseek-ai/dsh-session-persistence": ">=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0",
|
|
96
|
+
"@deepseek-ai/dsh-settings": ">=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0",
|
|
97
|
+
"@deepseek-ai/dsh-subprocess": ">=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0",
|
|
98
|
+
"@deepseek-ai/dsh-timeout": ">=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0",
|
|
99
|
+
"@deepseek-ai/dsh-typert-protocol": ">=0.1.5-rc.1 <0.1.6-0 || >=0.1.7-rc.1 <0.1.8-0 || >=0.2.0-rc.1 <0.2.2-0"
|
|
100
|
+
},
|
|
101
|
+
"devDependencies": {
|
|
102
|
+
"@deepseek-ai/dsh-agent": "0.2.1-rc.1",
|
|
103
|
+
"@deepseek-ai/dsh-agent-loop": "0.2.1-rc.1",
|
|
104
|
+
"@deepseek-ai/dsh-invariants": "0.2.0-rc.2",
|
|
105
|
+
"@deepseek-ai/dsh-llm": "0.2.1-rc.1",
|
|
106
|
+
"@deepseek-ai/dsh-scope": "0.2.1-rc.1",
|
|
107
|
+
"@deepseek-ai/dsh-session": "0.2.1-rc.1",
|
|
108
|
+
"@deepseek-ai/dsh-session-persistence": "0.2.1-rc.1",
|
|
109
|
+
"@deepseek-ai/dsh-settings": "0.2.1-rc.1",
|
|
110
|
+
"@deepseek-ai/dsh-subprocess": "0.2.1-rc.1",
|
|
111
|
+
"@deepseek-ai/dsh-timeout": "0.2.1-rc.1",
|
|
112
|
+
"@deepseek-ai/dsh-attachment": "0.2.1-rc.1",
|
|
113
|
+
"@deepseek-ai/dsh-client-locale": "0.2.1-rc.1",
|
|
114
|
+
"@deepseek-ai/dsh-client-store": "0.2.1-rc.1",
|
|
115
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.2.1-rc.1",
|
|
116
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.2.1-rc.1",
|
|
117
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.1-rc.1",
|
|
118
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.2.1-rc.1",
|
|
119
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.1-rc.1",
|
|
120
|
+
"@deepseek-ai/dsh-home-paths": "0.2.1-rc.1",
|
|
121
|
+
"@deepseek-ai/dsh-session-persistence-jsonl": "0.2.1-rc.1",
|
|
122
|
+
"@deepseek-ai/dsh-subprocess-local": "0.2.1-rc.1",
|
|
123
|
+
"@deepseek-ai/dsh-system-prompt": "0.2.1-rc.1",
|
|
124
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.1-rc.1",
|
|
125
|
+
"@types/node": "^22.20.0",
|
|
126
|
+
"@types/react": "^19.0.0",
|
|
127
|
+
"@vitest/coverage-v8": "^4.1.8",
|
|
128
|
+
"esbuild": "^0.28.2",
|
|
129
|
+
"tsx": "^4.22.4",
|
|
130
|
+
"typescript": "^6.0.3",
|
|
131
|
+
"vite": "^7.0.0",
|
|
132
|
+
"vite-tsconfig-paths": "^6.1.1",
|
|
133
|
+
"vitest": "^4.1.8",
|
|
134
|
+
"@deepseek-ai/cordis": "4.0.5",
|
|
135
|
+
"@deepseek-ai/schemastery": "3.18.5"
|
|
136
|
+
},
|
|
137
|
+
"bugs": {
|
|
138
|
+
"url": "https://github.com/yaliklinty/dsh-loop-engine-allinone/issues"
|
|
139
|
+
},
|
|
140
|
+
"homepage": "https://github.com/yaliklinty/dsh-loop-engine-allinone#readme",
|
|
141
|
+
"author": "dsh-loop-engine-allinone contributors",
|
|
142
|
+
"keywords": [
|
|
143
|
+
"deepseek-harness",
|
|
144
|
+
"dsh",
|
|
145
|
+
"dsh-plugin",
|
|
146
|
+
"agent-loop",
|
|
147
|
+
"coding-agent",
|
|
148
|
+
"claude-code",
|
|
149
|
+
"codex",
|
|
150
|
+
"kimi",
|
|
151
|
+
"antigravity",
|
|
152
|
+
"grok",
|
|
153
|
+
"minimax",
|
|
154
|
+
"acp"
|
|
155
|
+
],
|
|
156
|
+
"peerDependenciesMeta": {
|
|
157
|
+
"@deepseek-ai/dsh-invariants": {
|
|
158
|
+
"optional": true
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* JSON-RPC client for the `kimi acp` subprocess (Agent Client Protocol over
|
|
3
|
-
* stdio).
|
|
4
|
-
*
|
|
5
|
-
* The driver hands the client a process handle carrying its stdin/stdout/stderr
|
|
6
|
-
* (projected from the dsh subprocess seam). The client frames JSON-RPC 2.0
|
|
7
|
-
* records on a bare `\n` (via a byte decoder, tolerating a trailing `\r`),
|
|
8
|
-
* correlates request responses by `id`, dispatches every `session/update`
|
|
9
|
-
* notification to a buffered event stream, and answers the reverse-RPC
|
|
10
|
-
* `session/request_permission` requests the agent publishes. The child is
|
|
11
|
-
* long-lived (one per factory) and stepped over via `newSession` + `prompt`.
|
|
12
|
-
*
|
|
13
|
-
* @module dsh-loop-engine/engine-kimi/acp/client
|
|
14
|
-
*/
|
|
15
|
-
import type { KimiProcess, KimiSpawnCapability, KimiSpawnSpec } from '../process.ts';
|
|
16
|
-
import { type AcpFrame, type AcpImageContent, type AcpPermissionOption, type AcpPermissionResponse, type AcpUpdate } from './types.ts';
|
|
17
|
-
/** How the client answers one `session/request_permission`. */
|
|
18
|
-
export type AcpPermissionHandler = (request: AcpFrame) => boolean | Promise<boolean>;
|
|
19
|
-
/**
|
|
20
|
-
* The answerable options of one `session/request_permission` frame. The wire is
|
|
21
|
-
* untrusted, so entries without a usable `optionId` are dropped rather than
|
|
22
|
-
* echoed back.
|
|
23
|
-
* @param frame - the reverse-RPC request frame.
|
|
24
|
-
* @returns the options the client may answer with.
|
|
25
|
-
*/
|
|
26
|
-
export declare function permissionOptionsOf(frame: AcpFrame): readonly AcpPermissionOption[];
|
|
27
|
-
/**
|
|
28
|
-
* Encode one approval decision as the ACP `RequestPermissionResponse` the agent
|
|
29
|
-
* correlates against the options it advertised. The agent reads a terminal
|
|
30
|
-
* *option*, never a boolean: an outcome it cannot resolve (or a response that
|
|
31
|
-
* fails to parse at all) is reported to the model as a user rejection, so a
|
|
32
|
-
* decision that no single option expresses becomes `cancelled` — the honest
|
|
33
|
-
* "this client has no answer". Kimi re-uses this RPC for its question and
|
|
34
|
-
* plan-review bridges, which offer one `allow_once` option per choice; picking
|
|
35
|
-
* one of those would answer a question no human was asked, so any ambiguous
|
|
36
|
-
* set (zero or several `allow_once`/`reject_once` candidates) cancels instead.
|
|
37
|
-
* `allow_once` is preferred over `allow_always` because the decision is re-read
|
|
38
|
-
* from the session knobs on every request: letting the agent cache a session
|
|
39
|
-
* grant would outlive a mid-session switch back to `ask`.
|
|
40
|
-
* @param approved - whether the driver approves the request.
|
|
41
|
-
* @param options - the options the agent advertised for this request.
|
|
42
|
-
* @returns the result payload to send back.
|
|
43
|
-
*/
|
|
44
|
-
export declare function permissionResponse(approved: boolean, options: readonly AcpPermissionOption[]): AcpPermissionResponse;
|
|
45
|
-
/** Callback receiving every non-response event line. */
|
|
46
|
-
export type AcpUpdateHandler = (update: AcpUpdate) => void;
|
|
47
|
-
/**
|
|
48
|
-
* ACP client over one `kimi acp` child. Created once per driver scope and reused
|
|
49
|
-
* across steps, matching the Pi RPC client's lifecycle.
|
|
50
|
-
*/
|
|
51
|
-
export declare class AcpClient {
|
|
52
|
-
private readonly process;
|
|
53
|
-
private readonly pending;
|
|
54
|
-
private readonly updateBuffer;
|
|
55
|
-
private updateWake;
|
|
56
|
-
private updateHandler;
|
|
57
|
-
private permissionHandler;
|
|
58
|
-
private sealed;
|
|
59
|
-
private nextId;
|
|
60
|
-
private readonly decoder;
|
|
61
|
-
private buffer;
|
|
62
|
-
/** Whether this client was sealed or its process exited. */
|
|
63
|
-
get closed(): boolean;
|
|
64
|
-
/** Mount a client over an already-spawned `kimi acp` process. */
|
|
65
|
-
constructor(process: KimiProcess);
|
|
66
|
-
/**
|
|
67
|
-
* Create a client, spawning the `kimi acp` child through the supplied
|
|
68
|
-
* capability (or the default node spawn when none is given).
|
|
69
|
-
* @param spec - the `kimi acp` argv/cwd/env the child should run with.
|
|
70
|
-
* @param spawn - optional process-spawn capability (the subprocess seam).
|
|
71
|
-
* @returns the connected client.
|
|
72
|
-
*/
|
|
73
|
-
static create(spec: KimiSpawnSpec, spawn?: KimiSpawnCapability): AcpClient;
|
|
74
|
-
/** Register the event dispatch handler. */
|
|
75
|
-
onUpdate(handler: AcpUpdateHandler): void;
|
|
76
|
-
/** Register the permission-approval handler (reverse-RPC answers). */
|
|
77
|
-
onPermission(handler: AcpPermissionHandler): void;
|
|
78
|
-
/** Send one request and await the correlated response. */
|
|
79
|
-
request(method: string, params: unknown): Promise<unknown>;
|
|
80
|
-
/** Send a notification (no correlated response awaited). */
|
|
81
|
-
notify(method: string, params: unknown): void;
|
|
82
|
-
/** Open the protocol handshake. */
|
|
83
|
-
initialize(): Promise<unknown>;
|
|
84
|
-
/** Start a fresh ACP session and resolve to its session id. */
|
|
85
|
-
newSession(cwd: string): Promise<string>;
|
|
86
|
-
/**
|
|
87
|
-
* Select the model for one ACP session. The agent answers with an error frame
|
|
88
|
-
* when it cannot serve the id, and {@link request} rejects on that frame — so
|
|
89
|
-
* an engine that refuses the model fails the step loud rather than silently
|
|
90
|
-
* running its own default.
|
|
91
|
-
* @param sessionId - the ACP session the model applies to.
|
|
92
|
-
* @param modelId - the model id to select.
|
|
93
|
-
* @returns the agent's response to `session/set_model`.
|
|
94
|
-
*/
|
|
95
|
-
setModel(sessionId: string, modelId: string): Promise<unknown>;
|
|
96
|
-
/**
|
|
97
|
-
* Prompt the agent in a session and resolve when the turn completes.
|
|
98
|
-
* @param sessionId - the ACP session to prompt.
|
|
99
|
-
* @param text - the serialized transcript, or a bare slash command.
|
|
100
|
-
* @param images - image blocks to carry after the text block; omitted or
|
|
101
|
-
* empty leaves the request exactly the text-only shape.
|
|
102
|
-
* @returns the agent's response to `session/prompt`.
|
|
103
|
-
*/
|
|
104
|
-
prompt(sessionId: string, text: string, images?: readonly AcpImageContent[]): Promise<unknown>;
|
|
105
|
-
/** Cancel the active turn in a session (fire-and-forget). */
|
|
106
|
-
cancel(sessionId: string): void;
|
|
107
|
-
/**
|
|
108
|
-
* Answer a pending `session/request_permission`.
|
|
109
|
-
* @param id - the reverse-RPC request id.
|
|
110
|
-
* @param response - the ACP outcome to answer with.
|
|
111
|
-
*/
|
|
112
|
-
respondPermission(id: number, response: AcpPermissionResponse): void;
|
|
113
|
-
/** Consume every buffered update as an async generator. */
|
|
114
|
-
updates(): AsyncGenerator<AcpUpdate, void, void>;
|
|
115
|
-
/** Seal the client and request child termination. */
|
|
116
|
-
dispose(): void;
|
|
117
|
-
private feed;
|
|
118
|
-
/** Dispatch one parsed line: a response, an update notification, or a reverse-RPC request. */
|
|
119
|
-
private dispatch;
|
|
120
|
-
private settle;
|
|
121
|
-
private handlePermission;
|
|
122
|
-
}
|
|
123
|
-
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Maps `kimi acp` `session/update` events to dsh session-log projections.
|
|
3
|
-
*
|
|
4
|
-
* Kimi streams incremental assistant text (`agent_message_chunk`), incremental
|
|
5
|
-
* thinking (`agent_thought_chunk`), a tool-call announcement (`tool_call`) and its
|
|
6
|
-
* progress/result updates (`tool_call_update`). Assistant text and thinking are
|
|
7
|
-
* Deltas; a tool update's content is a whole Snapshot that replaces the previous
|
|
8
|
-
* one. A tool call's identity arrives on the announcement but its input
|
|
9
|
-
* (`rawInput`) does not — only a later update carries it. This module is pure: it
|
|
10
|
-
* classifies an update, extracts chunk deltas, and projects the tool-call
|
|
11
|
-
* identity/input/content/result so the agent can fold them into the durable log.
|
|
12
|
-
* Content blocks use the observed kimi
|
|
13
|
-
* `{ type: 'content', content: { type: 'text', text } }` nesting; unknown block
|
|
14
|
-
* types are ignored.
|
|
15
|
-
*
|
|
16
|
-
* @module dsh-loop-engine/engine-kimi/acp/mapping
|
|
17
|
-
*/
|
|
18
|
-
import type { ToolResultMessage } from '@deepseek-ai/dsh-llm';
|
|
19
|
-
import type { AcpContentBlock, AcpToolCallExt, AcpToolCallStreamExt, AcpUpdate } from './types.ts';
|
|
20
|
-
/** Whether the update is an incremental assistant text chunk. */
|
|
21
|
-
export declare function isTextChunk(update: AcpUpdate): update is AcpUpdate & {
|
|
22
|
-
readonly sessionUpdate: 'agent_message_chunk';
|
|
23
|
-
readonly content: AcpContentBlock;
|
|
24
|
-
};
|
|
25
|
-
/** Whether the update is an incremental thinking chunk. */
|
|
26
|
-
export declare function isThoughtChunk(update: AcpUpdate): update is AcpUpdate & {
|
|
27
|
-
readonly sessionUpdate: 'agent_thought_chunk';
|
|
28
|
-
readonly content: AcpContentBlock;
|
|
29
|
-
};
|
|
30
|
-
/** Whether the update announces a tool call. */
|
|
31
|
-
export declare function isToolCall(update: AcpUpdate): update is AcpToolCallExt;
|
|
32
|
-
/** Whether the update streams a tool call's progress/result. */
|
|
33
|
-
export declare function isToolCallUpdate(update: AcpUpdate): update is AcpToolCallStreamExt;
|
|
34
|
-
/** The delta text of a text/thinking chunk. */
|
|
35
|
-
export declare function chunkDelta(update: AcpUpdate): string;
|
|
36
|
-
/** The raw tool-call id (+ content index) as the wire carries it. */
|
|
37
|
-
export declare function toolCallIdOf(update: AcpUpdate): string;
|
|
38
|
-
/** The tool display name (`title`). */
|
|
39
|
-
export declare function toolCallName(update: AcpUpdate): string;
|
|
40
|
-
/**
|
|
41
|
-
* The tool call's real input as the JSON `arguments` string the durable
|
|
42
|
-
* `tool/call` carries, when the frame supplies it.
|
|
43
|
-
*
|
|
44
|
-
* The `tool_call` announcement never carries `rawInput`; a later
|
|
45
|
-
* `tool_call_update` does (measured against kimi 0.28.x: the execution-start
|
|
46
|
-
* frame, `status: 'in_progress'`). A call's arguments are therefore unknowable
|
|
47
|
-
* at announce time, and the driver logs the call only once an update supplies
|
|
48
|
-
* them — or when the call settles, whichever comes first.
|
|
49
|
-
* @param update - one tool-call announcement or update.
|
|
50
|
-
* @returns the arguments string, or `undefined` when the frame omits the field.
|
|
51
|
-
*/
|
|
52
|
-
export declare function toolRawInput(update: AcpToolCallExt | AcpToolCallStreamExt): string | undefined;
|
|
53
|
-
/** Whether a tool stream status is settled (no longer streaming). */
|
|
54
|
-
export declare function isToolSettledStatus(status: string): boolean;
|
|
55
|
-
/** Whether a tool stream status denotes a failure. */
|
|
56
|
-
export declare function isToolErrorStatus(status: string): boolean;
|
|
57
|
-
/**
|
|
58
|
-
* The tool call's content as ONE update carries it: the joined text of its
|
|
59
|
-
* observed `{ type: 'content', content: { type: 'text', text } }` blocks.
|
|
60
|
-
*
|
|
61
|
-
* Kimi re-sends the call's whole content on every `tool_call_update` rather than
|
|
62
|
-
* streaming deltas (measured against 0.28.1: the string grows from the tool
|
|
63
|
-
* input's rendering to the final output), so this is a *snapshot* — callers
|
|
64
|
-
* replace with it, never append. `undefined` means the update carried no
|
|
65
|
-
* content field at all (nothing to replace), which is distinct from a present
|
|
66
|
-
* but empty one.
|
|
67
|
-
* @param update - one tool-call announcement or update.
|
|
68
|
-
* @returns the content snapshot, or `undefined` when the field is absent.
|
|
69
|
-
*/
|
|
70
|
-
export declare function toolContentText(update: AcpToolCallExt | AcpToolCallStreamExt): string | undefined;
|
|
71
|
-
/** Project a completed tool call to a durable tool/result message. */
|
|
72
|
-
export declare function toolResult(callId: string, text: string, isError: boolean): ToolResultMessage;
|
|
73
|
-
//# sourceMappingURL=mapping.d.ts.map
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent Client Protocol (ACP) wire types for the `kimi acp` driver.
|
|
3
|
-
*
|
|
4
|
-
* Kimi exposes the ACP adapter over stdio (JSON-RPC 2.0). The driver speaks a
|
|
5
|
-
* minimal, stable subset that a normal agent flow needs: initialize, session/new,
|
|
6
|
-
* session/prompt, session/cancel, plus the `session/update` notifications carrying
|
|
7
|
-
* incremental assistant text (`agent_message_chunk`), thinking
|
|
8
|
-
* (`agent_thought_chunk`), and tool calls (`tool_call` / `tool_call_update`).
|
|
9
|
-
* Tool-approval arrives as the reverse-RPC `session/request_permission`, which the
|
|
10
|
-
* client must answer. Shapes below are the live-record deltas observed against the
|
|
11
|
-
* 0.28.1 CLI; content blocks re-use a `{ type, text }` text shape (and tolerate
|
|
12
|
-
* other block types by ignoring them). The image block is modelled for the
|
|
13
|
-
* OUTGOING side — the bytes a dsh step delivers as an ACP image block.
|
|
14
|
-
*
|
|
15
|
-
* @module dsh-loop-engine/engine-kimi/acp/types
|
|
16
|
-
*/
|
|
17
|
-
/** A text content block in an ACP update (the observed kimi shape). */
|
|
18
|
-
export interface AcpTextContent {
|
|
19
|
-
readonly type: 'text';
|
|
20
|
-
readonly text: string;
|
|
21
|
-
}
|
|
22
|
-
/** One tool-call content block: the observed kimi `{ type: 'content', content }` nesting. */
|
|
23
|
-
export interface AcpToolContentBlock {
|
|
24
|
-
readonly type: 'content';
|
|
25
|
-
readonly content: AcpTextContent;
|
|
26
|
-
}
|
|
27
|
-
/** An image content block, as ACP/MCP spells it (base64 bytes + media type). */
|
|
28
|
-
export interface AcpImageContent {
|
|
29
|
-
readonly type: 'image';
|
|
30
|
-
/** Base64-encoded image bytes. */
|
|
31
|
-
readonly data: string;
|
|
32
|
-
/** The image's own media type. */
|
|
33
|
-
readonly mimeType: string;
|
|
34
|
-
}
|
|
35
|
-
/** A content block in a chunk/thought update; text is handled, others are ignored. */
|
|
36
|
-
export type AcpContentBlock = AcpTextContent | AcpImageContent | {
|
|
37
|
-
readonly type: 'resource_link' | 'audio' | string;
|
|
38
|
-
readonly [key: string]: unknown;
|
|
39
|
-
};
|
|
40
|
-
/** One `session/update` notification (partial; the discriminator is `sessionUpdate`). */
|
|
41
|
-
export interface AcpUpdate {
|
|
42
|
-
readonly sessionUpdate: string;
|
|
43
|
-
readonly [key: string]: unknown;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* A tool-call announcement (`sessionUpdate: 'tool_call'`).
|
|
47
|
-
*
|
|
48
|
-
* Measured against kimi 0.28.x: an announcement carries the call's identity
|
|
49
|
-
* (`toolCallId`/`title`/`kind`) and an empty content card, but **never** its
|
|
50
|
-
* input — `rawInput` only ever arrives on a later `tool_call_update` (the
|
|
51
|
-
* execution-start frame).
|
|
52
|
-
*/
|
|
53
|
-
export interface AcpToolCallExt extends AcpUpdate {
|
|
54
|
-
readonly sessionUpdate: 'tool_call';
|
|
55
|
-
readonly toolCallId: string;
|
|
56
|
-
readonly title: string;
|
|
57
|
-
readonly kind: string;
|
|
58
|
-
readonly status: string;
|
|
59
|
-
readonly content?: readonly AcpToolContentBlock[];
|
|
60
|
-
/** The call's real input; absent on the announcement (see above). */
|
|
61
|
-
readonly rawInput?: unknown;
|
|
62
|
-
}
|
|
63
|
-
/** A tool-call progress/result stream (`sessionUpdate: 'tool_call_update'`). */
|
|
64
|
-
export interface AcpToolCallStreamExt extends AcpUpdate {
|
|
65
|
-
readonly sessionUpdate: 'tool_call_update';
|
|
66
|
-
readonly toolCallId: string;
|
|
67
|
-
readonly status: string;
|
|
68
|
-
readonly content?: readonly AcpToolContentBlock[];
|
|
69
|
-
/** The call's real input, first present on the execution-start frame. */
|
|
70
|
-
readonly rawInput?: unknown;
|
|
71
|
-
/** The tool's raw structured output, present once the call settles. */
|
|
72
|
-
readonly rawOutput?: unknown;
|
|
73
|
-
}
|
|
74
|
-
/** One option the agent offers for a `session/request_permission`. */
|
|
75
|
-
export interface AcpPermissionOption {
|
|
76
|
-
/** Opaque id the client sends back in `outcome.optionId` (the only field the agent reads). */
|
|
77
|
-
readonly optionId: string;
|
|
78
|
-
/** Human-readable label for the option. */
|
|
79
|
-
readonly name?: string;
|
|
80
|
-
/** Option class: `allow_once` / `allow_always` / `reject_once` / `reject_always`. */
|
|
81
|
-
readonly kind?: string;
|
|
82
|
-
}
|
|
83
|
-
/** The `session/request_permission` reverse-RPC params. */
|
|
84
|
-
export interface AcpPermissionRequest {
|
|
85
|
-
readonly sessionId?: string;
|
|
86
|
-
/** Every option the agent will accept an answer for; empty means no answerable choice. */
|
|
87
|
-
readonly options?: readonly AcpPermissionOption[];
|
|
88
|
-
/** The tool call the prompt belongs to (presentation/correlation only). */
|
|
89
|
-
readonly toolCall?: unknown;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Terminal outcome of a permission request: the option the client picked, or
|
|
93
|
-
* `cancelled` when it had no answer to give.
|
|
94
|
-
*/
|
|
95
|
-
export type AcpPermissionOutcome = {
|
|
96
|
-
readonly outcome: 'selected';
|
|
97
|
-
readonly optionId: string;
|
|
98
|
-
} | {
|
|
99
|
-
readonly outcome: 'cancelled';
|
|
100
|
-
};
|
|
101
|
-
/** The `session/request_permission` result the agent expects (ACP `RequestPermissionResponse`). */
|
|
102
|
-
export interface AcpPermissionResponse {
|
|
103
|
-
readonly outcome: AcpPermissionOutcome;
|
|
104
|
-
}
|
|
105
|
-
/** Result of a completed `session/prompt` request (opaque; the turn ended). */
|
|
106
|
-
export interface AcpPromptResult {
|
|
107
|
-
readonly [key: string]: unknown;
|
|
108
|
-
}
|
|
109
|
-
/** The id-scoped response to a request (result or error). */
|
|
110
|
-
export interface AcpResponse {
|
|
111
|
-
readonly id: number;
|
|
112
|
-
readonly result?: unknown;
|
|
113
|
-
readonly error?: {
|
|
114
|
-
readonly code: number;
|
|
115
|
-
readonly message: string;
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
/** A JSON-RPC request/notification frame on the wire. */
|
|
119
|
-
export interface AcpFrame {
|
|
120
|
-
readonly jsonrpc: '2.0';
|
|
121
|
-
readonly id?: number;
|
|
122
|
-
readonly method?: string;
|
|
123
|
-
readonly params?: unknown;
|
|
124
|
-
readonly result?: unknown;
|
|
125
|
-
readonly error?: {
|
|
126
|
-
readonly code: number;
|
|
127
|
-
readonly message: string;
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
/** Guards toolkit: is the frame a `session/update` notification carrying an update. */
|
|
131
|
-
export declare function isUpdateFrame(frame: AcpFrame): frame is AcpFrame & {
|
|
132
|
-
readonly method: 'session/update';
|
|
133
|
-
readonly params: {
|
|
134
|
-
readonly sessionId: string;
|
|
135
|
-
readonly update: AcpUpdate;
|
|
136
|
-
};
|
|
137
|
-
};
|
|
138
|
-
/** Guards toolkit: is the frame a reverse-RPC request needing an approval answer. */
|
|
139
|
-
export declare function isPermissionRequestFrame(frame: AcpFrame): frame is AcpFrame & {
|
|
140
|
-
readonly id: number;
|
|
141
|
-
readonly method: 'session/request_permission';
|
|
142
|
-
};
|
|
143
|
-
//# sourceMappingURL=types.d.ts.map
|